use local devtools configs instead of global ones

This commit is contained in:
2026-08-13 18:15:48 +03:00
parent 695424fa16
commit 885893ab35
11 changed files with 162 additions and 46 deletions
+15 -1
View File
@@ -7,16 +7,19 @@ usage() {
echo "Usage: $cmd [options] -- [archbuild args]" echo "Usage: $cmd [options] -- [archbuild args]"
echo " -r <repository> Repository name" echo " -r <repository> Repository name"
echo " -a <architecture> Repository architecture" echo " -a <architecture> Repository architecture"
echo " -c <directory> Read devtools pacman configurations from this directory"
exit 1 exit 1
} }
repository= repository=
architecture= architecture=
pacman_config_dir=
while getopts ":r:a:" arg; do while getopts ":r:a:c:" arg; do
case "$arg" in case "$arg" in
r) repository="$OPTARG" ;; r) repository="$OPTARG" ;;
a) architecture="$OPTARG" ;; a) architecture="$OPTARG" ;;
c) pacman_config_dir="$OPTARG" ;;
*) usage ;; *) usage ;;
esac esac
done done
@@ -28,6 +31,17 @@ fi
source "/usr/share/devtools/lib/archroot.sh" source "/usr/share/devtools/lib/archroot.sh"
check_root "SOURCE_DATE_EPOCH,SRCDEST,SRCPKGDEST,PKGDEST,LOGDEST,NPROC,MAKEFLAGS,PACKAGER,GNUPGHOME" "${BASH_SOURCE[0]}" "$@" check_root "SOURCE_DATE_EPOCH,SRCDEST,SRCPKGDEST,PKGDEST,LOGDEST,NPROC,MAKEFLAGS,PACKAGER,GNUPGHOME" "${BASH_SOURCE[0]}" "$@"
# because devtools doesn't allow to read configuration from custom path
# here is a workaround, which uses unshare to bind-mount directory with configuration files
# for specific process
if [[ -n $pacman_config_dir && -z ${AHRIMAN_ARCHBUILD_MOUNTED:-} ]]; then
export AHRIMAN_ARCHBUILD_MOUNTED=1
exec unshare --mount --propagation private bash -e -c '
mount --bind "$0" /usr/share/devtools/pacman.conf.d
exec "$@"
' "$(readlink -f "$pacman_config_dir")" "${BASH_SOURCE[0]}" "$@"
fi
exec bash -c ' exec bash -c '
source "$1" "${@:2}" source "$1" "${@:2}"
' "${repository}-${architecture}-build" "archbuild" "${@:$OPTIND}" ' "${repository}-${architecture}-build" "archbuild" "${@:$OPTIND}"
@@ -1,6 +1,6 @@
[settings] [settings]
; Relative path to directory with configuration files overrides. Overrides will be applied in alphabetic order. ; Relative path to directory with configuration files overrides. Overrides will be applied in alphabetic order.
include = ahriman.ini.d $HOME/.config/ahriman.ini.d include = ahriman.ini.d ${repository:root}/.config/ahriman/ahriman.ini.d
; Relative path to configuration used by logging package. ; Relative path to configuration used by logging package.
logging = ahriman.ini.d/logging.ini logging = ahriman.ini.d/logging.ini
; Perform database migrations on the application start. Do not touch this option unless you know what you are doing. ; Perform database migrations on the application start. Do not touch this option unless you know what you are doing.
@@ -34,6 +34,8 @@ retry_backoff = 1.0
[build] [build]
; List of additional flags passed to archbuild command. ; List of additional flags passed to archbuild command.
;archbuild_flags = ;archbuild_flags =
; Path to local directory with devtools configuration files, which will be bind-mounted for devtools.
devtools_configs = ${repository:root}/.config/ahriman/pacman.conf.d
; Path to build command. ; Path to build command.
devtools_wrapper = ahriman-archbuild devtools_wrapper = ahriman-archbuild
; List of packages to be ignored during automatic updates. ; List of packages to be ignored during automatic updates.
@@ -28,7 +28,7 @@ from urllib.parse import quote_plus as url_encode
from ahriman.application.application import Application from ahriman.application.application import Application
from ahriman.application.handlers.handler import Handler, SubParserAction from ahriman.application.handlers.handler import Handler, SubParserAction
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.exceptions import InitializeError, MissingArchitectureError
from ahriman.core.utils import enum_values from ahriman.core.utils import enum_values
from ahriman.models.repository_id import RepositoryId from ahriman.models.repository_id import RepositoryId
from ahriman.models.sign_settings import SignSettings from ahriman.models.sign_settings import SignSettings
@@ -63,18 +63,20 @@ class Setup(Handler):
if args.architecture is None or args.repository is None: if args.architecture is None or args.repository is None:
raise MissingArchitectureError(args.command) raise MissingArchitectureError(args.command)
Setup.configuration_create_ahriman(args, repository_id, configuration) target_directory = Setup.configuration_create_directory(configuration)
Setup.configuration_create_ahriman(args, repository_id, configuration, target_directory)
configuration.reload() configuration.reload()
application = Application(repository_id, configuration, report=report) application = Application(repository_id, configuration, report=report)
paths = application.repository.paths
# basically we create configuration here as root, but it is ok, because those files are only used for reading repository_server = f"file://{paths.repository}" if args.server is None else args.server
repository_server = f"file://{application.repository.paths.repository}" if args.server is None else args.server target_directory = paths.ensure_exists(configuration.getpath("build", "devtools_configs"))
Setup.configuration_create_devtools( Setup.configuration_create_devtools(repository_id, args.from_configuration, target_directory, args.mirror,
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server) args.multilib, repository_server)
# finish initialization # finish initialization
with application.repository.paths.preserve_owner(): with paths.preserve_owner():
application.repository.repo.init() application.repository.repo.init()
# lazy database sync # lazy database sync
application.repository.pacman.handle # pylint: disable=pointless-statement application.repository.pacman.handle # pylint: disable=pointless-statement
@@ -119,7 +121,7 @@ class Setup(Handler):
@staticmethod @staticmethod
def configuration_create_ahriman(args: argparse.Namespace, repository_id: RepositoryId, def configuration_create_ahriman(args: argparse.Namespace, repository_id: RepositoryId,
root: Configuration) -> None: root: Configuration, target_directory: Path) -> None:
""" """
create service specific configuration create service specific configuration
@@ -127,6 +129,7 @@ class Setup(Handler):
args(argparse.Namespace): command line args args(argparse.Namespace): command line args
repository_id(RepositoryId): repository unique identifier repository_id(RepositoryId): repository unique identifier
root(Configuration): root configuration instance root(Configuration): root configuration instance
target_directory(Path): path to directory where configuration files will be written
""" """
configuration = Configuration() configuration = Configuration()
@@ -164,15 +167,13 @@ class Setup(Handler):
if args.generate_salt: if args.generate_salt:
configuration.set_option("auth", "salt", User.generate_password(20)) configuration.set_option("auth", "salt", User.generate_password(20))
include_path = next(path for path in root.getpathlist("settings", "include") if os.access(path, os.W_OK)) target = target_directory / f"00-setup-overrides-{repository_id.id}.ini"
(include_path / "00-setup-overrides.ini").unlink(missing_ok=True) # remove old-style configuration
target = include_path / f"00-setup-overrides-{repository_id.id}.ini"
with target.open("w", encoding="utf8") as ahriman_configuration: with target.open("w", encoding="utf8") as ahriman_configuration:
configuration.write(ahriman_configuration) configuration.write(ahriman_configuration)
@staticmethod @staticmethod
def configuration_create_devtools(repository_id: RepositoryId, source: Path, mirror: str | None, def configuration_create_devtools(repository_id: RepositoryId, source: Path, target_directory: Path,
multilib: bool, repository_server: str) -> None: mirror: str | None, multilib: bool, repository_server: str) -> None:
""" """
create configuration for devtools based on ``source`` configuration create configuration for devtools based on ``source`` configuration
@@ -182,6 +183,7 @@ class Setup(Handler):
Args: Args:
repository_id(RepositoryId): repository unique identifier repository_id(RepositoryId): repository unique identifier
source(Path): path to source configuration file source(Path): path to source configuration file
target_directory(Path): path to directory where configuration files will be written
mirror(str | None): link to package server mirror mirror(str | None): link to package server mirror
multilib(bool): add or do not multilib repository to the configuration multilib(bool): add or do not multilib repository to the configuration
repository_server(str): url of the repository repository_server(str): url of the repository
@@ -216,8 +218,32 @@ class Setup(Handler):
configuration.set_option(repository_id.name, "SigLevel", "Never") # we don't care configuration.set_option(repository_id.name, "SigLevel", "Never") # we don't care
configuration.set_option(repository_id.name, "Server", repository_server) configuration.set_option(repository_id.name, "Server", repository_server)
target = source.parent / f"{repository_id.name}-{repository_id.architecture}.conf" target = target_directory / f"{repository_id.name}-{repository_id.architecture}.conf"
with target.open("w", encoding="utf8") as devtools_configuration: with target.open("w", encoding="utf8") as devtools_configuration:
configuration.write(devtools_configuration) configuration.write(devtools_configuration)
@staticmethod
def configuration_create_directory(root: Configuration) -> Path:
"""
create directory for includes
Args:
root(Configuration): root configuration instance
Returns:
Path: path to first writable directory
Raises:
InitializeError: if no writable directories have been found
"""
for include_path in root.getpathlist("settings", "include"):
try:
directory = root.repository_paths.ensure_exists(include_path)
if os.access(directory, os.W_OK | os.X_OK):
return directory
except OSError:
continue
raise InitializeError("No writable include directory found")
arguments = [_set_service_setup_parser] arguments = [_set_service_setup_parser]
@@ -38,6 +38,7 @@ class Task(LazyLogging):
Attributes: Attributes:
archbuild_flags(list[str]): command flags for archbuild command archbuild_flags(list[str]): command flags for archbuild command
build_command(list[str]): build command build_command(list[str]): build command
devtools_configs(Path): path to local directory with devtools configuration files
include_debug_packages(bool): whether to include debug packages or not include_debug_packages(bool): whether to include debug packages or not
make_flags(str): MAKEFLAGS variable for makepkg command make_flags(str): MAKEFLAGS variable for makepkg command
makechrootpkg_flags(list[str]): command flags for makechrootpkg command makechrootpkg_flags(list[str]): command flags for makechrootpkg command
@@ -64,6 +65,7 @@ class Task(LazyLogging):
self.archbuild_flags = configuration.getlist("build", "archbuild_flags", fallback=[]) self.archbuild_flags = configuration.getlist("build", "archbuild_flags", fallback=[])
self.build_command = configuration.getlist("build", "devtools_wrapper") self.build_command = configuration.getlist("build", "devtools_wrapper")
self.devtools_configs = configuration.getpath("build", "devtools_configs")
self._legacy_build_command = configuration.getlist("build", "build_command", fallback=[]) self._legacy_build_command = configuration.getlist("build", "build_command", fallback=[])
self.include_debug_packages = configuration.getboolean("build", "include_debug_packages", fallback=True) 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, # even though this option is declared as list, there is no need to read it as list,
@@ -116,7 +118,12 @@ class Task(LazyLogging):
""" """
command = self._legacy_build_command[:] command = self._legacy_build_command[:]
if not command: if not command:
command = self.build_command + ["-r", self.repository_id.name, "-a", self.repository_id.architecture, "--"] command = self.build_command + [
"-r", self.repository_id.name,
"-a", self.repository_id.architecture,
"-c", str(self.devtools_configs),
"--",
]
command.extend(["-r", str(self.paths.chroot)] + self.archbuild_flags) # archbuild flags command.extend(["-r", str(self.paths.chroot)] + self.archbuild_flags) # archbuild flags
command.extend(["--", "-D", str(self.paths.archive)] + self.makechrootpkg_flags) # makechrootpkg flags command.extend(["--", "-D", str(self.paths.archive)] + self.makechrootpkg_flags) # makechrootpkg flags
@@ -200,6 +200,13 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
"empty": False, "empty": False,
}, },
}, },
"devtools_configs": {
"type": "path",
"coerce": "absolute_path",
"required": True,
"path_exists": True,
"path_type": "dir",
},
"devtools_wrapper": { "devtools_wrapper": {
"type": "list", "type": "list",
"coerce": "list", "coerce": "list",
@@ -103,7 +103,7 @@ class RepositoryPaths(LazyLogging):
Returns: Returns:
Path: path to directory in which build process is run Path: path to directory in which build process is run
""" """
uid, _ = owner(self.root) uid, _ = self.root_owner
return self.chroot / f"{self.repository_id.name}-{self.repository_id.architecture}" / getpwuid(uid).pw_name return self.chroot / f"{self.repository_id.name}-{self.repository_id.architecture}" / getpwuid(uid).pw_name
@property @property
@@ -127,6 +127,16 @@ class RepositoryPaths(LazyLogging):
# for the chroot directory devtools will create own tree, and we don't have to specify architecture here # for the chroot directory devtools will create own tree, and we don't have to specify architecture here
return self.root / "chroot" / self.repository_id.name return self.root / "chroot" / self.repository_id.name
@property
def configs(self) -> Path:
"""
get directory for local configuration files
Returns:
Path: full path to local configuration directory
"""
return self.root / ".config" / "ahriman"
@property @property
def packages(self) -> Path: def packages(self) -> Path:
""" """
@@ -323,6 +333,7 @@ class RepositoryPaths(LazyLogging):
self.archive, self.archive,
self.cache, self.cache,
self.chroot, self.chroot,
self.configs,
self.packages, self.packages,
self.pacman, self.pacman,
self.repository, self.repository,
@@ -1,5 +1,6 @@
import argparse import argparse
import multiprocessing import multiprocessing
import os
import pytest import pytest
from pathlib import Path from pathlib import Path
@@ -11,9 +12,8 @@ from urllib.parse import quote_plus as url_encode
from ahriman.application.handlers.setup import Setup from ahriman.application.handlers.setup import Setup
from ahriman.core.configuration import Configuration from ahriman.core.configuration import Configuration
from ahriman.core.database import SQLite from ahriman.core.database import SQLite
from ahriman.core.exceptions import MissingArchitectureError from ahriman.core.exceptions import InitializeError, MissingArchitectureError
from ahriman.core.repository import Repository from ahriman.core.repository import Repository
from ahriman.models.repository_id import RepositoryId
from ahriman.models.repository_paths import RepositoryPaths from ahriman.models.repository_paths import RepositoryPaths
from ahriman.models.sign_settings import SignSettings from ahriman.models.sign_settings import SignSettings
@@ -51,8 +51,11 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
must run command must run command
""" """
args = _default_args(args) args = _default_args(args)
local = Path("local")
mocker.patch("ahriman.core.database.SQLite.load", return_value=database) mocker.patch("ahriman.core.database.SQLite.load", return_value=database)
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository) mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
mkdir_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_directory",
return_value=local)
ahriman_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_ahriman") 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") devtools_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_devtools")
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init") init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
@@ -61,9 +64,16 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False) Setup.run(args, repository_id, configuration, report=False)
owner_guard_mock.assert_called_once_with() owner_guard_mock.assert_called_once_with()
ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration) mkdir_mock.assert_called_once_with(configuration)
ahriman_configuration_mock.assert_called_once_with(args, repository_id, configuration, local)
devtools_configuration_mock.assert_called_once_with( devtools_configuration_mock.assert_called_once_with(
repository_id, args.from_configuration, args.mirror, args.multilib, f"file://{repository_paths.repository}") repository_id,
args.from_configuration,
configuration.getpath("build", "devtools_configs"),
args.mirror,
args.multilib,
f"file://{repository_paths.repository}",
)
init_mock.assert_called_once_with() init_mock.assert_called_once_with()
@@ -102,11 +112,17 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration,
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.run(args, repository_id, configuration, report=False) Setup.run(args, repository_id, configuration, report=False)
devtools_configuration_mock.assert_called_once_with( devtools_configuration_mock.assert_called_once_with(
repository_id, args.from_configuration, args.mirror, args.multilib, "server") repository_id,
args.from_configuration,
configuration.getpath("build", "devtools_configs"),
args.mirror,
args.multilib,
"server",
)
def test_configuration_create_ahriman(args: argparse.Namespace, configuration: Configuration, def test_configuration_create_ahriman(args: argparse.Namespace, configuration: Configuration, tmp_path: Path,
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None: mocker: MockerFixture) -> None:
""" """
must create configuration for the service must create configuration for the service
""" """
@@ -114,10 +130,9 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C
mocker.patch("pathlib.Path.open") mocker.patch("pathlib.Path.open")
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option") set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write") write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
remove_mock = mocker.patch("pathlib.Path.unlink", autospec=True)
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.configuration_create_ahriman(args, repository_id, configuration) Setup.configuration_create_ahriman(args, repository_id, configuration, tmp_path)
set_option_mock.assert_has_calls([ set_option_mock.assert_has_calls([
MockCall("repository", "name", repository_id.name), MockCall("repository", "name", repository_id.name),
MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture),
@@ -139,15 +154,10 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C
MockCall("auth", "salt", pytest.helpers.anyvar(str, strict=True)), MockCall("auth", "salt", pytest.helpers.anyvar(str, strict=True)),
]) ])
write_mock.assert_called_once_with(pytest.helpers.anyvar(int)) write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
remove_mock.assert_called_once_with(
next(
path for path in configuration.getpathlist("settings", "include")) /
"00-setup-overrides.ini",
missing_ok=True)
def test_configuration_create_ahriman_no_multilib(args: argparse.Namespace, configuration: Configuration, def test_configuration_create_ahriman_no_multilib(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None: tmp_path: Path, mocker: MockerFixture) -> None:
""" """
must create configuration for the service without multilib repository must create configuration for the service without multilib repository
""" """
@@ -158,14 +168,14 @@ def test_configuration_create_ahriman_no_multilib(args: argparse.Namespace, conf
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option") set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.configuration_create_ahriman(args, repository_id, configuration) Setup.configuration_create_ahriman(args, repository_id, configuration, tmp_path)
set_option_mock.assert_has_calls([ set_option_mock.assert_has_calls([
MockCall(Configuration.section_name("alpm", repository_id.name, repository_id.architecture), "mirror", MockCall(Configuration.section_name("alpm", repository_id.name, repository_id.architecture), "mirror",
args.mirror), args.mirror),
]) # non-strict check called intentionally ]) # non-strict check called intentionally
def test_configuration_create_devtools(args: argparse.Namespace, configuration: Configuration, def test_configuration_create_devtools(args: argparse.Namespace, configuration: Configuration, tmp_path: Path,
mocker: MockerFixture) -> None: mocker: MockerFixture) -> None:
""" """
must create configuration for the devtools must create configuration for the devtools
@@ -177,12 +187,12 @@ def test_configuration_create_devtools(args: argparse.Namespace, configuration:
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write") write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.configuration_create_devtools(repository_id, args.from_configuration, None, args.multilib, "server") Setup.configuration_create_devtools(repository_id, args.from_configuration, tmp_path, None, args.multilib, "server")
add_section_mock.assert_has_calls([MockCall("multilib"), MockCall(repository_id.name)]) add_section_mock.assert_has_calls([MockCall("multilib"), MockCall(repository_id.name)])
write_mock.assert_called_once_with(pytest.helpers.anyvar(int)) write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
def test_configuration_create_devtools_mirror(args: argparse.Namespace, configuration: Configuration, def test_configuration_create_devtools_mirror(args: argparse.Namespace, configuration: Configuration, tmp_path: Path,
mocker: MockerFixture) -> None: mocker: MockerFixture) -> None:
""" """
must create configuration for the devtools with mirror set explicitly must create configuration for the devtools with mirror set explicitly
@@ -202,14 +212,21 @@ def test_configuration_create_devtools_mirror(args: argparse.Namespace, configur
set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option") set_option_mock = mocker.patch("ahriman.core.configuration.Configuration.set_option")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.configuration_create_devtools(repository_id, args.from_configuration, args.mirror, args.multilib, "server") Setup.configuration_create_devtools(
repository_id,
args.from_configuration,
tmp_path,
args.mirror,
args.multilib,
"server",
)
get_mock.assert_has_calls([MockCall("core", "Include", fallback=None), MockCall("extra", "Include", fallback=None)]) get_mock.assert_has_calls([MockCall("core", "Include", fallback=None), MockCall("extra", "Include", fallback=None)])
remove_option_mock.assert_called_once_with("core", "Include") remove_option_mock.assert_called_once_with("core", "Include")
set_option_mock.assert_has_calls([MockCall("core", "Server", args.mirror)]) # non-strict check called intentionally set_option_mock.assert_has_calls([MockCall("core", "Server", args.mirror)]) # non-strict check called intentionally
def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, configuration: Configuration, def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, configuration: Configuration,
mocker: MockerFixture) -> None: tmp_path: Path, mocker: MockerFixture) -> None:
""" """
must create configuration for the devtools without multilib must create configuration for the devtools without multilib
""" """
@@ -219,10 +236,33 @@ def test_configuration_create_devtools_no_multilib(args: argparse.Namespace, con
write_mock = mocker.patch("ahriman.core.configuration.Configuration.write") write_mock = mocker.patch("ahriman.core.configuration.Configuration.write")
_, repository_id = configuration.check_loaded() _, repository_id = configuration.check_loaded()
Setup.configuration_create_devtools(repository_id, args.from_configuration, args.mirror, False, "server") Setup.configuration_create_devtools(repository_id, args.from_configuration, tmp_path, args.mirror, False, "server")
write_mock.assert_called_once_with(pytest.helpers.anyvar(int)) write_mock.assert_called_once_with(pytest.helpers.anyvar(int))
def test_configuration_create_directory(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must create writable directory for includes
"""
configuration.set_option("settings", "include", f"/path1 /path2 /path3")
mkdir_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.ensure_exists",
side_effect=[OSError, "/path2", "/path3"])
access_mock = mocker.patch("os.access", side_effect=[False, True])
assert Setup.configuration_create_directory(configuration) == "/path3"
mkdir_mock.assert_has_calls([MockCall(Path("/path1")), MockCall(Path("/path2")), MockCall(Path("/path3"))])
access_mock.assert_has_calls([MockCall("/path2", os.W_OK | os.X_OK), MockCall("/path3", os.W_OK | os.X_OK)])
def test_configuration_create_directory_no_writable(configuration: Configuration, mocker: MockerFixture) -> None:
"""
must raise InitializeError if no writable directories found
"""
mocker.patch("ahriman.models.repository_paths.RepositoryPaths.ensure_exists", side_effect=OSError)
with pytest.raises(InitializeError):
Setup.configuration_create_directory(configuration)
def test_disallow_multi_architecture_run() -> None: def test_disallow_multi_architecture_run() -> None:
""" """
must not allow multi architecture run must not allow multi architecture run
@@ -63,7 +63,7 @@ def test_run_default(args: argparse.Namespace, configuration: Configuration) ->
default = Configuration.from_path(Configuration.SYSTEM_CONFIGURATION_PATH, repository_id) default = Configuration.from_path(Configuration.SYSTEM_CONFIGURATION_PATH, repository_id)
# copy autogenerated values # copy autogenerated values
for section, key in (("repository", "root"),): for section, key in (("repository", "root"), ("build", "devtools_configs")):
value = configuration.get(section, key) value = configuration.get(section, key)
default.set_option(section, key, value) default.set_option(section, key, value)
@@ -54,7 +54,9 @@ def test_build(task_ahriman: Task, mocker: MockerFixture) -> None:
assert task_ahriman.build(local) == [task_ahriman.package.base] assert task_ahriman.build(local) == [task_ahriman.package.base]
check_output_mock.assert_called_once_with( check_output_mock.assert_called_once_with(
"ahriman-archbuild", "ahriman-archbuild",
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, "-r", task_ahriman.repository_id.name,
"-a", task_ahriman.repository_id.architecture,
"-c", str(task_ahriman.devtools_configs),
"--", "-r", str(task_ahriman.paths.chroot), "--", "-r", str(task_ahriman.paths.chroot),
"--", "-D", str(task_ahriman.paths.archive), "--", "-D", str(task_ahriman.paths.archive),
"--", "--skippgpcheck", "--", "--skippgpcheck",
@@ -81,7 +83,9 @@ def test_build_environment(task_ahriman: Task, mocker: MockerFixture) -> None:
task_ahriman.build(local, **environment, empty=None) task_ahriman.build(local, **environment, empty=None)
check_output_mock.assert_called_once_with( check_output_mock.assert_called_once_with(
"ahriman-archbuild", "ahriman-archbuild",
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, "-r", task_ahriman.repository_id.name,
"-a", task_ahriman.repository_id.architecture,
"-c", str(task_ahriman.devtools_configs),
"--", "-r", str(task_ahriman.paths.chroot), "--", "-r", str(task_ahriman.paths.chroot),
"--", "-D", str(task_ahriman.paths.archive), "--", "-D", str(task_ahriman.paths.archive),
"--", "--skippgpcheck", "--", "--skippgpcheck",
@@ -106,7 +110,9 @@ def test_build_makeflags(task_ahriman: Task, mocker: MockerFixture) -> None:
task_ahriman.build(local) task_ahriman.build(local)
check_output_mock.assert_called_once_with( check_output_mock.assert_called_once_with(
"ahriman-archbuild", "ahriman-archbuild",
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, "-r", task_ahriman.repository_id.name,
"-a", task_ahriman.repository_id.architecture,
"-c", str(task_ahriman.devtools_configs),
"--", "-r", str(task_ahriman.paths.chroot), "--", "-r", str(task_ahriman.paths.chroot),
"--", "-D", str(task_ahriman.paths.archive), "--", "-D", str(task_ahriman.paths.archive),
"--", "--skippgpcheck", "--", "--skippgpcheck",
@@ -130,7 +136,9 @@ def test_build_dry_run(task_ahriman: Task, mocker: MockerFixture) -> None:
task_ahriman.build(local, dry_run=True) task_ahriman.build(local, dry_run=True)
check_output_mock.assert_called_once_with( check_output_mock.assert_called_once_with(
"ahriman-archbuild", "ahriman-archbuild",
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture, "-r", task_ahriman.repository_id.name,
"-a", task_ahriman.repository_id.architecture,
"-c", str(task_ahriman.devtools_configs),
"--", "-r", str(task_ahriman.paths.chroot), "--", "-r", str(task_ahriman.paths.chroot),
"--", "-D", str(task_ahriman.paths.archive), "--", "-D", str(task_ahriman.paths.archive),
"--", "--skippgpcheck", "--", "--skippgpcheck",
+1 -1
View File
@@ -48,7 +48,7 @@ if [ -n "$AHRIMAN_UNIX_SOCKET" ]; then
fi fi
[ -n "$AHRIMAN_PRESETUP_COMMAND" ] && eval "$AHRIMAN_PRESETUP_COMMAND" [ -n "$AHRIMAN_PRESETUP_COMMAND" ] && eval "$AHRIMAN_PRESETUP_COMMAND"
ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" service-setup "${AHRIMAN_SETUP_ARGS[@]}" sudo -E -u "$AHRIMAN_USER" -- ahriman "${AHRIMAN_DEFAULT_ARGS[@]}" service-setup "${AHRIMAN_SETUP_ARGS[@]}"
[ -n "$AHRIMAN_POSTSETUP_COMMAND" ] && eval "$AHRIMAN_POSTSETUP_COMMAND" [ -n "$AHRIMAN_POSTSETUP_COMMAND" ] && eval "$AHRIMAN_POSTSETUP_COMMAND"
# validate configuration if set # validate configuration if set
+1
View File
@@ -23,6 +23,7 @@ allow_read_only = no
[build] [build]
archbuild_flags = archbuild_flags =
devtools_configs = .
devtools_wrapper = ahriman-archbuild devtools_wrapper = ahriman-archbuild
ignore_packages = ignore_packages =
makechrootpkg_flags = makechrootpkg_flags =