mirror of
https://github.com/arcan1s/ahriman.git
synced 2025-09-11 11:20:02 +00:00
fix: support provides in aur (#146)
* support provides in aur * process provides during tree resolution * stylish
This commit is contained in:
@ -133,18 +133,18 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
if not process_dependencies or not packages:
|
||||
return packages
|
||||
|
||||
def missing_dependencies(source: Iterable[Package]) -> dict[str, str | None]:
|
||||
def missing_dependencies(sources: Iterable[Package]) -> dict[str, str | None]:
|
||||
# append list of known packages with packages which are in current sources
|
||||
satisfied_packages = known_packages | {
|
||||
single
|
||||
for package in source
|
||||
for single in package.packages_full
|
||||
for source in sources
|
||||
for single in source.packages_full
|
||||
}
|
||||
|
||||
return {
|
||||
dependency: package.packager
|
||||
for package in source
|
||||
for dependency in package.depends_build
|
||||
dependency: source.packager
|
||||
for source in sources
|
||||
for dependency in source.depends_build
|
||||
if dependency not in satisfied_packages
|
||||
}
|
||||
|
||||
@ -156,7 +156,7 @@ class Application(ApplicationPackages, ApplicationRepository):
|
||||
# there is local cache, load package from it
|
||||
leaf = Package.from_build(source_dir, self.repository.architecture, packager)
|
||||
else:
|
||||
leaf = Package.from_aur(package_name, packager)
|
||||
leaf = Package.from_aur(package_name, packager, include_provides=True)
|
||||
portion[leaf.base] = leaf
|
||||
|
||||
# register package in the database
|
||||
|
@ -255,3 +255,19 @@ class Pacman(LazyLogging):
|
||||
result.update(trim_package(provides) for provides in package.provides)
|
||||
|
||||
return result
|
||||
|
||||
def provided_by(self, package_name: str) -> Generator[Package, None, None]:
|
||||
"""
|
||||
search through databases and emit packages which provides the ``package_name``
|
||||
|
||||
Args:
|
||||
package_name(str): package name to search
|
||||
|
||||
Yields:
|
||||
Package: list of packages which were returned by the query
|
||||
"""
|
||||
def is_package_provided(package: Package) -> bool:
|
||||
return package_name in package.provides
|
||||
|
||||
for database in self.handle.get_syncdbs():
|
||||
yield from filter(is_package_provided, database.search(package_name))
|
||||
|
@ -130,15 +130,36 @@ class AUR(Remote):
|
||||
except StopIteration:
|
||||
raise UnknownPackageError(package_name) from None
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
||||
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||
"""
|
||||
get package list which provide the specified package name
|
||||
|
||||
Args:
|
||||
package_name(str): package name to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return [
|
||||
package
|
||||
# search api provides reduced models
|
||||
for stub in self.package_search(package_name, pacman=pacman, search_by="provides")
|
||||
# verity that found package actually provides it
|
||||
if package_name in (package := self.package_info(stub.package_base, pacman=pacman)).provides
|
||||
]
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
Args:
|
||||
*keywords(str): keywords to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
search_by(str | None): search by keywords
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return self.aur_request("search", *keywords, by="name-desc")
|
||||
search_by = search_by or "name-desc"
|
||||
return self.aur_request("search", *keywords, by=search_by)
|
||||
|
@ -127,15 +127,17 @@ class Official(Remote):
|
||||
except StopIteration:
|
||||
raise UnknownPackageError(package_name) from None
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
Args:
|
||||
*keywords(str): keywords to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
search_by(str | None): search by keywords
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return self.arch_request(*keywords, by="q")
|
||||
search_by = search_by or "q"
|
||||
return self.arch_request(*keywords, by=search_by)
|
||||
|
@ -59,3 +59,22 @@ class OfficialSyncdb(Official):
|
||||
return next(AURPackage.from_pacman(package) for package in pacman.package(package_name))
|
||||
except StopIteration:
|
||||
raise UnknownPackageError(package_name) from None
|
||||
|
||||
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||
"""
|
||||
get package list which provide the specified package name
|
||||
|
||||
Args:
|
||||
package_name(str): package name to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
if pacman is None:
|
||||
return []
|
||||
|
||||
return [
|
||||
AURPackage.from_pacman(package)
|
||||
for package in pacman.provided_by(package_name)
|
||||
]
|
||||
|
@ -18,6 +18,7 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.exceptions import UnknownPackageError
|
||||
from ahriman.core.http import SyncHttpClient
|
||||
from ahriman.models.aur_package import AURPackage
|
||||
|
||||
@ -41,22 +42,36 @@ class Remote(SyncHttpClient):
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def info(cls, package_name: str, *, pacman: Pacman | None = None) -> AURPackage:
|
||||
def info(cls, package_name: str, *, pacman: Pacman | None = None, include_provides: bool = False) -> AURPackage:
|
||||
"""
|
||||
get package info by its name
|
||||
get package info by its name. If ``include_provides`` is set to ``True``, then, in addition, this method
|
||||
will perform search by :attr:`ahriman.models.aur_package.AURPackage.provides` and return first package found.
|
||||
Note, however, that in this case some implementation might not provide this method and search result will might
|
||||
not be stable
|
||||
|
||||
Args:
|
||||
package_name(str): package name to search
|
||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||
(Default value = None)
|
||||
include_provides(bool, optional): search by provides if no exact match found (Default value = False)
|
||||
|
||||
Returns:
|
||||
AURPackage: package which match the package name
|
||||
|
||||
Raises:
|
||||
UnknownPackageError: if requested package not found
|
||||
"""
|
||||
return cls().package_info(package_name, pacman=pacman)
|
||||
instance = cls()
|
||||
try:
|
||||
return instance.package_info(package_name, pacman=pacman)
|
||||
except UnknownPackageError:
|
||||
if include_provides and (provided_by := instance.package_provided_by(package_name, pacman=pacman)):
|
||||
return next(iter(provided_by))
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def multisearch(cls, *keywords: str, pacman: Pacman | None = None) -> list[AURPackage]:
|
||||
def multisearch(cls, *keywords: str, pacman: Pacman | None = None,
|
||||
search_by: str | None = None) -> list[AURPackage]:
|
||||
"""
|
||||
search in remote repository by using API with multiple words. This method is required in order to handle
|
||||
https://bugs.archlinux.org/task/49133. In addition, short words will be dropped
|
||||
@ -65,6 +80,7 @@ class Remote(SyncHttpClient):
|
||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||
(Default value = None)
|
||||
search_by(str | None, optional): search by keywords (Default value = None)
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages each of them matches all search terms
|
||||
@ -72,7 +88,7 @@ class Remote(SyncHttpClient):
|
||||
instance = cls()
|
||||
packages: dict[str, AURPackage] = {}
|
||||
for term in filter(lambda word: len(word) >= 3, keywords):
|
||||
portion = instance.search(term, pacman=pacman)
|
||||
portion = instance.package_search(term, pacman=pacman, search_by=search_by)
|
||||
packages = {
|
||||
package.name: package # not mistake to group them by name
|
||||
for package in portion
|
||||
@ -114,7 +130,7 @@ class Remote(SyncHttpClient):
|
||||
raise NotImplementedError
|
||||
|
||||
@classmethod
|
||||
def search(cls, *keywords: str, pacman: Pacman | None = None) -> list[AURPackage]:
|
||||
def search(cls, *keywords: str, pacman: Pacman | None = None, search_by: str | None = None) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
@ -122,11 +138,12 @@ class Remote(SyncHttpClient):
|
||||
*keywords(str): search terms, e.g. "ahriman", "is", "cool"
|
||||
pacman(Pacman | None, optional): alpm wrapper instance, required for official repositories search
|
||||
(Default value = None)
|
||||
search_by(str | None, optional): search by keywords (Default value = None)
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
return cls().package_search(*keywords, pacman=pacman)
|
||||
return cls().package_search(*keywords, pacman=pacman, search_by=search_by)
|
||||
|
||||
def package_info(self, package_name: str, *, pacman: Pacman | None) -> AURPackage:
|
||||
"""
|
||||
@ -144,13 +161,28 @@ class Remote(SyncHttpClient):
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None) -> list[AURPackage]:
|
||||
def package_provided_by(self, package_name: str, *, pacman: Pacman | None) -> list[AURPackage]:
|
||||
"""
|
||||
get package list which provide the specified package name
|
||||
|
||||
Args:
|
||||
package_name(str): package name to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
"""
|
||||
del package_name, pacman
|
||||
return []
|
||||
|
||||
def package_search(self, *keywords: str, pacman: Pacman | None, search_by: str | None) -> list[AURPackage]:
|
||||
"""
|
||||
search package in AUR web
|
||||
|
||||
Args:
|
||||
*keywords(str): keywords to search
|
||||
pacman(Pacman | None): alpm wrapper instance, required for official repositories search
|
||||
search_by(str | None): search by keywords
|
||||
|
||||
Returns:
|
||||
list[AURPackage]: list of packages which match the criteria
|
||||
|
@ -33,6 +33,7 @@ class Leaf:
|
||||
|
||||
Attributes:
|
||||
dependencies(set[str]): list of package dependencies
|
||||
items(list[str]): list of packages in this leaf including provides
|
||||
package(Package): leaf package properties
|
||||
"""
|
||||
|
||||
@ -42,17 +43,9 @@ class Leaf:
|
||||
package(Package): package properties
|
||||
"""
|
||||
self.package = package
|
||||
# store frequently used properties
|
||||
self.dependencies = package.depends_build
|
||||
|
||||
@property
|
||||
def items(self) -> Iterable[str]:
|
||||
"""
|
||||
extract all packages from the leaf
|
||||
|
||||
Returns:
|
||||
Iterable[str]: packages containing in this leaf
|
||||
"""
|
||||
return self.package.packages.keys()
|
||||
self.items = self.package.packages_full
|
||||
|
||||
def is_dependency(self, packages: Iterable[Leaf]) -> bool:
|
||||
"""
|
||||
|
@ -213,18 +213,19 @@ class Package(LazyLogging):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_aur(cls, name: str, packager: str | None = None) -> Self:
|
||||
def from_aur(cls, name: str, packager: str | None = None, *, include_provides: bool = False) -> Self:
|
||||
"""
|
||||
construct package properties from AUR page
|
||||
|
||||
Args:
|
||||
name(str): package name (either base or normal name)
|
||||
packager(str | None, optional): packager to be used for this build (Default value = None)
|
||||
include_provides(bool, optional): search by provides if no exact match found (Default value = False)
|
||||
|
||||
Returns:
|
||||
Self: package properties
|
||||
"""
|
||||
package = AUR.info(name)
|
||||
package = AUR.info(name, include_provides=include_provides)
|
||||
|
||||
remote = RemoteSource(
|
||||
source=PackageSource.AUR,
|
||||
@ -310,7 +311,8 @@ class Package(LazyLogging):
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def from_official(cls, name: str, pacman: Pacman, packager: str | None = None, *, use_syncdb: bool = True) -> Self:
|
||||
def from_official(cls, name: str, pacman: Pacman, packager: str | None = None, *, use_syncdb: bool = True,
|
||||
include_provides: bool = False) -> Self:
|
||||
"""
|
||||
construct package properties from official repository page
|
||||
|
||||
@ -319,11 +321,13 @@ class Package(LazyLogging):
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
packager(str | None, optional): packager to be used for this build (Default value = None)
|
||||
use_syncdb(bool, optional): use pacman databases instead of official repositories RPC (Default value = True)
|
||||
include_provides(bool, optional): search by provides if no exact match found (Default value = False)
|
||||
|
||||
Returns:
|
||||
Self: package properties
|
||||
"""
|
||||
package = OfficialSyncdb.info(name, pacman=pacman) if use_syncdb else Official.info(name)
|
||||
impl = OfficialSyncdb if use_syncdb else Official
|
||||
package = impl.info(name, pacman=pacman, include_provides=include_provides)
|
||||
|
||||
remote = RemoteSource(
|
||||
source=PackageSource.Repository,
|
||||
|
Reference in New Issue
Block a user