improve setup command by --makeflags-jobs argument and fix repository sign on creation

This commit is contained in:
Evgenii Alekseev 2022-11-29 16:06:41 +02:00
parent fe66c6c45c
commit ebd06cb443
8 changed files with 54 additions and 26 deletions

View File

@ -507,9 +507,10 @@ root path of the extracted files
.SH COMMAND \fI\,'ahriman repo\-setup'\/\fR .SH COMMAND \fI\,'ahriman repo\-setup'\/\fR
usage: ahriman repo\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND] usage: ahriman repo\-setup [\-h] [\-\-build\-as\-user BUILD_AS_USER] [\-\-build\-command BUILD_COMMAND]
[\-\-from\-configuration FROM_CONFIGURATION] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER [\-\-from\-configuration FROM_CONFIGURATION] [\-\-makeflags\-jobs | \-\-no\-makeflags\-jobs]
\-\-repository REPOSITORY [\-\-sign\-key SIGN_KEY] [\-\-sign\-target {disabled,pacakges,repository}] [\-\-multilib | \-\-no\-multilib] \-\-packager PACKAGER \-\-repository REPOSITORY [\-\-sign\-key SIGN_KEY]
[\-\-web\-port WEB_PORT] [\-\-web\-unix\-socket WEB_UNIX_SOCKET] [\-\-sign\-target {disabled,pacakges,repository}] [\-\-web\-port WEB_PORT]
[\-\-web\-unix\-socket WEB_UNIX_SOCKET]
create initial service configuration, requires root create initial service configuration, requires root
@ -526,6 +527,10 @@ build command prefix
\fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR \fB\-\-from\-configuration\fR \fI\,FROM_CONFIGURATION\/\fR
path to default devtools pacman configuration path to default devtools pacman configuration
.TP
\fB\-\-makeflags\-jobs\fR, \fB\-\-no\-makeflags\-jobs\fR
append MAKEFLAGS variable with parallelism set to number of cores (default: True)
.TP .TP
\fB\-\-multilib\fR, \fB\-\-no\-multilib\fR \fB\-\-multilib\fR, \fB\-\-no\-multilib\fR
add or do not multilib repository (default: True) add or do not multilib repository (default: True)

View File

@ -632,6 +632,8 @@ def _set_repo_setup_parser(root: SubParserAction) -> argparse.ArgumentParser:
parser.add_argument("--build-command", help="build command prefix", default="ahriman") parser.add_argument("--build-command", help="build command prefix", default="ahriman")
parser.add_argument("--from-configuration", help="path to default devtools pacman configuration", parser.add_argument("--from-configuration", help="path to default devtools pacman configuration",
type=Path, default=Path("/usr/share/devtools/pacman-extra.conf")) type=Path, default=Path("/usr/share/devtools/pacman-extra.conf"))
parser.add_argument("--makeflags-jobs", help="append MAKEFLAGS variable with parallelism set to number of cores",
action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--multilib", help="add or do not multilib repository", parser.add_argument("--multilib", help="add or do not multilib repository",
action=argparse.BooleanOptionalAction, default=True) action=argparse.BooleanOptionalAction, default=True)
parser.add_argument("--packager", help="packager name and email", required=True) parser.add_argument("--packager", help="packager name and email", required=True)

View File

@ -64,7 +64,7 @@ class Setup(Handler):
application = Application(architecture, configuration, report=report, unsafe=unsafe) application = Application(architecture, configuration, report=report, unsafe=unsafe)
Setup.configuration_create_makepkg(args.packager, application.repository.paths) Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, application.repository.paths)
Setup.executable_create(application.repository.paths, args.build_command, architecture) Setup.executable_create(application.repository.paths, args.build_command, architecture)
Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration, Setup.configuration_create_devtools(args.build_command, architecture, args.from_configuration,
args.multilib, args.repository, application.repository.paths) args.multilib, args.repository, application.repository.paths)
@ -170,17 +170,23 @@ class Setup(Handler):
configuration.write(devtools_configuration) configuration.write(devtools_configuration)
@staticmethod @staticmethod
def configuration_create_makepkg(packager: str, paths: RepositoryPaths) -> None: def configuration_create_makepkg(packager: str, makeflags_jobs: bool, paths: RepositoryPaths) -> None:
""" """
create configuration for makepkg create configuration for makepkg
Args: Args:
packager(str): packager identifier (e.g. name, email) packager(str): packager identifier (e.g. name, email)
makeflags_jobs(bool): set MAKEFLAGS variable to number of cores
paths(RepositoryPaths): repository paths instance paths(RepositoryPaths): repository paths instance
""" """
content = f"PACKAGER='{packager}'\n"
if makeflags_jobs:
content += """MAKEFLAGS="-j$(nproc)"\n"""
uid, _ = paths.root_owner uid, _ = paths.root_owner
home_dir = Path(getpwuid(uid).pw_dir) home_dir = Path(getpwuid(uid).pw_dir)
(home_dir / ".makepkg.conf").write_text(f"PACKAGER='{packager}'\n", encoding="utf8") (home_dir / ".makepkg.conf").write_text(content, encoding="utf8")
@staticmethod @staticmethod
def configuration_create_sudo(paths: RepositoryPaths, prefix: str, architecture: str) -> None: def configuration_create_sudo(paths: RepositoryPaths, prefix: str, architecture: str) -> None:

View File

