mirror of
https://github.com/arcan1s/ahriman.git
synced 2026-08-12 03:39:54 +00:00
feat: get rid of sudoers modification during setup command
This commit introduces small shell wrapper, which calls archbuild mimicing symlinked command. It allows to distribute static sudoers file. Additionally build_command option has been renamed to devtools_wrapper in order to allow to keep backward compatibility
This commit is contained in:
@@ -31,7 +31,7 @@ For installation details kindly refer to the [documentation](https://ahriman.rea
|
|||||||
|
|
||||||
Every available option is described in the [documentation](https://ahriman.readthedocs.io/en/stable/configuration.html).
|
Every available option is described in the [documentation](https://ahriman.readthedocs.io/en/stable/configuration.html).
|
||||||
|
|
||||||
The application provides reasonable defaults which allow to use it out-of-box; however additional steps (like configuring build toolchain and sudoers) are recommended and can be easily achieved by following install instructions.
|
The application provides reasonable defaults which allow to use it out-of-box; however additional steps (like configuring build toolchain) are recommended and can be easily achieved by following install instructions.
|
||||||
|
|
||||||
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq/index.html)
|
## [FAQ](https://ahriman.readthedocs.io/en/stable/faq/index.html)
|
||||||
|
|
||||||
|
|||||||
Executable
+33
@@ -0,0 +1,33 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
local cmd="${0##*/}"
|
||||||
|
echo "Usage: $cmd [options] -- [archbuild args]"
|
||||||
|
echo " -r <repository> Repository name"
|
||||||
|
echo " -a <architecture> Repository architecture"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
repository=
|
||||||
|
architecture=
|
||||||
|
|
||||||
|
while getopts ":r:a:" arg; do
|
||||||
|
case "$arg" in
|
||||||
|
r) repository="$OPTARG" ;;
|
||||||
|
a) architecture="$OPTARG" ;;
|
||||||
|
*) usage ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
if [[ -z $repository || -z $architecture ]]; then
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
source "/usr/share/devtools/lib/archroot.sh"
|
||||||
|
check_root "SOURCE_DATE_EPOCH,SRCDEST,SRCPKGDEST,PKGDEST,LOGDEST,NPROC,MAKEFLAGS,PACKAGER,GNUPGHOME" "${BASH_SOURCE[0]}" "$@"
|
||||||
|
|
||||||
|
exec bash -c '
|
||||||
|
source "$1" "${@:2}"
|
||||||
|
' "${repository}-${architecture}-build" "archbuild" "${@:$OPTIND}"
|
||||||
@@ -35,7 +35,7 @@ retry_backoff = 1.0
|
|||||||
; List of additional flags passed to archbuild command.
|
; List of additional flags passed to archbuild command.
|
||||||
;archbuild_flags =
|
;archbuild_flags =
|
||||||
; Path to build command.
|
; Path to build command.
|
||||||
;build_command =
|
devtools_wrapper = ahriman-archbuild
|
||||||
; List of packages to be ignored during automatic updates.
|
; List of packages to be ignored during automatic updates.
|
||||||
;ignore_packages =
|
;ignore_packages =
|
||||||
; Include debug packages.
|
; Include debug packages.
|
||||||
|
|||||||
@@ -57,6 +57,7 @@ packages = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel.shared-data]
|
[tool.hatch.build.targets.wheel.shared-data]
|
||||||
|
"package/bin" = "bin"
|
||||||
"package/lib" = "lib"
|
"package/lib" = "lib"
|
||||||
"package/share" = "share"
|
"package/share" = "share"
|
||||||
|
|
||||||
|
|||||||
@@ -40,16 +40,12 @@ class Setup(Handler):
|
|||||||
setup handler
|
setup handler
|
||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
ARCHBUILD_COMMAND_PATH(Path): (class attribute) default devtools command
|
|
||||||
MIRRORLIST_PATH(Path): (class attribute) path to pacman default mirrorlist (used by multilib repository)
|
MIRRORLIST_PATH(Path): (class attribute) path to pacman default mirrorlist (used by multilib repository)
|
||||||
SUDOERS_DIR_PATH(Path): (class attribute) path to sudoers.d includes directory
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
ALLOW_MULTI_ARCHITECTURE_RUN = False # conflicting io
|
||||||
|
|
||||||
ARCHBUILD_COMMAND_PATH: ClassVar[Path] = Path("/") / "usr" / "bin" / "archbuild"
|
|
||||||
MIRRORLIST_PATH: ClassVar[Path] = Path("/") / "etc" / "pacman.d" / "mirrorlist"
|
MIRRORLIST_PATH: ClassVar[Path] = Path("/") / "etc" / "pacman.d" / "mirrorlist"
|
||||||
SUDOERS_DIR_PATH: ClassVar[Path] = Path("/") / "etc" / "sudoers.d"
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
def run(cls, args: argparse.Namespace, repository_id: RepositoryId, configuration: Configuration, *,
|
||||||
@@ -74,11 +70,9 @@ class Setup(Handler):
|
|||||||
|
|
||||||
# basically we create configuration here as root, but it is ok, because those files are only used for reading
|
# 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)
|
Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
|
||||||
Setup.executable_create(application.repository.paths, repository_id)
|
|
||||||
repository_server = f"file://{application.repository.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
|
||||||
Setup.configuration_create_devtools(
|
Setup.configuration_create_devtools(
|
||||||
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
|
repository_id, args.from_configuration, args.mirror, args.multilib, repository_server)
|
||||||
Setup.configuration_create_sudo(application.repository.paths, repository_id)
|
|
||||||
|
|
||||||
# finish initialization
|
# finish initialization
|
||||||
with application.repository.paths.preserve_owner():
|
with application.repository.paths.preserve_owner():
|
||||||
@@ -124,20 +118,6 @@ class Setup(Handler):
|
|||||||
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
|
parser.set_defaults(lock=None, quiet=True, report=False, unsafe=True)
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def build_command(root: Path, repository_id: RepositoryId) -> Path:
|
|
||||||
"""
|
|
||||||
generate build command name
|
|
||||||
|
|
||||||
Args:
|
|
||||||
root(Path): root directory for the build command (must be root of the repository)
|
|
||||||
repository_id(RepositoryId): repository unique identifier
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Path: valid devtools command name
|
|
||||||
"""
|
|
||||||
return root / f"{repository_id.name}-{repository_id.architecture}-build"
|
|
||||||
|
|
||||||
@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) -> None:
|
||||||
@@ -152,8 +132,6 @@ class Setup(Handler):
|
|||||||
configuration = Configuration()
|
configuration = Configuration()
|
||||||
|
|
||||||
section = Configuration.section_name("build", repository_id.name, repository_id.architecture)
|
section = Configuration.section_name("build", repository_id.name, repository_id.architecture)
|
||||||
build_command = Setup.build_command(root.repository_paths.root, repository_id)
|
|
||||||
configuration.set_option(section, "build_command", str(build_command))
|
|
||||||
configuration.set_option("repository", "name", repository_id.name) # backward compatibility for docker
|
configuration.set_option("repository", "name", repository_id.name) # backward compatibility for docker
|
||||||
if args.build_as_user is not None:
|
if args.build_as_user is not None:
|
||||||
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
configuration.set_option(section, "makechrootpkg_flags", f"-U {args.build_as_user}")
|
||||||
@@ -257,31 +235,4 @@ class Setup(Handler):
|
|||||||
home_dir = Path(getpwuid(uid).pw_dir)
|
home_dir = Path(getpwuid(uid).pw_dir)
|
||||||
(home_dir / ".makepkg.conf").write_text(content, encoding="utf8")
|
(home_dir / ".makepkg.conf").write_text(content, encoding="utf8")
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def configuration_create_sudo(paths: RepositoryPaths, repository_id: RepositoryId) -> None:
|
|
||||||
"""
|
|
||||||
create configuration to run build command with sudo without password
|
|
||||||
|
|
||||||
Args:
|
|
||||||
paths(RepositoryPaths): repository paths instance
|
|
||||||
repository_id(RepositoryId): repository unique identifier
|
|
||||||
"""
|
|
||||||
command = Setup.build_command(paths.root, repository_id)
|
|
||||||
sudoers_file = Setup.build_command(Setup.SUDOERS_DIR_PATH, repository_id)
|
|
||||||
sudoers_file.write_text(f"ahriman ALL=(ALL) NOPASSWD:SETENV: {command} *\n", encoding="utf8")
|
|
||||||
sudoers_file.chmod(0o400) # security!
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def executable_create(paths: RepositoryPaths, repository_id: RepositoryId) -> None:
|
|
||||||
"""
|
|
||||||
create executable for the service
|
|
||||||
|
|
||||||
Args:
|
|
||||||
paths(RepositoryPaths): repository paths instance
|
|
||||||
repository_id(RepositoryId): repository unique identifier
|
|
||||||
"""
|
|
||||||
command = Setup.build_command(paths.root, repository_id)
|
|
||||||
command.unlink(missing_ok=True)
|
|
||||||
command.symlink_to(Setup.ARCHBUILD_COMMAND_PATH)
|
|
||||||
|
|
||||||
arguments = [_set_service_setup_parser]
|
arguments = [_set_service_setup_parser]
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ class PackageVersion(LazyLogging):
|
|||||||
|
|
||||||
_, repository_id = configuration.check_loaded()
|
_, repository_id = configuration.check_loaded()
|
||||||
paths = configuration.repository_paths
|
paths = configuration.repository_paths
|
||||||
task = Task(self.package, configuration, repository_id.architecture, paths)
|
task = Task(self.package, configuration, repository_id, paths)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# create fresh chroot environment, fetch sources and - automagically - update PKGBUILD
|
# create fresh chroot environment, fetch sources and - automagically - update PKGBUILD
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ from ahriman.core.log import LazyLogging
|
|||||||
from ahriman.core.utils import check_output, package_like
|
from ahriman.core.utils import check_output, package_like
|
||||||
from ahriman.models.package import Package
|
from ahriman.models.package import Package
|
||||||
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
from ahriman.models.pkgbuild_patch import PkgbuildPatch
|
||||||
|
from ahriman.models.repository_id import RepositoryId
|
||||||
from ahriman.models.repository_paths import RepositoryPaths
|
from ahriman.models.repository_paths import RepositoryPaths
|
||||||
|
|
||||||
|
|
||||||
@@ -36,32 +37,33 @@ class Task(LazyLogging):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
archbuild_flags(list[str]): command flags for archbuild command
|
archbuild_flags(list[str]): command flags for archbuild command
|
||||||
architecture(str): repository architecture
|
build_command(list[str]): build command
|
||||||
build_command(str): build command
|
|
||||||
include_debug_packages(bool): whether to include debug packages or not
|
include_debug_packages(bool): whether to include debug packages or not
|
||||||
makechrootpkg_flags(list[str]): command flags for makechrootpkg command
|
makechrootpkg_flags(list[str]): command flags for makechrootpkg command
|
||||||
makepkg_flags(list[str]): command flags for makepkg command
|
makepkg_flags(list[str]): command flags for makepkg command
|
||||||
package(Package): package definitions
|
package(Package): package definitions
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
|
repository_id(RepositoryId): repository unique identifier
|
||||||
uid(int): uid of the repository owner user
|
uid(int): uid of the repository owner user
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, package: Package, configuration: Configuration, architecture: str,
|
def __init__(self, package: Package, configuration: Configuration, repository_id: RepositoryId,
|
||||||
paths: RepositoryPaths) -> None:
|
paths: RepositoryPaths) -> None:
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
package(Package): package definitions
|
package(Package): package definitions
|
||||||
configuration(Configuration): configuration instance
|
configuration(Configuration): configuration instance
|
||||||
architecture(str): repository architecture
|
repository_id(RepositoryId): repository unique identifier
|
||||||
paths(RepositoryPaths): repository paths instance
|
paths(RepositoryPaths): repository paths instance
|
||||||
"""
|
"""
|
||||||
self.package = package
|
self.package = package
|
||||||
self.paths = paths
|
self.paths = paths
|
||||||
self.uid, _ = paths.root_owner
|
self.uid, _ = paths.root_owner
|
||||||
self.architecture = architecture
|
self.repository_id = repository_id
|
||||||
|
|
||||||
self.archbuild_flags = configuration.getlist("build", "archbuild_flags", fallback=[])
|
self.archbuild_flags = configuration.getlist("build", "archbuild_flags", fallback=[])
|
||||||
self.build_command = configuration.get("build", "build_command")
|
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)
|
self.include_debug_packages = configuration.getboolean("build", "include_debug_packages", fallback=True)
|
||||||
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
self.makepkg_flags = configuration.getlist("build", "makepkg_flags", fallback=[])
|
||||||
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
self.makechrootpkg_flags = configuration.getlist("build", "makechrootpkg_flags", fallback=[])
|
||||||
@@ -108,12 +110,16 @@ class Task(LazyLogging):
|
|||||||
Returns:
|
Returns:
|
||||||
list[Path]: paths of produced packages
|
list[Path]: paths of produced packages
|
||||||
"""
|
"""
|
||||||
command = [self.build_command, "-r", str(self.paths.chroot)]
|
command = self._legacy_build_command[:]
|
||||||
command.extend(self.archbuild_flags)
|
if not command:
|
||||||
command.extend(["--", "-D", str(self.paths.archive)] + self.makechrootpkg_flags)
|
command = self.build_command + ["-r", self.repository_id.name, "-a", self.repository_id.architecture, "--"]
|
||||||
command.extend(["--"] + self.makepkg_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(["--"] + self.makepkg_flags) # makepkg flags
|
||||||
if dry_run:
|
if dry_run:
|
||||||
command.extend(["--nobuild"])
|
command.extend(["--nobuild"])
|
||||||
|
|
||||||
self.logger.info("using %s for %s", command, self.package.base)
|
self.logger.info("using %s for %s", command, self.package.base)
|
||||||
|
|
||||||
environment: dict[str, str] = {
|
environment: dict[str, str] = {
|
||||||
@@ -156,7 +162,7 @@ class Task(LazyLogging):
|
|||||||
return last_commit_sha
|
return last_commit_sha
|
||||||
|
|
||||||
# load fresh package
|
# load fresh package
|
||||||
loaded_package = Package.from_build(sources_dir, self.architecture, None)
|
loaded_package = Package.from_build(sources_dir, self.repository_id.architecture, None)
|
||||||
if (pkgrel := loaded_package.next_pkgrel(local_version)) is not None:
|
if (pkgrel := loaded_package.next_pkgrel(local_version)) is not None:
|
||||||
self.logger.info("package %s is the same as in repo, bumping pkgrel to %s", self.package.base, pkgrel)
|
self.logger.info("package %s is the same as in repo, bumping pkgrel to %s", self.package.base, pkgrel)
|
||||||
patch = PkgbuildPatch("pkgrel", pkgrel)
|
patch = PkgbuildPatch("pkgrel", pkgrel)
|
||||||
|
|||||||
@@ -190,8 +190,20 @@ CONFIGURATION_SCHEMA: ConfigurationSchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"build_command": {
|
"build_command": {
|
||||||
"type": "string",
|
"type": "list",
|
||||||
"required": True,
|
"coerce": "list",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"empty": False,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"devtools_wrapper": {
|
||||||
|
"type": "list",
|
||||||
|
"coerce": "list",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"empty": False,
|
||||||
|
},
|
||||||
"empty": False,
|
"empty": False,
|
||||||
},
|
},
|
||||||
"ignore_packages": {
|
"ignore_packages": {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ class Executor(PackageInfo, Cleaner):
|
|||||||
"""
|
"""
|
||||||
self.reporter.set_building(package.base)
|
self.reporter.set_building(package.base)
|
||||||
|
|
||||||
task = Task(package, self.configuration, self.repository_id.architecture, self.paths)
|
task = Task(package, self.configuration, self.repository_id, self.paths)
|
||||||
patches = self.reporter.package_patches_get(package.base, None)
|
patches = self.reporter.package_patches_get(package.base, None)
|
||||||
commit_sha = task.init(path, patches, local_version)
|
commit_sha = task.init(path, patches, local_version)
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
|
|||||||
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")
|
||||||
makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
makepkg_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
||||||
sudo_configuration_mock = mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
|
|
||||||
executable_mock = mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
|
|
||||||
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
init_mock = mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
||||||
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
|
owner_guard_mock = mocker.patch("ahriman.models.repository_paths.RepositoryPaths.preserve_owner")
|
||||||
|
|
||||||
@@ -67,8 +65,6 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository:
|
|||||||
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, args.mirror, args.multilib, f"file://{repository_paths.repository}")
|
||||||
makepkg_configuration_mock.assert_called_once_with(args.packager, args.makeflags_jobs, repository_paths)
|
makepkg_configuration_mock.assert_called_once_with(args.packager, args.makeflags_jobs, repository_paths)
|
||||||
sudo_configuration_mock.assert_called_once_with(repository_paths, repository_id)
|
|
||||||
executable_mock.assert_called_once_with(repository_paths, repository_id)
|
|
||||||
init_mock.assert_called_once_with()
|
init_mock.assert_called_once_with()
|
||||||
|
|
||||||
|
|
||||||
@@ -102,8 +98,6 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration,
|
|||||||
mocker.patch("ahriman.core.repository.Repository.load", return_value=repository)
|
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_ahriman")
|
||||||
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_makepkg")
|
||||||
mocker.patch("ahriman.application.handlers.setup.Setup.configuration_create_sudo")
|
|
||||||
mocker.patch("ahriman.application.handlers.setup.Setup.executable_create")
|
|
||||||
mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
mocker.patch("ahriman.core.alpm.repo.Repo.init")
|
||||||
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")
|
||||||
|
|
||||||
@@ -113,17 +107,6 @@ def test_run_with_server(args: argparse.Namespace, configuration: Configuration,
|
|||||||
repository_id, args.from_configuration, args.mirror, args.multilib, "server")
|
repository_id, args.from_configuration, args.mirror, args.multilib, "server")
|
||||||
|
|
||||||
|
|
||||||
def test_build_command(repository_id: RepositoryId) -> None:
|
|
||||||
"""
|
|
||||||
must generate correct build command name
|
|
||||||
"""
|
|
||||||
path = Path("local")
|
|
||||||
|
|
||||||
build_command = Setup.build_command(path, repository_id)
|
|
||||||
assert build_command.name == f"{repository_id.name}-{repository_id.architecture}-build"
|
|
||||||
assert build_command.parent == path
|
|
||||||
|
|
||||||
|
|
||||||
def test_configuration_create_ahriman(args: argparse.Namespace, configuration: Configuration,
|
def test_configuration_create_ahriman(args: argparse.Namespace, configuration: Configuration,
|
||||||
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
repository_paths: RepositoryPaths, mocker: MockerFixture) -> None:
|
||||||
"""
|
"""
|
||||||
@@ -135,12 +118,9 @@ def test_configuration_create_ahriman(args: argparse.Namespace, configuration: C
|
|||||||
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)
|
remove_mock = mocker.patch("pathlib.Path.unlink", autospec=True)
|
||||||
_, repository_id = configuration.check_loaded()
|
_, repository_id = configuration.check_loaded()
|
||||||
command = Setup.build_command(repository_paths.root, repository_id)
|
|
||||||
|
|
||||||
Setup.configuration_create_ahriman(args, repository_id, configuration)
|
Setup.configuration_create_ahriman(args, repository_id, configuration)
|
||||||
set_option_mock.assert_has_calls([
|
set_option_mock.assert_has_calls([
|
||||||
MockCall(Configuration.section_name("build", repository_id.name, repository_id.architecture), "build_command",
|
|
||||||
str(command)),
|
|
||||||
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),
|
||||||
"makechrootpkg_flags", f"-U {args.build_as_user}"),
|
"makechrootpkg_flags", f"-U {args.build_as_user}"),
|
||||||
@@ -251,34 +231,6 @@ def test_configuration_create_makepkg(args: argparse.Namespace, repository_paths
|
|||||||
Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8")
|
Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8")
|
||||||
|
|
||||||
|
|
||||||
def test_configuration_create_sudo(configuration: Configuration, repository_paths: RepositoryPaths,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must create sudo configuration
|
|
||||||
"""
|
|
||||||
chmod_text_mock = mocker.patch("pathlib.Path.chmod")
|
|
||||||
write_text_mock = mocker.patch("pathlib.Path.write_text")
|
|
||||||
|
|
||||||
_, repository_id = configuration.check_loaded()
|
|
||||||
Setup.configuration_create_sudo(repository_paths, repository_id)
|
|
||||||
chmod_text_mock.assert_called_once_with(0o400)
|
|
||||||
write_text_mock.assert_called_once_with(pytest.helpers.anyvar(str, True), encoding="utf8")
|
|
||||||
|
|
||||||
|
|
||||||
def test_executable_create(configuration: Configuration, repository_paths: RepositoryPaths,
|
|
||||||
mocker: MockerFixture) -> None:
|
|
||||||
"""
|
|
||||||
must create executable
|
|
||||||
"""
|
|
||||||
symlink_mock = mocker.patch("pathlib.Path.symlink_to")
|
|
||||||
unlink_mock = mocker.patch("pathlib.Path.unlink")
|
|
||||||
|
|
||||||
_, repository_id = configuration.check_loaded()
|
|
||||||
Setup.executable_create(repository_paths, repository_id)
|
|
||||||
symlink_mock.assert_called_once_with(Setup.ARCHBUILD_COMMAND_PATH)
|
|
||||||
unlink_mock.assert_called_once_with(missing_ok=True)
|
|
||||||
|
|
||||||
|
|
||||||
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 (("build", "build_command"), ("repository", "root")):
|
for section, key in (("repository", "root"),):
|
||||||
value = configuration.get(section, key)
|
value = configuration.get(section, key)
|
||||||
default.set_option(section, key, value)
|
default.set_option(section, key, value)
|
||||||
|
|
||||||
|
|||||||
@@ -53,8 +53,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(
|
||||||
"extra-x86_64-build",
|
"ahriman-archbuild",
|
||||||
"-r", str(task_ahriman.paths.chroot),
|
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture,
|
||||||
|
"--", "-r", str(task_ahriman.paths.chroot),
|
||||||
"--", "-D", str(task_ahriman.paths.archive),
|
"--", "-D", str(task_ahriman.paths.archive),
|
||||||
"--", "--skippgpcheck",
|
"--", "--skippgpcheck",
|
||||||
exception=pytest.helpers.anyvar(int),
|
exception=pytest.helpers.anyvar(int),
|
||||||
@@ -79,8 +80,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(
|
||||||
"extra-x86_64-build",
|
"ahriman-archbuild",
|
||||||
"-r", str(task_ahriman.paths.chroot),
|
"-r", task_ahriman.repository_id.name, "-a", task_ahriman.repository_id.architecture,
|
||||||
|
"--", "-r", str(task_ahriman.paths.chroot),
|
||||||
"--", "-D", str(task_ahriman.paths.archive),
|
"--", "-D", str(task_ahriman.paths.archive),
|
||||||
"--", "--skippgpcheck",
|
"--", "--skippgpcheck",
|
||||||
exception=pytest.helpers.anyvar(int),
|
exception=pytest.helpers.anyvar(int),
|
||||||
@@ -101,12 +103,37 @@ def test_build_dry_run(task_ahriman: Task, mocker: MockerFixture) -> None:
|
|||||||
check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output")
|
check_output_mock = mocker.patch("ahriman.core.build_tools.task.check_output")
|
||||||
|
|
||||||
assert task_ahriman.build(local, dry_run=True) == [task_ahriman.package.base]
|
assert task_ahriman.build(local, dry_run=True) == [task_ahriman.package.base]
|
||||||
|
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",
|
||||||
|
"--nobuild",
|
||||||
|
exception=pytest.helpers.anyvar(int),
|
||||||
|
cwd=local,
|
||||||
|
logger=task_ahriman.logger,
|
||||||
|
user=task_ahriman.uid,
|
||||||
|
environment={},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_legacy_subcommand(task_ahriman: Task, mocker: MockerFixture) -> None:
|
||||||
|
"""
|
||||||
|
must build package by using legacy subcommand 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._legacy_build_command = ["extra-x86_64-build"]
|
||||||
|
|
||||||
|
task_ahriman.build(local)
|
||||||
check_output_mock.assert_called_once_with(
|
check_output_mock.assert_called_once_with(
|
||||||
"extra-x86_64-build",
|
"extra-x86_64-build",
|
||||||
"-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",
|
||||||
"--nobuild",
|
|
||||||
exception=pytest.helpers.anyvar(int),
|
exception=pytest.helpers.anyvar(int),
|
||||||
cwd=local,
|
cwd=local,
|
||||||
logger=task_ahriman.logger,
|
logger=task_ahriman.logger,
|
||||||
|
|||||||
@@ -76,4 +76,5 @@ def task_ahriman(package_ahriman: Package, configuration: Configuration, reposit
|
|||||||
Returns:
|
Returns:
|
||||||
Task: built task test instance
|
Task: built task test instance
|
||||||
"""
|
"""
|
||||||
return Task(package_ahriman, configuration, "x86_64", repository_paths)
|
_, repository_id = configuration.check_loaded()
|
||||||
|
return Task(package_ahriman, configuration, repository_id, repository_paths)
|
||||||
|
|||||||
+4
-1
@@ -12,7 +12,8 @@ depends=('devtools>=1:1.0.0' 'git' 'pyalpm' 'python-bcrypt' 'python-filelock' 'p
|
|||||||
makedepends=('npm' 'python-build' 'python-hatchling' 'python-installer' 'python-wheel')
|
makedepends=('npm' 'python-build' 'python-hatchling' 'python-installer' 'python-wheel')
|
||||||
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgbase-$pkgver.tar.gz"
|
source=("https://github.com/arcan1s/ahriman/releases/download/$pkgver/$pkgbase-$pkgver.tar.gz"
|
||||||
"$pkgbase.sysusers"
|
"$pkgbase.sysusers"
|
||||||
"$pkgbase.tmpfiles")
|
"$pkgbase.tmpfiles"
|
||||||
|
"sudoers.conf")
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "$pkgbase-$pkgver"
|
cd "$pkgbase-$pkgver"
|
||||||
@@ -59,6 +60,8 @@ package_ahriman-core() {
|
|||||||
|
|
||||||
install -Dm644 "$srcdir/$pkgbase.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgbase.conf"
|
install -Dm644 "$srcdir/$pkgbase.sysusers" "$pkgdir/usr/lib/sysusers.d/$pkgbase.conf"
|
||||||
install -Dm644 "$srcdir/$pkgbase.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgbase.conf"
|
install -Dm644 "$srcdir/$pkgbase.tmpfiles" "$pkgdir/usr/lib/tmpfiles.d/$pkgbase.conf"
|
||||||
|
|
||||||
|
install -Dm440 "$srcdir/sudoers.conf" "$pkgdir/etc/sudoers.d/$pkgname"
|
||||||
}
|
}
|
||||||
|
|
||||||
package_ahriman-triggers() {
|
package_ahriman-triggers() {
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
ahriman ALL= NOPASSWD:SETENV: /usr/bin/ahriman-archbuild *
|
||||||
@@ -131,7 +131,7 @@ Authorized users are stored inside internal database, if any of external provide
|
|||||||
Build related configuration. Group name can refer to architecture, e.g. ``build:x86_64`` can be used for x86_64 architecture specific settings.
|
Build related configuration. Group name can refer to architecture, e.g. ``build:x86_64`` can be used for x86_64 architecture specific settings.
|
||||||
|
|
||||||
* ``archbuild_flags`` - additional flags passed to ``archbuild`` command, space separated list of strings, optional.
|
* ``archbuild_flags`` - additional flags passed to ``archbuild`` command, space separated list of strings, optional.
|
||||||
* ``build_command`` - default build command, string, required.
|
* ``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.
|
* ``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``.
|
* ``include_debug_packages`` - distribute debug packages, boolean, optional, default ``yes``.
|
||||||
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
|
* ``makepkg_flags`` - additional flags passed to ``makepkg`` command, space separated list of strings, optional.
|
||||||
|
|||||||
+12
-36
@@ -27,48 +27,24 @@ Initial setup
|
|||||||
#.
|
#.
|
||||||
Configure build tools (it is required for correct dependency management system):
|
Configure build tools (it is required for correct dependency management system):
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Create build command (you can choose any name for command, basically it should be ``{name}-{arch}-build``):
|
Create configuration file ``{name}.conf`` or ``{name}-{arch}.conf``, where ``name`` is the repostory name and ``arch`` is the repository architecture, e.g.:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
ln -s /usr/bin/archbuild /usr/local/bin/aur-x86_64-build
|
cp /usr/share/devtools/pacman.conf.d/{extra,aur-x86_64}.conf
|
||||||
|
|
||||||
#.
|
#.
|
||||||
Create configuration file (same as previous ``{name}.conf``):
|
Change configuration file, add your own repository, add multilib repository etc:
|
||||||
|
|
||||||
.. code-block:: shell
|
.. code-block:: shell
|
||||||
|
|
||||||
cp /usr/share/devtools/pacman.conf.d/{extra,aur}.conf
|
echo '[multilib]' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
||||||
|
echo 'Include = /etc/pacman.d/mirrorlist' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
||||||
|
|
||||||
#.
|
echo '[aur]' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
||||||
Change configuration file, add your own repository, add multilib repository etc:
|
echo 'SigLevel = Optional TrustAll' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
||||||
|
echo 'Server = file:///var/lib/ahriman/repository/$repo/$arch' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo '[multilib]' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
|
||||||
echo 'Include = /etc/pacman.d/mirrorlist' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
|
||||||
|
|
||||||
echo '[aur]' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
|
||||||
echo 'SigLevel = Optional TrustAll' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
|
||||||
echo 'Server = file:///var/lib/ahriman/repository/$repo/$arch' | tee -a /usr/share/devtools/pacman.conf.d/aur-x86_64.conf
|
|
||||||
|
|
||||||
#.
|
|
||||||
Set ``build_command`` option to point to your command:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo '[build]' | tee -a /etc/ahriman.ini.d/build.ini
|
|
||||||
echo 'build_command = aur-x86_64-build' | tee -a /etc/ahriman.ini.d/build.ini
|
|
||||||
|
|
||||||
#.
|
|
||||||
Configure ``/etc/sudoers.d/ahriman`` to allow running command without a password:
|
|
||||||
|
|
||||||
.. code-block:: shell
|
|
||||||
|
|
||||||
echo 'Cmnd_Alias CARCHBUILD_CMD = /usr/local/bin/aur-x86_64-build *' | tee -a /etc/sudoers.d/ahriman
|
|
||||||
echo 'ahriman ALL=(ALL) NOPASSWD:SETENV: CARCHBUILD_CMD' | tee -a /etc/sudoers.d/ahriman
|
|
||||||
chmod 400 /etc/sudoers.d/ahriman
|
|
||||||
|
|
||||||
This command supports several arguments, kindly refer to its help message.
|
This command supports several arguments, kindly refer to its help message.
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ allow_read_only = no
|
|||||||
|
|
||||||
[build]
|
[build]
|
||||||
archbuild_flags =
|
archbuild_flags =
|
||||||
build_command = extra-x86_64-build
|
devtools_wrapper = ahriman-archbuild
|
||||||
ignore_packages =
|
ignore_packages =
|
||||||
makechrootpkg_flags =
|
makechrootpkg_flags =
|
||||||
makepkg_flags = --skippgpcheck
|
makepkg_flags = --skippgpcheck
|
||||||
|
|||||||
Reference in New Issue
Block a user