Compare commits

...

5 Commits
1.6.4 ... 1.7.0

22 changed files with 2894 additions and 2660 deletions

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 416 KiB

After

Width:  |  Height:  |  Size: 405 KiB

View File

@ -496,7 +496,7 @@ create empty repository tree. Optional command for auto architecture support
.SH OPTIONS 'ahriman repo-rebuild'
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON]
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run]
force rebuild whole repository
@ -505,8 +505,12 @@ force rebuild whole repository
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
only rebuild packages that depend on specified package
.TP
\fB\-\-dry\-run\fR
just perform check for packages without rebuild process itself
.SH OPTIONS 'ahriman rebuild'
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON]
usage: ahriman repo-rebuild [-h] [--depends-on DEPENDS_ON] [--dry-run]
force rebuild whole repository
@ -515,6 +519,10 @@ force rebuild whole repository
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
only rebuild packages that depend on specified package
.TP
\fB\-\-dry\-run\fR
just perform check for packages without rebuild process itself
.SH OPTIONS 'ahriman repo-remove-unknown'
usage: ahriman repo-remove-unknown [-h] [--dry-run] [-i]
@ -695,7 +703,7 @@ target to sync
.SH OPTIONS 'ahriman repo-update'
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-manual] [--no-vcs] [package ...]
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
check for packages updates and run build process if requested
@ -711,6 +719,10 @@ just perform check for updates, same as check command
\fB\-\-no\-aur\fR
do not check for AUR updates. Implies \-\-no\-vcs
.TP
\fB\-\-no\-local\fR
do not check local packages for updates
.TP
\fB\-\-no\-manual\fR
do not include manual updates
@ -720,7 +732,7 @@ do not include manual updates
do not check VCS packages
.SH OPTIONS 'ahriman update'
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-manual] [--no-vcs] [package ...]
usage: ahriman repo-update [-h] [--dry-run] [--no-aur] [--no-local] [--no-manual] [--no-vcs] [package ...]
check for packages updates and run build process if requested
@ -736,6 +748,10 @@ just perform check for updates, same as check command
\fB\-\-no\-aur\fR
do not check for AUR updates. Implies \-\-no\-vcs
.TP
\fB\-\-no\-local\fR
do not check local packages for updates
.TP
\fB\-\-no\-manual\fR
do not include manual updates

View File

@ -1,7 +1,7 @@
# Maintainer: Evgeniy Alekseev
pkgname='ahriman'
pkgver=1.6.4
pkgver=1.7.0
pkgrel=1
pkgdesc="ArcH Linux ReposItory MANager"
arch=('any')

View File

@ -22,6 +22,7 @@ import sys
import tempfile
from pathlib import Path
from typing import TypeVar
from ahriman import version
from ahriman.application import handlers
@ -32,8 +33,11 @@ from ahriman.models.sign_settings import SignSettings
from ahriman.models.user_access import UserAccess
# pylint thinks it is bad idea, but get the fuck off
SubParserAction = argparse._SubParsersAction # pylint: disable=protected-access
# this workaround is for several things
# firstly python devs don't think that is it error and asking you for workarounds https://bugs.python.org/issue41592
# secondly linters don't like when you are importing private members
# thirdly new mypy doesn't like _SubParsersAction and thinks it is a template
SubParserAction = TypeVar("SubParserAction", bound="argparse._SubParsersAction[argparse.ArgumentParser]")
def _formatter(prog: str) -> argparse.HelpFormatter:
@ -285,7 +289,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("--no-vcs", help="do not check VCS packages", action="store_true")
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_manual=True)
parser.set_defaults(handler=handlers.Update, dry_run=True, no_aur=False, no_local=False, no_manual=True)
return parser
@ -346,6 +350,8 @@ def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
description="force rebuild whole repository", formatter_class=_formatter)
parser.add_argument("--depends-on", help="only rebuild packages that depend on specified package", action="append")
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
action="store_true")
parser.set_defaults(handler=handlers.Rebuild)
return parser
@ -461,6 +467,7 @@ 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("--no-aur", help="do not check for AUR updates. Implies --no-vcs", action="store_true")
parser.add_argument("--no-local", help="do not check local packages for updates", action="store_true")
parser.add_argument("--no-manual", help="do not include manual updates", action="store_true")
parser.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
parser.set_defaults(handler=handlers.Update)

