From 00326483f4aa44c32b62dcf7f238992e4303c630 Mon Sep 17 00:00:00 2001 From: Evgeniy Alekseev Date: Fri, 3 Sep 2021 02:22:36 +0300 Subject: [PATCH] add remove uknown method --- src/ahriman/application/ahriman.py | 15 +++++ src/ahriman/application/application.py | 13 ++++ src/ahriman/application/handlers/__init__.py | 1 + .../application/handlers/remove_unknown.py | 59 ++++++++++++++++++ .../handlers/test_handler_remove_unknown.py | 60 +++++++++++++++++++ tests/ahriman/application/test_ahriman.py | 8 +++ tests/ahriman/application/test_application.py | 21 +++++++ 7 files changed, 177 insertions(+) create mode 100644 src/ahriman/application/handlers/remove_unknown.py create mode 100644 tests/ahriman/application/handlers/test_handler_remove_unknown.py diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py index 39d6acc6..889ea954 100644 --- a/src/ahriman/application/ahriman.py +++ b/src/ahriman/application/ahriman.py @@ -68,6 +68,7 @@ def _parser() -> argparse.ArgumentParser: _set_key_import_parser(subparsers) _set_rebuild_parser(subparsers) _set_remove_parser(subparsers) + _set_remove_unknown_parser(subparsers) _set_report_parser(subparsers) _set_search_parser(subparsers) _set_setup_parser(subparsers) @@ -219,6 +220,20 @@ def _set_remove_parser(root: SubParserAction) -> argparse.ArgumentParser: return parser +def _set_remove_unknown_parser(root: SubParserAction) -> argparse.ArgumentParser: + """ + add parser for remove unknown packages subcommand + :param root: subparsers for the commands + :return: created argument parser + """ + parser = root.add_parser("remove-unknown", help="remove unknown packages", + description="remove packages which are missing in AUR", + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + parser.add_argument("--dry-run", help="just perform check for packages without removal", action="store_true") + parser.set_defaults(handler=handlers.RemoveUnknown, architecture=[]) + return parser + + def _set_report_parser(root: SubParserAction) -> argparse.ArgumentParser: """ add parser for report subcommand diff --git a/src/ahriman/application/application.py b/src/ahriman/application/application.py index d66e5166..277fe884 100644 --- a/src/ahriman/application/application.py +++ b/src/ahriman/application/application.py @@ -205,6 +205,19 @@ class Application: targets = target or None self.repository.process_sync(targets, built_packages) + def unknown(self) -> List[Package]: + """ + get packages which were not found in AUR + :return: unknown package list + """ + packages = [] + for base in self.repository.packages(): + try: + _ = Package.from_aur(base.base, base.aur_url) + except Exception: + packages.append(base) + return packages + def update(self, updates: Iterable[Package]) -> None: """ run package updates diff --git a/src/ahriman/application/handlers/__init__.py b/src/ahriman/application/handlers/__init__.py index 62047489..58574521 100644 --- a/src/ahriman/application/handlers/__init__.py +++ b/src/ahriman/application/handlers/__init__.py @@ -27,6 +27,7 @@ from ahriman.application.handlers.init import Init from ahriman.application.handlers.key_import import KeyImport 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.report import Report from ahriman.application.handlers.search import Search from ahriman.application.handlers.setup import Setup diff --git a/src/ahriman/application/handlers/remove_unknown.py b/src/ahriman/application/handlers/remove_unknown.py new file mode 100644 index 00000000..1e19f79c --- /dev/null +++ b/src/ahriman/application/handlers/remove_unknown.py @@ -0,0 +1,59 @@ +# +# Copyright (c) 2021 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 . +# +import argparse + +from typing import Type + +from ahriman.application.application import Application +from ahriman.application.handlers.handler import Handler +from ahriman.core.configuration import Configuration +from ahriman.models.package import Package + + +class RemoveUnknown(Handler): + """ + remove unknown packages handler + """ + + @classmethod + def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, configuration: Configuration) -> None: + """ + callback for command line + :param args: command line args + :param architecture: repository architecture + :param configuration: configuration instance + """ + application = Application(architecture, configuration) + unknown_packages = application.unknown() + if args.dry_run: + for package in unknown_packages: + RemoveUnknown.log_fn(package) + return + + application.remove(package.base for package in unknown_packages) + + @staticmethod + def log_fn(package: Package) -> None: + """ + log package information + :param package: package object to log + """ + print(f"=> {package.base} {package.version}") + print(f" {package.web_url}") diff --git a/tests/ahriman/application/handlers/test_handler_remove_unknown.py b/tests/ahriman/application/handlers/test_handler_remove_unknown.py new file mode 100644 index 00000000..5d83ce47 --- /dev/null +++ b/tests/ahriman/application/handlers/test_handler_remove_unknown.py @@ -0,0 +1,60 @@ +import argparse + +from pytest_mock import MockerFixture + +from ahriman.application.handlers import RemoveUnknown +from ahriman.core.configuration import Configuration +from ahriman.models.package import Package + + +def _default_args(args: argparse.Namespace) -> argparse.Namespace: + """ + default arguments for these test cases + :param args: command line arguments fixture + :return: generated arguments for these test cases + """ + args.dry_run = False + return args + + +def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None: + """ + must run command + """ + args = _default_args(args) + mocker.patch("pathlib.Path.mkdir") + application_mock = mocker.patch("ahriman.application.application.Application.unknown") + remove_mock = mocker.patch("ahriman.application.application.Application.remove") + + RemoveUnknown.run(args, "x86_64", configuration) + application_mock.assert_called_once() + remove_mock.assert_called_once() + + +def test_run_dry_run(args: argparse.Namespace, configuration: Configuration, package_ahriman: Package, + mocker: MockerFixture) -> None: + """ + must run simplified command + """ + args = _default_args(args) + args.dry_run = True + mocker.patch("pathlib.Path.mkdir") + application_mock = mocker.patch("ahriman.application.application.Application.unknown", + return_value=[package_ahriman]) + remove_mock = mocker.patch("ahriman.application.application.Application.remove") + log_fn_mock = mocker.patch("ahriman.application.handlers.remove_unknown.RemoveUnknown.log_fn") + + RemoveUnknown.run(args, "x86_64", configuration) + application_mock.assert_called_once() + remove_mock.assert_not_called() + log_fn_mock.assert_called_with(package_ahriman) + + +def test_log_fn(package_ahriman: Package, mocker: MockerFixture) -> None: + """ + log function must call print built-in + """ + print_mock = mocker.patch("builtins.print") + + RemoveUnknown.log_fn(package_ahriman) + print_mock.assert_called() # we don't really care about call details tbh diff --git a/tests/ahriman/application/test_ahriman.py b/tests/ahriman/application/test_ahriman.py index f709e308..91838703 100644 --- a/tests/ahriman/application/test_ahriman.py +++ b/tests/ahriman/application/test_ahriman.py @@ -140,6 +140,14 @@ def test_subparsers_remove(parser: argparse.ArgumentParser) -> None: assert args.architecture == [] +def test_subparsers_remove_unknown(parser: argparse.ArgumentParser) -> None: + """ + remove-unknown command must imply empty architectures list + """ + args = parser.parse_args(["remove-unknown"]) + assert args.architecture == [] + + def test_subparsers_report(parser: argparse.ArgumentParser) -> None: """ report command must imply empty architectures list diff --git a/tests/ahriman/application/test_application.py b/tests/ahriman/application/test_application.py index 8913ec42..8643c6eb 100644 --- a/tests/ahriman/application/test_application.py +++ b/tests/ahriman/application/test_application.py @@ -283,6 +283,27 @@ def test_sync(application: Application, mocker: MockerFixture) -> None: executor_mock.assert_called_once() +def test_unknown(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: + """ + must return list of packages missing in aur + """ + mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman]) + mocker.patch("ahriman.models.package.Package.from_aur", side_effect=Exception()) + + packages = application.unknown() + assert packages == [package_ahriman] + + +def test_unknown_empty(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: + """ + must return list of packages missing in aur + """ + mocker.patch("ahriman.core.repository.repository.Repository.packages", return_value=[package_ahriman]) + mocker.patch("ahriman.models.package.Package.from_aur") + + assert not application.unknown() + + def test_update(application: Application, package_ahriman: Package, mocker: MockerFixture) -> None: """ must process package updates