move argument parsers to handlers themselves

This commit is contained in:
Evgenii Alekseev 2024-09-30 19:21:20 +03:00
parent 6fe77eb465
commit be57045972
81 changed files with 1472 additions and 1457 deletions

View File

@ -36,6 +36,14 @@ ahriman.core.exceptions module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.module\_loader module
----------------------------------
.. automodule:: ahriman.core.module_loader
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.spawn module ahriman.core.spawn module
------------------------- -------------------------

View File

@ -18,7 +18,7 @@ Full dependency diagram:
``ahriman.application`` package ``ahriman.application`` package
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This package contains application (aka executable) related classes and everything for it. It also contains package called ``ahriman.application.handlers`` in which all available subcommands are described as separated classes derived from the base ``ahriman.application.handlers.Handler`` class. This package contains application (aka executable) related classes and everything for it. It also contains package called ``ahriman.application.handlers`` in which all available subcommands are described as separated classes derived from the base ``ahriman.application.handlers.handler.Handler`` class.
``ahriman.application.application.Application`` (god class) is used for any interaction from parsers with repository. It is divided into multiple traits by functions (package related and repository related) in the same package. ``ahriman.application.application.Application`` (god class) is used for any interaction from parsers with repository. It is divided into multiple traits by functions (package related and repository related) in the same package.

View File

@ -30,12 +30,14 @@ class ImportType(StrEnum):
import type enumeration import type enumeration
Attributes: Attributes:
Future(MethodTypeOrder): (class attribute) from __future__ import
Package(MethodTypeOrder): (class attribute) package import Package(MethodTypeOrder): (class attribute) package import
PackageFrom(MethodTypeOrder): (class attribute) package import, from clause PackageFrom(MethodTypeOrder): (class attribute) package import, from clause
System(ImportType): (class attribute) system installed packages System(ImportType): (class attribute) system installed packages
SystemFrom(MethodTypeOrder): (class attribute) system installed packages, from clause SystemFrom(MethodTypeOrder): (class attribute) system installed packages, from clause
""" """
Future = "future"
Package = "package" Package = "package"
PackageFrom = "package-from" PackageFrom = "package-from"
System = "system" System = "system"
@ -70,6 +72,7 @@ class ImportOrder(BaseRawFileChecker):
"import-type-order", "import-type-order",
{ {
"default": [ "default": [
"future",
"system", "system",
"system-from", "system-from",
"package", "package",
@ -91,7 +94,7 @@ class ImportOrder(BaseRawFileChecker):
) )
@staticmethod @staticmethod
def imports(source: Iterable[Any], start_lineno: int = 0) -> list[nodes.Import | nodes.ImportFrom]: def imports(source: Iterable[Any], start_lineno: int = 0) -> Iterable[nodes.Import | nodes.ImportFrom]:
""" """
extract import nodes from list of raw nodes extract import nodes from list of raw nodes
@ -100,7 +103,7 @@ class ImportOrder(BaseRawFileChecker):
start_lineno(int, optional): minimal allowed line number (Default value = 0) start_lineno(int, optional): minimal allowed line number (Default value = 0)
Returns: Returns:
list[nodes.Import | nodes.ImportFrom]: list of import nodes Iterable[nodes.Import | nodes.ImportFrom]: list of import nodes
""" """
def is_defined_import(imports: Any) -> bool: def is_defined_import(imports: Any) -> bool:
@ -108,7 +111,7 @@ class ImportOrder(BaseRawFileChecker):
and imports.lineno is not None \ and imports.lineno is not None \
and imports.lineno >= start_lineno and imports.lineno >= start_lineno
return list(filter(is_defined_import, source)) return sorted(filter(is_defined_import, source), key=lambda imports: imports.lineno)
def check_from_imports(self, imports: nodes.ImportFrom) -> None: def check_from_imports(self, imports: nodes.ImportFrom) -> None:
""" """
@ -124,30 +127,36 @@ class ImportOrder(BaseRawFileChecker):
self.add_message("from-imports-out-of-order", line=imports.lineno, args=(real, expected)) self.add_message("from-imports-out-of-order", line=imports.lineno, args=(real, expected))
break break
def check_imports(self, imports: list[nodes.Import | nodes.ImportFrom], root_package: str) -> None: def check_imports(self, imports: Iterable[nodes.Import | nodes.ImportFrom], root_package: str) -> None:
""" """
check imports check imports
Args: Args:
imports(list[nodes.Import | nodes.ImportFrom]): list of imports in their defined order imports(Iterable[nodes.Import | nodes.ImportFrom]): list of imports in their defined order
root_package(str): root package name root_package(str): root package name
""" """
last_statement: tuple[int, str] | None = None last_statement: tuple[int, str] | None = None
for statement in imports: for statement in imports:
# define types and perform specific checks # define types and perform specific checks
if isinstance(statement, nodes.ImportFrom): match statement:
import_name = statement.modname case nodes.ImportFrom() if statement.modname == "__future__":
root, *_ = import_name.split(".", maxsplit=1) import_name = statement.modname
import_type = ImportType.PackageFrom if root_package == root else ImportType.SystemFrom import_type = ImportType.Future
# check from import itself case nodes.ImportFrom():
self.check_from_imports(statement) import_name = statement.modname
else: root, *_ = import_name.split(".", maxsplit=1)
import_name = next(name for name, _ in statement.names) import_type = ImportType.PackageFrom if root_package == root else ImportType.SystemFrom
root, *_ = import_name.split(".", maxsplit=1)[0] # check from import itself
import_type = ImportType.Package if root_package == root else ImportType.System self.check_from_imports(statement)
# check import itself case nodes.Import():
self.check_package_imports(statement) import_name = next(name for name, _ in statement.names)
root, *_ = import_name.split(".", maxsplit=1)
import_type = ImportType.Package if root_package == root else ImportType.System
# check import itself
self.check_package_imports(statement)
case _:
continue
# extract index # extract index
try: try:

File diff suppressed because it is too large Load Diff

View File

@ -17,37 +17,3 @@
# 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/>.
# #
from ahriman.application.handlers.add import Add
from ahriman.application.handlers.backup import Backup
from ahriman.application.handlers.change import Change
from ahriman.application.handlers.clean import Clean
from ahriman.application.handlers.copy import Copy
from ahriman.application.handlers.daemon import Daemon
from ahriman.application.handlers.dump import Dump
from ahriman.application.handlers.handler import Handler
from ahriman.application.handlers.help import Help
from ahriman.application.handlers.key_import import KeyImport
from ahriman.application.handlers.patch import Patch
from ahriman.application.handlers.rebuild import Rebuild
from ahriman.application.handlers.remove import Remove
from ahriman.application.handlers.remove_unknown import RemoveUnknown
from ahriman.application.handlers.repositories import Repositories
from ahriman.application.handlers.restore import Restore
from ahriman.application.handlers.run import Run
from ahriman.application.handlers.search import Search
from ahriman.application.handlers.service_updates import ServiceUpdates
from ahriman.application.handlers.setup import Setup
from ahriman.application.handlers.shell import Shell
from ahriman.application.handlers.sign import Sign
from ahriman.application.handlers.statistics import Statistics
from ahriman.application.handlers.status import Status
from ahriman.application.handlers.status_update import StatusUpdate
from ahriman.application.handlers.structure import Structure
from ahriman.application.handlers.tree_migrate import TreeMigrate
from ahriman.application.handlers.triggers import Triggers
from ahriman.application.handlers.unsafe_commands import UnsafeCommands
from ahriman.application.handlers.update import Update
from ahriman.application.handlers.users import Users
from ahriman.application.handlers.validate import Validate
from ahriman.application.handlers.versions import Versions
from ahriman.application.handlers.web import Web

View File

@ -20,8 +20,10 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values, extract_user
from ahriman.models.package_source import PackageSource
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
from ahriman.models.pkgbuild_patch import PkgbuildPatch from ahriman.models.pkgbuild_patch import PkgbuildPatch
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -66,3 +68,49 @@ class Add(Handler):
application.print_updates(packages, log_fn=application.logger.info) application.print_updates(packages, log_fn=application.logger.info)
result = application.update(packages, packagers, bump_pkgrel=args.increment) result = application.update(packages, packagers, bump_pkgrel=args.increment)
Add.check_status(args.exit_code, not result.is_empty) Add.check_status(args.exit_code, not result.is_empty)
@staticmethod
def _set_package_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package addition subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-add", aliases=["add", "package-update"], help="add package",
description="add existing or new package to the build queue",
epilog="This subcommand should be used for new package addition. "
"It also supports flag --now in case if you would like to build "
"the package immediately. You can add new package from one of "
"supported sources:\n\n"
"1. If it is already built package you can specify the path to the archive.\n"
"2. You can also add built packages from the directory (e.g. during the "
"migration from another repository source).\n"
"3. It is also possible to add package from local PKGBUILD, but in this case "
"it will be ignored during the next automatic updates.\n"
"4. Ahriman supports downloading archives from remote (e.g. HTTP) sources.\n"
"5. Finally you can add package from AUR.")
parser.add_argument("package", help="package source (base name, path to local files, remote URL)", nargs="+")
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--increment", help="increment package release (pkgrel) version on duplicate",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-n", "--now", help="run update function after", action="store_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",
action="count", default=False)
parser.add_argument("-s", "--source", help="explicitly specify the package source for this command",
type=PackageSource, choices=enum_values(PackageSource), default=PackageSource.Auto)
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
parser.add_argument("-v", "--variable", help="apply specified makepkg variables to the next build",
action="append")
return parser
arguments = [_set_package_add_parser]

View File

@ -23,7 +23,7 @@ import tarfile
from pathlib import Path from pathlib import Path
from pwd import getpwuid from pwd import getpwuid
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -53,6 +53,23 @@ class Backup(Handler):
for backup_path in backup_paths: for backup_path in backup_paths:
archive.add(backup_path) archive.add(backup_path)
@staticmethod
def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository backup subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-backup", help="backup repository data",
description="backup repository settings and database")
parser.add_argument("path", help="path of the output archive", type=Path)
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def get_paths(configuration: Configuration) -> set[Path]: def get_paths(configuration: Configuration) -> set[Path]:
""" """
@ -83,3 +100,5 @@ class Backup(Handler):
paths.add(gnupg_home) paths.add(gnupg_home)
return paths return paths
arguments = [_set_repo_backup_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ChangesPrinter from ahriman.core.formatters import ChangesPrinter
from ahriman.models.action import Action from ahriman.models.action import Action
@ -57,3 +57,43 @@ class Change(Handler):
Change.check_status(args.exit_code, not changes.is_empty) Change.check_status(args.exit_code, not changes.is_empty)
case Action.Remove: case Action.Remove:
client.package_changes_update(args.package, Changes()) client.package_changes_update(args.package, Changes())
@staticmethod
def _set_package_changes_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package changes subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-changes", help="get package changes",
description="retrieve package changes stored in database",
epilog="This command requests package status from the web interface "
"if it is available.")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.set_defaults(action=Action.List, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_package_changes_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package change remove subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-changes-remove", help="remove package changes",
description="remove the package changes stored remotely")
parser.add_argument("package", help="package base")
parser.set_defaults(action=Action.Remove, exit_code=False, lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_package_changes_parser, _set_package_changes_remove_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +46,33 @@ class Clean(Handler):
application.on_start() application.on_start()
application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages, application.clean(cache=args.cache, chroot=args.chroot, manual=args.manual, packages=args.packages,
pacman=args.pacman) pacman=args.pacman)
@staticmethod
def _set_service_clean_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository clean subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-clean", aliases=["clean", "repo-clean"], help="clean local caches",
description="remove local caches",
epilog="The subcommand clears every temporary directories (builds, caches etc). "
"Normally you should not run this command manually. Also in case if "
"you are going to clear the chroot directories you will need root privileges.")
parser.add_argument("--cache", help="clear directory with package caches",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--chroot", help="clear build chroot", action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--manual", help="clear manually added packages queue",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--packages", help="clear directory with built packages",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--pacman", help="clear directory with pacman local database cache",
action=argparse.BooleanOptionalAction, default=False)
parser.set_defaults(lock=None, quiet=True, unsafe=True)
return parser
arguments = [_set_service_clean_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
@ -67,6 +67,26 @@ class Copy(Handler):
if args.remove: if args.remove:
source_application.remove(args.package) source_application.remove(args.package)
@staticmethod
def _set_package_copy_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package copy subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-copy", aliases=["copy"], help="copy package from another repository",
description="copy package and its metadata from another repository")
parser.add_argument("source", help="source repository name")
parser.add_argument("package", help="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("--remove", help="remove package from the source repository after", action="store_true")
return parser
@staticmethod @staticmethod
def copy_package(package: Package, application: Application, source_application: Application) -> None: def copy_package(package: Package, application: Application, source_application: Application) -> None:
""" """
@ -93,3 +113,5 @@ class Copy(Handler):
package.base, source_application.reporter.package_dependencies_get(package.base) package.base, source_application.reporter.package_dependencies_get(package.base)
) )
application.reporter.package_update(package, BuildStatusEnum.Pending) application.reporter.package_update(package, BuildStatusEnum.Pending)
arguments = [_set_package_copy_parser]

