diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index ea6efbdb..03ab648e 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -157,7 +157,8 @@ def _set_aur_search_parser(root: SubParserAction) -> argparse.ArgumentParser: 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(handlers.Search.SORT_FIELDS)) - parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, report=False, quiet=True, unsafe=True) + parser.set_defaults(handler=handlers.Search, architecture=[""], lock=None, report=False, repository=[""], + quiet=True, unsafe=True) return parser @@ -175,8 +176,8 @@ def _set_help_parser(root: SubParserAction) -> argparse.ArgumentParser: description="show help message for application or command and exit", formatter_class=_formatter) parser.add_argument("command", help="show help message for specific command", nargs="?") - parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, report=False, quiet=True, unsafe=True, - parser=_parser) + parser.set_defaults(handler=handlers.Help, architecture=[""], lock=None, report=False, repository=[""], quiet=True, + unsafe=True, parser=_parser) return parser @@ -194,8 +195,8 @@ def _set_help_commands_unsafe_parser(root: SubParserAction) -> argparse.Argument description="list unsafe commands as defined in default args", formatter_class=_formatter) parser.add_argument("command", 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(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, quiet=True, - unsafe=True, parser=_parser) + parser.set_defaults(handler=handlers.UnsafeCommands, architecture=[""], lock=None, report=False, repository=[""], + quiet=True, unsafe=True, parser=_parser) return parser @@ -213,8 +214,8 @@ def _set_help_updates_parser(root: SubParserAction) -> argparse.ArgumentParser: description="request AUR for current version and compare with current service version", formatter_class=_formatter) parser.add_argument("-e", "--exit-code", help="return non-zero exit code if updates available", action="store_true") - parser.set_defaults(handler=handlers.ServiceUpdates, architecture=[""], lock=None, report=False, quiet=True, - unsafe=True) + parser.set_defaults(handler=handlers.ServiceUpdates, architecture=[""], lock=None, report=False, repository=[""], + quiet=True, unsafe=True) return parser @@ -230,7 +231,8 @@ def _set_help_version_parser(root: SubParserAction) -> argparse.ArgumentParser: """ parser = root.add_parser("help-version", aliases=["version"], help="application version", description="print application and its dependencies versions", formatter_class=_formatter) - parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, report=False, quiet=True, unsafe=True) + parser.set_defaults(handler=handlers.Versions, architecture=[""], lock=None, report=False, repository=[""], + quiet=True, unsafe=True) return parser @@ -381,7 +383,8 @@ def _set_patch_add_parser(root: SubParserAction) -> argparse.ArgumentParser: "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(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False) + parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False, + repository=[""]) return parser @@ -402,7 +405,7 @@ def _set_patch_list_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("-v", "--variable", help="if set, show only patches for specified PKGBUILD variables", action="append") parser.set_defaults(handler=handlers.Patch, action=Action.List, architecture=[""], lock=None, report=False, - unsafe=True) + repository=[""], unsafe=True) return parser @@ -423,7 +426,8 @@ def _set_patch_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: "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(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, report=False) + parser.set_defaults(handler=handlers.Patch, action=Action.Remove, architecture=[""], lock=None, report=False, + repository=[""]) return parser @@ -448,7 +452,7 @@ def _set_patch_set_add_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("-t", "--track", help="files which has to be tracked", action="append", default=["*.diff", "*.patch"]) parser.set_defaults(handler=handlers.Patch, action=Action.Update, architecture=[""], lock=None, report=False, - variable=None) + repository=[""], variable=None) return parser @@ -465,7 +469,8 @@ def _set_repo_backup_parser(root: SubParserAction) -> argparse.ArgumentParser: parser = root.add_parser("repo-backup", help="backup repository data", description="backup repository settings and database", formatter_class=_formatter) parser.add_argument("path", help="path of the output archive", type=Path) - parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, report=False, unsafe=True) + parser.set_defaults(handler=handlers.Backup, architecture=[""], lock=None, report=False, repository=[""], + unsafe=True) return parser @@ -644,7 +649,8 @@ def _set_repo_restore_parser(root: SubParserAction) -> argparse.ArgumentParser: description="restore settings and database", formatter_class=_formatter) 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(handler=handlers.Restore, architecture=[""], lock=None, report=False, unsafe=True) + parser.set_defaults(handler=handlers.Restore, architecture=[""], lock=None, report=False, repository=[""], + unsafe=True) return parser @@ -681,7 +687,7 @@ def _set_repo_status_update_parser(root: SubParserAction) -> argparse.ArgumentPa description="update repository status on the status page", formatter_class=_formatter) parser.add_argument("-s", "--status", help="new status", type=BuildStatusEnum, choices=enum_values(BuildStatusEnum), default=BuildStatusEnum.Success) - parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, report=False, package=[], + parser.set_defaults(handler=handlers.StatusUpdate, action=Action.Update, lock=None, package=[], report=False, quiet=True, unsafe=True) return parser @@ -865,7 +871,7 @@ def _set_service_key_import_parser(root: SubParserAction) -> argparse.ArgumentPa formatter_class=_formatter) 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(handler=handlers.KeyImport, architecture=[""], lock=None, report=False) + parser.set_defaults(handler=handlers.KeyImport, architecture=[""], lock=None, report=False, repository=[""]) return parser @@ -946,7 +952,7 @@ def _set_user_add_parser(root: SubParserAction) -> argparse.ArgumentParser: parser.add_argument("-R", "--role", help="user access level", type=UserAccess, choices=enum_values(UserAccess), default=UserAccess.Read) parser.set_defaults(handler=handlers.Users, action=Action.Update, architecture=[""], lock=None, report=False, - quiet=True) + repository=[""], quiet=True) return parser @@ -967,7 +973,7 @@ def _set_user_list_parser(root: SubParserAction) -> argparse.ArgumentParser: 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(handler=handlers.Users, action=Action.List, architecture=[""], lock=None, report=False, - quiet=True, unsafe=True) + repository=[""], quiet=True, unsafe=True) return parser @@ -986,7 +992,7 @@ def _set_user_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: formatter_class=_formatter) parser.add_argument("username", help="username for web service") parser.set_defaults(handler=handlers.Users, action=Action.Remove, architecture=[""], lock=None, report=False, - quiet=True) + repository=[""], quiet=True) return parser diff --git a/src/ahriman/application/handlers/backup.py b/src/ahriman/application/handlers/backup.py index ec10b913..c01ac485 100644 --- a/src/ahriman/application/handlers/backup.py +++ b/src/ahriman/application/handlers/backup.py @@ -34,7 +34,7 @@ class Backup(Handler): backup packages handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/dump.py b/src/ahriman/application/handlers/dump.py index 63fa6358..15533059 100644 --- a/src/ahriman/application/handlers/dump.py +++ b/src/ahriman/application/handlers/dump.py @@ -30,7 +30,7 @@ class Dump(Handler): dump configuration handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/handler.py b/src/ahriman/application/handlers/handler.py index f670f3a3..b717b1bc 100644 --- a/src/ahriman/application/handlers/handler.py +++ b/src/ahriman/application/handlers/handler.py @@ -35,7 +35,6 @@ class Handler: base handler class for command callbacks Attributes: - ALLOW_AUTO_ARCHITECTURE_RUN(bool): (class attribute) allow defining architecture from existing repositories ALLOW_MULTI_ARCHITECTURE_RUN(bool): (class attribute) allow running with multiple architectures Examples: @@ -47,7 +46,6 @@ class Handler: >>> Add.execute(args) """ - ALLOW_AUTO_ARCHITECTURE_RUN = True ALLOW_MULTI_ARCHITECTURE_RUN = True @classmethod @@ -121,32 +119,35 @@ class Handler: Raises: MissingArchitectureError: if no architecture set and automatic detection is not allowed or failed """ - if not cls.ALLOW_AUTO_ARCHITECTURE_RUN and args.architecture is None: - # for some parsers (e.g. config) we need to run with specific architecture - # for those cases architecture must be set explicitly - raise MissingArchitectureError(args.command) - configuration = Configuration() configuration.load(args.configuration) - name = configuration.get("repository", "name", fallback="") # will only be used for legacy mode + # pylint, wtf??? + root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return - if args.architecture: # architecture is specified explicitly - repositories = args.repository or [name] # fallback for legacy mode - return sorted( - set( - RepositoryId(architecture, repository) - for architecture in args.architecture - for repository in repositories - ) + # extract repository names first + names = args.repository + if names is None: # try to read file system first + names = RepositoryPaths.known_repositories(root) + if not names: # try to read configuration now + names = [configuration.get("repository", "name")] + + # extract architecture names + if (architectures := args.architecture) is not None: + repositories = set( + RepositoryId(architecture, name) + for name in names + for architecture in architectures + ) + else: # try to read from file system + repositories = set( + RepositoryId(architecture, name) + for name in names + for architecture in RepositoryPaths.known_architectures(root, name) ) - # wtf??? - root = configuration.getpath("repository", "root") # pylint: disable=assignment-from-no-return - architectures = RepositoryPaths.known_architectures(root, name) - - if not architectures: # well we did not find anything + if not repositories: raise MissingArchitectureError(args.command) - return sorted(architectures) + return sorted(repositories) @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/help.py b/src/ahriman/application/handlers/help.py index ba0354f0..9be37636 100644 --- a/src/ahriman/application/handlers/help.py +++ b/src/ahriman/application/handlers/help.py @@ -29,7 +29,7 @@ class Help(Handler): help handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/key_import.py b/src/ahriman/application/handlers/key_import.py index 2d4ed7f7..4dac06fb 100644 --- a/src/ahriman/application/handlers/key_import.py +++ b/src/ahriman/application/handlers/key_import.py @@ -30,7 +30,7 @@ class KeyImport(Handler): key import packages handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/patch.py b/src/ahriman/application/handlers/patch.py index 6b417703..9121a236 100644 --- a/src/ahriman/application/handlers/patch.py +++ b/src/ahriman/application/handlers/patch.py @@ -38,6 +38,8 @@ class Patch(Handler): patch control handler """ + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action + @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, report: bool) -> None: diff --git a/src/ahriman/application/handlers/restore.py b/src/ahriman/application/handlers/restore.py index 05901904..e06cefa7 100644 --- a/src/ahriman/application/handlers/restore.py +++ b/src/ahriman/application/handlers/restore.py @@ -31,7 +31,7 @@ class Restore(Handler): restore packages handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/search.py b/src/ahriman/application/handlers/search.py index c9607775..fd1df635 100644 --- a/src/ahriman/application/handlers/search.py +++ b/src/ahriman/application/handlers/search.py @@ -40,7 +40,7 @@ class Search(Handler): SORT_FIELDS(set[str]): (class attribute) allowed fields to sort the package list """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action SORT_FIELDS = { field.name for field in fields(AURPackage) diff --git a/src/ahriman/application/handlers/service_updates.py b/src/ahriman/application/handlers/service_updates.py index 758c4a5b..f45b7599 100644 --- a/src/ahriman/application/handlers/service_updates.py +++ b/src/ahriman/application/handlers/service_updates.py @@ -33,7 +33,7 @@ class ServiceUpdates(Handler): service updates handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/setup.py b/src/ahriman/application/handlers/setup.py index 3e459c11..d2790053 100644 --- a/src/ahriman/application/handlers/setup.py +++ b/src/ahriman/application/handlers/setup.py @@ -25,6 +25,7 @@ from pwd import getpwuid from ahriman.application.application import Application from ahriman.application.handlers import Handler from ahriman.core.configuration import Configuration +from ahriman.core.exceptions import MissingArchitectureError from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.user import User @@ -40,7 +41,7 @@ class Setup(Handler): SUDOERS_DIR_PATH(Path): (class attribute) path to sudoers.d includes directory """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io ARCHBUILD_COMMAND_PATH = Path("/usr") / "bin" / "archbuild" MIRRORLIST_PATH = Path("/etc") / "pacman.d" / "mirrorlist" @@ -58,6 +59,10 @@ class Setup(Handler): configuration(Configuration): configuration instance report(bool): force enable or disable reporting """ + # special check for args to avoid auto definition for setup command + if args.architecture is None or args.repository is None: + raise MissingArchitectureError(args.command) + Setup.configuration_create_ahriman(args, repository_id, configuration) configuration.reload() diff --git a/src/ahriman/application/handlers/shell.py b/src/ahriman/application/handlers/shell.py index 9e1ef7cb..d3d026fb 100644 --- a/src/ahriman/application/handlers/shell.py +++ b/src/ahriman/application/handlers/shell.py @@ -34,7 +34,7 @@ class Shell(Handler): python shell handler """ - ALLOW_MULTI_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/status.py b/src/ahriman/application/handlers/status.py index 75776e94..6700ca36 100644 --- a/src/ahriman/application/handlers/status.py +++ b/src/ahriman/application/handlers/status.py @@ -35,7 +35,7 @@ class Status(Handler): package status handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/status_update.py b/src/ahriman/application/handlers/status_update.py index 3df723ec..ff1f63f4 100644 --- a/src/ahriman/application/handlers/status_update.py +++ b/src/ahriman/application/handlers/status_update.py @@ -31,7 +31,7 @@ class StatusUpdate(Handler): status update handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/structure.py b/src/ahriman/application/handlers/structure.py index f3ba279c..cc7d5bb4 100644 --- a/src/ahriman/application/handlers/structure.py +++ b/src/ahriman/application/handlers/structure.py @@ -32,7 +32,7 @@ class Structure(Handler): dump repository structure handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/unsafe_commands.py b/src/ahriman/application/handlers/unsafe_commands.py index e6d384b9..68c85c85 100644 --- a/src/ahriman/application/handlers/unsafe_commands.py +++ b/src/ahriman/application/handlers/unsafe_commands.py @@ -30,7 +30,7 @@ class UnsafeCommands(Handler): unsafe command help parser """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/users.py b/src/ahriman/application/handlers/users.py index 11357e21..17ef9876 100644 --- a/src/ahriman/application/handlers/users.py +++ b/src/ahriman/application/handlers/users.py @@ -35,7 +35,7 @@ class Users(Handler): user management handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/validate.py b/src/ahriman/application/handlers/validate.py index 741c436d..bc983bcd 100644 --- a/src/ahriman/application/handlers/validate.py +++ b/src/ahriman/application/handlers/validate.py @@ -37,7 +37,7 @@ class Validate(Handler): configuration validator handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False + ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io @classmethod def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *, diff --git a/src/ahriman/application/handlers/versions.py b/src/ahriman/application/handlers/versions.py index c966fd18..3c1d8157 100644 --- a/src/ahriman/application/handlers/versions.py +++ b/src/ahriman/application/handlers/versions.py @@ -39,7 +39,7 @@ class Versions(Handler): PEP423_PACKAGE_NAME(str): (class attribute) special regex for valid PEP423 package name """ - ALLOW_AUTO_ARCHITECTURE_RUN = False # it should be called only as "no-architecture" + ALLOW_MULTI_ARCHITECTURE_RUN = False # system-wide action PEP423_PACKAGE_NAME = re.compile(r"^[A-Za-z0-9._-]+") @classmethod diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py index 7d24bc8c..7868c392 100644 --- a/src/ahriman/application/handlers/web.py +++ b/src/ahriman/application/handlers/web.py @@ -32,7 +32,6 @@ class Web(Handler): web server handler """ - ALLOW_AUTO_ARCHITECTURE_RUN = False ALLOW_MULTI_ARCHITECTURE_RUN = False # required to be able to spawn external processes @classmethod diff --git a/src/ahriman/core/exceptions.py b/src/ahriman/core/exceptions.py index 2be3fbc9..f342a0fe 100644 --- a/src/ahriman/core/exceptions.py +++ b/src/ahriman/core/exceptions.py @@ -165,7 +165,7 @@ class MissingArchitectureError(ValueError): Args: command(str): command name which throws exception """ - ValueError.__init__(self, f"Architecture required for subcommand {command}, but missing") + ValueError.__init__(self, f"Architecture/repository required for subcommand {command}, but missing") class MultipleArchitecturesError(ValueError): @@ -180,7 +180,7 @@ class MultipleArchitecturesError(ValueError): Args: command(str): command name which throws exception """ - ValueError.__init__(self, f"Multiple architectures are not supported by subcommand {command}") + ValueError.__init__(self, f"Multiple architectures/repositories are not supported by subcommand {command}") class OptionError(ValueError): diff --git a/src/ahriman/models/repository_id.py b/src/ahriman/models/repository_id.py index 1d1c4bd1..8b94b78c 100644 --- a/src/ahriman/models/repository_id.py +++ b/src/ahriman/models/repository_id.py @@ -20,8 +20,6 @@ from dataclasses import dataclass from typing import Any -from ahriman.core.exceptions import InitializeError - @dataclass(frozen=True) class RepositoryId: @@ -36,16 +34,6 @@ class RepositoryId: architecture: str name: str - def __post_init__(self) -> None: - """ - check that name is set - - Raises: - InitializeError: in case if name is not set - """ - if not self.name: - raise InitializeError("Repository name is not set") - def __lt__(self, other: Any) -> bool: """ comparison operator for sorting diff --git a/src/ahriman/models/repository_paths.py b/src/ahriman/models/repository_paths.py index bef12ba4..bb3fdf23 100644 --- a/src/ahriman/models/repository_paths.py +++ b/src/ahriman/models/repository_paths.py @@ -140,31 +140,57 @@ class RepositoryPaths: """ return self.owner(self.root) + # TODO see https://github.com/python/mypy/issues/12534, remove type: ignore after release + # pylint: disable=protected-access @classmethod - def known_architectures(cls, root: Path, name: str) -> set[RepositoryId]: + def known_architectures(cls, root: Path, name: str = "") -> set[str]: # type: ignore[return] """ - get known architectures + get known architecture names Args: root(Path): repository root - name(str): repository name from configuration + name(str, optional): repository name (Default value = "") Returns: - set[RepositoryId]: list of tuple of repository name and architectures for which tree is created + set[str]: list of repository architectures for which there is created tree """ - def walk(repository_path: Path, repository_name: str) -> Generator[RepositoryId, None, None]: - for architecture in filter(lambda path: path.is_dir(), repository_path.iterdir()): - yield RepositoryId(architecture.name, repository_name) + def walk(repository_dir: Path) -> Generator[str, None, None]: + for architecture in filter(lambda path: path.is_dir(), repository_dir.iterdir()): + yield architecture.name - def walk_root(paths: RepositoryPaths) -> Generator[RepositoryId, None, None]: - # pylint: disable=protected-access + instance = cls(root, RepositoryId("", "")) + match (instance._repository_root / name): + case full_tree if full_tree.is_dir(): + return set(walk(full_tree)) # actually works for legacy too in case if name is set to empty string + case _ if instance._repository_root.is_dir(): + return set(walk(instance._repository_root)) # legacy only tree + case _: + return set() # no tree detected at all + + # pylint: disable=protected-access + @classmethod + def known_repositories(cls, root: Path) -> set[str]: + """ + get known repository names + + Args: + root(Path): repository root + + Returns: + set[str]: list of repository names for which there is created tree. Returns empty set in case if repository + is loaded in legacy mode + """ + # simply walk through the root. In case if there are subdirectories, emit the name + def walk(paths: RepositoryPaths) -> Generator[str, None, None]: for repository in filter(lambda path: path.is_dir(), paths._repository_root.iterdir()): - print(repository) - yield from walk(repository, repository.name) + if any(path.is_dir() for path in repository.iterdir()): + yield repository.name - instance = cls(root, RepositoryId("", root.name)) # suppress initialization error - # try to get list per repository first and then fallback to old schema if nothing found - return set(walk_root(instance)) or set(walk(instance._repository_root, name)) + instance = cls(root, RepositoryId("", "")) + if not instance._repository_root.is_dir(): + return set() # no tree created + + return set(walk(instance)) @staticmethod def owner(path: Path) -> tuple[int, int]: diff --git a/tests/ahriman/application/handlers/test_handler.py b/tests/ahriman/application/handlers/test_handler.py index 9b16ce9d..d49bf8b4 100644 --- a/tests/ahriman/application/handlers/test_handler.py +++ b/tests/ahriman/application/handlers/test_handler.py @@ -117,14 +117,68 @@ def test_run(args: argparse.Namespace, configuration: Configuration) -> None: def test_repositories_extract(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: """ - must generate list of available architectures + must generate list of available repositories based on flags """ + args.architecture = ["arch"] args.configuration = configuration.path - _, repository_id = configuration.check_loaded() + args.repository = ["repo"] known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") + known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories") - Handler.repositories_extract(args) - known_architectures_mock.assert_called_once_with(configuration.getpath("repository", "root"), repository_id.name) + assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")] + known_architectures_mock.assert_not_called() + known_repositories_mock.assert_not_called() + + +def test_repositories_extract_repository(args: argparse.Namespace, configuration: Configuration, + mocker: MockerFixture) -> None: + """ + must generate list of available repositories based on flags and tree + """ + args.architecture = ["arch"] + args.configuration = configuration.path + args.repository = None + known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") + known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories", + return_value={"repo"}) + + assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")] + known_architectures_mock.assert_not_called() + known_repositories_mock.assert_called_once_with(configuration.repository_paths.root) + + +def test_repositories_extract_repository_legacy(args: argparse.Namespace, configuration: Configuration, + mocker: MockerFixture) -> None: + """ + must generate list of available repositories based on flags and tree + """ + args.architecture = ["arch"] + args.configuration = configuration.path + args.repository = None + known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures") + known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories", + return_value={"repo"}) + + assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")] + known_architectures_mock.assert_not_called() + known_repositories_mock.assert_called_once_with(configuration.repository_paths.root) + + +def test_repositories_extract_architecture(args: argparse.Namespace, configuration: Configuration, + mocker: MockerFixture) -> None: + """ + must read repository name from config + """ + args.architecture = None + args.configuration = configuration.path + args.repository = ["repo"] + known_architectures_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures", + return_value={"arch"}) + known_repositories_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories") + + assert Handler.repositories_extract(args) == [RepositoryId("arch", "repo")] + known_architectures_mock.assert_called_once_with(configuration.repository_paths.root, "repo") + known_repositories_mock.assert_not_called() def test_repositories_extract_empty(args: argparse.Namespace, configuration: Configuration, @@ -133,52 +187,16 @@ def test_repositories_extract_empty(args: argparse.Namespace, configuration: Con must raise exception if no available architectures found """ args.command = "config" + args.architecture = None args.configuration = configuration.path + args.repository = None mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_architectures", return_value=set()) + mocker.patch("ahriman.models.repository_paths.RepositoryPaths.known_repositories", return_value=set()) with pytest.raises(MissingArchitectureError): Handler.repositories_extract(args) -def test_repositories_extract_exception(args: argparse.Namespace, mocker: MockerFixture) -> None: - """ - must raise exception on missing architectures - """ - args.command = "config" - mocker.patch.object(Handler, "ALLOW_AUTO_ARCHITECTURE_RUN", False) - with pytest.raises(MissingArchitectureError): - Handler.repositories_extract(args) - - -def test_repositories_extract_specified(args: argparse.Namespace, configuration: Configuration) -> None: - """ - must return architecture list if it has been specified - """ - args.configuration = configuration.path - args.architecture = ["i686", "x86_64"] - args.repository = [] - _, repository_id = configuration.check_loaded() - - ids = [RepositoryId(architecture, repository_id.name) for architecture in args.architecture] - assert Handler.repositories_extract(args) == sorted(set(ids)) - - -def test_repositories_extract_specified_with_repository(args: argparse.Namespace, configuration: Configuration) -> None: - """ - must return architecture list if it has been specified together with repositories - """ - args.configuration = configuration.path - args.architecture = ["i686", "x86_64"] - args.repository = ["repo1", "repo2"] - - ids = [ - RepositoryId(architecture, name) - for architecture in args.architecture - for name in args.repository - ] - assert Handler.repositories_extract(args) == sorted(set(ids)) - - def test_check_if_empty() -> None: """ must raise exception in case if predicate is True and enabled diff --git a/tests/ahriman/application/handlers/test_handler_backup.py b/tests/ahriman/application/handlers/test_handler_backup.py index b7683459..a1349694 100644 --- a/tests/ahriman/application/handlers/test_handler_backup.py +++ b/tests/ahriman/application/handlers/test_handler_backup.py @@ -56,8 +56,8 @@ def test_get_paths(configuration: Configuration, mocker: MockerFixture) -> None: assert all(path.exists() for path in paths if path.name not in (".gnupg", "cache")) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Backup.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Backup.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_dump.py b/tests/ahriman/application/handlers/test_handler_dump.py index aeb6ac47..8816baa8 100644 --- a/tests/ahriman/application/handlers/test_handler_dump.py +++ b/tests/ahriman/application/handlers/test_handler_dump.py @@ -35,8 +35,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc print_mock.assert_called() -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Dump.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Dump.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_help.py b/tests/ahriman/application/handlers/test_handler_help.py index 13f91434..6e8f13cd 100644 --- a/tests/ahriman/application/handlers/test_handler_help.py +++ b/tests/ahriman/application/handlers/test_handler_help.py @@ -47,8 +47,8 @@ def test_run_command(args: argparse.Namespace, configuration: Configuration, moc parse_mock.assert_called_once_with(["aur-search", "--help"]) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Help.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Help.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_key_import.py b/tests/ahriman/application/handlers/test_handler_key_import.py index bb202e9b..dc8e9fd3 100644 --- a/tests/ahriman/application/handlers/test_handler_key_import.py +++ b/tests/ahriman/application/handlers/test_handler_key_import.py @@ -36,8 +36,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: application_mock.assert_called_once_with(args.key_server, args.key) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not KeyImport.ALLOW_AUTO_ARCHITECTURE_RUN + assert not KeyImport.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_patch.py b/tests/ahriman/application/handlers/test_handler_patch.py index 97dbb3cd..42e3ee50 100644 --- a/tests/ahriman/application/handlers/test_handler_patch.py +++ b/tests/ahriman/application/handlers/test_handler_patch.py @@ -190,3 +190,10 @@ def test_patch_set_remove(application: Application, package_ahriman: Package, mo remove_mock = mocker.patch("ahriman.core.database.SQLite.patches_remove") Patch.patch_set_remove(application, package_ahriman.base, ["version"]) remove_mock.assert_called_once_with(package_ahriman.base, ["version"]) + + +def test_disallow_multi_architecture_run() -> None: + """ + must not allow multi architecture run + """ + assert not Patch.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_restore.py b/tests/ahriman/application/handlers/test_handler_restore.py index e2a6dad6..3b2053cf 100644 --- a/tests/ahriman/application/handlers/test_handler_restore.py +++ b/tests/ahriman/application/handlers/test_handler_restore.py @@ -37,8 +37,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, mocker: Moc extract_mock.extractall.assert_called_once_with(path=args.output) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Restore.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Restore.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_search.py b/tests/ahriman/application/handlers/test_handler_search.py index 8e57f43f..f2c08181 100644 --- a/tests/ahriman/application/handlers/test_handler_search.py +++ b/tests/ahriman/application/handlers/test_handler_search.py @@ -128,11 +128,11 @@ def test_sort_exception(aur_package_ahriman: AURPackage) -> None: Search.sort([aur_package_ahriman], "random_field") -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Search.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Search.ALLOW_MULTI_ARCHITECTURE_RUN def test_sort_fields(aur_package_ahriman: AURPackage) -> None: diff --git a/tests/ahriman/application/handlers/test_handler_service_updates.py b/tests/ahriman/application/handlers/test_handler_service_updates.py index d652e7f6..0f04128a 100644 --- a/tests/ahriman/application/handlers/test_handler_service_updates.py +++ b/tests/ahriman/application/handlers/test_handler_service_updates.py @@ -58,3 +58,10 @@ def test_run_skip(args: argparse.Namespace, configuration: Configuration, reposi ServiceUpdates.run(args, repository_id, configuration, report=False) application_mock.assert_not_called() check_mock.assert_not_called() + + +def test_disallow_multi_architecture_run() -> None: + """ + must not allow multi architecture run + """ + assert not ServiceUpdates.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_setup.py b/tests/ahriman/application/handlers/test_handler_setup.py index e550a047..6f09a548 100644 --- a/tests/ahriman/application/handlers/test_handler_setup.py +++ b/tests/ahriman/application/handlers/test_handler_setup.py @@ -8,6 +8,7 @@ from unittest.mock import call as MockCall from ahriman.application.handlers import Setup from ahriman.core.configuration import Configuration +from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.repository import Repository from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_paths import RepositoryPaths @@ -24,6 +25,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace: Returns: argparse.Namespace: generated arguments for these test cases """ + args.architecture = ["x86_64"] args.build_as_user = "ahriman" args.from_configuration = Path("/usr/share/devtools/pacman.conf.d/extra.conf") args.generate_salt = True @@ -31,6 +33,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace: args.mirror = "mirror" args.multilib = True args.packager = "John Doe " + args.repository = ["aur-clone"] args.server = None args.sign_key = "key" args.sign_target = [SignSettings.Packages] @@ -64,6 +67,25 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: init_mock.assert_called_once_with() +def test_run_no_architecture_or_repository(configuration: Configuration) -> None: + """ + must raise MissingArchitectureError if either architecture or repository are not supplied + """ + _, repository_id = configuration.check_loaded() + + args = argparse.Namespace(architecture=None, command="service-setup", repository=None) + with pytest.raises(MissingArchitectureError): + Setup.run(args, repository_id, configuration, report=False) + + args = argparse.Namespace(architecture=[repository_id.architecture], command="service-setup", repository=None) + with pytest.raises(MissingArchitectureError): + Setup.run(args, repository_id, configuration, report=False) + + args = argparse.Namespace(architecture=None, command="service-setup", repository=[repository_id.name]) + with pytest.raises(MissingArchitectureError): + Setup.run(args, repository_id, configuration, report=False) + + def test_run_with_server(args: argparse.Namespace, configuration: Configuration, repository: Repository, mocker: MockerFixture) -> None: """ @@ -251,8 +273,8 @@ def test_executable_create(configuration: Configuration, repository_paths: Repos unlink_mock.assert_called_once_with(missing_ok=True) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Setup.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Setup.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_shell.py b/tests/ahriman/application/handlers/test_handler_shell.py index 80799524..d5104afb 100644 --- a/tests/ahriman/application/handlers/test_handler_shell.py +++ b/tests/ahriman/application/handlers/test_handler_shell.py @@ -69,3 +69,10 @@ def test_run_verbose(args: argparse.Namespace, configuration: Configuration, rep application_mock.assert_called_once_with(local=pytest.helpers.anyvar(int)) read_mock.assert_called_once_with(encoding="utf8") print_mock.assert_called_once_with(verbose=False) + + +def test_disallow_multi_architecture_run() -> None: + """ + must not allow multi architecture run + """ + assert not Shell.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_status.py b/tests/ahriman/application/handlers/test_handler_status.py index a4e41086..3988aa0b 100644 --- a/tests/ahriman/application/handlers/test_handler_status.py +++ b/tests/ahriman/application/handlers/test_handler_status.py @@ -133,8 +133,8 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Status.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Status.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_status_update.py b/tests/ahriman/application/handlers/test_handler_status_update.py index ad051579..427f1ca6 100644 --- a/tests/ahriman/application/handlers/test_handler_status_update.py +++ b/tests/ahriman/application/handlers/test_handler_status_update.py @@ -86,8 +86,8 @@ def test_imply_with_report(args: argparse.Namespace, configuration: Configuratio load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not StatusUpdate.ALLOW_AUTO_ARCHITECTURE_RUN + assert not StatusUpdate.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_structure.py b/tests/ahriman/application/handlers/test_handler_structure.py index 441d89cb..bde85b0c 100644 --- a/tests/ahriman/application/handlers/test_handler_structure.py +++ b/tests/ahriman/application/handlers/test_handler_structure.py @@ -46,8 +46,8 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: ]) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Structure.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Structure.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py index f377631d..01fcc5d9 100644 --- a/tests/ahriman/application/handlers/test_handler_unsafe_commands.py +++ b/tests/ahriman/application/handlers/test_handler_unsafe_commands.py @@ -83,8 +83,8 @@ def test_get_unsafe_commands() -> None: assert subparser.choices[command].get_default("unsafe") -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not UnsafeCommands.ALLOW_AUTO_ARCHITECTURE_RUN + assert not UnsafeCommands.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_users.py b/tests/ahriman/application/handlers/test_handler_users.py index a5128048..82ac16dc 100644 --- a/tests/ahriman/application/handlers/test_handler_users.py +++ b/tests/ahriman/application/handlers/test_handler_users.py @@ -175,8 +175,8 @@ def test_user_create_getpass_exception(args: argparse.Namespace, mocker: MockerF Users.user_create(args) -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Users.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Users.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_validate.py b/tests/ahriman/application/handlers/test_handler_validate.py index 2a81e259..ad89cea6 100644 --- a/tests/ahriman/application/handlers/test_handler_validate.py +++ b/tests/ahriman/application/handlers/test_handler_validate.py @@ -115,8 +115,8 @@ def test_schema_merge() -> None: assert key in merged["gitremote"]["schema"] -def test_disallow_auto_architecture_run() -> None: +def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run """ - assert not Validate.ALLOW_AUTO_ARCHITECTURE_RUN + assert not Validate.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_versions.py b/tests/ahriman/application/handlers/test_handler_versions.py index 4f4964e9..25d37dbe 100644 --- a/tests/ahriman/application/handlers/test_handler_versions.py +++ b/tests/ahriman/application/handlers/test_handler_versions.py @@ -37,3 +37,10 @@ def test_package_dependencies_missing() -> None: assert packages assert packages.get("pyalpm") is not None assert packages.get("Sphinx") is None + + +def test_disallow_multi_architecture_run() -> None: + """ + must not allow multi architecture run + """ + assert not Versions.ALLOW_MULTI_ARCHITECTURE_RUN diff --git a/tests/ahriman/application/handlers/test_handler_web.py b/tests/ahriman/application/handlers/test_handler_web.py index ae2649e4..3090d375 100644 --- a/tests/ahriman/application/handlers/test_handler_web.py +++ b/tests/ahriman/application/handlers/test_handler_web.py @@ -116,13 +116,6 @@ def test_extract_arguments_full(parser: argparse.ArgumentParser, configuration: ] -def test_disallow_auto_architecture_run() -> None: - """ - must not allow auto architecture run - """ - assert not Web.ALLOW_AUTO_ARCHITECTURE_RUN - - def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index d331471c..24c3ec54 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -18,16 +18,16 @@ def test_parser(parser: argparse.ArgumentParser) -> None: """ must parse valid command line """ - parser.parse_args(["-a", "x86_64", "service-config"]) + parser.parse_args(["-a", "x86_64", "-r", "repo", "service-config"]) def test_parser_option_configuration(parser: argparse.ArgumentParser) -> None: """ must convert configuration option to Path instance """ - args = parser.parse_args(["-a", "x86_64", "service-config"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-config"]) assert isinstance(args.configuration, Path) - args = parser.parse_args(["-a", "x86_64", "-c", "ahriman.ini", "service-config"]) + args = parser.parse_args(["-a", "x86_64", "-c", "ahriman.ini", "-r", "repo", "service-config"]) assert isinstance(args.configuration, Path) @@ -93,12 +93,13 @@ def test_parser_option_repository_multiple(parser: argparse.ArgumentParser) -> N def test_subparsers_aur_search(parser: argparse.ArgumentParser) -> None: """ - aur-search command must imply architecture list, lock, report, quiet and unsafe + aur-search command must imply architecture list, lock, report, repository, quiet and unsafe """ args = parser.parse_args(["aur-search", "ahriman"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe @@ -111,14 +112,23 @@ def test_subparsers_aur_search_option_architecture(parser: argparse.ArgumentPars assert args.architecture == [""] +def test_subparsers_aur_search_option_repository(parser: argparse.ArgumentParser) -> None: + """ + aur-search command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "aur-search", "ahriman"]) + assert args.repository == [""] + + def test_subparsers_help(parser: argparse.ArgumentParser) -> None: """ - help command must imply architecture list, lock, report, quiet, unsafe and parser + help command must imply architecture list, lock, report, repository, quiet, unsafe and parser """ args = parser.parse_args(["help"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe assert args.parser is not None and args.parser() @@ -132,14 +142,23 @@ def test_subparsers_help_option_architecture(parser: argparse.ArgumentParser) -> assert args.architecture == [""] +def test_subparsers_help_option_repository(parser: argparse.ArgumentParser) -> None: + """ + help command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "help"]) + assert args.repository == [""] + + def test_subparsers_help_commands_unsafe(parser: argparse.ArgumentParser) -> None: """ - help-commands-unsafe command must imply architecture list, lock, report, quiet, unsafe and parser + help-commands-unsafe command must imply architecture list, lock, report, repository, quiet, unsafe and parser """ args = parser.parse_args(["help-commands-unsafe"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe assert args.parser is not None and args.parser() @@ -153,14 +172,23 @@ def test_subparsers_help_commands_unsafe_option_architecture(parser: argparse.Ar assert args.architecture == [""] +def test_subparsers_help_commands_unsafe_option_repository(parser: argparse.ArgumentParser) -> None: + """ + help-commands-unsafe command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "help-commands-unsafe"]) + assert args.repository == [""] + + def test_subparsers_help_updates(parser: argparse.ArgumentParser) -> None: """ - help-updates command must imply architecture list, lock, report, quiet and unsafe + help-updates command must imply architecture list, lock, report, repository, quiet and unsafe """ args = parser.parse_args(["help-updates"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe @@ -173,14 +201,23 @@ def test_subparsers_help_updates_option_architecture(parser: argparse.ArgumentPa assert args.architecture == [""] +def test_subparsers_help_updates_option_repository(parser: argparse.ArgumentParser) -> None: + """ + help-updates command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "help-updates"]) + assert args.repository == [""] + + def test_subparsers_help_version(parser: argparse.ArgumentParser) -> None: """ - help-version command must imply architecture, lock, report, quiet and unsafe + help-version command must imply architecture, lock, report, repository, quiet and unsafe """ args = parser.parse_args(["help-version"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe @@ -193,6 +230,14 @@ def test_subparsers_help_version_option_architecture(parser: argparse.ArgumentPa assert args.architecture == [""] +def test_subparsers_help_version_option_repository(parser: argparse.ArgumentParser) -> None: + """ + help-version command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "help-version"]) + assert args.repository == [""] + + def test_subparsers_package_add_option_architecture(parser: argparse.ArgumentParser) -> None: """ package-add command must correctly parse architecture list @@ -203,6 +248,16 @@ def test_subparsers_package_add_option_architecture(parser: argparse.ArgumentPar assert args.architecture == ["x86_64"] +def test_subparsers_package_add_option_repository(parser: argparse.ArgumentParser) -> None: + """ + package-add command must correctly parse repository list + """ + args = parser.parse_args(["package-add", "ahriman"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "package-add", "ahriman"]) + assert args.repository == ["repo"] + + def test_subparsers_package_add_option_refresh(parser: argparse.ArgumentParser) -> None: """ package-add command must count refresh options @@ -225,14 +280,25 @@ def test_subparsers_package_remove_option_architecture(parser: argparse.Argument assert args.architecture == ["x86_64"] +def test_subparsers_package_remove_option_repository(parser: argparse.ArgumentParser) -> None: + """ + package-remove command must correctly parse repository list + """ + args = parser.parse_args(["package-remove", "ahriman"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "package-remove", "ahriman"]) + assert args.repository == ["repo"] + + def test_subparsers_package_status(parser: argparse.ArgumentParser) -> None: """ package-status command must imply lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "package-status"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status"]) assert args.architecture == ["x86_64"] assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe @@ -241,11 +307,12 @@ def test_subparsers_package_status_remove(parser: argparse.ArgumentParser) -> No """ package-status-remove command must imply action, lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "package-status-remove", "ahriman"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-remove", "ahriman"]) assert args.architecture == ["x86_64"] assert args.action == Action.Remove assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe @@ -254,11 +321,12 @@ def test_subparsers_package_status_update(parser: argparse.ArgumentParser) -> No """ package-status-update command must imply action, lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "package-status-update"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update"]) assert args.architecture == ["x86_64"] assert args.action == Action.Update assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe @@ -267,21 +335,22 @@ def test_subparsers_package_status_update_option_status(parser: argparse.Argumen """ package-status-update command must convert status option to buildstatusenum instance """ - args = parser.parse_args(["-a", "x86_64", "package-status-update"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update"]) assert isinstance(args.status, BuildStatusEnum) - args = parser.parse_args(["-a", "x86_64", "package-status-update", "--status", "failed"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update", "--status", "failed"]) assert isinstance(args.status, BuildStatusEnum) def test_subparsers_patch_add(parser: argparse.ArgumentParser) -> None: """ - patch-add command must imply action, architecture list, lock and report + patch-add command must imply action, architecture list, lock, report and repository """ args = parser.parse_args(["patch-add", "ahriman", "version"]) assert args.action == Action.Update assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] def test_subparsers_patch_add_option_architecture(parser: argparse.ArgumentParser) -> None: @@ -292,15 +361,24 @@ def test_subparsers_patch_add_option_architecture(parser: argparse.ArgumentParse assert args.architecture == [""] +def test_subparsers_patch_add_option_repository(parser: argparse.ArgumentParser) -> None: + """ + patch-add command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "patch-add", "ahriman", "version"]) + assert args.repository == [""] + + def test_subparsers_patch_list(parser: argparse.ArgumentParser) -> None: """ - patch-list command must imply action, architecture list, lock, report and unsafe + patch-list command must imply action, architecture list, lock, report, repository and unsafe """ args = parser.parse_args(["patch-list", "ahriman"]) assert args.action == Action.List assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.unsafe @@ -312,6 +390,14 @@ def test_subparsers_patch_list_option_architecture(parser: argparse.ArgumentPars assert args.architecture == [""] +def test_subparsers_patch_list_option_repository(parser: argparse.ArgumentParser) -> None: + """ + patch-list command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "patch-list", "ahriman"]) + assert args.repository == [""] + + def test_subparsers_patch_list_option_variable_empty(parser: argparse.ArgumentParser) -> None: """ patch-list command must accept empty variable list as None @@ -330,13 +416,14 @@ def test_subparsers_patch_list_option_variable_multiple(parser: argparse.Argumen def test_subparsers_patch_remove(parser: argparse.ArgumentParser) -> None: """ - patch-remove command must imply action, architecture list, lock and report + patch-remove command must imply action, architecture list, lock, report and repository """ args = parser.parse_args(["patch-remove", "ahriman"]) assert args.action == Action.Remove assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] def test_subparsers_patch_remove_option_architecture(parser: argparse.ArgumentParser) -> None: @@ -347,6 +434,14 @@ def test_subparsers_patch_remove_option_architecture(parser: argparse.ArgumentPa assert args.architecture == [""] +def test_subparsers_patch_remove_option_repository(parser: argparse.ArgumentParser) -> None: + """ + patch-remove command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "patch-remove", "ahriman"]) + assert args.repository == [""] + + def test_subparsers_patch_remove_option_variable_empty(parser: argparse.ArgumentParser) -> None: """ patch-remove command must accept empty variable list as None @@ -365,13 +460,14 @@ def test_subparsers_patch_remove_option_variable_multiple(parser: argparse.Argum def test_subparsers_patch_set_add(parser: argparse.ArgumentParser) -> None: """ - patch-set-add command must imply action, architecture list, lock, report and variable + patch-set-add command must imply action, architecture list, lock, report, repository and variable """ args = parser.parse_args(["patch-set-add", "ahriman"]) assert args.action == Action.Update assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.variable is None @@ -391,6 +487,14 @@ def test_subparsers_patch_set_add_option_package(parser: argparse.ArgumentParser assert isinstance(args.package, Path) +def test_subparsers_patch_set_add_option_repository(parser: argparse.ArgumentParser) -> None: + """ + patch-set-add command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "patch-set-add", "ahriman"]) + assert args.repository == [""] + + def test_subparsers_patch_set_add_option_track(parser: argparse.ArgumentParser) -> None: """ patch-set-add command must correctly parse track files patterns @@ -401,12 +505,13 @@ def test_subparsers_patch_set_add_option_track(parser: argparse.ArgumentParser) def test_subparsers_repo_backup(parser: argparse.ArgumentParser) -> None: """ - repo-backup command must imply architecture list, lock, report and unsafe + repo-backup command must imply architecture list, lock, report, repository and unsafe """ args = parser.parse_args(["repo-backup", "output.zip"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.unsafe @@ -418,6 +523,14 @@ def test_subparsers_repo_backup_option_architecture(parser: argparse.ArgumentPar assert args.architecture == [""] +def test_subparsers_repo_backup_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-backup command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "repo-backup", "output.zip"]) + assert args.repository == [""] + + def test_subparsers_repo_check(parser: argparse.ArgumentParser) -> None: """ repo-check command must imply dependencies, dry-run, aur, manual and username @@ -440,6 +553,16 @@ def test_subparsers_repo_check_option_architecture(parser: argparse.ArgumentPars assert args.architecture == ["x86_64"] +def test_subparsers_repo_check_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-check command must correctly parse architecture list + """ + args = parser.parse_args(["repo-check"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-check"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_check_option_refresh(parser: argparse.ArgumentParser) -> None: """ repo-check command must count refresh options @@ -470,6 +593,16 @@ def test_subparsers_repo_create_keyring_option_architecture(parser: argparse.Arg assert args.architecture == ["x86_64"] +def test_subparsers_repo_create_keyring_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-create-keyring command must correctly parse repository list + """ + args = parser.parse_args(["repo-create-keyring"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-create-keyring"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_create_mirrorlist(parser: argparse.ArgumentParser) -> None: """ repo-create-mirrorlist command must imply trigger @@ -488,6 +621,16 @@ def test_subparsers_repo_create_mirrorlist_option_architecture(parser: argparse. assert args.architecture == ["x86_64"] +def test_subparsers_repo_create_mirrorlist_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-create-mirrorlist command must correctly parse repository list + """ + args = parser.parse_args(["repo-create-mirrorlist"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-create-mirrorlist"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_daemon(parser: argparse.ArgumentParser) -> None: """ repo-daemon command must imply dry run, exit code and package @@ -530,6 +673,16 @@ def test_subparsers_repo_rebuild_option_architecture(parser: argparse.ArgumentPa assert args.architecture == ["x86_64"] +def test_subparsers_repo_rebuild_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-rebuild command must correctly parse repository list + """ + args = parser.parse_args(["repo-rebuild"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-rebuild"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_rebuild_option_depends_on_empty(parser: argparse.ArgumentParser) -> None: """ repo-rebuild command must accept empty depends-on list as None @@ -550,7 +703,7 @@ def test_subparsers_repo_rebuild_option_status(parser: argparse.ArgumentParser) """ repo-rebuild command must convert status option to BuildStatusEnum instance """ - args = parser.parse_args(["-a", "x86_64", "repo-rebuild", "--status", "failed"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "repo-rebuild", "--status", "failed"]) assert isinstance(args.status, BuildStatusEnum) @@ -564,6 +717,16 @@ def test_subparsers_repo_remove_unknown_option_architecture(parser: argparse.Arg assert args.architecture == ["x86_64"] +def test_subparsers_repo_remove_unknown_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-remove-unknown command must correctly parse repository list + """ + args = parser.parse_args(["repo-remove-unknown"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-remove-unknown"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_report(parser: argparse.ArgumentParser) -> None: """ repo-report command must imply trigger @@ -582,14 +745,25 @@ def test_subparsers_repo_report_option_architecture(parser: argparse.ArgumentPar assert args.architecture == ["x86_64"] +def test_subparsers_repo_report_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-report command must correctly parse repository list + """ + args = parser.parse_args(["repo-report"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-report"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_restore(parser: argparse.ArgumentParser) -> None: """ - repo-restore command must imply architecture list, lock, report and unsafe + repo-restore command must imply architecture list, lock, report, repository and unsafe """ args = parser.parse_args(["repo-restore", "output.zip"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.unsafe @@ -601,6 +775,14 @@ def test_subparsers_repo_restore_option_architecture(parser: argparse.ArgumentPa assert args.architecture == [""] +def test_subparsers_repo_restore_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-restore command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "repo-restore", "output.zip"]) + assert args.repository == [""] + + def test_subparsers_repo_sign_option_architecture(parser: argparse.ArgumentParser) -> None: """ repo-sign command must correctly parse architecture list @@ -611,15 +793,26 @@ def test_subparsers_repo_sign_option_architecture(parser: argparse.ArgumentParse assert args.architecture == ["x86_64"] +def test_subparsers_repo_sign_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-sign command must correctly parse repository list + """ + args = parser.parse_args(["repo-sign"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-sign"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_status_update(parser: argparse.ArgumentParser) -> None: """ re[p-status-update command must imply action, lock, report, package, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "package-status-update"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "package-status-update"]) assert args.architecture == ["x86_64"] assert args.action == Action.Update assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert not args.package assert args.quiet assert args.unsafe @@ -629,9 +822,9 @@ def test_subparsers_repo_status_update_option_status(parser: argparse.ArgumentPa """ repo-status-update command must convert status option to BuildStatusEnum instance """ - args = parser.parse_args(["-a", "x86_64", "repo-status-update"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "repo-status-update"]) assert isinstance(args.status, BuildStatusEnum) - args = parser.parse_args(["-a", "x86_64", "repo-status-update", "--status", "failed"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "repo-status-update", "--status", "failed"]) assert isinstance(args.status, BuildStatusEnum) @@ -653,6 +846,16 @@ def test_subparsers_repo_sync_option_architecture(parser: argparse.ArgumentParse assert args.architecture == ["x86_64"] +def test_subparsers_repo_sync_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-sync command must correctly parse repository list + """ + args = parser.parse_args(["repo-sync"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-sync"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_tree(parser: argparse.ArgumentParser) -> None: """ repo-tree command must imply lock, report, quiet and unsafe @@ -674,6 +877,16 @@ def test_subparsers_repo_tree_option_architecture(parser: argparse.ArgumentParse assert args.architecture == ["x86_64"] +def test_subparsers_repo_tree_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-tree command must correctly parse repository list + """ + args = parser.parse_args(["repo-tree"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-tree"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_tree_option_partitions(parser: argparse.ArgumentParser) -> None: """ must convert partitions option to int instance @@ -694,6 +907,16 @@ def test_subparsers_repo_triggers_option_architecture(parser: argparse.ArgumentP assert args.architecture == ["x86_64"] +def test_subparsers_repo_triggers_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-triggers command must correctly parse repository list + """ + args = parser.parse_args(["repo-triggers"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-triggers"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_update_option_architecture(parser: argparse.ArgumentParser) -> None: """ repo-update command must correctly parse architecture list @@ -704,6 +927,16 @@ def test_subparsers_repo_update_option_architecture(parser: argparse.ArgumentPar assert args.architecture == ["x86_64"] +def test_subparsers_repo_update_option_repository(parser: argparse.ArgumentParser) -> None: + """ + repo-update command must correctly parse repository list + """ + args = parser.parse_args(["repo-update"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "repo-update"]) + assert args.repository == ["repo"] + + def test_subparsers_repo_update_option_refresh(parser: argparse.ArgumentParser) -> None: """ repo-update command must count refresh options @@ -735,14 +968,25 @@ def test_subparsers_service_clean_option_architecture(parser: argparse.ArgumentP assert args.architecture == ["x86_64"] +def test_subparsers_service_clean_option_repository(parser: argparse.ArgumentParser) -> None: + """ + service-clean command must correctly parse repository list + """ + args = parser.parse_args(["service-clean"]) + assert args.repository is None + args = parser.parse_args(["-r", "repo", "service-clean"]) + assert args.repository == ["repo"] + + def test_subparsers_service_config(parser: argparse.ArgumentParser) -> None: """ service-config command must imply lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "service-config"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-config"]) assert args.architecture == ["x86_64"] assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe @@ -751,22 +995,24 @@ def test_subparsers_service_config_validate(parser: argparse.ArgumentParser) -> """ service-config-validate command must imply lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "service-config-validate"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-config-validate"]) assert args.architecture == ["x86_64"] assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe def test_subparsers_service_key_import(parser: argparse.ArgumentParser) -> None: """ - service-key-import command must imply architecture list, lock and report + service-key-import command must imply architecture list, lock, report and repository """ args = parser.parse_args(["service-key-import", "key"]) assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] def test_subparsers_service_key_import_option_architecture(parser: argparse.ArgumentParser) -> None: @@ -777,14 +1023,23 @@ def test_subparsers_service_key_import_option_architecture(parser: argparse.Argu assert args.architecture == [""] +def test_subparsers_service_key_import_option_repository(parser: argparse.ArgumentParser) -> None: + """ + service-key-import command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "service-key-import", "key"]) + assert args.repository == [""] + + def test_subparsers_service_setup(parser: argparse.ArgumentParser) -> None: """ service-setup command must imply lock, report, quiet and unsafe """ - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe "]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe "]) assert args.architecture == ["x86_64"] assert args.lock is None assert not args.report + assert args.repository == ["repo"] assert args.quiet assert args.unsafe @@ -793,9 +1048,9 @@ def test_subparsers_service_setup_option_from_configuration(parser: argparse.Arg """ service-setup command must convert from-configuration option to path instance """ - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe "]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe "]) assert isinstance(args.from_configuration, Path) - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe ", "--from-configuration", "path"]) assert isinstance(args.from_configuration, Path) @@ -804,7 +1059,7 @@ def test_subparsers_service_setup_option_sign_target(parser: argparse.ArgumentPa """ service-setup command must convert sign-target option to SignSettings instance """ - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe ", "--sign-target", "packages"]) assert args.sign_target assert all(isinstance(target, SignSettings) for target in args.sign_target) @@ -814,7 +1069,7 @@ def test_subparsers_service_setup_option_sign_target_empty(parser: argparse.Argu """ service-setup command must accept empty sign-target list as None """ - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe "]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe "]) assert args.sign_target is None @@ -822,7 +1077,7 @@ def test_subparsers_service_setup_option_sign_target_multiple(parser: argparse.A """ service-setup command must accept multiple sign-target """ - args = parser.parse_args(["-a", "x86_64", "service-setup", "--packager", "John Doe ", + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "service-setup", "--packager", "John Doe ", "--sign-target", "packages", "--sign-target", "repository"]) assert args.sign_target == [SignSettings.Packages, SignSettings.Repository] @@ -838,13 +1093,14 @@ def test_subparsers_service_shell(parser: argparse.ArgumentParser) -> None: def test_subparsers_user_add(parser: argparse.ArgumentParser) -> None: """ - user-add command must imply action, architecture, lock, report and quiet + user-add command must imply action, architecture, lock, report, repository and quiet """ args = parser.parse_args(["user-add", "username"]) assert args.action == Action.Update assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet @@ -856,6 +1112,14 @@ def test_subparsers_user_add_option_architecture(parser: argparse.ArgumentParser assert args.architecture == [""] +def test_subparsers_user_add_option_repository(parser: argparse.ArgumentParser) -> None: + """ + user-add command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "user-add", "username"]) + assert args.repository == [""] + + def test_subparsers_user_add_option_role(parser: argparse.ArgumentParser) -> None: """ user-add command must convert role option to UserAccess instance @@ -868,13 +1132,14 @@ def test_subparsers_user_add_option_role(parser: argparse.ArgumentParser) -> Non def test_subparsers_user_list(parser: argparse.ArgumentParser) -> None: """ - user-list command must imply action, architecture, lock, report, quiet and unsafe + user-list command must imply action, architecture, lock, report, repository, quiet and unsafe """ args = parser.parse_args(["user-list"]) assert args.action == Action.List assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet assert args.unsafe @@ -887,6 +1152,14 @@ def test_subparsers_user_list_option_architecture(parser: argparse.ArgumentParse assert args.architecture == [""] +def test_subparsers_user_list_option_repository(parser: argparse.ArgumentParser) -> None: + """ + user-list command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "user-list"]) + assert args.repository == [""] + + def test_subparsers_user_list_option_role(parser: argparse.ArgumentParser) -> None: """ user-list command must convert role option to UserAccess instance @@ -897,13 +1170,14 @@ def test_subparsers_user_list_option_role(parser: argparse.ArgumentParser) -> No def test_subparsers_user_remove(parser: argparse.ArgumentParser) -> None: """ - user-remove command must imply action, architecture, lock, report and quiet + user-remove command must imply action, architecture, lock, report, repository and quiet """ args = parser.parse_args(["user-remove", "username"]) assert args.action == Action.Remove assert args.architecture == [""] assert args.lock is None assert not args.report + assert args.repository == [""] assert args.quiet @@ -915,13 +1189,22 @@ def test_subparsers_user_remove_option_architecture(parser: argparse.ArgumentPar assert args.architecture == [""] +def test_subparsers_user_remove_option_repository(parser: argparse.ArgumentParser) -> None: + """ + user-remove command must correctly parse repository list + """ + args = parser.parse_args(["-r", "repo", "user-remove", "username"]) + assert args.repository == [""] + + def test_subparsers_web(parser: argparse.ArgumentParser) -> None: """ web command must imply report and parser """ - args = parser.parse_args(["-a", "x86_64", "web"]) + args = parser.parse_args(["-a", "x86_64", "-r", "repo", "web"]) assert args.architecture == ["x86_64"] assert not args.report + assert args.repository == ["repo"] assert args.parser is not None and args.parser() diff --git a/tests/ahriman/models/test_repository_id.py b/tests/ahriman/models/test_repository_id.py index dfb14d6f..37638656 100644 --- a/tests/ahriman/models/test_repository_id.py +++ b/tests/ahriman/models/test_repository_id.py @@ -1,19 +1,8 @@ import pytest -from ahriman.core.exceptions import InitializeError from ahriman.models.repository_id import RepositoryId -def test_post_init() -> None: - """ - must raise InitializeError if name is empty - """ - RepositoryId("x86_64", "aur-clone") - - with pytest.raises(InitializeError): - RepositoryId("x86_64", "") - - def test_lt() -> None: """ must correctly compare instances diff --git a/tests/ahriman/models/test_repository_paths.py b/tests/ahriman/models/test_repository_paths.py index bcfac33b..34f15b22 100644 --- a/tests/ahriman/models/test_repository_paths.py +++ b/tests/ahriman/models/test_repository_paths.py @@ -51,61 +51,127 @@ def test_known_architectures(repository_paths: RepositoryPaths, mocker: MockerFi """ must list available directory paths /repository/repo/arch """ - def iterdir(root: Path) -> list[Path]: - if root == repository_paths._repository_root: + is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True) + iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, return_value=[Path("i686"), Path("x86_64")]) + + assert repository_paths.known_architectures(repository_paths.root, repository_paths.repository_id.name) == { + "i686", + "x86_64", + } + iterdir_mock.assert_called_once_with(repository_paths._repository_root / repository_paths.repository_id.name) + is_dir_mock.assert_has_calls([ + MockCall(repository_paths._repository_root / repository_paths.repository_id.name), + MockCall(Path("i686")), + MockCall(Path("x86_64")), + ]) + + +def test_known_architectures_legacy(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: + """ + must list available directory paths /repository/arch + """ + def is_dir(path: Path) -> bool: + return path.name != repository_paths.repository_id.name + + is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=is_dir) + iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, return_value=[Path("i686"), Path("x86_64")]) + + assert repository_paths.known_architectures(repository_paths.root, repository_paths.repository_id.name) == { + "i686", + "x86_64", + } + iterdir_mock.assert_called_once_with(repository_paths._repository_root) + is_dir_mock.assert_has_calls([ + MockCall(repository_paths._repository_root / repository_paths.repository_id.name), + MockCall(repository_paths._repository_root), + MockCall(Path("i686")), + MockCall(Path("x86_64")), + ]) + + +def test_known_architectures_legacy_backward(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: + """ + must list available directory paths /repository/arch in backward compatibility mode + """ + def is_dir(path: Path) -> bool: + return path.name != repository_paths.repository_id.name + + is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=is_dir) + iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, return_value=[Path("i686"), Path("x86_64")]) + + assert repository_paths.known_architectures(repository_paths.root) == {"i686", "x86_64"} + iterdir_mock.assert_called_once_with(repository_paths._repository_root) + is_dir_mock.assert_has_calls([ + MockCall(repository_paths._repository_root), + MockCall(Path("i686")), + MockCall(Path("x86_64")), + ]) + + +def test_known_architectures_empty(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: + """ + must return empty architectures if tree is not available + """ + mocker.patch("pathlib.Path.is_dir", return_value=False) + iterdir_mock = mocker.patch("pathlib.Path.iterdir") + + # new style + assert not repository_paths.known_architectures(repository_paths.root, repository_paths.repository_id.name) + # legacy mode + assert not repository_paths.known_architectures(repository_paths.root) + iterdir_mock.assert_not_called() + + +def test_known_repositories(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: + """ + must list available directory paths /repository/repo + """ + def iterdir(path: Path) -> list[Path]: + if path == repository_paths._repository_root: return [Path("repo1"), Path("repo2")] - if root == Path("repo1"): - return [Path("i686"), Path("x86_64")] return [Path("x86_64")] is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True) iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, side_effect=iterdir) - assert repository_paths.known_architectures(repository_paths.root, "") == { - RepositoryId("i686", "repo1"), - RepositoryId("x86_64", "repo1"), - RepositoryId("x86_64", "repo2"), - } + assert repository_paths.known_repositories(repository_paths.root) == {"repo1", "repo2"} iterdir_mock.assert_has_calls([ MockCall(repository_paths._repository_root), MockCall(Path("repo1")), MockCall(Path("repo2")), ]) is_dir_mock.assert_has_calls([ + MockCall(repository_paths._repository_root), MockCall(Path("repo1")), - MockCall(Path("i686")), MockCall(Path("x86_64")), MockCall(Path("repo2")), MockCall(Path("x86_64")), ]) -def test_known_architectures_legacy(repository_id: RepositoryId, repository_paths: RepositoryPaths, - mocker: MockerFixture) -> None: +def test_known_repositories_legacy(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: """ - must correctly define legacy tree /repository/arch + must return empty repository list for legacy tree """ - def iterdir(root: Path) -> list[Path]: - if root == repository_paths._repository_root: - return [Path("i686"), Path("x86_64")] - return [] + def is_dir(path: Path) -> bool: + return path == repository_paths._repository_root - is_dir_mock = mocker.patch("pathlib.Path.is_dir", autospec=True, return_value=True) - iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, side_effect=iterdir) + mocker.patch("pathlib.Path.is_dir", autospec=True, side_effect=is_dir) + iterdir_mock = mocker.patch("pathlib.Path.iterdir", autospec=True, return_value=[Path("i686"), Path("x86_64")]) - assert repository_paths.known_architectures(repository_paths.root, repository_id.name) == { - RepositoryId("i686", repository_id.name), - RepositoryId("x86_64", repository_id.name), - } - iterdir_mock.assert_has_calls([ - MockCall(repository_paths._repository_root), - MockCall(Path("i686")), - MockCall(Path("x86_64")), - ]) - is_dir_mock.assert_has_calls([ - MockCall(Path("i686")), - MockCall(Path("x86_64")), - ]) + assert not repository_paths.known_repositories(repository_paths.root) + iterdir_mock.assert_called_once_with(repository_paths._repository_root) + + +def test_known_repositories_empty(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: + """ + must return empty repositories if tree is not available + """ + mocker.patch("pathlib.Path.is_dir", return_value=False) + iterdir_mock = mocker.patch("pathlib.Path.iterdir") + + assert not repository_paths.known_repositories(repository_paths.root) + iterdir_mock.assert_not_called() def test_owner(repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: @@ -207,6 +273,7 @@ def test_tree_create(repository_paths: RepositoryPaths, mocker: MockerFixture) - and not prop.endswith("_for") and prop not in ("chown", "known_architectures", + "known_repositories", "owner", "repository_id", "root",