consider vcs flag and vcs_allowed_age during local packages update

This commit is contained in:
Evgenii Alekseev 2023-01-11 18:22:06 +02:00
parent 419da3db89
commit 461fbd40ce
9 changed files with 114 additions and 53 deletions

View File

@ -394,7 +394,7 @@ return non\-zero exit status if result is empty
.TP
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
enable or disable checking of VCS packages (default: True)
fetch actual version of VCS packages (default: True)
.TP
\fB\-y\fR, \fB\-\-refresh\fR
@ -413,7 +413,7 @@ interval between runs in seconds
.TP
\fB\-\-aur\fR, \fB\-\-no\-aur\fR
enable or disable checking for AUR updates. Implies \-\-no\-vcs (default: True)
enable or disable checking for AUR updates (default: True)
.TP
\fB\-\-local\fR, \fB\-\-no\-local\fR
@ -425,7 +425,7 @@ include or exclude manual updates (default: True)
.TP
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
enable or disable checking of VCS packages (default: True)
fetch actual version of VCS packages (default: True)
.TP
\fB\-y\fR, \fB\-\-refresh\fR
@ -544,7 +544,7 @@ return non\-zero exit status if result is empty
.TP
\fB\-\-aur\fR, \fB\-\-no\-aur\fR
enable or disable checking for AUR updates. Implies \-\-no\-vcs (default: True)
enable or disable checking for AUR updates (default: True)
.TP
\fB\-\-local\fR, \fB\-\-no\-local\fR
@ -556,7 +556,7 @@ include or exclude manual updates (default: True)
.TP
\fB\-\-vcs\fR, \fB\-\-no\-vcs\fR
enable or disable checking of VCS packages (default: True)
fetch actual version of VCS packages (default: True)
.TP
\fB\-y\fR, \fB\-\-refresh\fR

View File

@ -106,7 +106,7 @@ _shtab_ahriman_aur_search_options=(
_shtab_ahriman_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty]"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
"(*)::filter check by package base:"
)
@ -132,10 +132,10 @@ _shtab_ahriman_config_validate_options=(
_shtab_ahriman_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds]:interval:"
{--aur,--no-aur}"[enable or disable checking for AUR updates. Implies --no-vcs (default\: \%(default)s)]:aur:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: \%(default)s)]:aur:"
{--local,--no-local}"[enable or disable checking of local packages for updates (default\: \%(default)s)]:local:"
{--manual,--no-manual}"[include or exclude manual updates (default\: \%(default)s)]:manual:"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
)
@ -276,7 +276,7 @@ _shtab_ahriman_repo_backup_options=(
_shtab_ahriman_repo_check_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-e,--exit-code}"[return non-zero exit status if result is empty]"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
"(*)::filter check by package base:"
)
@ -302,10 +302,10 @@ _shtab_ahriman_repo_config_validate_options=(
_shtab_ahriman_repo_daemon_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
{-i,--interval}"[interval between runs in seconds]:interval:"
{--aur,--no-aur}"[enable or disable checking for AUR updates. Implies --no-vcs (default\: \%(default)s)]:aur:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: \%(default)s)]:aur:"
{--local,--no-local}"[enable or disable checking of local packages for updates (default\: \%(default)s)]:local:"
{--manual,--no-manual}"[include or exclude manual updates (default\: \%(default)s)]:manual:"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
)
@ -389,10 +389,10 @@ _shtab_ahriman_repo_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--dry-run[just perform check for updates, same as check command]"
{-e,--exit-code}"[return non-zero exit status if result is empty]"
{--aur,--no-aur}"[enable or disable checking for AUR updates. Implies --no-vcs (default\: \%(default)s)]:aur:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: \%(default)s)]:aur:"
{--local,--no-local}"[enable or disable checking of local packages for updates (default\: \%(default)s)]:local:"
{--manual,--no-manual}"[include or exclude manual updates (default\: \%(default)s)]:manual:"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
"(*)::filter check by package base:"
)
@ -501,10 +501,10 @@ _shtab_ahriman_update_options=(
"(- : *)"{-h,--help}"[show this help message and exit]"
"--dry-run[just perform check for updates, same as check command]"
{-e,--exit-code}"[return non-zero exit status if result is empty]"
{--aur,--no-aur}"[enable or disable checking for AUR updates. Implies --no-vcs (default\: \%(default)s)]:aur:"
{--aur,--no-aur}"[enable or disable checking for AUR updates (default\: \%(default)s)]:aur:"
{--local,--no-local}"[enable or disable checking of local packages for updates (default\: \%(default)s)]:local:"
{--manual,--no-manual}"[include or exclude manual updates (default\: \%(default)s)]:manual:"
{--vcs,--no-vcs}"[enable or disable checking of VCS packages (default\: \%(default)s)]:vcs:"
{--vcs,--no-vcs}"[fetch actual version of VCS packages (default\: \%(default)s)]:vcs:"
"*"{-y,--refresh}"[download fresh package databases from the mirror before actions, -yy to force refresh even if up to date]"
"(*)::filter check by package base:"
)