View File

@ -19,11 +19,14 @@
# #
import argparse import argparse
from pathlib import Path
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator from ahriman.application.application.updates_iterator import FixedUpdatesIterator, UpdatesIterator
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.application.handlers.update import Update from ahriman.application.handlers.update import Update
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import extract_user
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -56,3 +59,48 @@ class Daemon(Handler):
args.package = packages args.package = packages
Update.run(args, repository_id, configuration, report=report) Update.run(args, repository_id, configuration, report=report)
@staticmethod
def _set_repo_daemon_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for daemon subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-daemon", aliases=["daemon"], help="run application as daemon",
description="start process which periodically will run update process")
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",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dry-run", help="just perform check for updates, same as check command",
action="store_true")
parser.add_argument("--increment", help="increment package release (pkgrel) on duplicate",
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("--partitions", help="instead of updating whole repository, split updates into chunks",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
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",
action="count", default=False)
parser.set_defaults(exit_code=False, lock=Path("ahriman-daemon.pid"), package=[])
return parser
arguments = [_set_repo_daemon_parser]

View File

@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter from ahriman.core.formatters import ConfigurationPathsPrinter, ConfigurationPrinter, StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -59,3 +59,27 @@ class Dump(Handler):
case section, key: # key only case section, key: # key only
value = configuration.get(section, key, fallback="") value = configuration.get(section, key, fallback="")
StringPrinter(value)(verbose=False) StringPrinter(value)(verbose=False)
@staticmethod
def _set_service_config_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for config subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-config", aliases=["config", "repo-config"], help="dump configuration",
description="dump configuration for the specified architecture")
parser.add_argument("section", help="filter settings by section", nargs="?")
parser.add_argument("key", help="filter settings by key", nargs="?")
parser.add_argument("--info", help="show additional information, e.g. configuration files",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--secure", help="hide passwords and secrets from output",
action=argparse.BooleanOptionalAction, default=True)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_service_config_parser]

View File

@ -22,6 +22,7 @@ import logging
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from multiprocessing import Pool from multiprocessing import Pool
from typing import TypeVar
from ahriman.application.lock import Lock from ahriman.application.lock import Lock
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -32,12 +33,21 @@ from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
# 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]")
class Handler: class Handler:
""" """
base handler class for command callbacks base handler class for command callbacks
Attributes: Attributes:
ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures
arguments(list[Callable[[SubParserAction], argparse.ArgumentParser]]): (class attribute) argument parser
methods, which will be called to create command line parsers
Examples: Examples:
Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually Wrapper for all command line actions, though each derived class implements :func:`run()` method, it usually
@ -49,6 +59,7 @@ class Handler:
""" """
ALLOW_MULTI_ARCHITECTURE_RUN = True ALLOW_MULTI_ARCHITECTURE_RUN = True
arguments: list[Callable[[SubParserAction], argparse.ArgumentParser]]
@classmethod @classmethod
def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool: def call(cls, args: argparse.Namespace, repository_id: RepositoryId) -> bool:

View File

@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -48,3 +48,22 @@ class Help(Handler):
parser.parse_args(["--help"]) parser.parse_args(["--help"])
else: else:
parser.parse_args([args.subcommand, "--help"]) parser.parse_args([args.subcommand, "--help"])
@staticmethod
def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for listing help subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help", help="show help message",
description="show help message for application or command and exit")
parser.add_argument("subcommand", help="show help message for specific command", nargs="?")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
arguments = [_set_help_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +46,27 @@ class KeyImport(Handler):
""" """
application = Application(repository_id, configuration, report=report) application = Application(repository_id, configuration, report=report)
application.repository.sign.key_import(args.key_server, args.key) application.repository.sign.key_import(args.key_server, args.key)
@staticmethod
def _set_service_key_import_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for key import subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-key-import", aliases=["key-import"], help="import PGP key",
description="import PGP key from public sources to the repository user",
epilog="By default ahriman runs build process with package sources validation "
"(in case if signature and keys are available in PKGBUILD). This process will "
"fail in case if key is not known for build user. This subcommand can be used "
"in order to import the PGP key to user keychain.")
parser.add_argument("--key-server", help="key server for key import", default="keyserver.ubuntu.com")
parser.add_argument("key", help="PGP key to import from public server")
parser.set_defaults(architecture="", lock=None, report=False, repository="")
return parser
arguments = [_set_service_key_import_parser]

View File

@ -23,7 +23,7 @@ import sys
from pathlib import Path from pathlib import Path
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.build_tools.sources import Sources from ahriman.core.build_tools.sources import Sources
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import PatchPrinter from ahriman.core.formatters import PatchPrinter
@ -67,6 +67,100 @@ class Patch(Handler):
case Action.Remove: case Action.Remove:
Patch.patch_set_remove(application, args.package, args.variable) Patch.patch_set_remove(application, args.package, args.variable)
@staticmethod
def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for new single-function patch subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-add", help="add patch for PKGBUILD function",
description="create or update patched PKGBUILD function or variable",
epilog="Unlike ``patch-set-add``, this function allows to patch only one PKGBUILD "
"function, e.g. typing ``ahriman patch-add ahriman pkgver`` it will change the "
"``pkgver`` inside PKGBUILD, typing ``ahriman patch-add ahriman build()`` "
"it will change ``build()`` function inside PKGBUILD.")
parser.add_argument("package", help="package base")
parser.add_argument("variable", help="PKGBUILD variable or function name. If variable is a function, "
"it must end with ()")
parser.add_argument("patch", help="path to file which contains function or variable value. If not set, "
"the value will be read from stdin", type=Path, nargs="?")
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, report=False,
repository="")
return parser
@staticmethod
def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for list patches subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-list", help="list patch sets",
description="list available patches for the package")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables",
action="append")
parser.set_defaults(action=Action.List, architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod
def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for remove patches subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-remove", help="remove patch set", description="remove patches for the package")
parser.add_argument("package", help="package base")
parser.add_argument("-v", "--variable",
help="should be used for single-function patches in case if you wold like "
"to remove only specified PKGBUILD variables. In case if not set, "
"it will remove all patches related to the package",
action="append")
parser.set_defaults(action=Action.Remove, architecture="", exit_code=False, lock=None, report=False,
repository="")
return parser
@staticmethod
def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for new full-diff patch subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("patch-set-add", help="add patch set", description="create or update source patches",
epilog="In order to add a patch set for the package you will need to:\n\n"
"1. Clone the AUR package manually.\n"
"2. Add required changes (e.g. external patches, edit PKGBUILD).\n"
"3. Run command, e.g. ``ahriman patch-set-add path/to/directory``.\n\n"
"By default it tracks ``*.patch`` and ``*.diff`` files, but this behavior "
"can be changed by using ``--track`` option.")
parser.add_argument("package", help="path to directory with changed files for patch addition/update", type=Path)
parser.add_argument("-t", "--track", help="files which has to be tracked", action="append",
default=["*.diff", "*.patch"])
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, report=False,
repository="", variable=None)
return parser
@staticmethod @staticmethod
def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]: def patch_create_from_diff(sources_dir: Path, architecture: str, track: list[str]) -> tuple[str, PkgbuildPatch]:
""" """
@ -155,3 +249,10 @@ class Patch(Handler):
application.reporter.package_patches_remove(package_base, variable) application.reporter.package_patches_remove(package_base, variable)
else: else:
application.reporter.package_patches_remove(package_base, None) # just pass as is application.reporter.package_patches_remove(package_base, None) # just pass as is
arguments = [
_set_patch_add_parser,
_set_patch_list_parser,
_set_patch_remove_parser,
_set_patch_set_add_parser,
]

View File

@ -20,8 +20,9 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values, extract_user
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
@ -59,6 +60,38 @@ class Rebuild(Handler):
result = application.update(packages, Packagers(args.username), bump_pkgrel=args.increment) result = application.update(packages, Packagers(args.username), bump_pkgrel=args.increment)
Rebuild.check_status(args.exit_code, not result.is_empty) Rebuild.check_status(args.exit_code, not result.is_empty)
@staticmethod
def _set_repo_rebuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository rebuild subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-rebuild", aliases=["rebuild"], help="rebuild repository",
description="force rebuild whole repository")
parser.add_argument("--depends-on", help="only rebuild packages that depend on specified packages",
action="append")
parser.add_argument("--dry-run", help="just perform check for packages without rebuild process itself",
action="store_true")
parser.add_argument("--from-database",
help="read packages from database instead of filesystem. This feature in particular is "
"required in case if you would like to restore repository from another repository "
"instance. Note, however, that in order to restore packages you need to have original "
"ahriman instance run with web service and have run repo-update at least once.",
action="store_true")
parser.add_argument("--increment", help="increment package release (pkgrel) on duplicate",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("-s", "--status", help="filter packages by status. Requires --from-database to be set",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
parser.add_argument("-u", "--username", help="build as user", default=extract_user())
return parser
@staticmethod @staticmethod
def extract_packages(application: Application, status: BuildStatusEnum | None, *, def extract_packages(application: Application, status: BuildStatusEnum | None, *,
from_database: bool) -> list[Package]: from_database: bool) -> list[Package]:
@ -81,3 +114,5 @@ class Rebuild(Handler):
] ]
return application.repository.packages() return application.repository.packages()
arguments = [_set_repo_rebuild_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -45,3 +45,21 @@ class Remove(Handler):
application = Application(repository_id, configuration, report=report) application = Application(repository_id, configuration, report=report)
application.on_start() application.on_start()
application.remove(args.package) application.remove(args.package)
@staticmethod
def _set_package_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package removal subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-remove", aliases=["remove"], help="remove package",
description="remove package from the repository")
parser.add_argument("package", help="package name or base", nargs="+")
return parser
arguments = [_set_package_remove_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -53,3 +53,21 @@ class RemoveUnknown(Handler):
return return
application.remove(unknown_packages) application.remove(unknown_packages)
@staticmethod
def _set_repo_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for remove unknown packages subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-remove-unknown", aliases=["remove-unknown"], help="remove unknown packages",
description="remove packages which are missing in AUR and do not have local PKGBUILDs")
parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true")
return parser
arguments = [_set_repo_remove_unknown_parser]

View File

