add sign command (#7) (#8)

This commit is contained in:
Evgenii Alekseev 2021-03-28 16:24:00 +03:00 committed by GitHub
parent 5cb3fd5853
commit 6f1b37c4cb
6 changed files with 138 additions and 7 deletions

View File

@ -81,6 +81,10 @@ def _parser() -> argparse.ArgumentParser:
report_parser.add_argument("target", help="target to generate report", nargs="*")
report_parser.set_defaults(handler=handlers.Report)
sign_parser = subparsers.add_parser("sign", description="(re-)sign packages and repository database")
sign_parser.add_argument("package", help="sign only specified packages", nargs="*")
sign_parser.set_defaults(handler=handlers.Sign)
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="*")

View File

@ -21,7 +21,7 @@ import logging
import shutil
from pathlib import Path
from typing import Callable, Iterable, List, Optional, Set
from typing import Callable, Iterable, List, Set
from ahriman.core.build_tools.task import Task
from ahriman.core.configuration import Configuration
@ -67,8 +67,8 @@ class Application:
"""
generate report and sync to remote server
"""
self.report()
self.sync()
self.report([])
self.sync([])
def get_updates(self, filter_packages: List[str], no_aur: bool, no_manual: bool, no_vcs: bool,
log_fn: Callable[[str], None]) -> List[Package]:
@ -162,7 +162,7 @@ class Application:
self.repository.process_remove(names)
self._finalize()
def report(self, target: Optional[Iterable[str]] = None) -> None:
def report(self, target: Iterable[str]) -> None:
"""
generate report
:param target: list of targets to run (e.g. html)
@ -170,7 +170,29 @@ class Application:
targets = target or None
self.repository.process_report(targets)
def sync(self, target: Optional[Iterable[str]] = None) -> None:
def sign(self, packages: Iterable[str]) -> None:
"""
sign packages and repository
:param packages: only sign specified packages
"""
# copy to prebuilt directory
for package in self.repository.packages():
# no one requested this package
if packages and package.base not in packages:
continue
for archive in package.packages.values():
if archive.filepath is None:
continue # avoid mypy warning
src = self.repository.paths.repository / archive.filepath
dst = self.repository.paths.packages / archive.filepath
shutil.copy(src, dst)
# run generic update function
self.update([])
# sign repository database if set
self.repository.sign.sign_repository(self.repository.repo.repo_path)
self._finalize()
def sync(self, target: Iterable[str]) -> None:
"""
sync to remote server
:param target: list of targets to run (e.g. s3)

View File

@ -25,6 +25,7 @@ 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.sign import Sign
from ahriman.application.handlers.status import Status
from ahriman.application.handlers.sync import Sync
from ahriman.application.handlers.update import Update

View File

@ -0,0 +1,42 @@
#
# 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 <http://www.gnu.org/licenses/>.
#
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 Sign(Handler):
"""
(re-)sign 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).sign(args.package)

View File

@ -0,0 +1,18 @@
import argparse
from pytest_mock import MockerFixture
from ahriman.application.handlers import Sign
from ahriman.core.configuration import Configuration
def test_run(args: argparse.Namespace, configuration: Configuration, mocker: MockerFixture) -> None:
"""
must run command
"""
args.package = []
mocker.patch("pathlib.Path.mkdir")
application_mock = mocker.patch("ahriman.application.application.Application.sign")
Sign.run(args, "x86_64", configuration)
application_mock.assert_called_once()

View File

@ -1,3 +1,6 @@
import pytest
from pathlib import Path
from pytest_mock import MockerFixture
from unittest import mock
@ -205,16 +208,57 @@ def test_report(application: Application, mocker: MockerFixture) -> None:
must generate report
"""
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_report")
application.report(None)
application.report([])
executor_mock.assert_called_once()
def test_sign(application: Application, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must sign world
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
copy_mock = mocker.patch("shutil.copy")
update_mock = mocker.patch("ahriman.application.application.Application.update")
sign_repository_mock = mocker.patch("ahriman.core.sign.gpg.GPG.sign_repository")
finalize_mock = mocker.patch("ahriman.application.application.Application._finalize")
application.sign([])
copy_mock.assert_has_calls([
mock.call(pytest.helpers.anyvar(str), pytest.helpers.anyvar(str)),
mock.call(pytest.helpers.anyvar(str), pytest.helpers.anyvar(str))
])
update_mock.assert_called_with([])
sign_repository_mock.assert_called_once()
finalize_mock.assert_called_once()
def test_sign_specific(application: Application, package_ahriman: Package, package_python_schedule: Package,
mocker: MockerFixture) -> None:
"""
must sign only specified packages
"""
mocker.patch("ahriman.core.repository.repository.Repository.packages",
return_value=[package_ahriman, package_python_schedule])
copy_mock = mocker.patch("shutil.copy")
update_mock = mocker.patch("ahriman.application.application.Application.update")
sign_repository_mock = mocker.patch("ahriman.core.sign.gpg.GPG.sign_repository")
finalize_mock = mocker.patch("ahriman.application.application.Application._finalize")
application.sign([package_ahriman.base])
copy_mock.assert_called_once()
update_mock.assert_called_with([])
sign_repository_mock.assert_called_once()
finalize_mock.assert_called_once()
def test_sync(application: Application, mocker: MockerFixture) -> None:
"""
must sync to remote
"""
executor_mock = mocker.patch("ahriman.core.repository.executor.Executor.process_sync")
application.sync(None)
application.sync([])
executor_mock.assert_called_once()