View File

@ -64,8 +64,7 @@ class Packages(Properties):
:param known_packages: list of packages which are known by the service
:param without_dependencies: if set, dependency check will be disabled
"""
aur_url = self.configuration.get("alpm", "aur_url")
package = Package.load(source, PackageSource.AUR, self.repository.pacman, aur_url)
package = Package.load(source, PackageSource.AUR, self.repository.pacman, self.repository.aur_url)
local_path = self.repository.paths.manual_for(package.base)
Sources.load(local_path, package.git_url, self.repository.paths.patches_for(package.base))
@ -87,8 +86,7 @@ class Packages(Properties):
:param known_packages: list of packages which are known by the service
:param without_dependencies: if set, dependency check will be disabled
"""
aur_url = self.configuration.get("alpm", "aur_url")
package = Package.load(source, PackageSource.Local, self.repository.pacman, aur_url)
package = Package.load(source, PackageSource.Local, self.repository.pacman, self.repository.aur_url)
cache_dir = self.repository.paths.cache_for(package.base)
shutil.copytree(Path(source), cache_dir) # copy package to store in caches
Sources.init(cache_dir) # we need to run init command in directory where we do have permissions

View File

@ -163,27 +163,31 @@ class Repository(Properties):
packages = self.repository.process_build(level)
process_update(packages)
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_manual: bool, no_vcs: bool,
def updates(self, filter_packages: Iterable[str], no_aur: bool, no_local: bool, no_manual: bool, no_vcs: bool,
log_fn: Callable[[str], None]) -> List[Package]:
"""
get list of packages to run update process
:param filter_packages: do not check every package just specified in the list
:param no_aur: do not check for aur updates
:param no_local: do not check local packages for updates
:param no_manual: do not check for manual updates
:param no_vcs: do not check VCS packages
:param log_fn: logger function to log updates
:return: list of out-of-dated packages
"""
updates = []
updates = {}
if not no_aur:
updates.extend(self.repository.updates_aur(filter_packages, no_vcs))
updates.update({package.base: package for package in self.repository.updates_aur(filter_packages, no_vcs)})
if not no_local:
updates.update({package.base: package for package in self.repository.updates_local()})
if not no_manual:
updates.extend(self.repository.updates_manual())
updates.update({package.base: package for package in self.repository.updates_manual()})
local_versions = {package.base: package.version for package in self.repository.packages()}
for package in updates:
updated_packages = [package for _, package in sorted(updates.items())]
for package in updated_packages:
UpdatePrinter(package, local_versions.get(package.base)).print(
verbose=True, log_fn=log_fn, separator=" -> ")
return updates
return updated_packages

View File

@ -46,5 +46,5 @@ class Add(Handler):
if not args.now:
return
packages = application.updates(args.package, True, False, True, application.logger.info)
packages = application.updates(args.package, True, True, False, True, application.logger.info)
application.update(packages)

View File

@ -22,6 +22,7 @@ import argparse
from typing import Type
from ahriman.application.application import Application
from ahriman.application.formatters.update_printer import UpdatePrinter
from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration
@ -44,9 +45,10 @@ class Rebuild(Handler):
depends_on = set(args.depends_on) if args.depends_on else None
application = Application(architecture, configuration, no_report)
packages = [
package
for package in application.repository.packages()
if depends_on is None or depends_on.intersection(package.depends)
] # we have to use explicit list here for testing purpose
application.update(packages)
updates = application.repository.packages_depends_on(depends_on)
if args.dry_run:
for package in updates:
UpdatePrinter(package, package.version).print(verbose=True)
return
application.update(updates)

View File

