mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-03-12 13:03:39 +00:00
refactor: separate package_archives method from trigger
This commit is contained in:
@@ -17,14 +17,10 @@
|
||||
# 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 collections.abc import Callable
|
||||
from functools import cmp_to_key
|
||||
|
||||
from ahriman.core import context
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.core.triggers import Trigger
|
||||
from ahriman.core.utils import package_like
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.repository_id import RepositoryId
|
||||
from ahriman.models.result import Result
|
||||
@@ -78,27 +74,20 @@ class ArchiveRotationTrigger(Trigger):
|
||||
"""
|
||||
return list(cls.CONFIGURATION_SCHEMA.keys())
|
||||
|
||||
def archives_remove(self, package: Package, pacman: Pacman) -> None:
|
||||
def archives_remove(self, package: Package, repository: Repository) -> None:
|
||||
"""
|
||||
remove older versions of the specified package
|
||||
|
||||
Args:
|
||||
package(Package): package which has been updated to check for older versions
|
||||
pacman(Pacman): alpm wrapper instance
|
||||
repository(Repository): repository instance
|
||||
"""
|
||||
# explicit guard to skip process in case if rotation is disabled
|
||||
# this guard is supposed to speedup process
|
||||
if self.keep_built_packages == 0:
|
||||
return
|
||||
|
||||
packages: dict[tuple[str, str], Package] = {}
|
||||
# we can't use here load_archives, because it ignores versions
|
||||
for full_path in filter(package_like, self.paths.archive_for(package.base).iterdir()):
|
||||
local = Package.from_archive(full_path, pacman)
|
||||
packages.setdefault((local.base, local.version), local).packages.update(local.packages)
|
||||
|
||||
comparator: Callable[[Package, Package], int] = lambda left, right: left.vercmp(right.version)
|
||||
to_remove = sorted(packages.values(), key=cmp_to_key(comparator))
|
||||
to_remove = repository.package_archives(package.base)
|
||||
|
||||
for single in to_remove[:-self.keep_built_packages]:
|
||||
self.logger.info("removing version %s of package %s", single.version, single.base)
|
||||
@@ -115,7 +104,7 @@ class ArchiveRotationTrigger(Trigger):
|
||||
packages(list[Package]): list of all available packages
|
||||
"""
|
||||
ctx = context.get()
|
||||
pacman = ctx.get(Pacman)
|
||||
repository = ctx.get(Repository)
|
||||
|
||||
for package in result.success:
|
||||
self.archives_remove(package, pacman)
|
||||
self.archives_remove(package, repository)
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
#
|
||||
import copy
|
||||
|
||||
from collections.abc import Iterable
|
||||
from collections.abc import Callable, Iterable
|
||||
from functools import cmp_to_key
|
||||
from pathlib import Path
|
||||
from tempfile import TemporaryDirectory
|
||||
|
||||
@@ -102,6 +103,27 @@ class PackageInfo(RepositoryProperties):
|
||||
self.logger.exception("could not load package from %s", full_path)
|
||||
return list(result.values())
|
||||
|
||||
def package_archives(self, package_base: str) -> list[Package]:
|
||||
"""
|
||||
load list of packages known for this package base. This method unlike
|
||||
:func:`ahriman.core.repository.package_info.PackageInfo.load_archives` scans archive directory and loads all
|
||||
versions available for the ``package_base``
|
||||
|
||||
Args:
|
||||
package_base(str): package base
|
||||
|
||||
Returns:
|
||||
list[Package]: list of packages belonging to this base, sorted by version by ascension
|
||||
"""
|
||||
packages: dict[tuple[str, str], Package] = {}
|
||||
# we can't use here load_archives, because it ignores versions
|
||||
for full_path in filter(package_like, self.paths.archive_for(package_base).iterdir()):
|
||||
local = Package.from_archive(full_path, self.pacman)
|
||||
packages.setdefault((local.base, local.version), local).packages.update(local.packages)
|
||||
|
||||
comparator: Callable[[Package, Package], int] = lambda left, right: left.vercmp(right.version)
|
||||
return sorted(packages.values(), key=cmp_to_key(comparator))
|
||||
|
||||
def package_changes(self, package: Package, last_commit_sha: str) -> Changes | None:
|
||||
"""
|
||||
extract package change for the package since last commit if available
|
||||
|
||||
@@ -3,12 +3,11 @@ import pytest
|
||||
from dataclasses import replace
|
||||
from pathlib import Path
|
||||
from pytest_mock import MockerFixture
|
||||
from typing import Any
|
||||
from unittest.mock import call as MockCall
|
||||
|
||||
from ahriman.core.alpm.pacman import Pacman
|
||||
from ahriman.core.configuration import Configuration
|
||||
from ahriman.core.housekeeping import ArchiveRotationTrigger
|
||||
from ahriman.core.repository import Repository
|
||||
from ahriman.models.package import Package
|
||||
from ahriman.models.result import Result
|
||||
|
||||
@@ -21,26 +20,24 @@ def test_configuration_sections(configuration: Configuration) -> None:
|
||||
|
||||
|
||||
def test_archives_remove(archive_rotation_trigger: ArchiveRotationTrigger, package_ahriman: Package,
|
||||
pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
repository: Repository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must remove older packages
|
||||
"""
|
||||
def package(version: Any, *args: Any, **kwargs: Any) -> Package:
|
||||
generated = replace(package_ahriman, version=str(version))
|
||||
packages = []
|
||||
for i in range(5):
|
||||
generated = replace(package_ahriman, version=str(i))
|
||||
generated.packages = {
|
||||
key: replace(value, filename=str(version))
|
||||
key: replace(value, filename=str(i))
|
||||
for key, value in generated.packages.items()
|
||||
}
|
||||
return generated
|
||||
packages.append(generated)
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.housekeeping.archive_rotation_trigger.package_like", return_value=True)
|
||||
mocker.patch("ahriman.core.repository.package_info.PackageInfo.package_archives", return_value=packages)
|
||||
mocker.patch("pathlib.Path.glob", return_value=[Path(str(i)) for i in range(5)])
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(str(i)) for i in range(5)])
|
||||
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=package)
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink", autospec=True)
|
||||
|
||||
archive_rotation_trigger.archives_remove(package_ahriman, pacman)
|
||||
archive_rotation_trigger.archives_remove(package_ahriman, repository)
|
||||
unlink_mock.assert_has_calls([
|
||||
MockCall(Path("0")),
|
||||
MockCall(Path("1")),
|
||||
@@ -48,28 +45,15 @@ def test_archives_remove(archive_rotation_trigger: ArchiveRotationTrigger, packa
|
||||
|
||||
|
||||
def test_archives_remove_keep(archive_rotation_trigger: ArchiveRotationTrigger, package_ahriman: Package,
|
||||
pacman: Pacman, mocker: MockerFixture) -> None:
|
||||
repository: Repository, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must keep all packages if set to
|
||||
"""
|
||||
def package(version: Any, *args: Any, **kwargs: Any) -> Package:
|
||||
generated = replace(package_ahriman, version=str(version))
|
||||
generated.packages = {
|
||||
key: replace(value, filename=str(version))
|
||||
for key, value in generated.packages.items()
|
||||
}
|
||||
return generated
|
||||
|
||||
mocker.patch("pathlib.Path.is_dir", return_value=True)
|
||||
mocker.patch("ahriman.core.housekeeping.archive_rotation_trigger.package_like", return_value=True)
|
||||
mocker.patch("pathlib.Path.glob", return_value=[Path(str(i)) for i in range(5)])
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(str(i)) for i in range(5)])
|
||||
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=package)
|
||||
unlink_mock = mocker.patch("pathlib.Path.unlink", autospec=True)
|
||||
archives_mock = mocker.patch("ahriman.core.repository.package_info.PackageInfo.package_archives")
|
||||
|
||||
archive_rotation_trigger.keep_built_packages = 0
|
||||
archive_rotation_trigger.archives_remove(package_ahriman, pacman)
|
||||
unlink_mock.assert_not_called()
|
||||
archive_rotation_trigger.archives_remove(package_ahriman, repository)
|
||||
archives_mock.assert_not_called()
|
||||
|
||||
|
||||
def test_on_result(archive_rotation_trigger: ArchiveRotationTrigger, package_ahriman: Package,
|
||||
|
||||
@@ -91,6 +91,30 @@ def test_load_archives_different_version(package_info: PackageInfo, package_pyth
|
||||
assert packages[0].version == package_python_schedule.version
|
||||
|
||||
|
||||
def test_package_archives(package_info: PackageInfo, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load package archives sorted by version
|
||||
"""
|
||||
from dataclasses import replace
|
||||
from typing import Any
|
||||
|
||||
def package(version: Any, *args: Any, **kwargs: Any) -> Package:
|
||||
generated = replace(package_ahriman, version=str(version))
|
||||
generated.packages = {
|
||||
key: replace(value, filename=str(version))
|
||||
for key, value in generated.packages.items()
|
||||
}
|
||||
return generated
|
||||
|
||||
mocker.patch("ahriman.core.repository.package_info.package_like", return_value=True)
|
||||
mocker.patch("pathlib.Path.iterdir", return_value=[Path(str(i)) for i in range(5)])
|
||||
mocker.patch("ahriman.models.package.Package.from_archive", side_effect=package)
|
||||
|
||||
result = package_info.package_archives(package_ahriman.base)
|
||||
assert len(result) == 5
|
||||
assert [p.version for p in result] == [str(i) for i in range(5)]
|
||||
|
||||
|
||||
def test_package_changes(package_info: PackageInfo, package_ahriman: Package, mocker: MockerFixture) -> None:
|
||||
"""
|
||||
must load package changes
|
||||
|
||||
Reference in New Issue
Block a user