@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import RepositoryPrinter from ahriman.core.formatters import RepositoryPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -52,3 +52,23 @@ class Repositories(Handler):
) )
for repository in cls.repositories_extract(dummy_args): for repository in cls.repositories_extract(dummy_args):
RepositoryPrinter(repository)(verbose=not args.id_only) RepositoryPrinter(repository)(verbose=not args.id_only)
@staticmethod
def _set_service_repositories(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repositories listing
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-repositories", help="show repositories",
description="list all available repositories")
parser.add_argument("--id-only", help="show machine readable identifier instead",
action=argparse.BooleanOptionalAction, default=False)
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
arguments = [_set_service_repositories]

View File

@ -20,7 +20,9 @@
import argparse import argparse
import tarfile import tarfile
from ahriman.application.handlers.handler import Handler from pathlib import Path
from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -46,3 +48,23 @@ class Restore(Handler):
""" """
with tarfile.open(args.path) as archive: with tarfile.open(args.path) as archive:
archive.extractall(path=args.output) # nosec archive.extractall(path=args.output) # nosec
@staticmethod
def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository restore subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-restore", help="restore repository data",
description="restore settings and database")
parser.add_argument("path", help="path of the input archive", type=Path)
parser.add_argument("-o", "--output", help="root path of the extracted files", type=Path, default=Path("/"))
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
arguments = [_set_repo_restore_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
import shlex import shlex
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -49,6 +49,25 @@ class Run(Handler):
status = Run.run_command(shlex.split(command), parser) status = Run.run_command(shlex.split(command), parser)
Run.check_status(True, status) Run.check_status(True, status)
@staticmethod
def _set_service_run(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for multicommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-run", aliases=["run"], help="run multiple commands",
description="run multiple commands on success run of the previous command",
epilog="Commands must be quoted by using usual bash rules. Processes will be spawned "
"under the same user as this command.")
parser.add_argument("command", help="command to be run (quoted) without ``ahriman``", nargs="+")
parser.set_defaults(architecture="", lock=None, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def run_command(command: list[str], parser: argparse.ArgumentParser) -> bool: def run_command(command: list[str], parser: argparse.ArgumentParser) -> bool:
""" """
@ -64,3 +83,5 @@ class Run(Handler):
args = parser.parse_args(command) args = parser.parse_args(command)
handler: Handler = args.handler handler: Handler = args.handler
return handler.execute(args) == 0 return handler.execute(args) == 0
arguments = [_set_service_run]

View File

@ -22,7 +22,7 @@ import argparse
from collections.abc import Callable, Iterable from collections.abc import Callable, Iterable
from dataclasses import fields from dataclasses import fields
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.alpm.remote import AUR, Official from ahriman.core.alpm.remote import AUR, Official
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import OptionError from ahriman.core.exceptions import OptionError
@ -68,6 +68,33 @@ class Search(Handler):
for package in Search.sort(packages_list, args.sort_by): for package in Search.sort(packages_list, args.sort_by):
AurPrinter(package)(verbose=args.info) AurPrinter(package)(verbose=args.info)
@staticmethod
def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for AUR search subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("aur-search", aliases=["search"], help="search for package",
description="search for package in AUR using API")
parser.add_argument("search",
help="search terms, can be specified multiple times, the result will match all terms",
nargs="+")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("--info", help="show additional package information",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--sort-by",
help="sort field by this field. In case if two packages have the same value of "
"the specified field, they will be always sorted by name",
default="name", choices=sorted(Search.SORT_FIELDS))
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]: def sort(packages: Iterable[AURPackage], sort_by: str) -> list[AURPackage]:
""" """
@ -90,3 +117,5 @@ class Search(Handler):
comparator: Callable[[AURPackage], tuple[str, str]] =\ comparator: Callable[[AURPackage], tuple[str, str]] =\
lambda package: (getattr(package, sort_by), package.name) lambda package: (getattr(package, sort_by), package.name)
return sorted(packages, key=comparator) return sorted(packages, key=comparator)
arguments = [_set_aur_search_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman import __version__ from ahriman import __version__
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import UpdatePrinter from ahriman.core.formatters import UpdatePrinter
from ahriman.models.package import Package from ahriman.models.package import Package
@ -58,3 +58,23 @@ class ServiceUpdates(Handler):
UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ") UpdatePrinter(remote, local_version)(verbose=True, separator=" -> ")
ServiceUpdates.check_status(args.exit_code, same_version) ServiceUpdates.check_status(args.exit_code, same_version)
@staticmethod
def _set_help_updates_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for service update check subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help-updates", help="check for service updates",
description="request AUR for current version and compare with current service version")
parser.add_argument("-e", "--exit-code", help="return non-zero exit code if updates available",
action="store_true")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
arguments = [_set_help_updates_parser]

View File

@ -24,11 +24,13 @@ from pwd import getpwuid
from urllib.parse import quote_plus as urlencode from urllib.parse import quote_plus as urlencode
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.exceptions import MissingArchitectureError
from ahriman.core.utils import enum_values
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
from ahriman.models.sign_settings import SignSettings
from ahriman.models.user import User from ahriman.models.user import User
@ -80,6 +82,44 @@ class Setup(Handler):
# lazy database sync # lazy database sync
application.repository.pacman.handle # pylint: disable=pointless-statement application.repository.pacman.handle # pylint: disable=pointless-statement
@staticmethod
def _set_service_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for setup subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-setup", aliases=["init", "repo-init", "repo-setup", "setup"],
help="initial service configuration",
description="create initial service configuration, requires root",
epilog="Create minimal configuration for the service according to provided options.")
parser.add_argument("--build-as-user", help="force makepkg user to the specific one")
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
type=Path,
default=Path("/") / "usr" / "share" / "devtools" / "pacman.conf.d" / "extra.conf")
parser.add_argument("--generate-salt", help="generate salt for user passwords",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("--makeflags-jobs",
help="append MAKEFLAGS variable with parallelism set to number of cores",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--mirror", help="use the specified explicitly mirror instead of including mirrorlist")
parser.add_argument("--multilib", help="add or do not multilib repository",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--packager", help="packager name and email", required=True)
parser.add_argument("--server", help="server to be used for devtools. If none set, local files will be used")
parser.add_argument("--sign-key", help="sign key id")
parser.add_argument("--sign-target", help="sign options", action="append",
type=SignSettings.from_option, choices=enum_values(SignSettings))
parser.add_argument("--web-port", help="port of the web service", type=int)
parser.add_argument("--web-unix-socket", help="path to unix socket used for interprocess communications",
type=Path)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod @staticmethod
def build_command(root: Path, repository_id: RepositoryId) -> Path: def build_command(root: Path, repository_id: RepositoryId) -> Path:
""" """
@ -240,3 +280,5 @@ class Setup(Handler):
command.unlink(missing_ok=True) command.unlink(missing_ok=True)
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH) command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
paths.chown(command) # we would like to keep owner inside ahriman's home paths.chown(command) # we would like to keep owner inside ahriman's home
arguments = [_set_service_setup_parser]

View File

@ -23,7 +23,7 @@ import sys
from pathlib import Path from pathlib import Path
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -63,3 +63,23 @@ class Shell(Handler):
code.interact(local=local_variables) code.interact(local=local_variables)
else: else:
code.InteractiveConsole(locals=local_variables).runcode(args.code) code.InteractiveConsole(locals=local_variables).runcode(args.code)
@staticmethod
def _set_service_shell_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for shell subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-shell", aliases=["shell"], help="invoke python shell",
description="drop into python shell")
parser.add_argument("code", help="instead of dropping into shell, just execute the specified code", nargs="?")
parser.add_argument("-v", "--verbose", help=argparse.SUPPRESS, action="store_true")
parser.set_defaults(lock=None, report=False)
return parser
arguments = [_set_service_shell_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -43,3 +43,22 @@ class Sign(Handler):
report(bool): force enable or disable reporting report(bool): force enable or disable reporting
""" """
Application(repository_id, configuration, report=report).sign(args.package) Application(repository_id, configuration, report=report).sign(args.package)
@staticmethod
def _set_repo_sign_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for sign subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-sign", aliases=["sign"], help="sign packages",
description="(re-)sign packages and repository database according to current settings",
epilog="Sign repository and/or packages as configured.")
parser.add_argument("package", help="sign only specified packages", nargs="*")
return parser
arguments = [_set_repo_sign_parser]

View File

@ -25,11 +25,11 @@ from collections.abc import Callable
from pathlib import Path from pathlib import Path
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter from ahriman.core.formatters import EventStatsPrinter, PackageStatsPrinter
from ahriman.core.utils import pretty_datetime from ahriman.core.utils import enum_values, pretty_datetime
from ahriman.models.event import Event from ahriman.models.event import Event, EventType
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -68,6 +68,30 @@ class Statistics(Handler):
case _: case _:
Statistics.stats_for_package(args.event, events, args.chart) Statistics.stats_for_package(args.event, events, args.chart)
@staticmethod
def _set_repo_statistics_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository statistics subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-statistics", help="repository statistics",
description="fetch repository statistics")
parser.add_argument("package", help="fetch only events for the specified package", nargs="?")
parser.add_argument("--chart", help="create updates chart and save it to the specified path", type=Path)
parser.add_argument("-e", "--event", help="event type filter",
type=EventType, choices=enum_values(EventType), default=EventType.PackageUpdated)
parser.add_argument("--from-date", help="only fetch events which are newer than the date")
parser.add_argument("--limit", help="limit response by specified amount of events", type=int, default=-1)
parser.add_argument("--offset", help="skip specified amount of events", type=int, default=0)
parser.add_argument("--to-date", help="only fetch events which are older than the date")
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod @staticmethod
def event_stats(event_type: str, events: list[Event]) -> None: def event_stats(event_type: str, events: list[Event]) -> None:
""" """
@ -168,3 +192,5 @@ class Statistics(Handler):
# chart if enabled # chart if enabled
if chart_path is not None: if chart_path is not None:
Statistics.plot_packages(event_type, by_object_id, chart_path) Statistics.plot_packages(event_type, by_object_id, chart_path)
arguments = [_set_repo_statistics_parser]

View File

@ -22,10 +22,11 @@ import argparse
from collections.abc import Callable from collections.abc import Callable
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import PackagePrinter, StatusPrinter from ahriman.core.formatters import PackagePrinter, StatusPrinter
from ahriman.models.build_status import BuildStatus from ahriman.core.utils import enum_values
from ahriman.models.build_status import BuildStatus, BuildStatusEnum
from ahriman.models.package import Package from ahriman.models.package import Package
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -68,3 +69,31 @@ class Status(Handler):
lambda item: args.status is None or item[1].status == args.status lambda item: args.status is None or item[1].status == args.status
for package, package_status in sorted(filter(filter_fn, packages), key=comparator): for package, package_status in sorted(filter(filter_fn, packages), key=comparator):
PackagePrinter(package, package_status)(verbose=args.info) PackagePrinter(package, package_status)(verbose=args.info)
@staticmethod
def _set_package_status_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status", aliases=["status"], help="get package status",
description="request status of the package",
epilog="This command requests package status from the web interface "
"if it is available.")
parser.add_argument("package", help="filter status by package base", nargs="*")
parser.add_argument("--ahriman", help="get service status itself", 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("--info", help="show additional package information",
action=argparse.BooleanOptionalAction, default=False)
parser.add_argument("-s", "--status", help="filter packages by status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum))
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_package_status_parser]

View File

@ -20,9 +20,11 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import enum_values
from ahriman.models.action import Action from ahriman.models.action import Action
from ahriman.models.build_status import BuildStatusEnum
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -59,3 +61,67 @@ class StatusUpdate(Handler):
case Action.Remove: case Action.Remove:
for package in args.package: for package in args.package:
client.package_remove(package) client.package_remove(package)
@staticmethod
def _set_package_status_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status remove subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status-remove", help="remove package status",
description="remove the package from the status page",
epilog="Please note that this subcommand does not remove the package itself, it just "
"clears the status page.")
parser.add_argument("package", help="remove specified packages from status page", nargs="+")
parser.set_defaults(action=Action.Remove, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_package_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package status update subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-status-update", aliases=["status-update"], help="update package status",
description="update package status on the status page")
parser.add_argument("package", help="set status for specified packages. "
"If no packages supplied, service status will be updated",
nargs="*")
parser.add_argument("-s", "--status", help="new package build status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
parser.set_defaults(action=Action.Update, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository status update subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-status-update", help="update repository status",
description="update repository status on the status page")
parser.add_argument("-s", "--status", help="new status",
type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success)
parser.set_defaults(action=Action.Update, lock=None, package=[], quiet=True, report=False, unsafe=True)
return parser
arguments = [
_set_package_status_remove_parser,
_set_package_status_update_parser,
_set_repo_status_update_parser,
]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter, TreePrinter from ahriman.core.formatters import StringPrinter, TreePrinter
from ahriman.core.tree import Tree from ahriman.core.tree import Tree
@ -58,3 +58,23 @@ class Structure(Handler):
# empty line # empty line
StringPrinter("")(verbose=False) StringPrinter("")(verbose=False)
@staticmethod
def _set_repo_tree_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository tree subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-tree", help="dump repository tree",
description="dump repository tree based on packages dependencies")
parser.add_argument("-p", "--partitions", help="also divide packages by independent partitions",
type=int, default=1)
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_repo_tree_parser]

View File

@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -50,6 +50,22 @@ class TreeMigrate(Handler):
# perform migration # perform migration
TreeMigrate.tree_move(current_tree, target_tree) TreeMigrate.tree_move(current_tree, target_tree)
@staticmethod
def _set_service_tree_migrate_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for tree migration subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-tree-migrate", help="migrate repository tree",
description="migrate repository tree between versions")
parser.set_defaults(lock=None, quiet=True, report=False)
return parser
@staticmethod @staticmethod
def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None: def tree_move(from_tree: RepositoryPaths, to_tree: RepositoryPaths) -> None:
""" """
@ -66,3 +82,5 @@ class TreeMigrate(Handler):
RepositoryPaths.repository, RepositoryPaths.repository,
): ):
attribute.fget(from_tree).rename(attribute.fget(to_tree)) # type: ignore[attr-defined] attribute.fget(from_tree).rename(attribute.fget(to_tree)) # type: ignore[attr-defined]
arguments = [_set_service_tree_migrate_parser]

View File

@ -20,7 +20,7 @@
import argparse import argparse
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.result import Result from ahriman.models.result import Result
@ -49,3 +49,98 @@ class Triggers(Handler):
loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger] loader.triggers = [loader.load_trigger(trigger, repository_id, configuration) for trigger in args.trigger]
application.on_start() application.on_start()
application.on_result(Result()) application.on_result(Result())
@staticmethod
def _set_repo_create_keyring_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for create-keyring subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-create-keyring", help="create keyring package",
description="create package which contains list of trusted keys as set by "
"configuration. Note, that this action will only create package, "
"the package itself has to be built manually")
parser.set_defaults(trigger=["ahriman.core.support.KeyringTrigger"])
return parser
@staticmethod
def _set_repo_create_mirrorlist_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for create-mirrorlist subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-create-mirrorlist", help="create mirrorlist package",
description="create package which contains list of available mirrors as set by "
"configuration. Note, that this action will only create package, "
"the package itself has to be built manually")
parser.set_defaults(trigger=["ahriman.core.support.MirrorlistTrigger"])
return parser
@staticmethod
def _set_repo_report_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for report subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-report", aliases=["report"], help="generate report",
description="generate repository report according to current settings",
epilog="Create and/or update repository report as configured.")
parser.set_defaults(trigger=["ahriman.core.report.ReportTrigger"])
return parser
@staticmethod
def _set_repo_sync_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository sync subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-sync", aliases=["sync"], help="sync repository",
description="sync repository files to remote server according to current settings",
epilog="Synchronize the repository to remote services as configured.")
parser.set_defaults(trigger=["ahriman.core.upload.UploadTrigger"])
return parser
@staticmethod
def _set_repo_triggers_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository triggers subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-triggers", help="run triggers",
description="run triggers on empty build result as configured by settings")
parser.add_argument("trigger", help="instead of running all triggers as set by configuration, just process "
"specified ones in order of mention", nargs="*")
return parser
arguments = [
_set_repo_create_keyring_parser,
_set_repo_create_mirrorlist_parser,
_set_repo_report_parser,
_set_repo_sync_parser,
_set_repo_triggers_parser,
]

View File

@ -19,7 +19,7 @@
# #
import argparse import argparse
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import StringPrinter from ahriman.core.formatters import StringPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -52,6 +52,25 @@ class UnsafeCommands(Handler):
for command in unsafe_commands: for command in unsafe_commands:
StringPrinter(command)(verbose=True) StringPrinter(command)(verbose=True)
@staticmethod
def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for listing unsafe commands
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help-commands-unsafe", help="list unsafe commands",
description="list unsafe commands as defined in default args")
parser.add_argument("subcommand",
help="instead of showing commands, just test command line for unsafe subcommand "
"and return 0 in case if command is safe and 1 otherwise", nargs="*")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def check_unsafe(command: list[str], unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None: def check_unsafe(command: list[str], unsafe_commands: list[str], parser: argparse.ArgumentParser) -> None:
""" """
@ -81,3 +100,5 @@ class UnsafeCommands(Handler):
subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None) subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None)
actions = subparser.choices if subparser is not None else {} actions = subparser.choices if subparser is not None else {}
return sorted(action_name for action_name, action in actions.items() if action.get_default("unsafe")) return sorted(action_name for action_name, action in actions.items() if action.get_default("unsafe"))
arguments = [_set_help_commands_unsafe_parser]

View File

@ -22,8 +22,9 @@ import argparse
from collections.abc import Callable from collections.abc import Callable
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import extract_user
from ahriman.models.packagers import Packagers from ahriman.models.packagers import Packagers
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -64,6 +65,78 @@ class Update(Handler):
result = application.update(packages, packagers, bump_pkgrel=args.increment) result = application.update(packages, packagers, bump_pkgrel=args.increment)
Update.check_status(args.exit_code, not result.is_empty) Update.check_status(args.exit_code, not result.is_empty)
@staticmethod
def _set_repo_check_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository check subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-check", aliases=["check"], help="check for updates",
description="check for packages updates. Same as repo-update --dry-run --no-manual")
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("--changes", help="calculate changes from the latest known commit if available",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
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",
action="count", default=False)
parser.set_defaults(aur=True, dependencies=False, dry_run=True, increment=False, local=True, manual=False,
username=None)
return parser
@staticmethod
def _set_repo_update_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for repository update subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("repo-update", aliases=["update"], help="update packages",
description="check for packages updates and run build process if requested")
parser.add_argument("package", help="filter check by package base", nargs="*")
parser.add_argument("--aur", help="enable or disable checking for AUR updates",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--changes", help="calculate changes from the latest known commit if available. "
"Only applicable in dry run mode",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--check-files", help="enable or disable checking of broken dependencies "
"(e.g. dynamically linked libraries or modules directories)",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--dependencies", help="process missing package dependencies",
action=argparse.BooleanOptionalAction, default=True)
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("--increment", help="increment package release (pkgrel) on duplicate",
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("-u", "--username", help="build as user", default=extract_user())
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",
action="count", default=False)
return parser
@staticmethod @staticmethod
def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]: def log_fn(application: Application, dry_run: bool) -> Callable[[str], None]:
""" """
@ -79,3 +152,8 @@ class Update(Handler):
def inner(line: str) -> None: def inner(line: str) -> None:
return print(line) if dry_run else application.logger.info(line) # pylint: disable=bad-builtin return print(line) if dry_run else application.logger.info(line) # pylint: disable=bad-builtin
return inner return inner
arguments = [
_set_repo_check_parser,
_set_repo_update_parser,
]

View File

@ -20,14 +20,16 @@
import argparse import argparse
import getpass import getpass
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.exceptions import PasswordError from ahriman.core.exceptions import PasswordError
from ahriman.core.formatters import UserPrinter from ahriman.core.formatters import UserPrinter
from ahriman.core.utils import enum_values
from ahriman.models.action import Action from ahriman.models.action import Action
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.user import User from ahriman.models.user import User
from ahriman.models.user_access import UserAccess
class Users(Handler): class Users(Handler):
@ -65,6 +67,73 @@ class Users(Handler):
case Action.Remove: case Action.Remove:
database.user_remove(args.username) database.user_remove(args.username)
@staticmethod
def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for create user subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("user-add", help="create or update user",
description="update user for web services with the given password and role. "
"In case if password was not entered it will be asked interactively")
parser.add_argument("username", help="username for web service")
parser.add_argument("--key", help="optional PGP key used by this user. The private key must be imported")
parser.add_argument("--packager", help="optional packager id used for build process in form of "
"`Name Surname <mail@example.com>`")
parser.add_argument(
"-p", "--password", help="user password. Blank password will be treated as empty password, "
"which is in particular must be used for OAuth2 authorization type.")
parser.add_argument("-R", "--role", help="user access level",
type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read)
parser.set_defaults(action=Action.Update, architecture="", exit_code=False, lock=None, quiet=True,
report=False, repository="")
return parser
@staticmethod
def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for user list subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("user-list", help="user known users and their access",
description="list users from the user mapping and their roles")
parser.add_argument("username", help="filter users by username", nargs="?")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.add_argument("-R", "--role", help="filter users by role", type=UserAccess,
choices=enum_values(UserAccess))
parser.set_defaults(action=Action.List, architecture="", lock=None, quiet=True, report=False, repository="",
unsafe=True)
return parser
@staticmethod
def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for user removal subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("user-remove", help="remove user",
description="remove user from the user mapping and update the configuration")
parser.add_argument("username", help="username for web service")
parser.set_defaults(action=Action.Remove, architecture="", exit_code=False, lock=None, quiet=True,
report=False, repository="")
return parser
@staticmethod @staticmethod
def user_create(args: argparse.Namespace) -> User: def user_create(args: argparse.Namespace) -> User:
""" """
@ -92,3 +161,9 @@ class Users(Handler):
return User(username=args.username, password=password, access=args.role, return User(username=args.username, password=password, access=args.role,
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
arguments = [
_set_user_add_parser,
_set_user_list_parser,
_set_user_remove_parser,
]

View File

@ -22,7 +22,7 @@ import copy
from typing import Any from typing import Any
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA, ConfigurationSchema from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA, ConfigurationSchema
from ahriman.core.exceptions import ExtensionError from ahriman.core.exceptions import ExtensionError
@ -63,6 +63,25 @@ class Validate(Handler):
# as we reach this part it means that we always have errors # as we reach this part it means that we always have errors
Validate.check_status(args.exit_code, False) Validate.check_status(args.exit_code, False)
@staticmethod
def _set_service_config_validate_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for config validation subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("service-config-validate", aliases=["config-validate", "repo-config-validate"],
help="validate system configuration",
description="validate configuration and print found errors")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if configuration is invalid",
action="store_true")
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod @staticmethod
def schema(repository_id: RepositoryId, configuration: Configuration) -> ConfigurationSchema: def schema(repository_id: RepositoryId, configuration: Configuration) -> ConfigurationSchema:
""" """
@ -136,3 +155,5 @@ class Validate(Handler):
Validate.schema_merge(value, schema[key]) Validate.schema_merge(value, schema[key])
return schema return schema
arguments = [_set_service_config_validate_parser]

View File

@ -25,7 +25,7 @@ from collections.abc import Generator
from importlib import metadata from importlib import metadata
from ahriman import __version__ from ahriman import __version__
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.formatters import VersionPrinter from ahriman.core.formatters import VersionPrinter
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
@ -59,6 +59,22 @@ class Versions(Handler):
packages = Versions.package_dependencies("ahriman") packages = Versions.package_dependencies("ahriman")
VersionPrinter("Installed packages", dict(packages))(verbose=False, separator=" ") VersionPrinter("Installed packages", dict(packages))(verbose=False, separator=" ")
@staticmethod
def _set_help_version_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for version subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("help-version", aliases=["version"], help="application version",
description="print application and its dependencies versions")
parser.set_defaults(architecture="", lock=None, quiet=True, report=False, repository="", unsafe=True)
return parser
@staticmethod @staticmethod
def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]: def package_dependencies(root: str) -> Generator[tuple[str, str], None, None]:
""" """
@ -96,3 +112,5 @@ class Versions(Handler):
yield distribution.name, distribution.version yield distribution.name, distribution.version
except metadata.PackageNotFoundError: except metadata.PackageNotFoundError:
continue continue
arguments = [_set_help_version_parser]