View File

@ -467,7 +467,7 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
formatter_class=_formatter)
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("--vcs", help="enable or disable checking of VCS packages",
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",
@ -490,13 +490,13 @@ def _set_repo_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
description="start process which periodically will run update process",
formatter_class=_formatter)
parser.add_argument("-i", "--interval", help="interval between runs in seconds", type=int, default=60 * 60 * 12)
parser.add_argument("--aur", help="enable or disable checking for AUR updates. Implies --no-vcs",
parser.add_argument("--aur", help="enable or disable checking for AUR updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--local", help="enable or disable checking of local packages for updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--manual", help="include or exclude manual updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--vcs", help="enable or disable checking of VCS packages",
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",
@ -693,13 +693,13 @@ def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("--dry-run", help="just perform check for updates, same as check command", action="store_true")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty", action="store_true")
parser.add_argument("--aur", help="enable or disable checking for AUR updates. Implies --no-vcs",
parser.add_argument("--aur", help="enable or disable checking for AUR updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--local", help="enable or disable checking of local packages for updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--manual", help="include or exclude manual updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--vcs", help="enable or disable checking of VCS packages",
parser.add_argument("--vcs", help="fetch actual version of VCS packages",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-y", "--refresh", help="download fresh package databases from the mirror before actions, "
"-yy to force refresh even if up to date",

View File

@ -175,7 +175,7 @@ class ApplicationRepository(ApplicationProperties):
if aur:
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, vcs=vcs)})
if local:
updates.update({package.base: package for package in self.repository.updates_local()})
updates.update({package.base: package for package in self.repository.updates_local(vcs=vcs)})
if manual:
updates.update({package.base: package for package in self.repository.updates_manual()})

View File

@ -21,7 +21,6 @@ from typing import Iterable, List
from ahriman.core.build_tools.sources import Sources
from ahriman.core.repository.cleaner import Cleaner
from ahriman.core.util import utcnow
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
@ -54,10 +53,6 @@ class UpdateHandler(Cleaner):
Returns:
List[Package]: list of packages which are out-of-dated
"""
# don't think there are packages older then 1970
now = utcnow()
min_vcs_build_date = (now.timestamp() - self.vcs_allowed_age) if vcs else now.timestamp()
result: List[Package] = []
for local in self.packages():
@ -74,8 +69,10 @@ class UpdateHandler(Cleaner):
else:
remote = Package.from_aur(local.base, self.pacman)
calculate_version = not local.is_newer_than(min_vcs_build_date)
if local.is_outdated(remote, self.paths, calculate_version=calculate_version):
if local.is_outdated(
remote, self.paths,
vcs_allowed_age=self.vcs_allowed_age,
calculate_version=vcs):
self.reporter.set_pending(local.base)
result.append(remote)
except Exception:
@ -84,10 +81,13 @@ class UpdateHandler(Cleaner):
return result
def updates_local(self) -> List[Package]:
def updates_local(self, *, vcs: bool) -> List[Package]:
"""
check local packages for updates
Args:
vcs(bool): enable or disable checking of VCS packages
Returns:
List[Package]: list of local packages which are out-of-dated
"""
@ -104,7 +104,9 @@ class UpdateHandler(Cleaner):
if local is None:
self.reporter.set_unknown(remote)
result.append(remote)
elif local.is_outdated(remote, self.paths, calculate_version=True):
elif local.is_outdated(remote, self.paths,
vcs_allowed_age=self.vcs_allowed_age,
calculate_version=vcs):
self.reporter.set_pending(local.base)
result.append(remote)
except Exception:

View File

@ -32,7 +32,7 @@ from ahriman.core.alpm.pacman import Pacman
from ahriman.core.alpm.remote import AUR, Official, OfficialSyncdb
from ahriman.core.exceptions import PackageInfoError
from ahriman.core.log import LazyLogging
from ahriman.core.util import check_output, full_version
from ahriman.core.util import check_output, full_version, utcnow
from ahriman.models.package_description import PackageDescription
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
@ -376,20 +376,29 @@ class Package(LazyLogging):
if package.build_date is not None
)
def is_outdated(self, remote: Package, paths: RepositoryPaths, *, calculate_version: bool) -> bool:
def is_outdated(self, remote: Package, paths: RepositoryPaths, *,
vcs_allowed_age: Union[float, int] = 0,
calculate_version: bool = True) -> bool:
"""
check if package is out-of-dated
Args:
remote(Package): package properties from remote source
paths(RepositoryPaths): repository paths instance. Required for VCS packages cache
vcs_allowed_age(Union[float, int], optional): max age of the built packages before they will be
forced to calculate actual version (Default value = 0)
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
"""
remote_version = remote.actual_version(paths) if calculate_version else remote.version
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(paths)
else:
remote_version = remote.version
result: int = vercmp(self.version, remote_version)
return result < 0

View File

@ -208,7 +208,7 @@ def test_updates_all(application_repository: ApplicationRepository, package_ahri
application_repository.updates([], aur=True, local=True, manual=True, vcs=True, log_fn=print)
updates_aur_mock.assert_called_once_with([], vcs=True)
updates_local_mock.assert_called_once_with()
updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with()
@ -238,7 +238,7 @@ def test_updates_no_aur(application_repository: ApplicationRepository, mocker: M
application_repository.updates([], aur=False, local=True, manual=True, vcs=True, log_fn=print)
updates_aur_mock.assert_not_called()
updates_local_mock.assert_called_once_with()
updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with()
@ -268,7 +268,7 @@ def test_updates_no_manual(application_repository: ApplicationRepository, mocker
application_repository.updates([], aur=True, local=True, manual=False, vcs=True, log_fn=print)
updates_aur_mock.assert_called_once_with([], vcs=True)
updates_local_mock.assert_called_once_with()
updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_not_called()
@ -283,7 +283,7 @@ def test_updates_no_vcs(application_repository: ApplicationRepository, mocker: M
application_repository.updates([], aur=True, local=True, manual=True, vcs=False, log_fn=print)
updates_aur_mock.assert_called_once_with([], vcs=False)
updates_local_mock.assert_called_once_with()
updates_local_mock.assert_called_once_with(vcs=False)
updates_manual_mock.assert_called_once_with()
@ -298,5 +298,5 @@ def test_updates_with_filter(application_repository: ApplicationRepository, mock
application_repository.updates(["filter"], aur=True, local=True, manual=True, vcs=True, log_fn=print)
updates_aur_mock.assert_called_once_with(["filter"], vcs=True)
updates_local_mock.assert_called_once_with()
updates_local_mock.assert_called_once_with(vcs=True)
updates_manual_mock.assert_called_once_with()

View File

@ -4,7 +4,6 @@ from pathlib import Path
from pytest_mock import MockerFixture
from ahriman.core.repository.update_handler import UpdateHandler
from ahriman.core.util import utcnow
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
from ahriman.models.remote_source import RemoteSource
@ -24,12 +23,16 @@ def test_updates_aur(update_handler: UpdateHandler, package_ahriman: Package,
must provide updates with status updates
"""
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.models.package.Package.from_aur", return_value=package_ahriman)
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
assert update_handler.updates_aur([], vcs=True) == [package_ahriman]
status_client_mock.assert_called_once_with(package_ahriman.base)
package_is_outdated_mock.assert_called_once_with(
package_ahriman, update_handler.paths,
vcs_allowed_age=update_handler.vcs_allowed_age,
calculate_version=True)
def test_updates_aur_official(update_handler: UpdateHandler, package_ahriman: Package,
@ -95,14 +98,13 @@ 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.models.package.Package.from_aur", return_value=package_ahriman)
mocker.patch("ahriman.models.package.Package.is_vcs", return_value=True)
package_is_newer_than_mock = mocker.patch("ahriman.models.package.Package.is_newer_than", return_value=True)
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=False)
ts1 = utcnow().timestamp()
assert not update_handler.updates_aur([], vcs=False)
package_is_newer_than_mock.assert_called_once_with(pytest.helpers.anyvar(float, strict=True))
assert ts1 < package_is_newer_than_mock.call_args[0][0] < utcnow().timestamp()
package_is_outdated_mock.assert_called_once_with(package_ahriman, update_handler.paths, calculate_version=False)
package_is_outdated_mock.assert_called_once_with(
package_ahriman, update_handler.paths,
vcs_allowed_age=update_handler.vcs_allowed_age,
calculate_version=False)
def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package, mocker: MockerFixture) -> None:
@ -111,15 +113,37 @@ def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package,
"""
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("ahriman.models.package.Package.is_outdated", return_value=True)
fetch_mock = mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
package_load_mock = mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
package_is_outdated_mock = mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
assert update_handler.updates_local() == [package_ahriman]
assert update_handler.updates_local(vcs=True) == [package_ahriman]
fetch_mock.assert_called_once_with(Path(package_ahriman.base), remote=None)
package_load_mock.assert_called_once_with(Path(package_ahriman.base))
status_client_mock.assert_called_once_with(package_ahriman.base)
package_is_outdated_mock.assert_called_once_with(
package_ahriman, update_handler.paths,
vcs_allowed_age=update_handler.vcs_allowed_age,
calculate_version=True)
def test_updates_local_ignore_vcs(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must skip VCS packages check if requested for locally stored packages
"""
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("ahriman.core.build_tools.sources.Sources.fetch")
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)
assert not update_handler.updates_local(vcs=False)
package_is_outdated_mock.assert_called_once_with(
package_ahriman, update_handler.paths,
vcs_allowed_age=update_handler.vcs_allowed_age,
calculate_version=False)
def test_updates_local_unknown(update_handler: UpdateHandler, package_ahriman: Package, mocker: MockerFixture) -> None:
@ -133,7 +157,7 @@ def test_updates_local_unknown(update_handler: UpdateHandler, package_ahriman: P
mocker.patch("ahriman.models.package.Package.from_build", return_value=package_ahriman)
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
assert update_handler.updates_local() == [package_ahriman]
assert update_handler.updates_local(vcs=True) == [package_ahriman]
status_client_mock.assert_called_once_with(package_ahriman)
@ -146,7 +170,7 @@ def test_updates_local_with_failures(update_handler: UpdateHandler, package_ahri
mocker.patch("pathlib.Path.iterdir", return_value=[Path(package_ahriman.base)])
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception())
assert not update_handler.updates_local()
assert not update_handler.updates_local(vcs=True)
def test_updates_manual_clear(update_handler: UpdateHandler, mocker: MockerFixture) -> None:

View File

@ -6,6 +6,7 @@ from unittest.mock import MagicMock
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.exceptions import PackageInfoError
from ahriman.core.util import utcnow
from ahriman.models.aur_package import AURPackage
from ahriman.models.package import Package
from ahriman.models.repository_paths import RepositoryPaths
@ -285,21 +286,46 @@ def test_is_newer_than(package_ahriman: Package, package_python_schedule: Packag
assert not package_python_schedule.is_newer_than(min_date)
def test_is_outdated_false(package_ahriman: Package, repository_paths: RepositoryPaths) -> None:
def test_is_outdated_false(package_ahriman: Package, repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
"""
must be not outdated for the same package
"""
assert not package_ahriman.is_outdated(package_ahriman, repository_paths, calculate_version=True)
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version",
return_value=package_ahriman.version)
assert not package_ahriman.is_outdated(package_ahriman, repository_paths)
actual_version_mock.assert_called_once_with(repository_paths)
def test_is_outdated_true(package_ahriman: Package, repository_paths: RepositoryPaths) -> None:
def test_is_outdated_true(package_ahriman: Package, repository_paths: RepositoryPaths, 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, repository_paths, calculate_version=True)
assert package_ahriman.is_outdated(other, repository_paths)
actual_version_mock.assert_called_once_with(repository_paths)
def test_is_outdated_no_version_calculation(package_ahriman: Package, repository_paths: RepositoryPaths,
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, repository_paths, calculate_version=False)
actual_version_mock.assert_not_called()
def test_is_outdated_fresh_package(package_ahriman: Package, repository_paths: RepositoryPaths,
mocker: MockerFixture) -> None:
"""
must not call actual version if package is never than specified time
"""
actual_version_mock = mocker.patch("ahriman.models.package.Package.actual_version")
assert not package_ahriman.is_outdated(package_ahriman, repository_paths, vcs_allowed_age=utcnow().timestamp())
actual_version_mock.assert_not_called()
def test_build_status_pretty_print(package_ahriman: Package) -> None: