mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-02-24 21:59:48 +00:00
refactor: drop some methods from package class into separated wrappers
This commit is contained in:
@@ -12,6 +12,14 @@ ahriman.core.build\_tools.package\_archive module
|
|||||||
:no-undoc-members:
|
:no-undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
ahriman.core.build\_tools.package\_version module
|
||||||
|
-------------------------------------------------
|
||||||
|
|
||||||
|
.. automodule:: ahriman.core.build_tools.package_version
|
||||||
|
:members:
|
||||||
|
:no-undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
ahriman.core.build\_tools.sources module
|
ahriman.core.build\_tools.sources module
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
|
|||||||
117
src/ahriman/core/build_tools/package_version.py
Normal file
117
src/ahriman/core/build_tools/package_version.py
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
#
|
||||||
|
# Copyright (c) 2021-2026 ahriman team.
|
||||||
|
#
|
||||||
|
# This file is part of ahriman
|
||||||
|
# (see https://github.com/arcan1s/ahriman).
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
from pyalpm import vercmp # type: ignore[import-not-found]
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.task import Task
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.log import LazyLogging
|
||||||
|
from ahriman.core.utils import full_version, utcnow
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild import Pkgbuild
|
||||||
|
|
||||||
|
|
||||||
|
class PackageVersion(LazyLogging):
|
||||||
|
"""
|
||||||
|
package version extractor and helper
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
package(Package): package definitions
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, package: Package) -> None:
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
package(Package): package definitions
|
||||||
|
"""
|
||||||
|
self.package = package
|
||||||
|
|
||||||
|
def actual_version(self, configuration: Configuration) -> str:
|
||||||
|
"""
|
||||||
|
additional method to handle VCS package versions
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: package version if package is not VCS and current version according to VCS otherwise
|
||||||
|
"""
|
||||||
|
if not self.package.is_vcs:
|
||||||
|
return self.package.version
|
||||||
|
|
||||||
|
_, repository_id = configuration.check_loaded()
|
||||||
|
paths = configuration.repository_paths
|
||||||
|
task = Task(self.package, configuration, repository_id.architecture, paths)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# create fresh chroot environment, fetch sources and - automagically - update PKGBUILD
|
||||||
|
task.init(paths.cache_for(self.package.base), [], None)
|
||||||
|
pkgbuild = Pkgbuild.from_file(paths.cache_for(self.package.base) / "PKGBUILD")
|
||||||
|
|
||||||
|
return full_version(pkgbuild.get("epoch"), pkgbuild["pkgver"], pkgbuild["pkgrel"])
|
||||||
|
except Exception:
|
||||||
|
self.logger.exception("cannot determine version of VCS package")
|
||||||
|
finally:
|
||||||
|
# clear log files generated by devtools
|
||||||
|
for log_file in paths.cache_for(self.package.base).glob("*.log"):
|
||||||
|
log_file.unlink()
|
||||||
|
|
||||||
|
return self.package.version
|
||||||
|
|
||||||
|
def is_newer_than(self, timestamp: float | int) -> bool:
|
||||||
|
"""
|
||||||
|
check if package was built after the specified timestamp
|
||||||
|
|
||||||
|
Args:
|
||||||
|
timestamp(float | int): timestamp to check build date against
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` in case if package was built after the specified date and ``False`` otherwise.
|
||||||
|
In case if build date is not set by any of packages, it returns False
|
||||||
|
"""
|
||||||
|
return any(
|
||||||
|
package.build_date > timestamp
|
||||||
|
for package in self.package.packages.values()
|
||||||
|
if package.build_date is not None
|
||||||
|
)
|
||||||
|
|
||||||
|
def is_outdated(self, remote: Package, configuration: Configuration, *,
|
||||||
|
calculate_version: bool = True) -> bool:
|
||||||
|
"""
|
||||||
|
check if package is out-of-dated
|
||||||
|
|
||||||
|
Args:
|
||||||
|
remote(Package): package properties from remote source
|
||||||
|
configuration(Configuration): configuration instance
|
||||||
|
calculate_version(bool, optional): expand version to actual value (by calculating git versions)
|
||||||
|
(Default value = True)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
bool: ``True`` if the package is out-of-dated and ``False`` otherwise
|
||||||
|
"""
|
||||||
|
vcs_allowed_age = configuration.getint("build", "vcs_allowed_age", fallback=0)
|
||||||
|
min_vcs_build_date = utcnow().timestamp() - vcs_allowed_age
|
||||||
|
|
||||||
|
if calculate_version and not self.is_newer_than(min_vcs_build_date):
|
||||||
|
remote_version = PackageVersion(remote).actual_version(configuration)
|
||||||
|
else:
|
||||||
|
remote_version = remote.version
|
||||||
|
|
||||||
|
result: int = vercmp(self.package.version, remote_version)
|
||||||
|
return result < 0
|
||||||
@@ -27,6 +27,7 @@ from ahriman.core.exceptions import CalledProcessError
|
|||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.utils import check_output, utcnow, walk
|
from ahriman.core.utils import check_output, utcnow, walk
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild import Pkgbuild
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
from ahriman.models.remote_source import RemoteSource
|
from ahriman.models.remote_source import RemoteSource
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
@@ -81,7 +82,7 @@ class Sources(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
list[PkgbuildPatch]: generated patch for PKGBUILD architectures if required
|
||||||
"""
|
"""
|
||||||
architectures = Package.supported_architectures(sources_dir)
|
architectures = Pkgbuild.supported_architectures(sources_dir)
|
||||||
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
if "any" in architectures: # makepkg does not like when there is any other arch except for any
|
||||||
return []
|
return []
|
||||||
architectures.add(architecture)
|
architectures.add(architecture)
|
||||||
@@ -161,7 +162,7 @@ class Sources(LazyLogging):
|
|||||||
cwd=sources_dir, logger=instance.logger)
|
cwd=sources_dir, logger=instance.logger)
|
||||||
|
|
||||||
# extract local files...
|
# extract local files...
|
||||||
files = ["PKGBUILD", ".SRCINFO"] + [str(path) for path in Package.local_files(sources_dir)]
|
files = ["PKGBUILD", ".SRCINFO"] + [str(path) for path in Pkgbuild.local_files(sources_dir)]
|
||||||
instance.add(sources_dir, *files)
|
instance.add(sources_dir, *files)
|
||||||
# ...and commit them
|
# ...and commit them
|
||||||
instance.commit(sources_dir)
|
instance.commit(sources_dir)
|
||||||
|
|||||||
@@ -17,10 +17,13 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
import copy
|
||||||
|
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.package_version import PackageVersion
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.repository.repository_properties import RepositoryProperties
|
from ahriman.core.repository.repository_properties import RepositoryProperties
|
||||||
from ahriman.core.utils import package_like
|
from ahriman.core.utils import package_like
|
||||||
@@ -33,6 +36,40 @@ class PackageInfo(RepositoryProperties):
|
|||||||
handler for the package information
|
handler for the package information
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
def full_depends(self, package: Package, packages: Iterable[Package]) -> list[str]:
|
||||||
|
"""
|
||||||
|
generate full dependencies list including transitive dependencies
|
||||||
|
|
||||||
|
Args:
|
||||||
|
package(Package): package to check dependencies for
|
||||||
|
packages(Iterable[Package]): repository package list
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[str]: all dependencies of the package
|
||||||
|
"""
|
||||||
|
dependencies = {}
|
||||||
|
# load own package dependencies
|
||||||
|
for package_base in packages:
|
||||||
|
for name, repo_package in package_base.packages.items():
|
||||||
|
dependencies[name] = repo_package.depends
|
||||||
|
for provides in repo_package.provides:
|
||||||
|
dependencies[provides] = repo_package.depends
|
||||||
|
# load repository dependencies
|
||||||
|
for database in self.pacman.handle.get_syncdbs():
|
||||||
|
for pacman_package in database.pkgcache:
|
||||||
|
dependencies[pacman_package.name] = pacman_package.depends
|
||||||
|
for provides in pacman_package.provides:
|
||||||
|
dependencies[provides] = pacman_package.depends
|
||||||
|
|
||||||
|
result = set(package.depends)
|
||||||
|
current_depends: set[str] = set()
|
||||||
|
while result != current_depends:
|
||||||
|
current_depends = copy.deepcopy(result)
|
||||||
|
for package_name in current_depends:
|
||||||
|
result.update(dependencies.get(package_name, []))
|
||||||
|
|
||||||
|
return sorted(result)
|
||||||
|
|
||||||
def load_archives(self, packages: Iterable[Path]) -> list[Package]:
|
def load_archives(self, packages: Iterable[Path]) -> list[Package]:
|
||||||
"""
|
"""
|
||||||
load packages from list of archives
|
load packages from list of archives
|
||||||
@@ -58,7 +95,7 @@ class PackageInfo(RepositoryProperties):
|
|||||||
# force version to max of them
|
# force version to max of them
|
||||||
self.logger.warning("version of %s differs, found %s and %s",
|
self.logger.warning("version of %s differs, found %s and %s",
|
||||||
current.base, current.version, local.version)
|
current.base, current.version, local.version)
|
||||||
if current.is_outdated(local, self.configuration, calculate_version=False):
|
if PackageVersion(current).is_outdated(local, self.configuration, calculate_version=False):
|
||||||
current.version = local.version
|
current.version = local.version
|
||||||
current.packages.update(local.packages)
|
current.packages.update(local.packages)
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -130,5 +167,5 @@ class PackageInfo(RepositoryProperties):
|
|||||||
return [
|
return [
|
||||||
package
|
package
|
||||||
for package in packages
|
for package in packages
|
||||||
if depends_on.intersection(package.full_depends(self.pacman, packages))
|
if depends_on.intersection(self.full_depends(package, packages))
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#
|
#
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.package_version import PackageVersion
|
||||||
from ahriman.core.build_tools.sources import Sources
|
from ahriman.core.build_tools.sources import Sources
|
||||||
from ahriman.core.exceptions import UnknownPackageError
|
from ahriman.core.exceptions import UnknownPackageError
|
||||||
from ahriman.core.repository.cleaner import Cleaner
|
from ahriman.core.repository.cleaner import Cleaner
|
||||||
@@ -68,7 +69,7 @@ class UpdateHandler(PackageInfo, Cleaner):
|
|||||||
try:
|
try:
|
||||||
remote = load_remote(local)
|
remote = load_remote(local)
|
||||||
|
|
||||||
if local.is_outdated(remote, self.configuration, calculate_version=vcs):
|
if PackageVersion(local).is_outdated(remote, self.configuration, calculate_version=vcs):
|
||||||
self.reporter.set_pending(local.base)
|
self.reporter.set_pending(local.base)
|
||||||
self.event(local.base, EventType.PackageOutdated, "Remote version is newer than local")
|
self.event(local.base, EventType.PackageOutdated, "Remote version is newer than local")
|
||||||
result.append(remote)
|
result.append(remote)
|
||||||
@@ -157,7 +158,7 @@ class UpdateHandler(PackageInfo, Cleaner):
|
|||||||
if local.remote.is_remote:
|
if local.remote.is_remote:
|
||||||
continue # avoid checking AUR packages
|
continue # avoid checking AUR packages
|
||||||
|
|
||||||
if local.is_outdated(remote, self.configuration, calculate_version=vcs):
|
if PackageVersion(local).is_outdated(remote, self.configuration, calculate_version=vcs):
|
||||||
self.reporter.set_pending(local.base)
|
self.reporter.set_pending(local.base)
|
||||||
self.event(local.base, EventType.PackageOutdated, "Locally pulled sources are outdated")
|
self.event(local.base, EventType.PackageOutdated, "Locally pulled sources are outdated")
|
||||||
result.append(remote)
|
result.append(remote)
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ from pwd import getpwuid
|
|||||||
from typing import Any, IO, TypeVar
|
from typing import Any, IO, TypeVar
|
||||||
|
|
||||||
from ahriman.core.exceptions import CalledProcessError, OptionError, UnsafeRunError
|
from ahriman.core.exceptions import CalledProcessError, OptionError, UnsafeRunError
|
||||||
|
from ahriman.core.types import Comparable
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@@ -45,6 +46,7 @@ __all__ = [
|
|||||||
"extract_user",
|
"extract_user",
|
||||||
"filter_json",
|
"filter_json",
|
||||||
"full_version",
|
"full_version",
|
||||||
|
"list_flatmap",
|
||||||
"minmax",
|
"minmax",
|
||||||
"owner",
|
"owner",
|
||||||
"package_like",
|
"package_like",
|
||||||
@@ -62,6 +64,7 @@ __all__ = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
R = TypeVar("R", bound=Comparable)
|
||||||
T = TypeVar("T")
|
T = TypeVar("T")
|
||||||
|
|
||||||
|
|
||||||
@@ -276,6 +279,24 @@ def full_version(epoch: str | int | None, pkgver: str, pkgrel: str) -> str:
|
|||||||
return f"{prefix}{pkgver}-{pkgrel}"
|
return f"{prefix}{pkgver}-{pkgrel}"
|
||||||
|
|
||||||
|
|
||||||
|
def list_flatmap(source: Iterable[T], extractor: Callable[[T], list[R]]) -> list[R]:
|
||||||
|
"""
|
||||||
|
extract elements from list of lists, flatten them and apply ``extractor``
|
||||||
|
|
||||||
|
Args:
|
||||||
|
source(Iterable[T]): source list
|
||||||
|
extractor(Callable[[T], list[R]): property extractor
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list[T]: combined list of unique entries in properties list
|
||||||
|
"""
|
||||||
|
def generator() -> Iterator[R]:
|
||||||
|
for inner in source:
|
||||||
|
yield from extractor(inner)
|
||||||
|
|
||||||
|
return sorted(set(generator()))
|
||||||
|
|
||||||
|
|
||||||
def minmax(source: Iterable[T], *, key: Callable[[T], Any] | None = None) -> tuple[T, T]:
|
def minmax(source: Iterable[T], *, key: Callable[[T], Any] | None = None) -> tuple[T, T]:
|
||||||
"""
|
"""
|
||||||
get min and max value from iterable
|
get min and max value from iterable
|
||||||
|
|||||||
@@ -17,23 +17,18 @@
|
|||||||
# You should have received a copy of the GNU General Public License
|
# You should have received a copy of the GNU General Public License
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
# pylint: disable=too-many-lines,too-many-public-methods
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import copy
|
from collections.abc import Iterable
|
||||||
|
|
||||||
from collections.abc import Callable, Iterable, Iterator
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pyalpm import vercmp # type: ignore[import-not-found]
|
from pyalpm import vercmp # type: ignore[import-not-found]
|
||||||
from typing import Any, Self
|
from typing import Any, Self
|
||||||
from urllib.parse import urlparse
|
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
|
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
|
||||||
from ahriman.core.configuration import Configuration
|
|
||||||
from ahriman.core.log import LazyLogging
|
from ahriman.core.log import LazyLogging
|
||||||
from ahriman.core.utils import dataclass_view, full_version, parse_version, srcinfo_property_list, utcnow
|
from ahriman.core.utils import dataclass_view, full_version, list_flatmap, parse_version, srcinfo_property_list
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
from ahriman.models.package_source import PackageSource
|
from ahriman.models.package_source import PackageSource
|
||||||
from ahriman.models.pkgbuild import Pkgbuild
|
from ahriman.models.pkgbuild import Pkgbuild
|
||||||
@@ -89,7 +84,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of dependencies per each package
|
list[str]: sum of dependencies per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.depends)
|
return list_flatmap(self.packages.values(), lambda package: package.depends)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def depends_build(self) -> set[str]:
|
def depends_build(self) -> set[str]:
|
||||||
@@ -109,7 +104,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of test dependencies per each package
|
list[str]: sum of test dependencies per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.check_depends)
|
return list_flatmap(self.packages.values(), lambda package: package.check_depends)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def depends_make(self) -> list[str]:
|
def depends_make(self) -> list[str]:
|
||||||
@@ -119,7 +114,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of make dependencies per each package
|
list[str]: sum of make dependencies per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.make_depends)
|
return list_flatmap(self.packages.values(), lambda package: package.make_depends)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def depends_opt(self) -> list[str]:
|
def depends_opt(self) -> list[str]:
|
||||||
@@ -129,7 +124,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of optional dependencies per each package
|
list[str]: sum of optional dependencies per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.opt_depends)
|
return list_flatmap(self.packages.values(), lambda package: package.opt_depends)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def groups(self) -> list[str]:
|
def groups(self) -> list[str]:
|
||||||
@@ -139,7 +134,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of groups per each package
|
list[str]: sum of groups per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.groups)
|
return list_flatmap(self.packages.values(), lambda package: package.groups)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_single_package(self) -> bool:
|
def is_single_package(self) -> bool:
|
||||||
@@ -174,7 +169,7 @@ class Package(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[str]: sum of licenses per each package
|
list[str]: sum of licenses per each package
|
||||||
"""
|
"""
|
||||||
return self._package_list_property(lambda package: package.licenses)
|
return list_flatmap(self.packages.values(), lambda package: package.licenses)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def packages_full(self) -> list[str]:
|
def packages_full(self) -> list[str]:
|
||||||
@@ -345,184 +340,6 @@ class Package(LazyLogging):
|
|||||||
packager=packager,
|
packager=packager,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def local_files(path: Path) -> Iterator[Path]:
|
|
||||||
"""
|
|
||||||
extract list of local files
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path(Path): path to package sources directory
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Path: list of paths of files which belong to the package and distributed together with this tarball.
|
|
||||||
All paths are relative to the ``path``
|
|
||||||
|
|
||||||
Raises:
|
|
||||||
PackageInfoError: if there are parsing errors
|
|
||||||
"""
|
|
||||||
pkgbuild = Pkgbuild.from_file(path / "PKGBUILD")
|
|
||||||
# we could use arch property, but for consistency it is better to call special method
|
|
||||||
architectures = Package.supported_architectures(path)
|
|
||||||
|
|
||||||
for architecture in architectures:
|
|
||||||
for source in srcinfo_property_list("source", pkgbuild, {}, architecture=architecture):
|
|
||||||
if "::" in source:
|
|
||||||
_, source = source.split("::", maxsplit=1) # in case if filename is specified, remove it
|
|
||||||
|
|
||||||
if urlparse(source).scheme:
|
|
||||||
# basically file schema should use absolute path which is impossible if we are distributing
|
|
||||||
# files together with PKGBUILD. In this case we are going to skip it also
|
|
||||||
continue
|
|
||||||
|
|
||||||
yield Path(source)
|
|
||||||
|
|
||||||
if (install := pkgbuild.get("install")) is not None:
|
|
||||||
yield Path(install)
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def supported_architectures(path: Path) -> set[str]:
|
|
||||||
"""
|
|
||||||
load supported architectures from package sources
|
|
||||||
|
|
||||||
Args:
|
|
||||||
path(Path): path to package sources directory
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
set[str]: list of package supported architectures
|
|
||||||
"""
|
|
||||||
pkgbuild = Pkgbuild.from_file(path / "PKGBUILD")
|
|
||||||
return set(pkgbuild.get("arch", []))
|
|
||||||
|
|
||||||
def _package_list_property(self, extractor: Callable[[PackageDescription], list[str]]) -> list[str]:
|
|
||||||
"""
|
|
||||||
extract list property from single packages and combine them into one list
|
|
||||||
|
|
||||||
Notes:
|
|
||||||
Basically this method is generic for type of ``list[T]``, but there is no trait ``Comparable`` in default
|
|
||||||
packages, thus we limit this method only to new types
|
|
||||||
|
|
||||||
Args:
|
|
||||||
extractor(Callable[[PackageDescription], list[str]): package property extractor
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[str]: combined list of unique entries in properties list
|
|
||||||
"""
|
|
||||||
def generator() -> Iterator[str]:
|
|
||||||
for package in self.packages.values():
|
|
||||||
yield from extractor(package)
|
|
||||||
|
|
||||||
return sorted(set(generator()))
|
|
||||||
|
|
||||||
def actual_version(self, configuration: Configuration) -> str:
|
|
||||||
"""
|
|
||||||
additional method to handle VCS package versions
|
|
||||||
|
|
||||||
Args:
|
|
||||||
configuration(Configuration): configuration instance
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: package version if package is not VCS and current version according to VCS otherwise
|
|
||||||
"""
|
|
||||||
if not self.is_vcs:
|
|
||||||
return self.version
|
|
||||||
|
|
||||||
from ahriman.core.build_tools.task import Task
|
|
||||||
|
|
||||||
_, repository_id = configuration.check_loaded()
|
|
||||||
paths = configuration.repository_paths
|
|
||||||
task = Task(self, configuration, repository_id.architecture, paths)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# create fresh chroot environment, fetch sources and - automagically - update PKGBUILD
|
|
||||||
task.init(paths.cache_for(self.base), [], None)
|
|
||||||
pkgbuild = Pkgbuild.from_file(paths.cache_for(self.base) / "PKGBUILD")
|
|
||||||
|
|
||||||
return full_version(pkgbuild.get("epoch"), pkgbuild["pkgver"], pkgbuild["pkgrel"])
|
|
||||||
except Exception:
|
|
||||||
self.logger.exception("cannot determine version of VCS package")
|
|
||||||
finally:
|
|
||||||
# clear log files generated by devtools
|
|
||||||
for log_file in paths.cache_for(self.base).glob("*.log"):
|
|
||||||
log_file.unlink()
|
|
||||||
|
|
||||||
return self.version
|
|
||||||
|
|
||||||
def full_depends(self, pacman: Pacman, packages: Iterable[Package]) -> list[str]:
|
|
||||||
"""
|
|
||||||
generate full dependencies list including transitive dependencies
|
|
||||||
|
|
||||||
Args:
|
|
||||||
pacman(Pacman): alpm wrapper instance
|
|
||||||
packages(Iterable[Package]): repository package list
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
list[str]: all dependencies of the package
|
|
||||||
"""
|
|
||||||
dependencies = {}
|
|
||||||
# load own package dependencies
|
|
||||||
for package_base in packages:
|
|
||||||
for name, repo_package in package_base.packages.items():
|
|
||||||
dependencies[name] = repo_package.depends
|
|
||||||
for provides in repo_package.provides:
|
|
||||||
dependencies[provides] = repo_package.depends
|
|
||||||
# load repository dependencies
|
|
||||||
for database in pacman.handle.get_syncdbs():
|
|
||||||
for pacman_package in database.pkgcache:
|
|
||||||
dependencies[pacman_package.name] = pacman_package.depends
|
|
||||||
for provides in pacman_package.provides:
|
|
||||||
dependencies[provides] = pacman_package.depends
|
|
||||||
|
|
||||||
result = set(self.depends)
|
|
||||||
current_depends: set[str] = set()
|
|
||||||
while result != current_depends:
|
|
||||||
current_depends = copy.deepcopy(result)
|
|
||||||
for package in current_depends:
|
|
||||||
result.update(dependencies.get(package, []))
|
|
||||||
|
|
||||||
return sorted(result)
|
|
||||||
|
|
||||||
def is_newer_than(self, timestamp: float | int) -> bool:
|
|
||||||
"""
|
|
||||||
check if package was built after the specified timestamp
|
|
||||||
|
|
||||||
Args:
|
|
||||||
timestamp(float | int): timestamp to check build date against
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: ``True`` in case if package was built after the specified date and ``False`` otherwise.
|
|
||||||
In case if build date is not set by any of packages, it returns False
|
|
||||||
"""
|
|
||||||
return any(
|
|
||||||
package.build_date > timestamp
|
|
||||||
for package in self.packages.values()
|
|
||||||
if package.build_date is not None
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_outdated(self, remote: Package, configuration: Configuration, *,
|
|
||||||
calculate_version: bool = True) -> bool:
|
|
||||||
"""
|
|
||||||
check if package is out-of-dated
|
|
||||||
|
|
||||||
Args:
|
|
||||||
remote(Package): package properties from remote source
|
|
||||||
configuration(Configuration): configuration instance
|
|
||||||
calculate_version(bool, optional): expand version to actual value (by calculating git versions)
|
|
||||||
(Default value = True)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
bool: ``True`` if the package is out-of-dated and ``False`` otherwise
|
|
||||||
"""
|
|
||||||
vcs_allowed_age = configuration.getint("build", "vcs_allowed_age", fallback=0)
|
|
||||||
min_vcs_build_date = utcnow().timestamp() - vcs_allowed_age
|
|
||||||
|
|
||||||
if calculate_version and not self.is_newer_than(min_vcs_build_date):
|
|
||||||
remote_version = remote.actual_version(configuration)
|
|
||||||
else:
|
|
||||||
remote_version = remote.version
|
|
||||||
|
|
||||||
result: int = vercmp(self.version, remote_version)
|
|
||||||
return result < 0
|
|
||||||
|
|
||||||
def next_pkgrel(self, local_version: str | None) -> str | None:
|
def next_pkgrel(self, local_version: str | None) -> str | None:
|
||||||
"""
|
"""
|
||||||
generate next pkgrel variable. The package release will be incremented if ``local_version`` is more or equal to
|
generate next pkgrel variable. The package release will be incremented if ``local_version`` is more or equal to
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ from dataclasses import dataclass
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, ClassVar, IO, Self
|
from typing import Any, ClassVar, IO, Self
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
from ahriman.core.alpm.pkgbuild_parser import PkgbuildParser, PkgbuildToken
|
from ahriman.core.alpm.pkgbuild_parser import PkgbuildParser, PkgbuildToken
|
||||||
|
from ahriman.core.utils import srcinfo_property_list
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
|
||||||
|
|
||||||
@@ -103,6 +105,54 @@ class Pkgbuild(Mapping[str, Any]):
|
|||||||
|
|
||||||
return cls({key: value for key, value in fields.items() if key})
|
return cls({key: value for key, value in fields.items() if key})
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def local_files(path: Path) -> Iterator[Path]:
|
||||||
|
"""
|
||||||
|
extract list of local files
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to package sources directory
|
||||||
|
|
||||||
|
Yields:
|
||||||
|
Path: list of paths of files which belong to the package and distributed together with this tarball.
|
||||||
|
All paths are relative to the ``path``
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
PackageInfoError: if there are parsing errors
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(path / "PKGBUILD")
|
||||||
|
# we could use arch property, but for consistency it is better to call special method
|
||||||
|
architectures = Pkgbuild.supported_architectures(path)
|
||||||
|
|
||||||
|
for architecture in architectures:
|
||||||
|
for source in srcinfo_property_list("source", pkgbuild, {}, architecture=architecture):
|
||||||
|
if "::" in source:
|
||||||
|
_, source = source.split("::", maxsplit=1) # in case if filename is specified, remove it
|
||||||
|
|
||||||
|
if urlparse(source).scheme:
|
||||||
|
# basically file schema should use absolute path which is impossible if we are distributing
|
||||||
|
# files together with PKGBUILD. In this case we are going to skip it also
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield Path(source)
|
||||||
|
|
||||||
|
if (install := pkgbuild.get("install")) is not None:
|
||||||
|
yield Path(install)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def supported_architectures(path: Path) -> set[str]:
|
||||||
|
"""
|
||||||
|
load supported architectures from package sources
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path(Path): path to package sources directory
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
set[str]: list of package supported architectures
|
||||||
|
"""
|
||||||
|
pkgbuild = Pkgbuild.from_file(path / "PKGBUILD")
|
||||||
|
return set(pkgbuild.get("arch", []))
|
||||||
|
|
||||||
def packages(self) -> dict[str, Self]:
|
def packages(self) -> dict[str, Self]:
|
||||||
"""
|
"""
|
||||||
extract properties from internal package functions
|
extract properties from internal package functions
|
||||||
|
|||||||
@@ -352,6 +352,27 @@ def package_python_schedule(
|
|||||||
packages=packages)
|
packages=packages)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def package_tpacpi_bat_git() -> Package:
|
||||||
|
"""
|
||||||
|
git package fixture
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Package: git package test instance
|
||||||
|
"""
|
||||||
|
return Package(
|
||||||
|
base="tpacpi-bat-git",
|
||||||
|
version="3.1.r12.g4959b52-1",
|
||||||
|
remote=RemoteSource(
|
||||||
|
source=PackageSource.AUR,
|
||||||
|
git_url=AUR.remote_git_url("tpacpi-bat-git", "aur"),
|
||||||
|
web_url=AUR.remote_web_url("tpacpi-bat-git"),
|
||||||
|
path=".",
|
||||||
|
branch="master",
|
||||||
|
),
|
||||||
|
packages={"tpacpi-bat-git": PackageDescription()})
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def package_description_ahriman() -> PackageDescription:
|
def package_description_ahriman() -> PackageDescription:
|
||||||
"""
|
"""
|
||||||
|
|||||||
111
tests/ahriman/core/build_tools/test_package_version.py
Normal file
111
tests/ahriman/core/build_tools/test_package_version.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
from pytest_mock import MockerFixture
|
||||||
|
|
||||||
|
from ahriman.core.build_tools.package_version import PackageVersion
|
||||||
|
from ahriman.core.configuration import Configuration
|
||||||
|
from ahriman.core.utils import utcnow
|
||||||
|
from ahriman.models.package import Package
|
||||||
|
from ahriman.models.pkgbuild import Pkgbuild
|
||||||
|
|
||||||
|
|
||||||
|
def test_actual_version(package_ahriman: Package, configuration: Configuration) -> None:
|
||||||
|
"""
|
||||||
|
must return same actual_version as version is
|
||||||
|
"""
|
||||||
|
assert PackageVersion(package_ahriman).actual_version(configuration) == package_ahriman.version
|
||||||
|
|
||||||
|
|
||||||
|
def test_actual_version_vcs(package_tpacpi_bat_git: Package, configuration: Configuration,
|
||||||
|
mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must return valid actual_version for VCS package
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild"
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
||||||
|
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
||||||
|
init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init")
|
||||||
|
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||||
|
|
||||||
|
assert PackageVersion(package_tpacpi_bat_git).actual_version(configuration) == "3.1.r13.g4959b52-1"
|
||||||
|
init_mock.assert_called_once_with(configuration.repository_paths.cache_for(package_tpacpi_bat_git.base), [], None)
|
||||||
|
unlink_mock.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
def test_actual_version_failed(package_tpacpi_bat_git: Package, configuration: Configuration,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must return same version in case if exception occurred
|
||||||
|
"""
|
||||||
|
mocker.patch("ahriman.core.build_tools.task.Task.init", side_effect=Exception)
|
||||||
|
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
||||||
|
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
||||||
|
|
||||||
|
assert PackageVersion(package_tpacpi_bat_git).actual_version(configuration) == package_tpacpi_bat_git.version
|
||||||
|
unlink_mock.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_newer_than(package_ahriman: Package, package_python_schedule: Package) -> None:
|
||||||
|
"""
|
||||||
|
must correctly check if package is newer than specified timestamp
|
||||||
|
"""
|
||||||
|
# base checks, true/false
|
||||||
|
older = package_ahriman.packages[package_ahriman.base].build_date - 1
|
||||||
|
assert PackageVersion(package_ahriman).is_newer_than(older)
|
||||||
|
|
||||||
|
newer = package_ahriman.packages[package_ahriman.base].build_date + 1
|
||||||
|
assert not PackageVersion(package_ahriman).is_newer_than(newer)
|
||||||
|
|
||||||
|
# list check
|
||||||
|
min_date = min(package.build_date for package in package_python_schedule.packages.values())
|
||||||
|
assert PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||||
|
|
||||||
|
# null list check
|
||||||
|
package_python_schedule.packages["python-schedule"].build_date = None
|
||||||
|
assert PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||||
|
|
||||||
|
package_python_schedule.packages["python2-schedule"].build_date = None
|
||||||
|
assert not PackageVersion(package_python_schedule).is_newer_than(min_date)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_outdated_false(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must be not outdated for the same package
|
||||||
|
"""
|
||||||
|
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version",
|
||||||
|
return_value=package_ahriman.version)
|
||||||
|
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration)
|
||||||
|
actual_version_mock.assert_called_once_with(configuration)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_outdated_true(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must be outdated for the new version
|
||||||
|
"""
|
||||||
|
other = Package.from_json(package_ahriman.view())
|
||||||
|
other.version = other.version.replace("-1", "-2")
|
||||||
|
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version",
|
||||||
|
return_value=other.version)
|
||||||
|
|
||||||
|
assert PackageVersion(package_ahriman).is_outdated(other, configuration)
|
||||||
|
actual_version_mock.assert_called_once_with(configuration)
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_outdated_no_version_calculation(package_ahriman: Package, configuration: Configuration,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must not call actual version if calculation is disabled
|
||||||
|
"""
|
||||||
|
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version")
|
||||||
|
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration, calculate_version=False)
|
||||||
|
actual_version_mock.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
|
def test_is_outdated_fresh_package(package_ahriman: Package, configuration: Configuration,
|
||||||
|
mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must not call actual version if package is never than specified time
|
||||||
|
"""
|
||||||
|
configuration.set_option("build", "vcs_allowed_age", str(int(utcnow().timestamp())))
|
||||||
|
actual_version_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.actual_version")
|
||||||
|
assert not PackageVersion(package_ahriman).is_outdated(package_ahriman, configuration)
|
||||||
|
actual_version_mock.assert_not_called()
|
||||||
@@ -55,7 +55,8 @@ def test_extend_architectures(mocker: MockerFixture) -> None:
|
|||||||
must update available architecture list
|
must update available architecture list
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||||
architectures_mock = mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"x86_64"})
|
architectures_mock = mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures",
|
||||||
|
return_value={"x86_64"})
|
||||||
|
|
||||||
assert Sources.extend_architectures(Path("local"), "i686") == [PkgbuildPatch("arch", list({"x86_64", "i686"}))]
|
assert Sources.extend_architectures(Path("local"), "i686") == [PkgbuildPatch("arch", list({"x86_64", "i686"}))]
|
||||||
architectures_mock.assert_called_once_with(Path("local"))
|
architectures_mock.assert_called_once_with(Path("local"))
|
||||||
@@ -66,7 +67,7 @@ def test_extend_architectures_any(mocker: MockerFixture) -> None:
|
|||||||
must skip architecture patching in case if there is any architecture
|
must skip architecture patching in case if there is any architecture
|
||||||
"""
|
"""
|
||||||
mocker.patch("pathlib.Path.is_file", return_value=True)
|
mocker.patch("pathlib.Path.is_file", return_value=True)
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value={"any"})
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value={"any"})
|
||||||
assert Sources.extend_architectures(Path("local"), "i686") == []
|
assert Sources.extend_architectures(Path("local"), "i686") == []
|
||||||
|
|
||||||
|
|
||||||
@@ -191,7 +192,7 @@ def test_init(sources: Sources, mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must create empty repository at the specified path
|
must create empty repository at the specified path
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.local_files", return_value=[Path("local")])
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
mocker.patch("pathlib.Path.is_dir", return_value=False)
|
||||||
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
add_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.check_output")
|
||||||
@@ -209,7 +210,7 @@ def test_init_skip(mocker: MockerFixture) -> None:
|
|||||||
"""
|
"""
|
||||||
must skip git init if it was already
|
must skip git init if it was already
|
||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.models.package.Package.local_files", return_value=[Path("local")])
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.local_files", return_value=[Path("local")])
|
||||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.add")
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.commit")
|
||||||
|
|||||||
@@ -2,12 +2,32 @@ import pytest
|
|||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from pytest_mock import MockerFixture
|
from pytest_mock import MockerFixture
|
||||||
|
from unittest.mock import MagicMock
|
||||||
|
|
||||||
from ahriman.core.repository.package_info import PackageInfo
|
from ahriman.core.repository.package_info import PackageInfo
|
||||||
from ahriman.models.changes import Changes
|
from ahriman.models.changes import Changes
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
|
|
||||||
|
|
||||||
|
def test_full_depends(package_info: PackageInfo, package_ahriman: Package, package_python_schedule: Package,
|
||||||
|
pyalpm_package_ahriman: MagicMock) -> None:
|
||||||
|
"""
|
||||||
|
must extract all dependencies from the package
|
||||||
|
"""
|
||||||
|
package_python_schedule.packages[package_python_schedule.base].provides = ["python3-schedule"]
|
||||||
|
|
||||||
|
database_mock = MagicMock()
|
||||||
|
database_mock.pkgcache = [pyalpm_package_ahriman]
|
||||||
|
package_info.pacman = MagicMock()
|
||||||
|
package_info.pacman.handle.get_syncdbs.return_value = [database_mock]
|
||||||
|
|
||||||
|
assert package_info.full_depends(package_ahriman, [package_python_schedule]) == package_ahriman.depends
|
||||||
|
|
||||||
|
package_python_schedule.packages[package_python_schedule.base].depends = [package_ahriman.base]
|
||||||
|
expected = sorted(set(package_python_schedule.depends + package_ahriman.depends))
|
||||||
|
assert package_info.full_depends(package_python_schedule, [package_python_schedule]) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_load_archives(package_ahriman: Package, package_python_schedule: Package,
|
def test_load_archives(package_ahriman: Package, package_python_schedule: Package,
|
||||||
package_info: PackageInfo, mocker: MockerFixture) -> None:
|
package_info: PackageInfo, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ def test_updates_aur(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
||||||
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
||||||
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
package_is_outdated_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated",
|
||||||
|
return_value=True)
|
||||||
|
|
||||||
assert update_handler.updates_aur([], vcs=True) == [package_ahriman]
|
assert update_handler.updates_aur([], vcs=True) == [package_ahriman]
|
||||||
packages_mock.assert_called_once_with([])
|
packages_mock.assert_called_once_with([])
|
||||||
@@ -43,7 +44,7 @@ def test_updates_aur_official(update_handler: UpdateHandler, package_ahriman: Pa
|
|||||||
"""
|
"""
|
||||||
package_ahriman.remote = RemoteSource(source=PackageSource.Repository)
|
package_ahriman.remote = RemoteSource(source=PackageSource.Repository)
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=True)
|
||||||
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_official", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
||||||
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
||||||
@@ -74,7 +75,7 @@ def test_updates_aur_up_to_date(update_handler: UpdateHandler, package_ahriman:
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=False)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_status_update")
|
status_client_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_status_update")
|
||||||
|
|
||||||
assert update_handler.updates_aur([], vcs=True) == []
|
assert update_handler.updates_aur([], vcs=True) == []
|
||||||
@@ -100,7 +101,7 @@ def test_updates_aur_filter(update_handler: UpdateHandler, package_ahriman: Pack
|
|||||||
"""
|
"""
|
||||||
packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
packages_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
||||||
return_value=[package_ahriman])
|
return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=True)
|
||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
|
|
||||||
assert update_handler.updates_aur([package_ahriman.base], vcs=True) == [package_ahriman]
|
assert update_handler.updates_aur([package_ahriman.base], vcs=True) == [package_ahriman]
|
||||||
@@ -129,7 +130,8 @@ def test_updates_aur_ignore_vcs(update_handler: UpdateHandler, package_ahriman:
|
|||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
|
||||||
mocker.patch("ahriman.models.package.Package.is_vcs", return_value=True)
|
mocker.patch("ahriman.models.package.Package.is_vcs", return_value=True)
|
||||||
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
package_is_outdated_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated",
|
||||||
|
return_value=False)
|
||||||
|
|
||||||
assert not update_handler.updates_aur([], vcs=False)
|
assert not update_handler.updates_aur([], vcs=False)
|
||||||
package_is_outdated_mock.assert_called_once_with(
|
package_is_outdated_mock.assert_called_once_with(
|
||||||
@@ -150,7 +152,7 @@ def test_updates_aur_load_by_package(update_handler: UpdateHandler, package_pyth
|
|||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages",
|
||||||
return_value=[package_python_schedule])
|
return_value=[package_python_schedule])
|
||||||
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=package_selector)
|
mocker.patch("ahriman.models.package.Package.from_aur", side_effect=package_selector)
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=True)
|
||||||
assert update_handler.updates_aur([], vcs=True) == [package_python_schedule]
|
assert update_handler.updates_aur([], vcs=True) == [package_python_schedule]
|
||||||
|
|
||||||
|
|
||||||
@@ -232,7 +234,8 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package,
|
|||||||
package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
status_client_mock = mocker.patch("ahriman.core.status.Client.set_pending")
|
||||||
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
event_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.event")
|
||||||
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
package_is_outdated_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated",
|
||||||
|
return_value=True)
|
||||||
|
|
||||||
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
assert update_handler.updates_local(vcs=True) == [package_ahriman]
|
||||||
fetch_mock.assert_called_once_with(Path(package_ahriman.base), pytest.helpers.anyvar(int))
|
fetch_mock.assert_called_once_with(Path(package_ahriman.base), pytest.helpers.anyvar(int))
|
||||||
@@ -255,7 +258,8 @@ def test_updates_local_ignore_vcs(update_handler: UpdateHandler, package_ahriman
|
|||||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
|
package_is_outdated_mock = mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated",
|
||||||
|
return_value=False)
|
||||||
|
|
||||||
assert not update_handler.updates_local(vcs=False)
|
assert not update_handler.updates_local(vcs=False)
|
||||||
package_is_outdated_mock.assert_called_once_with(
|
package_is_outdated_mock.assert_called_once_with(
|
||||||
@@ -269,7 +273,7 @@ def test_updates_local_unknown(update_handler: UpdateHandler, package_ahriman: P
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])
|
||||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=True)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
|
|
||||||
@@ -282,7 +286,7 @@ def test_updates_local_remote(update_handler: UpdateHandler, package_ahriman: Pa
|
|||||||
"""
|
"""
|
||||||
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
|
||||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
|
||||||
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
|
mocker.patch("ahriman.core.build_tools.package_version.PackageVersion.is_outdated", return_value=True)
|
||||||
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
|
||||||
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
|
||||||
|
|
||||||
|
|||||||
@@ -265,6 +265,15 @@ def test_full_version() -> None:
|
|||||||
assert full_version(1, "0.12.1", "1") == "1:0.12.1-1"
|
assert full_version(1, "0.12.1", "1") == "1:0.12.1-1"
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_flatmap() -> None:
|
||||||
|
"""
|
||||||
|
must flat map iterable correctly
|
||||||
|
"""
|
||||||
|
assert list_flatmap([], lambda e: [e * 2]) == []
|
||||||
|
assert list_flatmap([3, 1, 2], lambda e: [e * 2]) == [2, 4, 6]
|
||||||
|
assert list_flatmap([1, 2, 1], lambda e: [e * 2]) == [2, 4]
|
||||||
|
|
||||||
|
|
||||||
def test_minmax() -> None:
|
def test_minmax() -> None:
|
||||||
"""
|
"""
|
||||||
must correctly define minimal and maximal value
|
must correctly define minimal and maximal value
|
||||||
|
|||||||
@@ -78,27 +78,6 @@ def internal_status(counters: Counters) -> InternalStatus:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def package_tpacpi_bat_git() -> Package:
|
|
||||||
"""
|
|
||||||
git package fixture
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Package: git package test instance
|
|
||||||
"""
|
|
||||||
return Package(
|
|
||||||
base="tpacpi-bat-git",
|
|
||||||
version="3.1.r12.g4959b52-1",
|
|
||||||
remote=RemoteSource(
|
|
||||||
source=PackageSource.AUR,
|
|
||||||
git_url=AUR.remote_git_url("tpacpi-bat-git", "aur"),
|
|
||||||
web_url=AUR.remote_web_url("tpacpi-bat-git"),
|
|
||||||
path=".",
|
|
||||||
branch="master",
|
|
||||||
),
|
|
||||||
packages={"tpacpi-bat-git": PackageDescription()})
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def pkgbuild_ahriman(resource_path_root: Path) -> Pkgbuild:
|
def pkgbuild_ahriman(resource_path_root: Path) -> Pkgbuild:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -5,13 +5,10 @@ from pytest_mock import MockerFixture
|
|||||||
from unittest.mock import MagicMock, PropertyMock, call as MockCall
|
from unittest.mock import MagicMock, PropertyMock, call as MockCall
|
||||||
|
|
||||||
from ahriman.core.alpm.pacman import Pacman
|
from ahriman.core.alpm.pacman import Pacman
|
||||||
from ahriman.core.configuration import Configuration
|
|
||||||
from ahriman.core.utils import utcnow
|
|
||||||
from ahriman.models.aur_package import AURPackage
|
from ahriman.models.aur_package import AURPackage
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.package_description import PackageDescription
|
from ahriman.models.package_description import PackageDescription
|
||||||
from ahriman.models.pkgbuild import Pkgbuild
|
from ahriman.models.pkgbuild import Pkgbuild
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
|
||||||
|
|
||||||
|
|
||||||
def test_depends(package_python_schedule: Package) -> None:
|
def test_depends(package_python_schedule: Package) -> None:
|
||||||
@@ -322,183 +319,6 @@ def test_from_official(package_ahriman: Package, aur_package_ahriman: AURPackage
|
|||||||
assert package_ahriman.packager == package.packager
|
assert package_ahriman.packager == package.packager
|
||||||
|
|
||||||
|
|
||||||
def test_local_files(mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must extract local file sources
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
|
||||||
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
|
||||||
parsed_pkgbuild.fields["source"] = PkgbuildPatch("source", ["local-file.tar.gz"])
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
|
|
||||||
|
|
||||||
assert list(Package.local_files(Path("path"))) == [Path("local-file.tar.gz")]
|
|
||||||
|
|
||||||
|
|
||||||
def test_local_files_empty(mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must extract empty local files list when there are no local files
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
|
|
||||||
|
|
||||||
assert not list(Package.local_files(Path("path")))
|
|
||||||
|
|
||||||
|
|
||||||
def test_local_files_schema(mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must skip local file source when file schema is used
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
|
||||||
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
|
||||||
parsed_pkgbuild.fields["source"] = PkgbuildPatch("source", ["file:///local-file.tar.gz"])
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
|
|
||||||
|
|
||||||
assert not list(Package.local_files(Path("path")))
|
|
||||||
|
|
||||||
|
|
||||||
def test_local_files_with_install(mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must extract local file sources with install file
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
|
||||||
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
|
||||||
parsed_pkgbuild.fields["install"] = PkgbuildPatch("install", "install")
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
|
||||||
mocker.patch("ahriman.models.package.Package.supported_architectures", return_value=["any"])
|
|
||||||
|
|
||||||
assert list(Package.local_files(Path("path"))) == [Path("install")]
|
|
||||||
|
|
||||||
|
|
||||||
def test_supported_architectures(mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must generate list of available architectures
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
|
||||||
assert Package.supported_architectures(Path("path")) == \
|
|
||||||
{"i686", "pentium4", "x86_64", "arm", "armv7h", "armv6h", "aarch64", "riscv64"}
|
|
||||||
|
|
||||||
|
|
||||||
def test_actual_version(package_ahriman: Package, configuration: Configuration) -> None:
|
|
||||||
"""
|
|
||||||
must return same actual_version as version is
|
|
||||||
"""
|
|
||||||
assert package_ahriman.actual_version(configuration) == package_ahriman.version
|
|
||||||
|
|
||||||
|
|
||||||
def test_actual_version_vcs(package_tpacpi_bat_git: Package, configuration: Configuration,
|
|
||||||
mocker: MockerFixture, resource_path_root: Path) -> None:
|
|
||||||
"""
|
|
||||||
must return valid actual_version for VCS package
|
|
||||||
"""
|
|
||||||
pkgbuild = resource_path_root / "models" / "package_tpacpi-bat-git_pkgbuild"
|
|
||||||
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
|
||||||
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
|
||||||
init_mock = mocker.patch("ahriman.core.build_tools.task.Task.init")
|
|
||||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
|
||||||
|
|
||||||
assert package_tpacpi_bat_git.actual_version(configuration) == "3.1.r13.g4959b52-1"
|
|
||||||
init_mock.assert_called_once_with(configuration.repository_paths.cache_for(package_tpacpi_bat_git.base), [], None)
|
|
||||||
unlink_mock.assert_called_once_with()
|
|
||||||
|
|
||||||
|
|
||||||
def test_actual_version_failed(package_tpacpi_bat_git: Package, configuration: Configuration,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must return same version in case if exception occurred
|
|
||||||
"""
|
|
||||||
mocker.patch("ahriman.core.build_tools.task.Task.init", side_effect=Exception)
|
|
||||||
mocker.patch("pathlib.Path.glob", return_value=[Path("local")])
|
|
||||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
|
||||||
|
|
||||||
assert package_tpacpi_bat_git.actual_version(configuration) == package_tpacpi_bat_git.version
|
|
||||||
unlink_mock.assert_called_once_with()
|
|
||||||
|
|
||||||
|
|
||||||
def test_full_depends(package_ahriman: Package, package_python_schedule: Package, pyalpm_package_ahriman: MagicMock,
|
|
||||||
pyalpm_handle: MagicMock) -> None:
|
|
||||||
"""
|
|
||||||
must extract all dependencies from the package
|
|
||||||
"""
|
|
||||||
package_python_schedule.packages[package_python_schedule.base].provides = ["python3-schedule"]
|
|
||||||
|
|
||||||
database_mock = MagicMock()
|
|
||||||
database_mock.pkgcache = [pyalpm_package_ahriman]
|
|
||||||
pyalpm_handle.handle.get_syncdbs.return_value = [database_mock]
|
|
||||||
|
|
||||||
assert package_ahriman.full_depends(pyalpm_handle, [package_python_schedule]) == package_ahriman.depends
|
|
||||||
|
|
||||||
package_python_schedule.packages[package_python_schedule.base].depends = [package_ahriman.base]
|
|
||||||
expected = sorted(set(package_python_schedule.depends + package_ahriman.depends))
|
|
||||||
assert package_python_schedule.full_depends(pyalpm_handle, [package_python_schedule]) == expected
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_newer_than(package_ahriman: Package, package_python_schedule: Package) -> None:
|
|
||||||
"""
|
|
||||||
must correctly check if package is newer than specified timestamp
|
|
||||||
"""
|
|
||||||
# base checks, true/false
|
|
||||||
assert package_ahriman.is_newer_than(package_ahriman.packages[package_ahriman.base].build_date - 1)
|
|
||||||
assert not package_ahriman.is_newer_than(package_ahriman.packages[package_ahriman.base].build_date + 1)
|
|
||||||
|
|
||||||
# list check
|
|
||||||
min_date = min(package.build_date for package in package_python_schedule.packages.values())
|
|
||||||
assert package_python_schedule.is_newer_than(min_date)
|
|
||||||
|
|
||||||
# null list check
|
|
||||||
package_python_schedule.packages["python-schedule"].build_date = None
|
|
||||||
assert package_python_schedule.is_newer_than(min_date)
|
|
||||||
|
|
||||||
package_python_schedule.packages["python2-schedule"].build_date = None
|
|
||||||
assert not package_python_schedule.is_newer_than(min_date)
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_outdated_false(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must be not outdated for the same package
|
|
||||||
"""
|
|
||||||
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version",
|
|
||||||
return_value=package_ahriman.version)
|
|
||||||
assert not package_ahriman.is_outdated(package_ahriman, configuration)
|
|
||||||
actual_version_mock.assert_called_once_with(configuration)
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_outdated_true(package_ahriman: Package, configuration: Configuration, mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must be outdated for the new version
|
|
||||||
"""
|
|
||||||
other = Package.from_json(package_ahriman.view())
|
|
||||||
other.version = other.version.replace("-1", "-2")
|
|
||||||
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version", return_value=other.version)
|
|
||||||
|
|
||||||
assert package_ahriman.is_outdated(other, configuration)
|
|
||||||
actual_version_mock.assert_called_once_with(configuration)
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_outdated_no_version_calculation(package_ahriman: Package, configuration: Configuration,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must not call actual version if calculation is disabled
|
|
||||||
"""
|
|
||||||
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version")
|
|
||||||
assert not package_ahriman.is_outdated(package_ahriman, configuration, calculate_version=False)
|
|
||||||
actual_version_mock.assert_not_called()
|
|
||||||
|
|
||||||
|
|
||||||
def test_is_outdated_fresh_package(package_ahriman: Package, configuration: Configuration,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must not call actual version if package is never than specified time
|
|
||||||
"""
|
|
||||||
configuration.set_option("build", "vcs_allowed_age", str(int(utcnow().timestamp())))
|
|
||||||
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version")
|
|
||||||
assert not package_ahriman.is_outdated(package_ahriman, configuration)
|
|
||||||
actual_version_mock.assert_not_called()
|
|
||||||
|
|
||||||
|
|
||||||
def test_next_pkgrel(package_ahriman: Package) -> None:
|
def test_next_pkgrel(package_ahriman: Package) -> None:
|
||||||
"""
|
"""
|
||||||
must correctly bump pkgrel
|
must correctly bump pkgrel
|
||||||
|
|||||||
@@ -78,6 +78,66 @@ def test_from_io_empty(pkgbuild_ahriman: Pkgbuild, mocker: MockerFixture) -> Non
|
|||||||
assert Pkgbuild.from_io(StringIO("mock")) == pkgbuild_ahriman
|
assert Pkgbuild.from_io(StringIO("mock")) == pkgbuild_ahriman
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_files(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must extract local file sources
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
||||||
|
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
||||||
|
parsed_pkgbuild.fields["source"] = PkgbuildPatch("source", ["local-file.tar.gz"])
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value=["any"])
|
||||||
|
|
||||||
|
assert list(Pkgbuild.local_files(Path("path"))) == [Path("local-file.tar.gz")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_files_empty(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must extract empty local files list when there are no local files
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value=["any"])
|
||||||
|
|
||||||
|
assert not list(Pkgbuild.local_files(Path("path")))
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_files_schema(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must skip local file source when file schema is used
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
||||||
|
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
||||||
|
parsed_pkgbuild.fields["source"] = PkgbuildPatch("source", ["file:///local-file.tar.gz"])
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value=["any"])
|
||||||
|
|
||||||
|
assert not list(Pkgbuild.local_files(Path("path")))
|
||||||
|
|
||||||
|
|
||||||
|
def test_local_files_with_install(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must extract local file sources with install file
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
||||||
|
parsed_pkgbuild = Pkgbuild.from_file(pkgbuild)
|
||||||
|
parsed_pkgbuild.fields["install"] = PkgbuildPatch("install", "install")
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=parsed_pkgbuild)
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.supported_architectures", return_value=["any"])
|
||||||
|
|
||||||
|
assert list(Pkgbuild.local_files(Path("path"))) == [Path("install")]
|
||||||
|
|
||||||
|
|
||||||
|
def test_supported_architectures(mocker: MockerFixture, resource_path_root: Path) -> None:
|
||||||
|
"""
|
||||||
|
must generate list of available architectures
|
||||||
|
"""
|
||||||
|
pkgbuild = resource_path_root / "models" / "package_yay_pkgbuild"
|
||||||
|
mocker.patch("ahriman.models.pkgbuild.Pkgbuild.from_file", return_value=Pkgbuild.from_file(pkgbuild))
|
||||||
|
assert Pkgbuild.supported_architectures(Path("path")) == \
|
||||||
|
{"i686", "pentium4", "x86_64", "arm", "armv7h", "armv6h", "aarch64", "riscv64"}
|
||||||
|
|
||||||
|
|
||||||
def test_packages(pkgbuild_ahriman: Pkgbuild) -> None:
|
def test_packages(pkgbuild_ahriman: Pkgbuild) -> None:
|
||||||
"""
|
"""
|
||||||
must correctly load package function
|
must correctly load package function
|
||||||
|
|||||||
Reference in New Issue
Block a user