View File

@ -20,8 +20,9 @@
import argparse import argparse
from collections.abc import Generator from collections.abc import Generator
from pathlib import Path
from ahriman.application.handlers.handler import Handler from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.spawn import Spawn from ahriman.core.spawn import Spawn
from ahriman.core.triggers import TriggerLoader from ahriman.core.triggers import TriggerLoader
@ -71,6 +72,21 @@ class Web(Handler):
spawner.stop() spawner.stop()
spawner.join() spawner.join()
@staticmethod
def _set_web_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for web subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("web", help="web server", description="start web server")
parser.set_defaults(architecture="", lock=Path("ahriman-web.pid"), report=False, repository="")
return parser
@staticmethod @staticmethod
def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Generator[str, None, None]: def extract_arguments(args: argparse.Namespace, configuration: Configuration) -> Generator[str, None, None]:
""" """
@ -100,3 +116,5 @@ class Web(Handler):
# arguments from configuration # arguments from configuration
if (wait_timeout := configuration.getint("web", "wait_timeout", fallback=None)) is not None: if (wait_timeout := configuration.getint("web", "wait_timeout", fallback=None)) is not None:
yield from ["--wait-timeout", str(wait_timeout)] yield from ["--wait-timeout", str(wait_timeout)]
arguments = [_set_web_parser]

View File

@ -17,14 +17,14 @@
# 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/>.
# #
from typing import Any
try: try:
import aiohttp_security import aiohttp_security
_has_aiohttp_security = True _has_aiohttp_security = True
except ImportError: except ImportError:
_has_aiohttp_security = False _has_aiohttp_security = False
from typing import Any
__all__ = ["authorized_userid", "check_authorized", "forget", "remember"] __all__ = ["authorized_userid", "check_authorized", "forget", "remember"]

View File

@ -17,7 +17,8 @@
# 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/>.
# #
from logging import NullHandler # pylint: disable=imports-out-of-order # pylint: disable=imports-out-of-order
from logging import NullHandler
from typing import Any from typing import Any

View File

@ -0,0 +1,78 @@
#
# Copyright (c) 2021-2024 ahriman team.
#
# This file is part of ahriman
# (see https://github.com/arcan1s/ahriman).
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import inspect
from collections.abc import Generator
from importlib import import_module
from pathlib import Path
from pkgutil import ModuleInfo, walk_packages
from types import ModuleType
from typing import Any, TypeGuard, TypeVar
__all__ = ["implementations"]
T = TypeVar("T")
def _modules(module_root: Path, prefix: str) -> Generator[ModuleInfo, None, None]:
"""
extract available modules from package
Args:
module_root(Path): module root path
prefix(str): modules package prefix
Yields:
ModuleInfo: module information each available module
"""
prefix = f"{prefix}." if prefix else ""
for module_info in walk_packages([str(module_root)], prefix):
if module_info.ispkg:
yield from _modules(module_root / module_info.name, prefix)
else:
yield module_info
def implementations(root_module: ModuleType, base_class: type[T]) -> Generator[type[T], None, None]:
"""
extract implementations of the ``base_class`` from the module
Args:
root_module(ModuleType): root module
base_class(type[T]): base class type
Yields:
type[T]: found implementations
"""
def is_base_class(clazz: Any) -> TypeGuard[type[T]]:
return inspect.isclass(clazz) \
and issubclass(clazz, base_class) and clazz != base_class \
and clazz.__module__ == module.__name__
prefix = root_module.__name__
for module_root in root_module.__path__:
for module_info in _modules(Path(module_root), prefix):
module = import_module(module_info.name)
for _, attribute in inspect.getmembers(module, is_base_class):
yield attribute

View File

@ -18,93 +18,35 @@
# 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 aiohttp.web import Application, View from aiohttp.web import Application, View
from collections.abc import Generator
from importlib.machinery import SourceFileLoader import ahriman.web.views
from pathlib import Path
from pkgutil import ModuleInfo, iter_modules
from types import ModuleType
from typing import Any, Type, TypeGuard
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.module_loader import implementations
from ahriman.web.views.base import BaseView from ahriman.web.views.base import BaseView
__all__ = ["setup_routes"] __all__ = ["setup_routes"]
def _dynamic_routes(module_root: Path, configuration: Configuration) -> dict[str, Type[View]]: def _dynamic_routes(configuration: Configuration) -> dict[str, type[View]]:
""" """
extract dynamic routes based on views extract dynamic routes based on views
Args: Args:
module_root(Path): root module path with views
configuration(Configuration): configuration instance configuration(Configuration): configuration instance
Returns: Returns:
dict[str, Type[View]]: map of the route to its view dict[str, type[View]]: map of the route to its view
""" """
def is_base_view(clazz: Any) -> TypeGuard[Type[BaseView]]: routes: dict[str, type[View]] = {}
return isinstance(clazz, type) and issubclass(clazz, BaseView) for view in implementations(ahriman.web.views, BaseView):
view_routes = view.routes(configuration)
routes: dict[str, Type[View]] = {} routes.update([(route, view) for route in view_routes])
for module_info in _modules(module_root):
module = _module(module_info)
for attribute_name in dir(module):
view = getattr(module, attribute_name)
if not is_base_view(view):
continue
view_routes = view.routes(configuration)
routes.update([(route, view) for route in view_routes])
return routes return routes
def _module(module_info: ModuleInfo) -> ModuleType:
"""
load module from its info
Args:
module_info(ModuleInfo): module info descriptor
Returns:
ModuleType: loaded module
Raises:
ValueError: if loader is not an instance of :class:`importlib.machinery.SourceFileLoader`
"""
module_spec = module_info.module_finder.find_spec(module_info.name, None)
if module_spec is None:
raise ValueError(f"Module specification of {module_info.name} is empty")
loader = module_spec.loader
if not isinstance(loader, SourceFileLoader):
raise ValueError(f"Module {module_info.name} loader is not an instance of SourceFileLoader")
module = ModuleType(loader.name)
loader.exec_module(module)
return module
def _modules(module_root: Path) -> Generator[ModuleInfo, None, None]:
"""
extract available modules from package
Args:
module_root(Path): module root path
Yields:
ModuleInfo: module information each available module
"""
for module_info in iter_modules([str(module_root)]):
if module_info.ispkg:
yield from _modules(module_root / module_info.name)
else:
yield module_info
def setup_routes(application: Application, configuration: Configuration) -> None: def setup_routes(application: Application, configuration: Configuration) -> None:
""" """
setup all defined routes setup all defined routes
@ -115,6 +57,5 @@ def setup_routes(application: Application, configuration: Configuration) -> None
""" """
application.router.add_static("/static", configuration.getpath("web", "static_path"), follow_symlinks=True) application.router.add_static("/static", configuration.getpath("web", "static_path"), follow_symlinks=True)
views_root = Path(__file__).parent / "views" for route, view in _dynamic_routes(configuration).items():
for route, view in _dynamic_routes(views_root, configuration).items():
application.router.add_view(route, view) application.router.add_view(route, view)

View File

