Compare commits

..

2 Commits

13 changed files with 353 additions and 41 deletions

View File

@@ -92,6 +92,14 @@ ahriman.application.handlers.patch module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.application.handlers.pkgbuild module
--------------------------------------------
.. automodule:: ahriman.application.handlers.pkgbuild
:members:
:no-undoc-members:
:show-inheritance:
ahriman.application.handlers.rebuild module ahriman.application.handlers.rebuild module
------------------------------------------- -------------------------------------------

View File

@@ -140,6 +140,14 @@ ahriman.core.database.migrations.m016\_archive module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.database.migrations.m017\_pkgbuild module
------------------------------------------------------
.. automodule:: ahriman.core.database.migrations.m017_pkgbuild
:members:
:no-undoc-members:
:show-inheritance:
Module contents Module contents
--------------- ---------------

View File

@@ -76,6 +76,14 @@ ahriman.core.formatters.patch\_printer module
:no-undoc-members: :no-undoc-members:
:show-inheritance: :show-inheritance:
ahriman.core.formatters.pkgbuild\_printer module
------------------------------------------------
.. automodule:: ahriman.core.formatters.pkgbuild_printer
:members:
:no-undoc-members:
:show-inheritance:
ahriman.core.formatters.printer module ahriman.core.formatters.printer module
-------------------------------------- --------------------------------------

View File

@@ -54,7 +54,7 @@ class Change(Handler):
case Action.List: case Action.List:
changes = client.package_changes_get(args.package) changes = client.package_changes_get(args.package)
ChangesPrinter(changes)(verbose=True, separator="") ChangesPrinter(changes)(verbose=True, separator="")
Change.check_status(args.exit_code, not changes.is_empty) Change.check_status(args.exit_code, changes.changes is not None)
case Action.Remove: case Action.Remove:
client.package_changes_update(args.package, Changes()) client.package_changes_update(args.package, Changes())

View File

@@ -0,0 +1,101 @@
#
# Copyright (c) 2021-2026 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 dataclasses import replace
from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration
from ahriman.core.formatters import PkgbuildPrinter
from ahriman.models.action import Action
from ahriman.models.repository_id import RepositoryId
class Pkgbuild(Handler):
"""
package pkgbuild handler
"""
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
@classmethod
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
report: bool) -> None:
"""
callback for command line
Args:
args(argparse.Namespace): command line args
repository_id(RepositoryId): repository unique identifier
configuration(Configuration): configuration instance
report(bool): force enable or disable reporting
"""
application = Application(repository_id, configuration, report=True)
client = application.repository.reporter
match args.action:
case Action.List:
changes = client.package_changes_get(args.package)
PkgbuildPrinter(changes)(verbose=True, separator="")
Pkgbuild.check_status(args.exit_code, changes.pkgbuild is not None)
case Action.Remove:
changes = client.package_changes_get(args.package)
client.package_changes_update(args.package, replace(changes, pkgbuild=None))
@staticmethod
def _set_package_pkgbuild_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package pkgbuild subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-pkgbuild", help="get package pkgbuild",
description="retrieve package PKGBUILD stored in database",
epilog="This command requests package status from the web interface "
"if it is available.")
parser.add_argument("package", help="package base")
parser.add_argument("-e", "--exit-code", help="return non-zero exit status if result is empty",
action="store_true")
parser.set_defaults(action=Action.List, lock=None, quiet=True, report=False, unsafe=True)
return parser
@staticmethod
def _set_package_pkgbuild_remove_parser(root: SubParserAction) -> argparse.ArgumentParser:
"""
add parser for package pkgbuild remove subcommand
Args:
root(SubParserAction): subparsers for the commands
Returns:
argparse.ArgumentParser: created argument parser
"""
parser = root.add_parser("package-pkgbuild-remove", help="remove package pkgbuild",
description="remove the package PKGBUILD stored remotely")
parser.add_argument("package", help="package base")
parser.set_defaults(action=Action.Remove, exit_code=False, lock=None, quiet=True, report=False, unsafe=True)
return parser
arguments = [_set_package_pkgbuild_parser, _set_package_pkgbuild_remove_parser]

View File