@ -42,7 +42,7 @@ class Update(Handler):
:param no_report: force disable reporting
"""
application = Application(architecture, configuration, no_report)
packages = application.updates(args.package, args.no_aur, args.no_manual, args.no_vcs,
packages = application.updates(args.package, args.no_aur, args.no_local, args.no_manual, args.no_vcs,
Update.log_fn(application, args.dry_run))
if args.dry_run:
return

View File

@ -20,7 +20,7 @@
import logging
from pathlib import Path
from typing import List
from typing import List, Optional
from ahriman.core.util import check_output
@ -64,7 +64,7 @@ class Sources:
patch_path.write_text(patch)
@staticmethod
def fetch(sources_dir: Path, remote: str) -> None:
def fetch(sources_dir: Path, remote: Optional[str]) -> None:
"""
either clone repository or update it to origin/`branch`
:param sources_dir: local path to fetch
@ -81,6 +81,8 @@ class Sources:
Sources.logger.info("update HEAD to remote at %s", sources_dir)
Sources._check_output("git", "fetch", "origin", Sources._branch,
exception=None, cwd=sources_dir, logger=Sources.logger)
elif remote is None:
Sources.logger.warning("%s is not initialized, but no remote provided", sources_dir)
else:
Sources.logger.info("clone remote %s to %s", remote, sources_dir)
Sources._check_output("git", "clone", remote, str(sources_dir), exception=None, logger=Sources.logger)

View File

@ -18,7 +18,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
from pathlib import Path
from typing import Dict, Iterable, List
from typing import Dict, Iterable, List, Optional
from ahriman.core.repository.executor import Executor
from ahriman.core.repository.update_handler import UpdateHandler
@ -68,3 +68,20 @@ class Repository(Executor, UpdateHandler):
:return: list of filenames from the directory
"""
return list(filter(package_like, self.paths.packages.iterdir()))
def packages_depends_on(self, depends_on: Optional[Iterable[str]]) -> List[Package]:
"""
extract list of packages which depends on specified package
:param: depends_on: dependencies of the packages
:return: list of repository packages which depend on specified packages
"""
packages = self.packages()
if depends_on is None:
return packages # no list provided extract everything by default
depends_on = set(depends_on)
return [
package
for package in packages
if depends_on is None or depends_on.intersection(package.full_depends(self.pacman, packages))
]

View File

@ -19,6 +19,7 @@
#
from typing import Iterable, List
from ahriman.core.build_tools.sources import Sources
from ahriman.core.repository.cleaner import Cleaner
from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource
@ -65,6 +66,31 @@ class UpdateHandler(Cleaner):
return result
def updates_local(self) -> List[Package]:
"""
check local packages for updates
:return: list of local packages which are out-of-dated
"""
result: List[Package] = []
packages = {local.base: local for local in self.packages()}
for dirname in self.paths.cache.iterdir():
try:
Sources.fetch(dirname, remote=None)
remote = Package.load(str(dirname), PackageSource.Local, self.pacman, self.aur_url)
local = packages.get(remote.base)
if local is None:
self.reporter.set_unknown(remote)
result.append(remote)
elif local.is_outdated(remote, self.paths):
self.reporter.set_pending(local.base)
result.append(remote)
except Exception:
self.logger.exception("could not procees package at %s", dirname)
return result
def updates_manual(self) -> List[Package]:
"""
check for packages for which manual update has been requested

View File

@ -20,13 +20,14 @@
from __future__ import annotations
import aur # type: ignore
import copy
import logging
from dataclasses import asdict, dataclass
from pathlib import Path
from pyalpm import vercmp # type: ignore
from srcinfo.parse import parse_srcinfo # type: ignore
from typing import Any, Dict, List, Optional, Set, Type
from typing import Any, Dict, Iterable, List, Optional, Set, Type
from ahriman.core.alpm.pacman import Pacman
from ahriman.core.exceptions import InvalidPackageInfo
@ -257,6 +258,36 @@ class Package:
return self.version
def full_depends(self, pacman: Pacman, packages: Iterable[Package]) -> List[str]:
"""
generate full dependencies list including transitive dependencies
:param pacman: alpm wrapper instance
:param packages: repository package list
:return: 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_outdated(self, remote: Package, paths: RepositoryPaths, calculate_version: bool = True) -> bool:
"""
check if package is out-of-dated

View File

@ -17,4 +17,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
__version__ = "1.6.4"
__version__ = "1.7.0"

View File