@ -4,7 +4,7 @@ import pytest
from pathlib import Path from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Handler from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError from ahriman.core.exceptions import ExitCode, MissingArchitectureError, MultipleArchitecturesError
from ahriman.models.log_handler import LogHandler from ahriman.models.log_handler import LogHandler
@ -19,7 +19,7 @@ def test_call(args: argparse.Namespace, configuration: Configuration, mocker: Mo
args.log_handler = LogHandler.Console args.log_handler = LogHandler.Console
args.quiet = False args.quiet = False
args.report = False args.report = False
mocker.patch("ahriman.application.handlers.Handler.run") mocker.patch("ahriman.application.handlers.handler.Handler.run")
configuration_mock = mocker.patch("ahriman.core.configuration.Configuration.from_path", return_value=configuration) configuration_mock = mocker.patch("ahriman.core.configuration.Configuration.from_path", return_value=configuration)
log_handler_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.handler", return_value=args.log_handler) log_handler_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.handler", return_value=args.log_handler)
log_load_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.load") log_load_mock = mocker.patch("ahriman.core.log.log_loader.LogLoader.load")
@ -76,7 +76,7 @@ def test_execute(args: argparse.Namespace, mocker: MockerFixture) -> None:
RepositoryId("i686", "aur"), RepositoryId("i686", "aur"),
RepositoryId("x86_64", "aur"), RepositoryId("x86_64", "aur"),
] ]
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=ids) mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=ids)
starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap") starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap")
Handler.execute(args) Handler.execute(args)
@ -88,7 +88,7 @@ def test_execute_multiple_not_supported(args: argparse.Namespace, mocker: Mocker
must raise an exception if multiple architectures are not supported by the handler must raise an exception if multiple architectures are not supported by the handler
""" """
args.command = "web" args.command = "web"
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=[ mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=[
RepositoryId("i686", "aur"), RepositoryId("i686", "aur"),
RepositoryId("x86_64", "aur"), RepositoryId("x86_64", "aur"),
]) ])
@ -102,7 +102,7 @@ def test_execute_single(args: argparse.Namespace, mocker: MockerFixture) -> None
""" """
must run execution in current process if only one architecture supplied must run execution in current process if only one architecture supplied
""" """
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=[ mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=[
RepositoryId("x86_64", "aur"), RepositoryId("x86_64", "aur"),
]) ])
starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap") starmap_mock = mocker.patch("multiprocessing.pool.Pool.starmap")

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Add from ahriman.application.handlers.add import Add
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package
@ -82,7 +82,7 @@ def test_run_with_updates(args: argparse.Namespace, configuration: Configuration
mocker.patch("ahriman.application.application.Application.add") mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result) application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
changes_mock = mocker.patch("ahriman.application.application.Application.changes") changes_mock = mocker.patch("ahriman.application.application.Application.changes")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies", dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
@ -113,7 +113,7 @@ def test_run_no_changes(args: argparse.Namespace, configuration: Configuration,
mocker.patch("ahriman.application.application.Application.add") mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.application.handlers.Handler.check_status") mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
mocker.patch("ahriman.application.application.Application.updates") mocker.patch("ahriman.application.application.Application.updates")
mocker.patch("ahriman.application.application.Application.with_dependencies") mocker.patch("ahriman.application.application.Application.with_dependencies")
mocker.patch("ahriman.application.application.Application.print_updates") mocker.patch("ahriman.application.application.Application.print_updates")
@ -138,7 +138,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.application.application.Application.with_dependencies") mocker.patch("ahriman.application.application.Application.with_dependencies")
mocker.patch("ahriman.application.application.Application.updates") mocker.patch("ahriman.application.application.Application.updates")
mocker.patch("ahriman.application.application.Application.print_updates") mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Add.run(args, repository_id, configuration, report=False) Add.run(args, repository_id, configuration, report=False)

View File

@ -4,7 +4,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import MagicMock from unittest.mock import MagicMock
from ahriman.application.handlers import Backup from ahriman.application.handlers.backup import Backup
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -28,7 +28,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
must run command must run command
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.application.handlers.Backup.get_paths", return_value=[Path("path")]) mocker.patch("ahriman.application.handlers.backup.Backup.get_paths", return_value=[Path("path")])
tarfile = MagicMock() tarfile = MagicMock()
add_mock = tarfile.__enter__.return_value = MagicMock() add_mock = tarfile.__enter__.return_value = MagicMock()
mocker.patch("ahriman.application.handlers.backup.tarfile.open", return_value=tarfile) mocker.patch("ahriman.application.handlers.backup.tarfile.open", return_value=tarfile)

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Change from ahriman.application.handlers.change import Change
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
@ -36,7 +36,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get",
return_value=Changes("sha", "change")) return_value=Changes("sha", "change"))
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -55,7 +55,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args.exit_code = True args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes()) mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes())
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Change.run(args, repository_id, configuration, report=False) Change.run(args, repository_id, configuration, report=False)

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Clean from ahriman.application.handlers.clean import Clean
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers import Copy from ahriman.application.handlers.copy import Copy
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum
@ -37,7 +37,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.handlers.Copy.copy_package") application_mock = mocker.patch("ahriman.application.handlers.copy.Copy.copy_package")
update_mock = mocker.patch("ahriman.application.application.Application.update") update_mock = mocker.patch("ahriman.application.application.Application.update")
remove_mock = mocker.patch("ahriman.application.application.Application.remove") remove_mock = mocker.patch("ahriman.application.application.Application.remove")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
@ -59,7 +59,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args.remove = True args.remove = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.Repository.packages", return_value=[package_ahriman])
mocker.patch("ahriman.application.handlers.Copy.copy_package") mocker.patch("ahriman.application.handlers.copy.Copy.copy_package")
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
remove_mock = mocker.patch("ahriman.application.application.Application.remove") remove_mock = mocker.patch("ahriman.application.application.Application.remove")
@ -77,7 +77,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args.exit_code = True args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.packages", return_value=[]) mocker.patch("ahriman.core.repository.Repository.packages", return_value=[])
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Copy.run(args, repository_id, configuration, report=False) Copy.run(args, repository_id, configuration, report=False)

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Daemon from ahriman.application.handlers.daemon import Daemon
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package
@ -31,7 +31,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, package_ahr
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
run_mock = mocker.patch("ahriman.application.handlers.Update.run") run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__", iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
return_value=iter([[package_ahriman.base]])) return_value=iter([[package_ahriman.base]]))
@ -50,7 +50,7 @@ def test_run_no_partitions(args: argparse.Namespace, configuration: Configuratio
args = _default_args(args) args = _default_args(args)
args.partitions = False args.partitions = False
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
run_mock = mocker.patch("ahriman.application.handlers.Update.run") run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__", iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
return_value=iter([[]])) return_value=iter([[]]))
@ -67,7 +67,7 @@ def test_run_no_updates(args: argparse.Namespace, configuration: Configuration,
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
run_mock = mocker.patch("ahriman.application.handlers.Update.run") run_mock = mocker.patch("ahriman.application.handlers.update.Update.run")
iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__", iter_mock = mocker.patch("ahriman.application.application.updates_iterator.UpdatesIterator.__iter__",
return_value=iter([[package_ahriman.base], None])) return_value=iter([[package_ahriman.base], None]))

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Dump from ahriman.application.handlers.dump import Dump
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration

View File

@ -3,7 +3,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.ahriman import _parser from ahriman.application.ahriman import _parser
from ahriman.application.handlers import Help from ahriman.application.handlers.help import Help
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import KeyImport from ahriman.application.handlers.key_import import KeyImport
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -6,7 +6,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers import Patch from ahriman.application.handlers.patch import Patch
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.action import Action from ahriman.models.action import Action
@ -40,9 +40,9 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
args = _default_args(args) args = _default_args(args)
args.action = Action.Update args.action = Action.Update
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_diff", patch_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_create_from_diff",
return_value=(args.package, PkgbuildPatch(None, "patch"))) return_value=(args.package, PkgbuildPatch(None, "patch")))
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create") application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Patch.run(args, repository_id, configuration, report=False) Patch.run(args, repository_id, configuration, report=False)
@ -61,8 +61,9 @@ def test_run_function(args: argparse.Namespace, configuration: Configuration, re
args.variable = "version" args.variable = "version"
patch = PkgbuildPatch(args.variable, args.patch) patch = PkgbuildPatch(args.variable, args.patch)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
patch_mock = mocker.patch("ahriman.application.handlers.Patch.patch_create_from_function", return_value=patch) patch_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_create_from_function",
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_create") return_value=patch)
application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_create")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Patch.run(args, repository_id, configuration, report=False) Patch.run(args, repository_id, configuration, report=False)
@ -79,7 +80,7 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, reposi
args.action = Action.List args.action = Action.List
args.variable = ["version"] args.variable = ["version"]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_list") application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_list")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Patch.run(args, repository_id, configuration, report=False) Patch.run(args, repository_id, configuration, report=False)
@ -95,7 +96,7 @@ def test_run_remove(args: argparse.Namespace, configuration: Configuration, repo
args.action = Action.Remove args.action = Action.Remove
args.variable = ["version"] args.variable = ["version"]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.handlers.Patch.patch_set_remove") application_mock = mocker.patch("ahriman.application.handlers.patch.Patch.patch_set_remove")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Patch.run(args, repository_id, configuration, report=False) Patch.run(args, repository_id, configuration, report=False)
@ -163,7 +164,7 @@ def test_patch_set_list(application: Application, mocker: MockerFixture) -> None
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")]) return_value=[PkgbuildPatch(None, "patch"), PkgbuildPatch("version", "value")])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
Patch.patch_set_list(application, "ahriman", ["version"], False) Patch.patch_set_list(application, "ahriman", ["version"], False)
get_mock.assert_called_once_with("ahriman", None) get_mock.assert_called_once_with("ahriman", None)
@ -178,7 +179,7 @@ def test_patch_set_list_all(application: Application, mocker: MockerFixture) ->
get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", get_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get",
return_value=[PkgbuildPatch(None, "patch")]) return_value=[PkgbuildPatch(None, "patch")])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
Patch.patch_set_list(application, "ahriman", None, False) Patch.patch_set_list(application, "ahriman", None, False)
get_mock.assert_called_once_with("ahriman", None) get_mock.assert_called_once_with("ahriman", None)
@ -191,7 +192,7 @@ def test_patch_set_list_empty_exception(application: Application, mocker: Mocker
must raise ExitCode exception on empty patch list must raise ExitCode exception on empty patch list
""" """
mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", return_value={}) mocker.patch("ahriman.core.status.local_client.LocalClient.package_patches_get", return_value={})
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
Patch.patch_set_list(application, "ahriman", [], True) Patch.patch_set_list(application, "ahriman", [], True)
check_mock.assert_called_once_with(True, []) check_mock.assert_called_once_with(True, [])

View File

@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers import Rebuild from ahriman.application.handlers.rebuild import Rebuild
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.build_status import BuildStatus, BuildStatusEnum from ahriman.models.build_status import BuildStatus, BuildStatusEnum
@ -43,11 +43,12 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
result = Result() result = Result()
result.add_updated(package_ahriman) result.add_updated(package_ahriman)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
extract_mock = mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[package_ahriman]) extract_mock = mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages",
return_value=[package_ahriman])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on",
return_value=[package_ahriman]) return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result) application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
on_start_mock = mocker.patch("ahriman.application.application.Application.on_start") on_start_mock = mocker.patch("ahriman.application.application.Application.on_start")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -70,7 +71,7 @@ def test_run_extract_packages(args: argparse.Namespace, configuration: Configura
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.add") mocker.patch("ahriman.application.application.Application.add")
mocker.patch("ahriman.application.application.Application.print_updates") mocker.patch("ahriman.application.application.Application.print_updates")
extract_mock = mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) extract_mock = mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False) Rebuild.run(args, repository_id, configuration, report=False)
@ -85,9 +86,9 @@ def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, rep
args = _default_args(args) args = _default_args(args)
args.dry_run = True args.dry_run = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[package_ahriman]) mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[package_ahriman])
application_mock = mocker.patch("ahriman.application.application.Application.update") application_mock = mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
print_mock = mocker.patch("ahriman.application.application.Application.print_updates") print_mock = mocker.patch("ahriman.application.application.Application.print_updates")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -106,7 +107,7 @@ def test_run_filter(args: argparse.Namespace, configuration: Configuration, repo
args.depends_on = ["python-aur"] args.depends_on = ["python-aur"]
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on") application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -122,7 +123,7 @@ def test_run_without_filter(args: argparse.Namespace, configuration: Configurati
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages", return_value=[]) mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages", return_value=[])
application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on") application_packages_mock = mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -139,10 +140,10 @@ def test_run_update_empty_exception(args: argparse.Namespace, configuration: Con
args.exit_code = True args.exit_code = True
args.dry_run = True args.dry_run = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages") mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[]) mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[])
mocker.patch("ahriman.application.application.Application.print_updates") mocker.patch("ahriman.application.application.Application.print_updates")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False) Rebuild.run(args, repository_id, configuration, report=False)
@ -157,10 +158,10 @@ def test_run_build_empty_exception(args: argparse.Namespace, configuration: Conf
args = _default_args(args) args = _default_args(args)
args.exit_code = True args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Rebuild.extract_packages") mocker.patch("ahriman.application.handlers.rebuild.Rebuild.extract_packages")
mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[package_ahriman]) mocker.patch("ahriman.core.repository.repository.Repository.packages_depend_on", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.Application.update", return_value=Result()) mocker.patch("ahriman.application.application.Application.update", return_value=Result())
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Rebuild.run(args, repository_id, configuration, report=False) Rebuild.run(args, repository_id, configuration, report=False)

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Remove from ahriman.application.handlers.remove import Remove
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import RemoveUnknown from ahriman.application.handlers.remove_unknown import RemoveUnknown
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Repositories from ahriman.application.handlers.repositories import Repositories
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -29,7 +29,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
args = _default_args(args) args = _default_args(args)
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
application_mock = mocker.patch("ahriman.application.handlers.Handler.repositories_extract", application_mock = mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract",
return_value=[repository_id]) return_value=[repository_id])
Repositories.run(args, repository_id, configuration, report=False) Repositories.run(args, repository_id, configuration, report=False)

View File

