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' .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 force rebuild whole repository
@ -505,8 +505,12 @@ force rebuild whole repository
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR \fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
only rebuild packages that depend on specified package 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' .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 force rebuild whole repository
@ -515,6 +519,10 @@ force rebuild whole repository
\fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR \fB\-\-depends\-on\fR \fI\,DEPENDS_ON\/\fR
only rebuild packages that depend on specified package 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' .SH OPTIONS 'ahriman repo-remove-unknown'
usage: ahriman repo-remove-unknown [-h] [--dry-run] [-i] usage: ahriman repo-remove-unknown [-h] [--dry-run] [-i]
@ -695,7 +703,7 @@ target to sync
.SH OPTIONS 'ahriman repo-update' .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 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 \fB\-\-no\-aur\fR
do not check for AUR updates. Implies \-\-no\-vcs do not check for AUR updates. Implies \-\-no\-vcs
.TP
\fB\-\-no\-local\fR
do not check local packages for updates
.TP .TP
\fB\-\-no\-manual\fR \fB\-\-no\-manual\fR
do not include manual updates do not include manual updates
@ -720,7 +732,7 @@ do not include manual updates
do not check VCS packages do not check VCS packages
.SH OPTIONS 'ahriman update' .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 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 \fB\-\-no\-aur\fR
do not check for AUR updates. Implies \-\-no\-vcs do not check for AUR updates. Implies \-\-no\-vcs
.TP
\fB\-\-no\-local\fR
do not check local packages for updates
.TP .TP
\fB\-\-no\-manual\fR \fB\-\-no\-manual\fR
do not include manual updates do not include manual updates

View File

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

View File

@ -22,6 +22,7 @@ import sys
import tempfile import tempfile
from pathlib import Path from pathlib import Path
from typing import TypeVar
from ahriman import version from ahriman import version
from ahriman.application import handlers from ahriman.application import handlers
@ -32,8 +33,11 @@ from ahriman.models.sign_settings import SignSettings
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
# pylint thinks it is bad idea, but get the fuck off # this workaround is for several things
SubParserAction = argparse._SubParsersAction # pylint: disable=protected-access # 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: def _formatter(prog: str) -> argparse.HelpFormatter:
@ -285,7 +289,7 @@ def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
formatter_class=_formatter) formatter_class=_formatter)
parser.add_argument("package", help="filter check by package base", nargs="*") 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.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 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", parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
description="force rebuild whole repository", formatter_class=_formatter) 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("--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) parser.set_defaults(handler=handlers.Rebuild)
return parser 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("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("--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-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-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.add_argument("--no-vcs", help="do not check VCS packages", action="store_true")
parser.set_defaults(handler=handlers.Update) 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 known_packages: list of packages which are known by the service
:param without_dependencies: if set, dependency check will be disabled :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, self.repository.aur_url)
package = Package.load(source, PackageSource.AUR, self.repository.pacman, aur_url)
local_path = self.repository.paths.manual_for(package.base) local_path = self.repository.paths.manual_for(package.base)
Sources.load(local_path, package.git_url, self.repository.paths.patches_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 known_packages: list of packages which are known by the service
:param without_dependencies: if set, dependency check will be disabled :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, self.repository.aur_url)
package = Package.load(source, PackageSource.Local, self.repository.pacman, aur_url)
cache_dir = self.repository.paths.cache_for(package.base) cache_dir = self.repository.paths.cache_for(package.base)
shutil.copytree(Path(source), cache_dir) # copy package to store in caches 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 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) packages = self.repository.process_build(level)
process_update(packages) 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]: log_fn: Callable[[str], None]) -> List[Package]:
""" """
get list of packages to run update process get list of packages to run update process
:param filter_packages: do not check every package just specified in the list :param filter_packages: do not check every package just specified in the list
:param no_aur: do not check for aur updates :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_manual: do not check for manual updates
:param no_vcs: do not check VCS packages :param no_vcs: do not check VCS packages
:param log_fn: logger function to log updates :param log_fn: logger function to log updates
:return: list of out-of-dated packages :return: list of out-of-dated packages
""" """
updates = [] updates = {}
if not no_aur: 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: 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()} 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( UpdatePrinter(package, local_versions.get(package.base)).print(
verbose=True, log_fn=log_fn, separator=" -> ") 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: if not args.now:
return 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) application.update(packages)

View File

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

View File

@ -42,7 +42,7 @@ class Update(Handler):
:param no_report: force disable reporting :param no_report: force disable reporting
""" """
application = Application(architecture, configuration, no_report) 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)) Update.log_fn(application, args.dry_run))
if args.dry_run: if args.dry_run:
return return

View File