@@ -26,6 +26,7 @@ from ahriman.core.formatters.event_stats_printer import EventStatsPrinter
from ahriman.core.formatters.package_printer import PackagePrinter from ahriman.core.formatters.package_printer import PackagePrinter
from ahriman.core.formatters.package_stats_printer import PackageStatsPrinter from ahriman.core.formatters.package_stats_printer import PackageStatsPrinter
from ahriman.core.formatters.patch_printer import PatchPrinter from ahriman.core.formatters.patch_printer import PatchPrinter
from ahriman.core.formatters.pkgbuild_printer import PkgbuildPrinter
from ahriman.core.formatters.printer import Printer from ahriman.core.formatters.printer import Printer
from ahriman.core.formatters.repository_printer import RepositoryPrinter from ahriman.core.formatters.repository_printer import RepositoryPrinter
from ahriman.core.formatters.repository_stats_printer import RepositoryStatsPrinter from ahriman.core.formatters.repository_stats_printer import RepositoryStatsPrinter

View File

@@ -45,7 +45,7 @@ class ChangesPrinter(Printer):
Returns: Returns:
list[Property]: list of content properties list[Property]: list of content properties
""" """
if self.changes.is_empty: if self.changes.changes is None:
return [] return []
return [Property("", self.changes.changes, is_required=True, indent=0)] return [Property("", self.changes.changes, is_required=True, indent=0)]
@@ -57,6 +57,6 @@ class ChangesPrinter(Printer):
Returns: Returns:
str | None: content title if it can be generated and ``None`` otherwise str | None: content title if it can be generated and ``None`` otherwise
""" """
if self.changes.is_empty: if self.changes.changes is None:
return None return None
return self.changes.last_commit_sha return self.changes.last_commit_sha

View File

@@ -0,0 +1,62 @@
#
# Copyright (c) 2021-2026 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/>.
#
from ahriman.core.formatters.printer import Printer
from ahriman.models.changes import Changes
from ahriman.models.property import Property
class PkgbuildPrinter(Printer):
"""
print content of the pkgbuild stored in changes
Attributes:
changes(Changes): package changes
"""
def __init__(self, changes: Changes) -> None:
"""
Args:
changes(Changes): package changes
"""
Printer.__init__(self)
self.changes = changes
def properties(self) -> list[Property]:
"""
convert content into printable data
Returns:
list[Property]: list of content properties
"""
if self.changes.pkgbuild is None:
return []
return [Property("", self.changes.pkgbuild, is_required=True, indent=0)]
# pylint: disable=redundant-returns-doc
def title(self) -> str | None:
"""
generate entry title from content
Returns:
str | None: content title if it can be generated and ``None`` otherwise
"""
if self.changes.pkgbuild is None:
return None
return self.changes.last_commit_sha

View File

@@ -38,16 +38,6 @@ class Changes:
changes: str | None = None changes: str | None = None
pkgbuild: str | None = None pkgbuild: str | None = None
@property
def is_empty(self) -> bool:
"""
validate that changes are not empty
Returns:
bool: ``True`` in case if changes are not set and ``False`` otherwise
"""
return self.changes is None
@classmethod @classmethod
def from_json(cls, dump: dict[str, Any]) -> Self: def from_json(cls, dump: dict[str, Any]) -> Self:
""" """

View File

@@ -0,0 +1,100 @@
import argparse
import pytest
from pytest_mock import MockerFixture
from ahriman.application.handlers.pkgbuild import Pkgbuild
from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite
from ahriman.core.repository import Repository
from ahriman.models.action import Action
from ahriman.models.changes import Changes
def _default_args(args: argparse.Namespace) -> argparse.Namespace:
"""
default arguments for these test cases
Args:
args(argparse.Namespace): command line arguments fixture
Returns:
argparse.Namespace: generated arguments for these test cases
"""
args.action = Action.List
args.exit_code = False
args.package = "package"
return args
def test_run(args: argparse.Namespace, configuration: Configuration, repository: Repository,
mocker: MockerFixture) -> None:
"""
must run command
"""
args = _default_args(args)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
application_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get",
return_value=Changes("sha", "change", "pkgbuild content"))
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
print_mock = mocker.patch("ahriman.core.formatters.Printer.print")
_, repository_id = configuration.check_loaded()
Pkgbuild.run(args, repository_id, configuration, report=False)
application_mock.assert_called_once_with(args.package)
check_mock.assert_called_once_with(False, True)
print_mock.assert_called_once_with(verbose=True, log_fn=pytest.helpers.anyvar(int), separator="")
def test_run_empty_exception(args: argparse.Namespace, configuration: Configuration, repository: Repository,
mocker: MockerFixture) -> None:
"""
must raise ExitCode exception on empty pkgbuild result
"""
args = _default_args(args)
args.exit_code = True
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=Changes())
check_mock = mocker.patch("ahriman.application.handlers.handler.Handler.check_status")
_, repository_id = configuration.check_loaded()
Pkgbuild.run(args, repository_id, configuration, report=False)
check_mock.assert_called_once_with(True, False)
def test_run_remove(args: argparse.Namespace, configuration: Configuration, repository: Repository,
mocker: MockerFixture) -> None:
"""
must remove package pkgbuild
"""
args = _default_args(args)
args.action = Action.Remove
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
changes = Changes("sha", "change", "pkgbuild content")
mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_get", return_value=changes)
update_mock = mocker.patch("ahriman.core.status.local_client.LocalClient.package_changes_update")
_, repository_id = configuration.check_loaded()
Pkgbuild.run(args, repository_id, configuration, report=False)
update_mock.assert_called_once_with(args.package, Changes("sha", "change", None))
def test_imply_with_report(args: argparse.Namespace, configuration: Configuration, database: SQLite,
mocker: MockerFixture) -> None:
"""
must create application object with native reporting
"""
args = _default_args(args)
mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
load_mock = mocker.patch("ahriman.core.repository.Repository.load")
_, repository_id = configuration.check_loaded()
Pkgbuild.run(args, repository_id, configuration, report=False)
load_mock.assert_called_once_with(repository_id, configuration, database, report=True, refresh_pacman_database=0)
def test_disallow_multi_architecture_run() -> None:
"""
must not allow multi architecture run
"""
assert not Pkgbuild.ALLOW_MULTI_ARCHITECTURE_RUN