@ -4,7 +4,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import MagicMock from unittest.mock import MagicMock
from ahriman.application.handlers import Restore from ahriman.application.handlers.restore import Restore
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.ahriman import _parser from ahriman.application.ahriman import _parser
from ahriman.application.handlers import Run from ahriman.application.handlers.run import Run
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import ExitCode from ahriman.core.exceptions import ExitCode
@ -29,7 +29,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
must run command must run command
""" """
args = _default_args(args) args = _default_args(args)
application_mock = mocker.patch("ahriman.application.handlers.Run.run_command") application_mock = mocker.patch("ahriman.application.handlers.run.Run.run_command")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Run.run(args, repository_id, configuration, report=False) Run.run(args, repository_id, configuration, report=False)
@ -42,7 +42,7 @@ def test_run_failed(args: argparse.Namespace, configuration: Configuration, mock
""" """
args = _default_args(args) args = _default_args(args)
args.command = ["help", "config"] args.command = ["help", "config"]
application_mock = mocker.patch("ahriman.application.handlers.Run.run_command", return_value=False) application_mock = mocker.patch("ahriman.application.handlers.run.Run.run_command", return_value=False)
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
with pytest.raises(ExitCode): with pytest.raises(ExitCode):
@ -54,8 +54,13 @@ def test_run_command(mocker: MockerFixture) -> None:
""" """
must correctly run external command must correctly run external command
""" """
execute_mock = mocker.patch("ahriman.application.handlers.Help.execute") # because of dynamic load we need to patch exact instance of the object
Run.run_command(["help"], _parser()) parser = _parser()
subparser = next((action for action in parser._actions if isinstance(action, argparse._SubParsersAction)), None)
action = subparser.choices["help"]
execute_mock = mocker.patch.object(action.get_default("handler"), "execute")
Run.run_command(["help"], parser)
execute_mock.assert_called_once_with(pytest.helpers.anyvar(int)) execute_mock.assert_called_once_with(pytest.helpers.anyvar(int))

View File

@ -5,7 +5,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Search from ahriman.application.handlers.search import Search
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import OptionError from ahriman.core.exceptions import OptionError
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
@ -39,7 +39,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
aur_search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman]) aur_search_mock = mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
official_search_mock = mocker.patch("ahriman.core.alpm.remote.Official.multisearch", official_search_mock = mocker.patch("ahriman.core.alpm.remote.Official.multisearch",
return_value=[aur_package_ahriman]) return_value=[aur_package_ahriman])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -64,7 +64,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[]) mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
mocker.patch("ahriman.core.formatters.Printer.print") mocker.patch("ahriman.core.formatters.Printer.print")
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Search.run(args, repository_id, configuration, report=False) Search.run(args, repository_id, configuration, report=False)
@ -80,7 +80,7 @@ def test_run_sort(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman]) mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[]) mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort") sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Search.run(args, repository_id, configuration, report=False) Search.run(args, repository_id, configuration, report=False)
@ -100,7 +100,7 @@ def test_run_sort_by(args: argparse.Namespace, configuration: Configuration, rep
mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman]) mocker.patch("ahriman.core.alpm.remote.AUR.multisearch", return_value=[aur_package_ahriman])
mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[]) mocker.patch("ahriman.core.alpm.remote.Official.multisearch", return_value=[])
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
sort_mock = mocker.patch("ahriman.application.handlers.Search.sort") sort_mock = mocker.patch("ahriman.application.handlers.search.Search.sort")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Search.run(args, repository_id, configuration, report=False) Search.run(args, repository_id, configuration, report=False)

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman import __version__ from ahriman import __version__
from ahriman.application.handlers import ServiceUpdates from ahriman.application.handlers.service_updates import ServiceUpdates
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package
@ -34,7 +34,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
package_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) package_mock = mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
application_mock = mocker.patch("ahriman.core.formatters.Printer.print") application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
ServiceUpdates.run(args, repository_id, configuration, report=False) ServiceUpdates.run(args, repository_id, configuration, report=False)
@ -53,7 +53,7 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, reposi
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman) mocker.patch("ahriman.models.package.Package.from_aur", return_value=package_ahriman)
application_mock = mocker.patch("ahriman.core.formatters.Printer.print") application_mock = mocker.patch("ahriman.core.formatters.Printer.print")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
ServiceUpdates.run(args, repository_id, configuration, report=False) ServiceUpdates.run(args, repository_id, configuration, report=False)

View File

@ -7,7 +7,7 @@ from typing import Any
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from urllib.parse import quote_plus as urlencode from urllib.parse import quote_plus as urlencode
from ahriman.application.handlers import Setup from ahriman.application.handlers.setup import Setup
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.exceptions import MissingArchitectureError
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
@ -50,11 +50,11 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
""" """
args = _default_args(args) args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_ahriman") ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman")
devtools_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_devtools") devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools")
makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_makepkg") makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
sudo_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_sudo") sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
executable_mock = mocker.patch("ahriman.application.handlers.Setup.executable_create") executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init") init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -95,12 +95,12 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration,
args = _default_args(args) args = _default_args(args)
args.server = "server" args.server = "server"
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Setup.configuration_create_ahriman") mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman")
mocker.patch("ahriman.application.handlers.Setup.configuration_create_makepkg") mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
mocker.patch("ahriman.application.handlers.Setup.configuration_create_sudo") mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
mocker.patch("ahriman.application.handlers.Setup.executable_create") mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
mocker.patch("ahriman.core.alpm.repo.Repo.init") mocker.patch("ahriman.core.alpm.repo.Repo.init")
devtools_configuration_mock = mocker.patch("ahriman.application.handlers.Setup.configuration_create_devtools") devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False) Setup.run(args, repository_id, configuration, report=False)

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Shell from ahriman.application.handlers.shell import Shell
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Sign from ahriman.application.handlers.sign import Sign
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -5,7 +5,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Statistics from ahriman.application.handlers.statistics import Statistics
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.core.utils import pretty_datetime, utcnow from ahriman.core.utils import pretty_datetime, utcnow
@ -42,7 +42,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
events = [Event("1", "1"), Event("2", "2")] events = [Event("1", "1"), Event("2", "2")]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events) events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events)
application_mock = mocker.patch("ahriman.application.handlers.Statistics.stats_per_package") application_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Statistics.run(args, repository_id, configuration, report=False) Statistics.run(args, repository_id, configuration, report=False)
@ -60,7 +60,7 @@ def test_run_for_package(args: argparse.Namespace, configuration: Configuration,
events = [Event("1", "1"), Event("2", "2")] events = [Event("1", "1"), Event("2", "2")]
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events) events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=events)
application_mock = mocker.patch("ahriman.application.handlers.Statistics.stats_for_package") application_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_for_package")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Statistics.run(args, repository_id, configuration, report=False) Statistics.run(args, repository_id, configuration, report=False)
@ -77,7 +77,7 @@ def test_run_convert_from_date(args: argparse.Namespace, configuration: Configur
date = utcnow() date = utcnow()
args.from_date = date.isoformat() args.from_date = date.isoformat()
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Statistics.stats_per_package") mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[]) events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[])
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -94,7 +94,7 @@ def test_run_convert_to_date(args: argparse.Namespace, configuration: Configurat
date = utcnow() date = utcnow()
args.to_date = date.isoformat() args.to_date = date.isoformat()
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.handlers.Statistics.stats_per_package") mocker.patch("ahriman.application.handlers.statistics.Statistics.stats_per_package")
events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[]) events_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.event_get", return_value=[])
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -147,8 +147,8 @@ def test_stats_for_package(mocker: MockerFixture) -> None:
must print statistics for the package must print statistics for the package
""" """
events = [Event("event", "1"), Event("event", "1")] events = [Event("event", "1"), Event("event", "1")]
events_mock = mocker.patch("ahriman.application.handlers.Statistics.event_stats") events_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
chart_plot = mocker.patch("ahriman.application.handlers.Statistics.plot_times") chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_times")
Statistics.stats_for_package("event", events, None) Statistics.stats_for_package("event", events, None)
events_mock.assert_called_once_with("event", events) events_mock.assert_called_once_with("event", events)
@ -161,8 +161,8 @@ def test_stats_for_package_with_chart(mocker: MockerFixture) -> None:
""" """
local = Path("local") local = Path("local")
events = [Event("event", "1"), Event("event", "1")] events = [Event("event", "1"), Event("event", "1")]
mocker.patch("ahriman.application.handlers.Statistics.event_stats") mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
chart_plot = mocker.patch("ahriman.application.handlers.Statistics.plot_times") chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_times")
Statistics.stats_for_package("event", events, local) Statistics.stats_for_package("event", events, local)
chart_plot.assert_called_once_with("event", events, local) chart_plot.assert_called_once_with("event", events, local)
@ -174,8 +174,8 @@ def test_stats_per_package(mocker: MockerFixture) -> None:
""" """
events = [Event("event", "1"), Event("event", "2"), Event("event", "1")] events = [Event("event", "1"), Event("event", "2"), Event("event", "1")]
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
events_mock = mocker.patch("ahriman.application.handlers.Statistics.event_stats") events_mock = mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
chart_plot = mocker.patch("ahriman.application.handlers.Statistics.plot_packages") chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_packages")
Statistics.stats_per_package("event", events, None) Statistics.stats_per_package("event", events, None)
print_mock.assert_has_calls([ print_mock.assert_has_calls([
@ -192,8 +192,8 @@ def test_stats_per_package_with_chart(mocker: MockerFixture) -> None:
""" """
local = Path("local") local = Path("local")
events = [Event("event", "1"), Event("event", "2"), Event("event", "1")] events = [Event("event", "1"), Event("event", "2"), Event("event", "1")]
mocker.patch("ahriman.application.handlers.Statistics.event_stats") mocker.patch("ahriman.application.handlers.statistics.Statistics.event_stats")
chart_plot = mocker.patch("ahriman.application.handlers.Statistics.plot_packages") chart_plot = mocker.patch("ahriman.application.handlers.statistics.Statistics.plot_packages")
Statistics.stats_per_package("event", events, local) Statistics.stats_per_package("event", events, local)
chart_plot.assert_called_once_with("event", {"1": 2, "2": 1}, local) chart_plot.assert_called_once_with("event", {"1": 2, "2": 1}, local)

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Status from ahriman.application.handlers.status import Status
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
@ -43,7 +43,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.status.Client.status_get") application_mock = mocker.patch("ahriman.core.status.Client.status_get")
packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=packages) packages_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=packages)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -67,7 +67,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.Client.status_get") mocker.patch("ahriman.core.status.Client.status_get")
mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[]) mocker.patch("ahriman.core.status.local_client.LocalClient.package_get", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Status.run(args, repository_id, configuration, report=False) Status.run(args, repository_id, configuration, report=False)

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import StatusUpdate from ahriman.application.handlers.status_update import StatusUpdate
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.repository import Repository from ahriman.core.repository import Repository

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Structure from ahriman.application.handlers.structure import Structure
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package

View File

@ -4,7 +4,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import TreeMigrate from ahriman.application.handlers.tree_migrate import TreeMigrate
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
@ -15,7 +15,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
must run command must run command
""" """
tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create") tree_create_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.tree_create")
application_mock = mocker.patch("ahriman.application.handlers.TreeMigrate.tree_move") application_mock = mocker.patch("ahriman.application.handlers.tree_migrate.TreeMigrate.tree_move")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
old_paths = configuration.repository_paths old_paths = configuration.repository_paths
new_paths = RepositoryPaths(old_paths.root, old_paths.repository_id, _force_current_tree=True) new_paths = RepositoryPaths(old_paths.root, old_paths.repository_id, _force_current_tree=True)

View File

@ -2,7 +2,7 @@ import argparse
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Triggers from ahriman.application.handlers.triggers import Triggers
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.ahriman import _parser from ahriman.application.ahriman import _parser
from ahriman.application.handlers import UnsafeCommands from ahriman.application.handlers.unsafe_commands import UnsafeCommands
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -28,7 +28,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
must run command must run command
""" """
args = _default_args(args) args = _default_args(args)
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands", commands_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.get_unsafe_commands",
return_value=["command"]) return_value=["command"])
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
@ -44,9 +44,9 @@ def test_run_check(args: argparse.Namespace, configuration: Configuration, mocke
""" """
args = _default_args(args) args = _default_args(args)
args.subcommand = ["clean"] args.subcommand = ["clean"]
commands_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.get_unsafe_commands", commands_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.get_unsafe_commands",
return_value=["command"]) return_value=["command"])
check_mock = mocker.patch("ahriman.application.handlers.UnsafeCommands.check_unsafe") check_mock = mocker.patch("ahriman.application.handlers.unsafe_commands.UnsafeCommands.check_unsafe")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
UnsafeCommands.run(args, repository_id, configuration, report=False) UnsafeCommands.run(args, repository_id, configuration, report=False)
@ -58,7 +58,7 @@ def test_check_unsafe(mocker: MockerFixture) -> None:
""" """
must check if command is unsafe must check if command is unsafe
""" """
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
UnsafeCommands.check_unsafe(["service-clean"], ["service-clean"], _parser()) UnsafeCommands.check_unsafe(["service-clean"], ["service-clean"], _parser())
check_mock.assert_called_once_with(True, False) check_mock.assert_called_once_with(True, False)
@ -67,7 +67,7 @@ def test_check_unsafe_safe(mocker: MockerFixture) -> None:
""" """
must check if command is safe must check if command is safe
""" """
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
UnsafeCommands.check_unsafe(["package-status"], ["service-clean"], _parser()) UnsafeCommands.check_unsafe(["package-status"], ["service-clean"], _parser())
check_mock.assert_called_once_with(True, True) check_mock.assert_called_once_with(True, True)