@ -27,6 +27,7 @@ import subprocess
from enum import Enum from enum import Enum
from pathlib import Path from pathlib import Path
from pwd import getpwuid
from typing import Any, Dict, Generator, IO, Iterable, List, Optional, Type, Union from typing import Any, Dict, Generator, IO, Iterable, List, Optional, Type, Union
from ahriman.core.exceptions import OptionError, UnsafeRunError from ahriman.core.exceptions import OptionError, UnsafeRunError
@ -84,10 +85,11 @@ def check_output(*args: str, exception: Optional[Exception] = None, cwd: Optiona
if logger is not None: if logger is not None:
logger.debug(single) logger.debug(single)
environment = {"HOME": getpwuid(user).pw_dir} if user is not None else {}
# FIXME additional workaround for linter and type check which do not know that user arg is supported # FIXME additional workaround for linter and type check which do not know that user arg is supported
# pylint: disable=unexpected-keyword-arg # pylint: disable=unexpected-keyword-arg
with subprocess.Popen(args, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, with subprocess.Popen(args, cwd=cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
user=user, text=True, encoding="utf8", bufsize=1) as process: user=user, env=environment, text=True, encoding="utf8", bufsize=1) as process:
if input_data is not None: if input_data is not None:
input_channel = get_io(process, "stdin") input_channel = get_io(process, "stdin")
input_channel.write(input_data) input_channel.write(input_data)

View File

@ -1,16 +0,0 @@
import pytest
from unittest.mock import MagicMock
@pytest.fixture
def passwd() -> MagicMock:
"""
get passwd structure for the user
Returns:
MagicMock: passwd structure test instance
"""
passwd = MagicMock()
passwd.pw_dir = "home"
return passwd

View File

@ -25,6 +25,7 @@ def _default_args(args: argparse.Namespace) -> argparse.Namespace:
args.build_as_user = "ahriman" args.build_as_user = "ahriman"
args.build_command = "ahriman" args.build_command = "ahriman"
args.from_configuration = Path("/usr/share/devtools/pacman-extra.conf") args.from_configuration = Path("/usr/share/devtools/pacman-extra.conf")
args.makeflags_jobs = True
args.multilib = True args.multilib = True
args.packager = "John Doe <john@doe.com>" args.packager = "John Doe <john@doe.com>"
args.repository = "aur-clone" args.repository = "aur-clone"
@ -54,10 +55,10 @@ def test_run(args: argparse.Namespace, configuration: Configuration, repository_
args, "x86_64", args.repository, configuration.include, repository_paths) args, "x86_64", args.repository, configuration.include, repository_paths)
devtools_configuration_mock.assert_called_once_with( devtools_configuration_mock.assert_called_once_with(
args.build_command, "x86_64", args.from_configuration, args.multilib, args.repository, repository_paths) args.build_command, "x86_64", args.from_configuration, args.multilib, args.repository, repository_paths)
makepkg_configuration_mock.assert_called_once_with(args.packager, 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, args.build_command, "x86_64") sudo_configuration_mock.assert_called_once_with(repository_paths, args.build_command, "x86_64")
executable_mock.assert_called_once_with(repository_paths, args.build_command, "x86_64") executable_mock.assert_called_once_with(repository_paths, args.build_command, "x86_64")
init_mock.assert_called_once() init_mock.assert_called_once_with()
def test_build_command(args: argparse.Namespace) -> None: def test_build_command(args: argparse.Namespace) -> None:
@ -138,7 +139,7 @@ def test_configuration_create_makepkg(args: argparse.Namespace, repository_paths
mocker.patch("ahriman.application.handlers.setup.getpwuid", return_value=passwd) mocker.patch("ahriman.application.handlers.setup.getpwuid", return_value=passwd)
write_text_mock = mocker.patch("pathlib.Path.write_text", autospec=True) write_text_mock = mocker.patch("pathlib.Path.write_text", autospec=True)
Setup.configuration_create_makepkg(args.packager, repository_paths) Setup.configuration_create_makepkg(args.packager, args.makeflags_jobs, repository_paths)
write_text_mock.assert_called_once_with( write_text_mock.assert_called_once_with(
Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8") Path("home") / ".makepkg.conf", pytest.helpers.anyvar(str, True), encoding="utf8")

View File

@ -363,6 +363,19 @@ def pacman(configuration: Configuration) -> Pacman:
return Pacman("x86_64", configuration, refresh_database=0) return Pacman("x86_64", configuration, refresh_database=0)
@pytest.fixture
def passwd() -> MagicMock:
"""
get passwd structure for the user
Returns:
MagicMock: passwd structure test instance
"""
passwd = MagicMock()
passwd.pw_dir = "home"
return passwd
@pytest.fixture @pytest.fixture
def remote_source() -> RemoteSource: def remote_source() -> RemoteSource:
""" """

View File

@ -1,11 +1,13 @@
import datetime import datetime
import logging import logging
import os
import pytest import pytest
import requests import requests
import subprocess import subprocess
from pathlib import Path from pathlib import Path
from pytest_mock import MockerFixture from pytest_mock import MockerFixture
from typing import Any
from unittest.mock import MagicMock from unittest.mock import MagicMock
from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError from ahriman.core.exceptions import BuildError, OptionError, UnsafeRunError
@ -75,6 +77,19 @@ def test_check_output_multiple_with_stdin_newline() -> None:
input_data="multiple\nlines\n") == "multiple\nlines" input_data="multiple\nlines\n") == "multiple\nlines"
def test_check_output_with_user(passwd: Any, mocker: MockerFixture) -> None:
"""
must run command as specified user and set its homedir
"""
assert check_output("python", "-c", "import os; print(os.getenv('HOME'))") != passwd.pw_dir
getpwuid_mock = mocker.patch("ahriman.core.util.getpwuid", return_value=passwd)
user = os.getuid()
assert check_output("python", "-c", "import os; print(os.getenv('HOME'))", user=user) == passwd.pw_dir
getpwuid_mock.assert_called_once_with(user)
def test_check_output_failure(mocker: MockerFixture) -> None: def test_check_output_failure(mocker: MockerFixture) -> None:
""" """
must process exception correctly must process exception correctly