@ -205,10 +205,12 @@ def test_updates_all(application_repository: Repository, package_ahriman: Packag
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur",
return_value=[package_ahriman])
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=False, no_manual=False, no_vcs=False, log_fn=print)
application_repository.updates([], no_aur=False, no_local=False, no_manual=False, no_vcs=False, log_fn=print)
updates_aur_mock.assert_called_once_with([], False)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_called_once()
@ -218,10 +220,12 @@ def test_updates_disabled(application_repository: Repository, mocker: MockerFixt
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=True, no_manual=True, no_vcs=False, log_fn=print)
application_repository.updates([], no_aur=True, no_local=True, no_manual=True, no_vcs=False, log_fn=print)
updates_aur_mock.assert_not_called()
updates_local_mock.assert_not_called()
updates_manual_mock.assert_not_called()
@ -231,10 +235,27 @@ def test_updates_no_aur(application_repository: Repository, mocker: MockerFixtur
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=True, no_manual=False, no_vcs=False, log_fn=print)
application_repository.updates([], no_aur=True, no_local=False, no_manual=False, no_vcs=False, log_fn=print)
updates_aur_mock.assert_not_called()
updates_local_mock.assert_called_once()
updates_manual_mock.assert_called_once()
def test_updates_no_local(application_repository: Repository, mocker: MockerFixture) -> None:
"""
must get updates without local packages
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=False, no_local=True, no_manual=False, no_vcs=False, log_fn=print)
updates_aur_mock.assert_called_once_with([], False)
updates_local_mock.assert_not_called()
updates_manual_mock.assert_called_once()
@ -244,10 +265,12 @@ def test_updates_no_manual(application_repository: Repository, mocker: MockerFix
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=False, no_manual=True, no_vcs=False, log_fn=print)
application_repository.updates([], no_aur=False, no_local=False, no_manual=True, no_vcs=False, log_fn=print)
updates_aur_mock.assert_called_once_with([], False)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_not_called()
@ -257,21 +280,26 @@ def test_updates_no_vcs(application_repository: Repository, mocker: MockerFixtur
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates([], no_aur=False, no_manual=False, no_vcs=True, log_fn=print)
application_repository.updates([], no_aur=False, no_local=False, no_manual=False, no_vcs=True, log_fn=print)
updates_aur_mock.assert_called_once_with([], True)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_called_once()
def test_updates_with_filter(application_repository: Repository, mocker: MockerFixture) -> None:
"""
must get updates without VCS
must get updates with filter
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur")
updates_local_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_local")
updates_manual_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_manual")
application_repository.updates(["filter"], no_aur=False, no_manual=False, no_vcs=False, log_fn=print)
application_repository.updates(["filter"], no_aur=False, no_local=False, no_manual=False, no_vcs=False,
log_fn=print)
updates_aur_mock.assert_called_once_with(["filter"], False)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_called_once()

View File