View File

@ -5,7 +5,7 @@ from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers import Update from ahriman.application.handlers.update import Update
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.package import Package from ahriman.models.package import Package
@ -49,7 +49,7 @@ def test_run(args: argparse.Namespace, package_ahriman: Package, configuration:
result.add_updated(package_ahriman) result.add_updated(package_ahriman)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result) application_mock = mocker.patch("ahriman.application.application.Application.update", return_value=result)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies", dependencies_mock = mocker.patch("ahriman.application.application.Application.with_dependencies",
return_value=[package_ahriman]) return_value=[package_ahriman])
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
@ -81,7 +81,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args.dry_run = True args.dry_run = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.updates", return_value=[]) mocker.patch("ahriman.application.application.Application.updates", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False) Update.run(args, repository_id, configuration, report=False)
@ -101,7 +101,7 @@ def test_run_update_empty_exception(args: argparse.Namespace, package_ahriman: P
mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman]) mocker.patch("ahriman.application.application.Application.with_dependencies", return_value=[package_ahriman])
mocker.patch("ahriman.application.application.Application.print_updates") mocker.patch("ahriman.application.application.Application.print_updates")
mocker.patch("ahriman.application.application.Application.changes") mocker.patch("ahriman.application.application.Application.changes")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Update.run(args, repository_id, configuration, report=False) Update.run(args, repository_id, configuration, report=False)
@ -117,7 +117,7 @@ def test_run_dry_run(args: argparse.Namespace, package_ahriman: Package, configu
args.dry_run = True args.dry_run = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.application.application.Application.update") application_mock = mocker.patch("ahriman.application.application.Application.update")
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman]) updates_mock = mocker.patch("ahriman.application.application.Application.updates", return_value=[package_ahriman])
changes_mock = mocker.patch("ahriman.application.application.Application.changes") changes_mock = mocker.patch("ahriman.application.application.Application.changes")
@ -140,7 +140,7 @@ def test_run_no_changes(args: argparse.Namespace, configuration: Configuration,
args.changes = False args.changes = False
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.application.application.Application.update") mocker.patch("ahriman.application.application.Application.update")
mocker.patch("ahriman.application.handlers.Handler.check_status") mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
mocker.patch("ahriman.application.application.Application.updates") mocker.patch("ahriman.application.application.Application.updates")
changes_mock = mocker.patch("ahriman.application.application.Application.changes") changes_mock = mocker.patch("ahriman.application.application.Application.changes")

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Users from ahriman.application.handlers.users import Users
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.exceptions import PasswordError from ahriman.core.exceptions import PasswordError
@ -42,7 +42,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, database: S
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user) mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user) create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update") update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -60,7 +60,7 @@ def test_run_empty_salt(args: argparse.Namespace, configuration: Configuration,
user = User(username=args.username, password=args.password, access=args.role, user = User(username=args.username, password=args.password, access=args.role,
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user) mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user) create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update") update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -80,7 +80,7 @@ def test_run_empty_salt_without_password(args: argparse.Namespace, configuration
packager_id=args.packager, key=args.key) packager_id=args.packager, key=args.key)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.models.user.User.hash_password", return_value=user) mocker.patch("ahriman.models.user.User.hash_password", return_value=user)
create_user_mock = mocker.patch("ahriman.application.handlers.Users.user_create", return_value=user) create_user_mock = mocker.patch("ahriman.application.handlers.users.Users.user_create", return_value=user)
update_mock = mocker.patch("ahriman.core.database.SQLite.user_update") update_mock = mocker.patch("ahriman.core.database.SQLite.user_update")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -97,7 +97,7 @@ def test_run_list(args: argparse.Namespace, configuration: Configuration, databa
args = _default_args(args) args = _default_args(args)
args.action = Action.List args.action = Action.List
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user]) list_mock = mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[user])
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
@ -116,7 +116,7 @@ def test_run_empty_exception(args: argparse.Namespace, configuration: Configurat
args.exit_code = True args.exit_code = True
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[]) mocker.patch("ahriman.core.database.SQLite.user_list", return_value=[])
check_mock = mocker.patch("ahriman.application.handlers.Handler.check_status") check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Users.run(args, repository_id, configuration, report=False) Users.run(args, repository_id, configuration, report=False)

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Validate from ahriman.application.handlers.validate import Validate
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA from ahriman.core.configuration.schema import CONFIGURATION_SCHEMA
from ahriman.core.configuration.validator import Validator from ahriman.core.configuration.validator import Validator

View File

@ -4,7 +4,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from unittest.mock import call as MockCall from unittest.mock import call as MockCall
from ahriman.application.handlers import Versions from ahriman.application.handlers.versions import Versions
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
@ -12,7 +12,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc
""" """
must run command must run command
""" """
application_mock = mocker.patch("ahriman.application.handlers.Versions.package_dependencies") application_mock = mocker.patch("ahriman.application.handlers.versions.Versions.package_dependencies")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print") print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()

View File

@ -3,7 +3,7 @@ import pytest
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application.handlers import Web from ahriman.application.handlers.web import Web
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.log_handler import LogHandler from ahriman.models.log_handler import LogHandler
@ -43,7 +43,7 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop") stop_mock = mocker.patch("ahriman.core.spawn.Spawn.stop")
join_mock = mocker.patch("ahriman.core.spawn.Spawn.join") join_mock = mocker.patch("ahriman.core.spawn.Spawn.join")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
mocker.patch("ahriman.application.handlers.Handler.repositories_extract", return_value=[repository_id]) mocker.patch("ahriman.application.handlers.handler.Handler.repositories_extract", return_value=[repository_id])
Web.run(args, repository_id, configuration, report=False) Web.run(args, repository_id, configuration, report=False)
setup_mock.assert_called_once_with(configuration, pytest.helpers.anyvar(int), [repository_id]) setup_mock.assert_called_once_with(configuration, pytest.helpers.anyvar(int), [repository_id])

View File

@ -5,7 +5,7 @@ from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from ahriman.application import ahriman from ahriman.application import ahriman
from ahriman.application.handlers import Handler from ahriman.application.handlers.handler import Handler
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.models.action import Action from ahriman.models.action import Action
from ahriman.models.build_status import BuildStatusEnum from ahriman.models.build_status import BuildStatusEnum

View File

@ -0,0 +1,25 @@
import ahriman.web.views
from pathlib import Path
from ahriman.core.module_loader import _modules, implementations
from ahriman.web.views.base import BaseView
def test_implementations() -> None:
"""
must load implementations from the package
"""
routes = list(implementations(ahriman.web.views, BaseView))
assert routes
assert all(isinstance(view, type) for view in routes)
assert all(issubclass(view, BaseView) for view in routes)
def test_modules() -> None:
"""
must load modules
"""
modules = list(_modules(Path(__file__).parent.parent, "ahriman.web.views"))
assert modules
assert all(not module.ispkg for module in modules)

View File

@ -1,14 +1,9 @@
import pytest
from aiohttp.web import Application from aiohttp.web import Application
from importlib.machinery import ModuleSpec
from pathlib import Path from pathlib import Path
from pytest_mock import MockerFixture
from types import ModuleType
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.utils import walk from ahriman.core.utils import walk
from ahriman.web.routes import _dynamic_routes, _module, _modules, setup_routes from ahriman.web.routes import _dynamic_routes, setup_routes
def test_dynamic_routes(resource_path_root: Path, configuration: Configuration) -> None: def test_dynamic_routes(resource_path_root: Path, configuration: Configuration) -> None:
@ -22,54 +17,11 @@ def test_dynamic_routes(resource_path_root: Path, configuration: Configuration)
if file.suffix == ".py" and file.name not in ("__init__.py", "base.py", "status_view_guard.py") if file.suffix == ".py" and file.name not in ("__init__.py", "base.py", "status_view_guard.py")
] ]
routes = _dynamic_routes(views_root, configuration) routes = _dynamic_routes(configuration)
assert all(isinstance(view, type) for view in routes.values()) assert all(isinstance(view, type) for view in routes.values())
assert len(set(routes.values())) == len(expected_views) assert len(set(routes.values())) == len(expected_views)
def test_module(mocker: MockerFixture) -> None:
"""
must load module
"""
exec_mock = mocker.patch("importlib.machinery.SourceFileLoader.exec_module")
module_info = next(_modules(Path(__file__).parent))
module = _module(module_info)
assert isinstance(module, ModuleType)
exec_mock.assert_called_once_with(pytest.helpers.anyvar(int))
def test_module_no_spec(mocker: MockerFixture) -> None:
"""
must raise ValueError if spec is not available
"""
mocker.patch("importlib.machinery.FileFinder.find_spec", return_value=None)
module_info = next(_modules(Path(__file__).parent))
with pytest.raises(ValueError):
_module(module_info)
def test_module_no_loader(mocker: MockerFixture) -> None:
"""
must raise ValueError if loader is not available
"""
mocker.patch("importlib.machinery.FileFinder.find_spec", return_value=ModuleSpec("name", None))
module_info = next(_modules(Path(__file__).parent))
with pytest.raises(ValueError):
_module(module_info)
def test_modules() -> None:
"""
must load modules
"""
modules = list(_modules(Path(__file__).parent.parent))
assert modules
assert all(not module.ispkg for module in modules)
def test_setup_routes(application: Application, configuration: Configuration) -> None: def test_setup_routes(application: Application, configuration: Configuration) -> None:
""" """
must generate non-empty list of routes must generate non-empty list of routes

View File

@ -1,6 +1,7 @@
import pytest import pytest
from aiohttp.test_utils import TestClient from aiohttp.test_utils import TestClient
from pytest_mock import MockerFixture
from ahriman.models.user_access import UserAccess from ahriman.models.user_access import UserAccess
from ahriman.web.views.static import StaticView from ahriman.web.views.static import StaticView
@ -31,12 +32,12 @@ async def test_get(client_with_auth: TestClient) -> None:
assert response.headers["Location"] == "/static/favicon.ico" assert response.headers["Location"] == "/static/favicon.ico"
async def test_get_not_found(client_with_auth: TestClient) -> None: async def test_get_not_found(client_with_auth: TestClient, mocker: MockerFixture) -> None:
""" """
must raise not found if path is invalid must raise not found if path is invalid
""" """
for route in client_with_auth.app.router.routes(): print([route.handler for route in client_with_auth.app.router.routes()])
if hasattr(route.handler, "ROUTES"): static_route = next(route for route in client_with_auth.app.router.routes() if route.handler == StaticView)
route.handler.ROUTES = [] mocker.patch.object(static_route.handler, "ROUTES", [])
response = await client_with_auth.get("/favicon.ico", allow_redirects=False) response = await client_with_auth.get("/favicon.ico", allow_redirects=False)
assert response.status == 404 assert response.status == 404