update dependencies before build (#91)

Old implementation has used add step in order to fetch dependencies,
which could lead to build errors in case if dependency list was updated.

New solution uses dependencies which are declared at current version and
fetch them (if required and if enabled) before update process.

Closes #90
This commit is contained in:
2023-02-12 05:02:30 +02:00
committed by GitHub
parent 19bb19e9f5
commit 37e57c13c8
12 changed files with 159 additions and 125 deletions

View File

@ -1,4 +1,5 @@
from pytest_mock import MockerFixture
from unittest.mock import MagicMock, call as MockCall
from ahriman.application.application import Application
from ahriman.models.package import Package
@ -44,3 +45,55 @@ def test_on_stop(application: Application, mocker: MockerFixture) -> None:
application.on_stop()
triggers_mock.assert_called_once_with()
def test_with_dependencies(application: Application, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must append list of missing dependencies
"""
def create_package_mock(package_base) -> MagicMock:
mock = MagicMock()
mock.base = package_base
mock.depends_build = []
mock.packages_full = [package_base]
return mock
package_python_schedule.packages = {
package_python_schedule.base: package_python_schedule.packages[package_python_schedule.base]
}
package_ahriman.packages[package_ahriman.base].depends = ["devtools", "python", package_python_schedule.base]
package_ahriman.packages[package_ahriman.base].make_depends = ["python-build", "python-installer"]
packages = {
package_ahriman.base: package_ahriman,
package_python_schedule.base: package_python_schedule,
"python": create_package_mock("python"),
"python-installer": create_package_mock("python-installer"),
}
package_mock = mocker.patch("ahriman.models.package.Package.from_aur", side_effect=lambda p, _: packages[p])
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages",
return_value=["devtools", "python-build"])
result = application.with_dependencies([package_ahriman], process_dependencies=True)
assert {package.base: package for package in result} == packages
package_mock.assert_has_calls([
MockCall(package_python_schedule.base, application.repository.pacman),
MockCall("python", application.repository.pacman),
MockCall("python-installer", application.repository.pacman),
], any_order=True)
packages_mock.assert_called_once_with()
def test_with_dependencies_skip(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must skip processing of dependencies
"""
packages_mock = mocker.patch("ahriman.application.application.Application._known_packages")
assert application.with_dependencies([package_ahriman], process_dependencies=False) == [package_ahriman]
packages_mock.assert_not_called()
assert application.with_dependencies([], process_dependencies=True) == []
packages_mock.assert_not_called()

View File

@ -29,13 +29,10 @@ def test_add_aur(application_packages: ApplicationPackages, package_ahriman: Pac
must add package from AUR
"""
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
dependencies_mock = mocker.patch(
"ahriman.application.application.application_packages.ApplicationPackages._process_dependencies")
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
update_remote_mock = mocker.patch("ahriman.core.database.SQLite.remote_update")
application_packages._add_aur(package_ahriman.base, set(), False)
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
application_packages._add_aur(package_ahriman.base)
build_queue_mock.assert_called_once_with(package_ahriman)
update_remote_mock.assert_called_once_with(package_ahriman)
@ -64,15 +61,12 @@ def test_add_local(application_packages: ApplicationPackages, package_ahriman: P
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
init_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.init")
copytree_mock = mocker.patch("shutil.copytree")
dependencies_mock = mocker.patch(
"ahriman.application.application.application_packages.ApplicationPackages._process_dependencies")
build_queue_mock = mocker.patch("ahriman.core.database.SQLite.build_queue_insert")
application_packages._add_local(package_ahriman.base, set(), False)
application_packages._add_local(package_ahriman.base)
copytree_mock.assert_called_once_with(
Path(package_ahriman.base), application_packages.repository.paths.cache_for(package_ahriman.base))
init_mock.assert_called_once_with(application_packages.repository.paths.cache_for(package_ahriman.base))
dependencies_mock.assert_called_once_with(pytest.helpers.anyvar(int), set(), False)
build_queue_mock.assert_called_once_with(package_ahriman)
@ -107,59 +101,15 @@ def test_add_repository(application_packages: ApplicationPackages, package_ahrim
update_remote_mock.assert_called_once_with(package_ahriman)
def test_known_packages(application_packages: ApplicationPackages) -> None:
"""
must raise NotImplemented for missing known_packages method
"""
with pytest.raises(NotImplementedError):
application_packages._known_packages()
def test_process_dependencies(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must process dependencies addition
"""
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages.add")
application_packages._process_dependencies(package_ahriman, set(), False)
add_mock.assert_called_once_with(package_ahriman.depends_build, PackageSource.AUR, False)
def test_process_dependencies_missing(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must process dependencies addition only for missing packages
"""
missing = {"devtools"}
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages.add")
application_packages._process_dependencies(
package_ahriman, package_ahriman.depends_build.difference(missing), False)
add_mock.assert_called_once_with(missing, PackageSource.AUR, False)
def test_process_dependencies_skip(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must skip dependencies processing
"""
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages.add")
application_packages._process_dependencies(package_ahriman, set(), True)
add_mock.assert_not_called()
def test_add_add_archive(application_packages: ApplicationPackages, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must add package from archive via add function
"""
mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._known_packages",
return_value=set())
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_archive")
application_packages.add([package_ahriman.base], PackageSource.Archive, False)
add_mock.assert_called_once_with(package_ahriman.base, set(), False)
application_packages.add([package_ahriman.base], PackageSource.Archive)
add_mock.assert_called_once_with(package_ahriman.base)
def test_add_add_aur(
@ -169,12 +119,10 @@ def test_add_add_aur(
"""
must add package from AUR via add function
"""
mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._known_packages",
return_value=set())
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_aur")
application_packages.add([package_ahriman.base], PackageSource.AUR, True)
add_mock.assert_called_once_with(package_ahriman.base, set(), True)
application_packages.add([package_ahriman.base], PackageSource.AUR)
add_mock.assert_called_once_with(package_ahriman.base)
def test_add_add_directory(application_packages: ApplicationPackages, package_ahriman: Package,
@ -182,12 +130,10 @@ def test_add_add_directory(application_packages: ApplicationPackages, package_ah
"""
must add packages from directory via add function
"""
mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._known_packages",
return_value=set())
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_directory")
application_packages.add([package_ahriman.base], PackageSource.Directory, False)
add_mock.assert_called_once_with(package_ahriman.base, set(), False)
application_packages.add([package_ahriman.base], PackageSource.Directory)
add_mock.assert_called_once_with(package_ahriman.base)
def test_add_add_local(application_packages: ApplicationPackages, package_ahriman: Package,
@ -195,12 +141,10 @@ def test_add_add_local(application_packages: ApplicationPackages, package_ahrima
"""
must add package from local sources via add function
"""
mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._known_packages",
return_value=set())
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_local")
application_packages.add([package_ahriman.base], PackageSource.Local, False)
add_mock.assert_called_once_with(package_ahriman.base, set(), False)
application_packages.add([package_ahriman.base], PackageSource.Local)
add_mock.assert_called_once_with(package_ahriman.base)
def test_add_add_remote(application_packages: ApplicationPackages, package_description_ahriman: PackageDescription,
@ -208,13 +152,11 @@ def test_add_add_remote(application_packages: ApplicationPackages, package_descr
"""
must add package from remote source via add function
"""
mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._known_packages",
return_value=set())
add_mock = mocker.patch("ahriman.application.application.application_packages.ApplicationPackages._add_remote")
url = f"https://host/{package_description_ahriman.filename}"
application_packages.add([url], PackageSource.Remote, False)
add_mock.assert_called_once_with(url, set(), False)
application_packages.add([url], PackageSource.Remote)
add_mock.assert_called_once_with(url)
def test_on_result(application_packages: ApplicationPackages) -> None:

View File

@ -26,7 +26,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.now = False
args.refresh = 0
args.source = PackageSource.Auto
args.without_dependencies = False
args.dependencies = True
return args
@ -38,10 +38,12 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.add")
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
Add.run(args, "x86_64", configuration, report=False, unsafe=False)
application_mock.assert_called_once_with(args.package, args.source, args.without_dependencies)
application_mock.assert_called_once_with(args.package, args.source)
dependencies_mock.assert_not_called()
on_start_mock.assert_called_once_with()
@ -59,11 +61,14 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
return_value=[package_ahriman])
Add.run(args, "x86_64", configuration, report=False, unsafe=False)
updates_mock.assert_called_once_with(args.package, aur=False, local=False, manual=True, vcs=False,
log_fn=pytest.helpers.anyvar(int))
application_mock.assert_called_once_with([package_ahriman])
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_called_once_with(False, False)
@ -78,6 +83,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.with_dependencies")
mocker.patch("ahriman.application.application.Application.updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")

View File

@ -23,6 +23,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
argparse.Namespace: generated arguments for these test cases
"""
args.package = []
args.dependencies = True
args.dry_run = False
args.exit_code = False
args.aur = True
@ -44,6 +45,8 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
return_value=[package_ahriman])
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
@ -51,6 +54,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
application_mock.assert_called_once_with([package_ahriman])
updates_mock.assert_called_once_with(args.package, aur=args.aur, local=args.local, manual=args.manual, vcs=args.vcs,
log_fn=pytest.helpers.anyvar(int))
dependencies_mock.assert_called_once_with([package_ahriman], process_dependencies=args.dependencies)
check_mock.assert_has_calls([MockCall(False, False), MockCall(False, False)])
on_start_mock.assert_called_once_with()
@ -81,6 +85,7 @@ def test_run_update_empty_exception(args: argparse.Namespace, package_ahriman: P
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.update", return_value=Result())
mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_if_empty")
Update.run(args, "x86_64", configuration, report=False, unsafe=False)

View File

@ -342,9 +342,10 @@ def test_subparsers_repo_backup_architecture(parser: argparse.ArgumentParser) ->
def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None:
"""
repo-check command must imply dry-run, aur and manual
repo-check command must imply dependencies, dry-run, aur and manual
"""
args = parser.parse_args(["repo-check"])
assert not args.dependencies
assert args.dry_run
assert args.aur
assert not args.manual

View File

@ -125,6 +125,14 @@ def test_licenses(package_ahriman: Package) -> None:
assert sorted(package_ahriman.licenses) == package_ahriman.licenses
def test_packages_full(package_ahriman: Package) -> None:
"""
must return full list of packages including provides
"""
package_ahriman.packages[package_ahriman.base].provides = [f"{package_ahriman.base}-git"]
assert package_ahriman.packages_full == [package_ahriman.base, f"{package_ahriman.base}-git"]
def test_from_archive(package_ahriman: Package, pyalpm_handle: MagicMock, mocker: MockerFixture) -> None:
"""
must construct package from alpm library