@ -14,6 +14,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
:return: generated arguments for these test cases
"""
args.depends_on = []
args.dry_run = False
return args
@ -23,7 +24,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
"""
args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages")
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on")
application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration, True)
@ -31,34 +32,43 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
application_mock.assert_called_once()
def test_run_filter(args: argparse.Namespace, configuration: Configuration,
package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
def test_run_dry_run(args: argparse.Namespace, configuration: Configuration,
package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must run command with depends filter
must run command without update itself
"""
args = _default_args(args)
args.depends_on = ["python-aur"]
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
args.dry_run = True
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on", return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration, True)
application_mock.assert_called_once_with([package_ahriman])
application_mock.assert_not_called()
def test_run_without_filter(args: argparse.Namespace, configuration: Configuration,
package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
def test_run_filter(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run command with depends on filter
"""
args = _default_args(args)
args.depends_on = ["python-aur"]
mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on")
Rebuild.run(args, "x86_64", configuration, True)
application_packages_mock.assert_called_once_with({"python-aur"})
def test_run_without_filter(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run command for all packages if no filter supplied
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.application.Application.update")
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depends_on")
Rebuild.run(args, "x86_64", configuration, True)
application_mock.assert_called_once_with([package_ahriman, package_python_schedule])
application_packages_mock.assert_called_once_with(None)

View File

@ -16,6 +16,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.package = []
args.dry_run = False
args.no_aur = False
args.no_local = False
args.no_manual = False
args.no_vcs = False
return args

View File

@ -86,6 +86,23 @@ def test_fetch_new(mocker: MockerFixture) -> None:
])
def test_fetch_new_without_remote(mocker: MockerFixture) -> None:
"""
must fetch nothing in case if no remote set
"""
mocker.patch("pathlib.Path.is_dir", return_value=False)
check_output_mock = mocker.patch("ahriman.core.build_tools.sources.Sources._check_output")
local = Path("local")
Sources.fetch(local, None)
check_output_mock.assert_has_calls([
mock.call("git", "checkout", "--force", Sources._branch,
exception=None, cwd=local, logger=pytest.helpers.anyvar(int)),
mock.call("git", "reset", "--hard", f"origin/{Sources._branch}",
exception=None, cwd=local, logger=pytest.helpers.anyvar(int))
])
def test_has_remotes(mocker: MockerFixture) -> None:
"""
must ask for remotes

View File

@ -80,3 +80,23 @@ def test_packages_built(repository: Repository, mocker: MockerFixture) -> None:
"""
mocker.patch("pathlib.Path.iterdir", return_value=[Path("a.tar.xz"), Path("b.pkg.tar.xz")])
assert repository.packages_built() == [Path("b.pkg.tar.xz")]
def test_packages_depends_on(repository: Repository, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must filter packages by depends list
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
assert repository.packages_depends_on(["python-aur"]) == [package_ahriman]
def test_packages_depends_on_empty(repository: Repository, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must return all packages in case if no filter is provided
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
assert repository.packages_depends_on(None) == [package_ahriman, package_python_schedule]

View File

@ -81,6 +81,50 @@ def test_updates_aur_ignore_vcs(update_handler: UpdateHandler, package_ahriman:
package_is_outdated_mock.assert_not_called()
def test_updates_local(update_handler: UpdateHandler, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must check for updates for locally stored packages
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[package_ahriman])
mocker.patch("pathlib.Path.iterdir", return_value=[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.load", return_value=package_ahriman)
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_pending")
assert update_handler.updates_local() == [package_ahriman]
fetch_mock.assert_called_once_with(package_ahriman.base, remote=None)
package_load_mock.assert_called_once()
status_client_mock.assert_called_once()
def test_updates_local_unknown(update_handler: UpdateHandler, package_ahriman: Package, mocker: MockerFixture) -> None:
"""
must return unknown package as out-dated
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.models.package.Package.is_outdated", return_value=True)
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch")
mocker.patch("ahriman.models.package.Package.load", return_value=package_ahriman)
status_client_mock = mocker.patch("ahriman.core.status.client.Client.set_unknown")
assert update_handler.updates_local() == [package_ahriman]
status_client_mock.assert_called_once()
def test_updates_local_with_failures(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must process local through the packages with failure
"""
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages")
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.build_tools.sources.Sources.fetch", side_effect=Exception())
assert not update_handler.updates_local()
def test_updates_manual_clear(update_handler: UpdateHandler, mocker: MockerFixture) -> None:
"""
requesting manual updates must clear packages directory
@ -125,7 +169,7 @@ def test_updates_manual_status_unknown(update_handler: UpdateHandler, package_ah
def test_updates_manual_with_failures(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None:
"""
must process through the packages with failure
must process manual through the packages with failure
"""
mocker.patch("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[])

View File

@ -82,7 +82,9 @@ def pyalpm_package_ahriman(package_ahriman: Package) -> MagicMock:
"""
mock = MagicMock()
type(mock).base = PropertyMock(return_value=package_ahriman.base)
type(mock).depends = PropertyMock(return_value=["python-aur"])
type(mock).name = PropertyMock(return_value=package_ahriman.base)
type(mock).provides = PropertyMock(return_value=["python-ahriman"])
type(mock).version = PropertyMock(return_value=package_ahriman.version)
return mock

View File

@ -294,6 +294,24 @@ def test_actual_version_vcs_failed(package_tpacpi_bat_git: Package, repository_p
assert package_tpacpi_bat_git.actual_version(repository_paths) == package_tpacpi_bat_git.version
def test_full_depends(package_ahriman: Package, package_python_schedule: Package, pyalpm_package_ahriman: MagicMock,
pyalpm_handle: MagicMock, mocker: MockerFixture) -> 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 + ["python-aur"]))
assert package_python_schedule.full_depends(pyalpm_handle, [package_python_schedule]) == expected
def test_is_outdated_false(package_ahriman: Package, repository_paths: RepositoryPaths) -> None:
"""
must be not outdated for the same package