@ -20,7 +20,7 @@
import logging import logging
from pathlib import Path from pathlib import Path
from typing import List from typing import List, Optional
from ahriman.core.util import check_output from ahriman.core.util import check_output
@ -64,7 +64,7 @@ class Sources:
patch_path.write_text(patch) patch_path.write_text(patch)
@staticmethod @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` either clone repository or update it to origin/`branch`
:param sources_dir: local path to fetch :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.logger.info("update HEAD to remote at %s", sources_dir)
Sources._check_output("git", "fetch", "origin", Sources._branch, Sources._check_output("git", "fetch", "origin", Sources._branch,
exception=None, cwd=sources_dir, logger=Sources.logger) 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: else:
Sources.logger.info("clone remote %s to %s", remote, sources_dir) 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) 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/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# #
from pathlib import Path 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.executor import Executor
from ahriman.core.repository.update_handler import UpdateHandler 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 of filenames from the directory
""" """
return list(filter(package_like, self.paths.packages.iterdir())) 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 typing import Iterable, List
from ahriman.core.build_tools.sources import Sources
from ahriman.core.repository.cleaner import Cleaner from ahriman.core.repository.cleaner import Cleaner
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.package_source import PackageSource from ahriman.models.package_source import PackageSource
@ -65,6 +66,31 @@ class UpdateHandler(Cleaner):
return result 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]: def updates_manual(self) -> List[Package]:
""" """
check for packages for which manual update has been requested check for packages for which manual update has been requested

View File

@ -20,13 +20,14 @@
from __future__ import annotations from __future__ import annotations
import aur # type: ignore import aur # type: ignore
import copy
import logging import logging
from dataclasses import asdict, dataclass from dataclasses import asdict, dataclass
from pathlib import Path from pathlib import Path
from pyalpm import vercmp # type: ignore from pyalpm import vercmp # type: ignore
from srcinfo.parse import parse_srcinfo # 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.alpm.pacman import Pacman
from ahriman.core.exceptions import InvalidPackageInfo from ahriman.core.exceptions import InvalidPackageInfo
@ -257,6 +258,36 @@ class Package:
return self.version 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: def is_outdated(self, remote: Package, paths: RepositoryPaths, calculate_version: bool = True) -> bool:
""" """
check if package is out-of-dated 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 # 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/>.
# #
__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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur", updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur",
return_value=[package_ahriman]) 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") 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_aur_mock.assert_called_once_with([], False)
updates_local_mock.assert_called_once()
updates_manual_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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") 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") 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_aur_mock.assert_not_called()
updates_local_mock.assert_not_called()
updates_manual_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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") 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") 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_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() 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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") 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") 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_aur_mock.assert_called_once_with([], False)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_not_called() 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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") 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") 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_aur_mock.assert_called_once_with([], True)
updates_local_mock.assert_called_once()
updates_manual_mock.assert_called_once() updates_manual_mock.assert_called_once()
def test_updates_with_filter(application_repository: Repository, mocker: MockerFixture) -> None: 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=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[])
updates_aur_mock = mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.updates_aur") 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") 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_aur_mock.assert_called_once_with(["filter"], False)
updates_local_mock.assert_called_once()
updates_manual_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 :return: generated arguments for these test cases
""" """
args.depends_on = [] args.depends_on = []
args.dry_run = False
return args return args
@ -23,7 +24,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create") 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") application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration, True) 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() application_mock.assert_called_once()
def test_run_filter(args: argparse.Namespace, configuration: Configuration, def test_run_dry_run(args: argparse.Namespace, configuration: Configuration,
package_ahriman: Package, package_python_schedule: Package, package_ahriman: Package, mocker: MockerFixture) -> None:
mocker: MockerFixture) -> None:
""" """
must run command with depends filter must run command without update itself
""" """
args = _default_args(args) args = _default_args(args)
args.depends_on = ["python-aur"] args.dry_run = True
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create") 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") application_mock = mocker.patch("ahriman.application.application.Application.update")
Rebuild.run(args, "x86_64", configuration, True) 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, def test_run_filter(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
package_ahriman: Package, package_python_schedule: Package, """
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 must run command for all packages if no filter supplied
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.core.repository.repository.Repository.packages", mocker.patch("ahriman.application.application.Application.update")
return_value=[package_ahriman, package_python_schedule])
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create") 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) 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.package = []
args.dry_run = False args.dry_run = False
args.no_aur = False args.no_aur = False
args.no_local = False
args.no_manual = False args.no_manual = False
args.no_vcs = False args.no_vcs = False
return args 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: def test_has_remotes(mocker: MockerFixture) -> None:
""" """
must ask for remotes 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")]) 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")] 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() 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: def test_updates_manual_clear(update_handler: UpdateHandler, mocker: MockerFixture) -> None:
""" """
requesting manual updates must clear packages directory 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, def test_updates_manual_with_failures(update_handler: UpdateHandler, package_ahriman: Package,
mocker: MockerFixture) -> None: 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("pathlib.Path.iterdir", return_value=[package_ahriman.base])
mocker.patch("ahriman.core.repository.update_handler.UpdateHandler.packages", return_value=[]) 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() mock = MagicMock()
type(mock).base = PropertyMock(return_value=package_ahriman.base) 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).name = PropertyMock(return_value=package_ahriman.base)
type(mock).provides = PropertyMock(return_value=["python-ahriman"])
type(mock).version = PropertyMock(return_value=package_ahriman.version) type(mock).version = PropertyMock(return_value=package_ahriman.version)
return mock 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 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: def test_is_outdated_false(package_ahriman: Package, repository_paths: RepositoryPaths) -> None:
""" """
must be not outdated for the same package must be not outdated for the same package