View File

@@ -2,24 +2,26 @@ import pytest
from pathlib import Path from pathlib import Path
from ahriman.core.formatters import \ from ahriman.core.formatters import (
AurPrinter, \ AurPrinter,
ChangesPrinter, \ ChangesPrinter,
ConfigurationPathsPrinter, \ ConfigurationPathsPrinter,
ConfigurationPrinter, \ ConfigurationPrinter,
EventStatsPrinter, \ EventStatsPrinter,
PackagePrinter, \ PackagePrinter,
PackageStatsPrinter, \ PackageStatsPrinter,
PatchPrinter, \ PatchPrinter,
RepositoryPrinter, \ PkgbuildPrinter,
RepositoryStatsPrinter, \ RepositoryPrinter,
StatusPrinter, \ RepositoryStatsPrinter,
StringPrinter, \ StatusPrinter,
TreePrinter, \ StringPrinter,
UpdatePrinter, \ TreePrinter,
UserPrinter, \ UpdatePrinter,
ValidationPrinter, \ UserPrinter,
ValidationPrinter,
VersionPrinter VersionPrinter
)
from ahriman.models.aur_package import AURPackage from ahriman.models.aur_package import AURPackage
from ahriman.models.build_status import BuildStatus from ahriman.models.build_status import BuildStatus
from ahriman.models.changes import Changes from ahriman.models.changes import Changes
@@ -55,6 +57,17 @@ def changes_printer() -> ChangesPrinter:
return ChangesPrinter(Changes("sha", "changes")) return ChangesPrinter(Changes("sha", "changes"))
@pytest.fixture
def pkgbuild_printer() -> PkgbuildPrinter:
"""
fixture for pkgbuild printer
Returns:
PkgbuildPrinter: pkgbuild printer test instance
"""
return PkgbuildPrinter(Changes("sha", "changes", "pkgbuild content"))
@pytest.fixture @pytest.fixture
def configuration_paths_printer() -> ConfigurationPathsPrinter: def configuration_paths_printer() -> ConfigurationPathsPrinter:
""" """

View File

@@ -0,0 +1,32 @@
from ahriman.core.formatters import PkgbuildPrinter
from ahriman.models.changes import Changes
def test_properties(pkgbuild_printer: PkgbuildPrinter) -> None:
"""
must return non-empty properties list
"""
assert pkgbuild_printer.properties()
def test_properties_empty() -> None:
"""
must return empty properties list if pkgbuild is empty
"""
assert not PkgbuildPrinter(Changes()).properties()
assert not PkgbuildPrinter(Changes("sha", "changes")).properties()
def test_title(pkgbuild_printer: PkgbuildPrinter) -> None:
"""
must return non-empty title
"""
assert pkgbuild_printer.title()
def test_title_empty() -> None:
"""
must return empty title if change is empty
"""
assert not PkgbuildPrinter(Changes()).title()
assert not PkgbuildPrinter(Changes("sha")).title()

View File

@@ -1,17 +1,6 @@
from ahriman.models.changes import Changes from ahriman.models.changes import Changes
def test_is_empty() -> None:
"""
must check if changes are empty
"""
assert Changes().is_empty
assert Changes("sha").is_empty
assert not Changes("sha", "change").is_empty
assert not Changes(None, "change").is_empty # well, ok
def test_changes_from_json_view() -> None: def test_changes_from_json_view() -> None:
""" """
must construct same object from json must construct same object from json