From 8f70cb3d8d7f239e8f72122e93d702813361f519 Mon Sep 17 00:00:00 2001 From: Evgenii Alekseev Date: Mon, 10 Aug 2026 14:24:13 +0300 Subject: [PATCH] feat: remove makepkg.conf local configuration, use ahriman own configuration instead We used .makepkg.conf solely for two features - MAKEFLAGS and PACKAGER, which could be actually easily implemented by using environment variables --- .../share/ahriman/settings/ahriman.ini | 8 +++-- .../src/ahriman/application/handlers/setup.py | 29 ++++------------ .../src/ahriman/core/build_tools/task.py | 6 ++++ .../src/ahriman/core/configuration/schema.py | 26 ++++++++++---- .../src/ahriman/core/repository/executor.py | 3 +- .../handlers/test_handler_setup.py | 34 ++++++------------- .../ahriman/core/build_tools/test_task.py | 27 ++++++++++++++- docs/configuration.rst | 4 ++- 8 files changed, 79 insertions(+), 58 deletions(-) diff --git a/ahriman-core/package/share/ahriman/settings/ahriman.ini b/ahriman-core/package/share/ahriman/settings/ahriman.ini index 9bce65fc..67c92b3e 100644 --- a/ahriman-core/package/share/ahriman/settings/ahriman.ini +++ b/ahriman-core/package/share/ahriman/settings/ahriman.ini @@ -40,12 +40,16 @@ devtools_wrapper = ahriman-archbuild ;ignore_packages = ; Include debug packages. ;include_debug_packages = yes +; List of additional flags passed to make via environment variable via makepkg command. +;make_flags = ; List of additional flags passed to makechrootpkg command. ;makechrootpkg_flags = -; Minimal age in seconds since the latest AUR package modification before automatic updates are allowed. -;min_age = 0 ; List of additional flags passed to makepkg command. makepkg_flags = --nocolor --ignorearch +; Minimal age in seconds since the latest AUR package modification before automatic updates are allowed. +;min_age = 0 +; Default packager identifier to be used for package builds +;packager = ; List of paths to be used for implicit dependency scan. Regular expressions are supported. scan_paths = ^usr/lib(?!/cmake).*$ ; List of enabled triggers in the order of calls. diff --git a/ahriman-core/src/ahriman/application/handlers/setup.py b/ahriman-core/src/ahriman/application/handlers/setup.py index 00a84db3..aedbefbf 100644 --- a/ahriman-core/src/ahriman/application/handlers/setup.py +++ b/ahriman-core/src/ahriman/application/handlers/setup.py @@ -18,10 +18,10 @@ # along with this program. If not, see . # import argparse +import multiprocessing import os from pathlib import Path -from pwd import getpwuid from typing import ClassVar from urllib.parse import quote_plus as url_encode @@ -31,7 +31,6 @@ from ahriman.core.configuration import Configuration from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.utils import enum_values from ahriman.models.repository_id import RepositoryId -from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.sign_settings import SignSettings from ahriman.models.user import User @@ -70,7 +69,6 @@ class Setup(Handler): application = Application(repository_id, configuration, report=report) # basically we create configuration here as root, but it is ok, because those files are only used for reading - Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths) repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server Setup.configuration_create_devtools( repository_id, args.from_configuration, args.mirror, args.multilib, repository_server) @@ -132,8 +130,12 @@ class Setup(Handler): """ configuration = Configuration() - section = Configuration.section_name("build", repository_id.name, repository_id.architecture) configuration.set_option("repository", "name", repository_id.name) # backward compatibility for docker + + section = Configuration.section_name("build", repository_id.name, repository_id.architecture) + configuration.set_option(section, "packager", args.packager) + if args.makeflags_jobs: + configuration.set_option(section, "make_flags", f"-j{multiprocessing.cpu_count()}") if args.build_as_user is not None: configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}") @@ -218,23 +220,4 @@ class Setup(Handler): with target.open("w", encoding="utf8") as devtools_configuration: configuration.write(devtools_configuration) - @staticmethod - def configuration_create_makepkg(packager: str, makeflags_jobs: bool, paths: RepositoryPaths) -> None: - """ - create configuration for makepkg - - Args: - packager(str): packager identifier (e.g. name, email) - makeflags_jobs(bool): set MAKEFLAGS variable to number of cores - paths(RepositoryPaths): repository paths instance - """ - - content = f"PACKAGER='{packager}'\n" - if makeflags_jobs: - content += "MAKEFLAGS=\"-j$(nproc)\"\n" - - uid, _ = paths.root_owner - home_dir = Path(getpwuid(uid).pw_dir) - (home_dir / ".makepkg.conf").write_text(content, encoding="utf8") - arguments = [_set_service_setup_parser] diff --git a/ahriman-core/src/ahriman/core/build_tools/task.py b/ahriman-core/src/ahriman/core/build_tools/task.py index e4c7ef4f..3178a556 100644 --- a/ahriman-core/src/ahriman/core/build_tools/task.py +++ b/ahriman-core/src/ahriman/core/build_tools/task.py @@ -39,6 +39,7 @@ class Task(LazyLogging): archbuild_flags(list[str]): command flags for archbuild command build_command(list[str]): build command include_debug_packages(bool): whether to include debug packages or not + make_flags(str): MAKEFLAGS variable for makepkg command makechrootpkg_flags(list[str]): command flags for makechrootpkg command makepkg_flags(list[str]): command flags for makepkg command package(Package): package definitions @@ -65,6 +66,9 @@ class Task(LazyLogging): self.build_command = configuration.getlist("build", "devtools_wrapper") self._legacy_build_command = configuration.getlist("build", "build_command", fallback=[]) self.include_debug_packages = configuration.getboolean("build", "include_debug_packages", fallback=True) + # even though this option is declared as list, there is no need to read it as list, + # because it will be converted back to the string anyway + self.make_flags = configuration.get("build", "make_flags", fallback=None) self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[]) self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[]) @@ -127,6 +131,8 @@ class Task(LazyLogging): for key, value in kwargs.items() if value is not None } + if self.make_flags is not None: + environment["MAKEFLAGS"] = self.make_flags self.logger.info("using environment variables %s", environment) source_files = list(sources_dir.iterdir()) diff --git a/ahriman-core/src/ahriman/core/configuration/schema.py b/ahriman-core/src/ahriman/core/configuration/schema.py index 09e85f85..ca7a5bc2 100644 --- a/ahriman-core/src/ahriman/core/configuration/schema.py +++ b/ahriman-core/src/ahriman/core/configuration/schema.py @@ -221,6 +221,14 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = { "type": "boolean", "coerce": "boolean", }, + "make_flags": { + "type": "list", + "coerce": "list", + "schema": { + "type": "string", + "empty": False, + }, + }, "makechrootpkg_flags": { "type": "list", "coerce": "list", @@ -229,18 +237,22 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = { "empty": False, }, }, + "makepkg_flags": { + "type": "list", + "coerce": "list", + "schema": { + "type": "string", + "empty": False, + }, + }, "min_age": { "type": "integer", "coerce": "integer", "min": 0, }, - "makepkg_flags": { - "type": "list", - "coerce": "list", - "schema": { - "type": "string", - "empty": False, - }, + "packager": { + "type": "string", + "empty": False, }, "scan_paths": { "type": "list", diff --git a/ahriman-core/src/ahriman/core/repository/executor.py b/ahriman-core/src/ahriman/core/repository/executor.py index 5a9d81c7..8b20ea73 100644 --- a/ahriman-core/src/ahriman/core/repository/executor.py +++ b/ahriman-core/src/ahriman/core/repository/executor.py @@ -73,6 +73,7 @@ class Executor(PackageInfo, Cleaner): """ self.reporter.set_building(package.base) + default_packager = self.configuration.get("build", "packager", fallback=None) task = Task(package, self.configuration, self.repository_id, self.paths) patches = self.reporter.package_patches_get(package.base, None) commit_sha = task.init(path, patches, local_version) @@ -86,7 +87,7 @@ class Executor(PackageInfo, Cleaner): shutil.copy(artifact, path) built.append(path / artifact.name) else: - built = task.build(path, PACKAGER=packager) + built = task.build(path, PACKAGER=packager or default_packager) package.with_packages(built) for src in built: diff --git a/ahriman-core/tests/ahriman/application/handlers/test_handler_setup.py b/ahriman-core/tests/ahriman/application/handlers/test_handler_setup.py index f8a78d6d..01bf9d0b 100644 --- a/ahriman-core/tests/ahriman/application/handlers/test_handler_setup.py +++ b/ahriman-core/tests/ahriman/application/handlers/test_handler_setup.py @@ -1,4 +1,5 @@ import argparse +import multiprocessing import pytest from pathlib import Path @@ -54,7 +55,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman") devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools") - makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg") init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init") owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner") @@ -64,7 +64,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository: ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration) devtools_configuration_mock.assert_called_once_with( repository_id, args.from_configuration, args.mirror, args.multilib, f"file://{repository_paths.repository}") - makepkg_configuration_mock.assert_called_once_with(args.packager, args.makeflags_jobs, repository_paths) init_mock.assert_called_once_with() @@ -97,7 +96,6 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration, mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman") - mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg") mocker.patch("ahriman.core.alpm.repo.Repo.init") devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools") @@ -122,14 +120,18 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C Setup.configuration_create_ahriman(args, repository_id, configuration) set_option_mock.assert_has_calls([ MockCall("repository", "name", repository_id.name), + MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), + "packager", args.packager), + MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), + "make_flags", f"-j{multiprocessing.cpu_count()}"), MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), "makechrootpkg_flags", f"-U {args.build_as_user}"), - MockCall(Configuration.section_name( - "alpm", repository_id.name, repository_id.architecture), "mirror", args.mirror), - MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), "target", - " ".join([target.name.lower() for target in args.sign_target])), - MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), "key", - args.sign_key), + MockCall(Configuration.section_name("alpm", repository_id.name, repository_id.architecture), + "mirror", args.mirror), + MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), + "target", " ".join([target.name.lower() for target in args.sign_target])), + MockCall(Configuration.section_name("sign", repository_id.name, repository_id.architecture), + "key", args.sign_key), MockCall("web", "port", str(args.web_port)), MockCall("status", "address", f"http://127.0.0.1:{str(args.web_port)}"), MockCall("web", "unix_socket", str(args.web_unix_socket)), @@ -221,20 +223,6 @@ def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, con write_mock.assert_called_once_with(pytest.helpers.anyvar(int)) -def test_configuration_create_makepkg(args: argparse.Namespace, repository_paths: RepositoryPaths, - passwd: Any, mocker: MockerFixture) -> None: - """ - must create makepkg configuration - """ - args = _default_args(args) - mocker.patch("ahriman.application.handlers.setup.getpwuid", return_value=passwd) - write_text_mock = mocker.patch("pathlib.Path.write_text", autospec=True) - - Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, repository_paths) - write_text_mock.assert_called_once_with( - Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8") - - def test_disallow_multi_architecture_run() -> None: """ must not allow multi architecture run diff --git a/ahriman-core/tests/ahriman/core/build_tools/test_task.py b/ahriman-core/tests/ahriman/core/build_tools/test_task.py index 21222a12..7aa40f14 100644 --- a/ahriman-core/tests/ahriman/core/build_tools/test_task.py +++ b/ahriman-core/tests/ahriman/core/build_tools/test_task.py @@ -93,6 +93,31 @@ def test_build_environment(task_ahriman: Task, mocker: MockerFixture) -> None: ) +def test_build_makeflags(task_ahriman: Task, mocker: MockerFixture) -> None: + """ + must build package with MAKEFLAGS variable if set + """ + local = Path("local") + mocker.patch("pathlib.Path.iterdir", return_value=["file"]) + mocker.patch("ahriman.core.build_tools.task.Task._package_archives", return_value=[task_ahriman.package.base]) + check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output") + task_ahriman.make_flags = "-j1" + + task_ahriman.build(local) + check_output_mock.assert_called_once_with( + "ahriman-archbuild", + "-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, + "--", "-r", str(task_ahriman.paths.chroot), + "--", "-D", str(task_ahriman.paths.archive), + "--", "--skippgpcheck", + exception=pytest.helpers.anyvar(int), + cwd=local, + logger=task_ahriman.logger, + user=task_ahriman.uid, + environment={"MAKEFLAGS": "-j1"}, + ) + + def test_build_dry_run(task_ahriman: Task, mocker: MockerFixture) -> None: """ must run devtools in dry-run mode @@ -102,7 +127,7 @@ def test_build_dry_run(task_ahriman: Task, mocker: MockerFixture) -> None: mocker.patch("ahriman.core.build_tools.task.Task._package_archives", return_value=[task_ahriman.package.base]) check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output") - assert task_ahriman.build(local, dry_run=True) == [task_ahriman.package.base] + task_ahriman.build(local, dry_run=True) check_output_mock.assert_called_once_with( "ahriman-archbuild", "-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, diff --git a/docs/configuration.rst b/docs/configuration.rst index e1df5824..85471236 100644 --- a/docs/configuration.rst +++ b/docs/configuration.rst @@ -134,9 +134,11 @@ Build related configuration. Group name can refer to architecture, e.g. ``build: * ``devtools_wrapper`` - path to devtools wrapper, space separated list of strings, required. * ``ignore_packages`` - list packages to ignore during a regular update (manual update will still work), space separated list of strings, optional. * ``include_debug_packages`` - distribute debug packages, boolean, optional, default ``yes``. -* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional. +* ``make_flags`` - additional flags passed to ``make`` command via environment variable, space separated list of strings, optional. * ``makechrootpkg_flags`` - additional flags passed to ``makechrootpkg`` command, space separated list of strings, optional. +* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional. * ``min_age`` - minimal age in seconds since the latest AUR package modification before automatic updates are allowed, integer, optional, default ``0``. +* ``packager`` - default packager identifier in form ``Name Surname ``, string, optional. * ``scan_paths`` - paths to be used for implicit dependencies scan, space separated list of strings, optional. If any of those paths is matched against the path, it will be added to the allowed list. * ``triggers`` - list of ``ahriman.core.triggers.Trigger`` class implementation (e.g. ``ahriman.core.report.ReportTrigger ahriman.core.upload.UploadTrigger``) which will be loaded and run at the end of processing, space separated list of strings, optional. You can also specify triggers by their paths, e.g. ``/usr/lib/python3.10/site-packages/ahriman/core/report/report.py.ReportTrigger``. Triggers are run in the order of definition. * ``triggers_known`` - optional list of ``ahriman.core.triggers.Trigger`` class implementations which are not run automatically and used only for trigger discovery and configuration validation.