diff --git a/Makefile b/Makefile
index 17dd3130..e2138a20 100644
--- a/Makefile
+++ b/Makefile
@@ -25,7 +25,7 @@ archlinux: archive
sed -i "s/pkgver=[0-9.]*/pkgver=$(VERSION)/" package/archlinux/PKGBUILD
check:
- cd src && mypy --strict -p $(PROJECT)
+ cd src && mypy --implicit-reexport --strict -p $(PROJECT)
cd src && find $(PROJECT) -name '*.py' -execdir autopep8 --max-line-length 120 -aa -i {} +
cd src && pylint --rcfile=../.pylintrc $(PROJECT)
diff --git a/src/ahriman/application/ahriman.py b/src/ahriman/application/ahriman.py
index 23e91871..f19dcef6 100644
--- a/src/ahriman/application/ahriman.py
+++ b/src/ahriman/application/ahriman.py
@@ -18,34 +18,11 @@
# along with this program. If not, see .
#
import argparse
-import logging
import sys
-from multiprocessing import Pool
-
-import ahriman.application.functions as functions
+import ahriman.application.handlers as handlers
import ahriman.version as version
-from ahriman.application.lock import Lock
-from ahriman.core.configuration import Configuration
-
-
-def _call(args: argparse.Namespace, architecture: str, config: Configuration) -> bool:
- '''
- additional function to wrap all calls for multiprocessing library
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- :return: True on success, False otherwise
- '''
- try:
- with Lock(args, architecture, config):
- args.fn(args, architecture, config)
- return True
- except Exception:
- logging.getLogger('root').exception('process exception', exc_info=True)
- return False
-
if __name__ == '__main__':
parser = argparse.ArgumentParser(prog='ahriman', description='ArcHlinux ReposItory MANager')
@@ -66,12 +43,12 @@ if __name__ == '__main__':
add_parser = subparsers.add_parser('add', description='add package')
add_parser.add_argument('package', help='package base/name or archive path', nargs='+')
add_parser.add_argument('--without-dependencies', help='do not add dependencies', action='store_true')
- add_parser.set_defaults(fn=functions.add)
+ add_parser.set_defaults(handler=handlers.Add)
check_parser = subparsers.add_parser('check', description='check for updates. Same as update --dry-run --no-manual')
check_parser.add_argument('package', help='filter check by package base', nargs='*')
check_parser.add_argument('--no-vcs', help='do not check VCS packages', action='store_true')
- check_parser.set_defaults(fn=functions.update, no_aur=False, no_manual=True, dry_run=True)
+ check_parser.set_defaults(handler=handlers.Update, no_aur=False, no_manual=True, dry_run=True)
clean_parser = subparsers.add_parser('clean', description='clear all local caches')
clean_parser.add_argument('--no-build', help='do not clear directory with package sources', action='store_true')
@@ -82,30 +59,30 @@ if __name__ == '__main__':
help='do not clear directory with manually added packages',
action='store_true')
clean_parser.add_argument('--no-packages', help='do not clear directory with built packages', action='store_true')
- clean_parser.set_defaults(fn=functions.clean)
+ clean_parser.set_defaults(handler=handlers.Clean)
config_parser = subparsers.add_parser('config', description='dump configuration for specified architecture')
- config_parser.set_defaults(fn=functions.dump_config, lock=None, no_report=True, unsafe=True)
+ config_parser.set_defaults(handler=handlers.Dump, lock=None, no_report=True, unsafe=True)
rebuild_parser = subparsers.add_parser('rebuild', description='rebuild whole repository')
- rebuild_parser.set_defaults(fn=functions.rebuild)
+ rebuild_parser.set_defaults(handler=handlers.Rebuild)
remove_parser = subparsers.add_parser('remove', description='remove package')
remove_parser.add_argument('package', help='package name or base', nargs='+')
- remove_parser.set_defaults(fn=functions.remove)
+ remove_parser.set_defaults(handler=handlers.Remove)
report_parser = subparsers.add_parser('report', description='generate report')
report_parser.add_argument('target', help='target to generate report', nargs='*')
- report_parser.set_defaults(fn=functions.report)
+ report_parser.set_defaults(handler=handlers.Report)
status_parser = subparsers.add_parser('status', description='request status of the package')
status_parser.add_argument('--ahriman', help='get service status itself', action='store_true')
status_parser.add_argument('package', help='filter status by package base', nargs='*')
- status_parser.set_defaults(fn=functions.status, lock=None, no_report=True, unsafe=True)
+ status_parser.set_defaults(handler=handlers.Status, lock=None, no_report=True, unsafe=True)
sync_parser = subparsers.add_parser('sync', description='sync packages to remote server')
sync_parser.add_argument('target', help='target to sync', nargs='*')
- sync_parser.set_defaults(fn=functions.sync)
+ sync_parser.set_defaults(handler=handlers.Sync)
update_parser = subparsers.add_parser('update', description='run updates')
update_parser.add_argument('package', help='filter check by package base', nargs='*')
@@ -114,19 +91,17 @@ if __name__ == '__main__':
update_parser.add_argument('--no-aur', help='do not check for AUR updates. Implies --no-vcs', action='store_true')
update_parser.add_argument('--no-manual', help='do not include manual updates', action='store_true')
update_parser.add_argument('--no-vcs', help='do not check VCS packages', action='store_true')
- update_parser.set_defaults(fn=functions.update)
+ update_parser.set_defaults(handler=handlers.Update)
web_parser = subparsers.add_parser('web', description='start web server')
- web_parser.set_defaults(fn=functions.web, lock=None, no_report=True)
+ web_parser.set_defaults(handler=handlers.Web, lock=None, no_report=True)
- cmd_args = parser.parse_args()
- if 'fn' not in cmd_args:
+ args = parser.parse_args()
+ if 'handler' not in args:
parser.print_help()
sys.exit(1)
- configuration = Configuration.from_path(cmd_args.config, not cmd_args.no_log)
- with Pool(len(cmd_args.architecture)) as pool:
- result = pool.starmap(
- _call, [(cmd_args, architecture, configuration) for architecture in cmd_args.architecture])
+ handler: handlers.Handler = args.handler
+ status = handler.execute(args)
- sys.exit(0 if all(result) else 1)
+ sys.exit(status)
diff --git a/src/ahriman/application/functions.py b/src/ahriman/application/functions.py
deleted file mode 100644
index 1cc7cfb3..00000000
--- a/src/ahriman/application/functions.py
+++ /dev/null
@@ -1,163 +0,0 @@
-#
-# Copyright (c) 2021 Evgenii Alekseev.
-#
-# 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 Iterable, Tuple
-
-from ahriman.application.application import Application
-from ahriman.core.configuration import Configuration
-from ahriman.models.build_status import BuildStatus
-from ahriman.models.package import Package
-
-
-def add(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- add packages callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- Application(architecture, config).add(args.package, args.without_dependencies)
-
-
-def clean(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- clean caches callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- Application(architecture, config).clean(args.no_build, args.no_cache, args.no_chroot,
- args.no_manual, args.no_packages)
-
-
-def dump_config(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- configuration dump callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- del args
- config_dump = config.dump(architecture)
- for section, values in sorted(config_dump.items()):
- print(f'[{section}]')
- for key, value in sorted(values.items()):
- print(f'{key} = {value}')
- print()
-
-
-def rebuild(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- world rebuild callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- del args
- app = Application(architecture, config)
- packages = app.repository.packages()
- app.update(packages)
-
-
-def remove(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- remove packages callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- Application(architecture, config).remove(args.package)
-
-
-def report(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- generate report callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- Application(architecture, config).report(args.target)
-
-
-def status(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- package status callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- application = Application(architecture, config)
- if args.ahriman:
- ahriman = application.repository.reporter.get_self()
- print(ahriman.pretty_print())
- print()
- if args.package:
- packages: Iterable[Tuple[Package, BuildStatus]] = sum(
- [application.repository.reporter.get(base) for base in args.package],
- start=[])
- else:
- packages = application.repository.reporter.get(None)
- for package, package_status in sorted(packages, key=lambda item: item[0].base):
- print(package.pretty_print())
- print(f'\t{package.version}')
- print(f'\t{package_status.pretty_print()}')
-
-
-def sync(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- sync to remote server callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- Application(architecture, config).sync(args.target)
-
-
-def update(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- update packages callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- # typing workaround
- def log_fn(line: str) -> None:
- return print(line) if args.dry_run else application.logger.info(line)
-
- application = Application(architecture, config)
- packages = application.get_updates(args.package, args.no_aur, args.no_manual, args.no_vcs, log_fn)
- if args.dry_run:
- return
-
- application.update(packages)
-
-
-def web(args: argparse.Namespace, architecture: str, config: Configuration) -> None:
- '''
- web server callback
- :param args: command line args
- :param architecture: repository architecture
- :param config: configuration instance
- '''
- del args
- from ahriman.web.web import run_server, setup_service
- application = setup_service(architecture, config)
- run_server(application, architecture)
diff --git a/src/ahriman/application/handlers/__init__.py b/src/ahriman/application/handlers/__init__.py
new file mode 100644
index 00000000..5f1ea37d
--- /dev/null
+++ b/src/ahriman/application/handlers/__init__.py
@@ -0,0 +1,31 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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 .
+#
+from ahriman.application.handlers.handler import Handler
+
+from ahriman.application.handlers.add import Add
+from ahriman.application.handlers.clean import Clean
+from ahriman.application.handlers.dump import Dump
+from ahriman.application.handlers.rebuild import Rebuild
+from ahriman.application.handlers.remove import Remove
+from ahriman.application.handlers.report import Report
+from ahriman.application.handlers.status import Status
+from ahriman.application.handlers.sync import Sync
+from ahriman.application.handlers.update import Update
+from ahriman.application.handlers.web import Web
diff --git a/src/ahriman/application/handlers/add.py b/src/ahriman/application/handlers/add.py
new file mode 100644
index 00000000..e8c9aeca
--- /dev/null
+++ b/src/ahriman/application/handlers/add.py
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Add(Handler):
+ '''
+ add packages handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ Application(architecture, config).add(args.package, args.without_dependencies)
diff --git a/src/ahriman/application/handlers/clean.py b/src/ahriman/application/handlers/clean.py
new file mode 100644
index 00000000..7e47aa4f
--- /dev/null
+++ b/src/ahriman/application/handlers/clean.py
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Clean(Handler):
+ '''
+ clean caches handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ Application(architecture, config).clean(args.no_build, args.no_cache, args.no_chroot,
+ args.no_manual, args.no_packages)
diff --git a/src/ahriman/application/handlers/dump.py b/src/ahriman/application/handlers/dump.py
new file mode 100644
index 00000000..237baa6d
--- /dev/null
+++ b/src/ahriman/application/handlers/dump.py
@@ -0,0 +1,46 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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.handlers.handler import Handler
+from ahriman.core.configuration import Configuration
+
+
+class Dump(Handler):
+ '''
+ dump config handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ config_dump = config.dump(architecture)
+ for section, values in sorted(config_dump.items()):
+ print(f'[{section}]')
+ for key, value in sorted(values.items()):
+ print(f'{key} = {value}')
+ print()
diff --git a/src/ahriman/application/handlers/handler.py b/src/ahriman/application/handlers/handler.py
new file mode 100644
index 00000000..c1830c65
--- /dev/null
+++ b/src/ahriman/application/handlers/handler.py
@@ -0,0 +1,75 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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 .
+#
+from __future__ import annotations
+
+import argparse
+import logging
+from multiprocessing import Pool
+
+from typing import Type
+
+from ahriman.application.lock import Lock
+from ahriman.core.configuration import Configuration
+
+
+class Handler:
+ '''
+ base handler class for command callbacks
+ '''
+
+ @classmethod
+ def _call(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> bool:
+ '''
+ additional function to wrap all calls for multiprocessing library
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ :return: True on success, False otherwise
+ '''
+ try:
+ with Lock(args, architecture, config):
+ cls.run(args, architecture, config)
+ return True
+ except Exception:
+ logging.getLogger('root').exception('process exception', exc_info=True)
+ return False
+
+ @classmethod
+ def execute(cls: Type[Handler], args: argparse.Namespace) -> int:
+ '''
+ execute function for all aru
+ :param args: command line args
+ :return: 0 on success, 1 otherwise
+ '''
+ configuration = Configuration.from_path(args.config, not args.no_log)
+ with Pool(len(args.architecture)) as pool:
+ result = pool.starmap(
+ cls._call, [(args, architecture, configuration) for architecture in args.architecture])
+ return 0 if all(result) else 1
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ raise NotImplementedError
diff --git a/src/ahriman/application/handlers/rebuild.py b/src/ahriman/application/handlers/rebuild.py
new file mode 100644
index 00000000..6c2616ae
--- /dev/null
+++ b/src/ahriman/application/handlers/rebuild.py
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Rebuild(Handler):
+ '''
+ make world handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ application = Application(architecture, config)
+ packages = application.repository.packages()
+ application.update(packages)
diff --git a/src/ahriman/application/handlers/remove.py b/src/ahriman/application/handlers/remove.py
new file mode 100644
index 00000000..5a7ac5b4
--- /dev/null
+++ b/src/ahriman/application/handlers/remove.py
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Remove(Handler):
+ '''
+ remove packages handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ Application(architecture, config).remove(args.package)
diff --git a/src/ahriman/application/handlers/report.py b/src/ahriman/application/handlers/report.py
new file mode 100644
index 00000000..7c24417b
--- /dev/null
+++ b/src/ahriman/application/handlers/report.py
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Report(Handler):
+ '''
+ generate report handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ Application(architecture, config).report(args.target)
diff --git a/src/ahriman/application/handlers/status.py b/src/ahriman/application/handlers/status.py
new file mode 100644
index 00000000..25ed4634
--- /dev/null
+++ b/src/ahriman/application/handlers/status.py
@@ -0,0 +1,58 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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 Iterable, Tuple, Type
+
+from ahriman.application.application import Application
+from ahriman.application.handlers.handler import Handler
+from ahriman.core.configuration import Configuration
+from ahriman.models.build_status import BuildStatus
+from ahriman.models.package import Package
+
+
+class Status(Handler):
+ '''
+ package status handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ application = Application(architecture, config)
+ if args.ahriman:
+ ahriman = application.repository.reporter.get_self()
+ print(ahriman.pretty_print())
+ print()
+ if args.package:
+ packages: Iterable[Tuple[Package, BuildStatus]] = sum(
+ [application.repository.reporter.get(base) for base in args.package],
+ start=[])
+ else:
+ packages = application.repository.reporter.get(None)
+ for package, package_status in sorted(packages, key=lambda item: item[0].base):
+ print(package.pretty_print())
+ print(f'\t{package.version}')
+ print(f'\t{package_status.pretty_print()}')
diff --git a/src/ahriman/application/handlers/sync.py b/src/ahriman/application/handlers/sync.py
new file mode 100644
index 00000000..931776cf
--- /dev/null
+++ b/src/ahriman/application/handlers/sync.py
@@ -0,0 +1,42 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Sync(Handler):
+ '''
+ remove sync handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ Application(architecture, config).sync(args.target)
diff --git a/src/ahriman/application/handlers/update.py b/src/ahriman/application/handlers/update.py
new file mode 100644
index 00000000..fa56d89c
--- /dev/null
+++ b/src/ahriman/application/handlers/update.py
@@ -0,0 +1,51 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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
+
+
+class Update(Handler):
+ '''
+ package update handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ # typing workaround
+ def log_fn(line: str) -> None:
+ return print(line) if args.dry_run else application.logger.info(line)
+
+ application = Application(architecture, config)
+ packages = application.get_updates(args.package, args.no_aur, args.no_manual, args.no_vcs, log_fn)
+ if args.dry_run:
+ return
+
+ application.update(packages)
diff --git a/src/ahriman/application/handlers/web.py b/src/ahriman/application/handlers/web.py
new file mode 100644
index 00000000..5cb438c1
--- /dev/null
+++ b/src/ahriman/application/handlers/web.py
@@ -0,0 +1,43 @@
+#
+# Copyright (c) 2021 Evgenii Alekseev.
+#
+# 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.handlers.handler import Handler
+from ahriman.core.configuration import Configuration
+
+
+class Web(Handler):
+ '''
+ web server handler
+ '''
+
+ @classmethod
+ def run(cls: Type[Handler], args: argparse.Namespace, architecture: str, config: Configuration) -> None:
+ '''
+ callback for command line
+ :param args: command line args
+ :param architecture: repository architecture
+ :param config: configuration instance
+ '''
+ from ahriman.web.web import run_server, setup_service
+ application = setup_service(architecture, config)
+ run_server(application, architecture)