diff --git a/chroot/abstract.py b/chroot/abstract.py index 9c10d83..ffef4a6 100644 --- a/chroot/abstract.py +++ b/chroot/abstract.py @@ -2,6 +2,8 @@ import atexit import logging import os import subprocess +import sys + from copy import deepcopy from shlex import quote as shell_quote from typing import ClassVar, Iterable, Protocol, Union, Optional, Mapping @@ -10,7 +12,7 @@ from uuid import uuid4 from config.state import config from constants import Arch, CHROOT_PATHS, GCC_HOSTSPECS from distro.distro import get_base_distro, get_kupfer_local, RepoInfo -from exec.cmd import run_root_cmd, generate_env_cmd, flatten_shell_script, wrap_in_bash, generate_cmd_su +from exec.cmd import FileDescriptor, run_root_cmd, generate_env_cmd, flatten_shell_script, wrap_in_bash, generate_cmd_su from exec.file import makedir, root_makedir, root_write_file, write_file from generator import generate_makepkg_conf from utils import mount, umount, check_findmnt, log_or_exception @@ -58,7 +60,8 @@ class AbstractChroot(Protocol): capture_output: bool, cwd: str, fail_inactive: bool, - stdout: Optional[int], + stdout: Optional[FileDescriptor], + stderr: Optional[FileDescriptor], ): pass @@ -222,7 +225,8 @@ class Chroot(AbstractChroot): capture_output: bool = False, cwd: Optional[str] = None, fail_inactive: bool = True, - stdout: Optional[int] = None, + stdout: Optional[FileDescriptor] = None, + stderr: Optional[FileDescriptor] = None, switch_user: Optional[str] = None, ) -> Union[int, subprocess.CompletedProcess]: if not self.active and fail_inactive: @@ -246,7 +250,7 @@ class Chroot(AbstractChroot): inner_cmd = wrap_in_bash(script, flatten_result=False) cmd = flatten_shell_script(['chroot', self.path] + env_cmd + inner_cmd, shell_quote_items=True) - return run_root_cmd(cmd, env=outer_env, attach_tty=attach_tty, capture_output=capture_output, stdout=stdout) + return run_root_cmd(cmd, env=outer_env, attach_tty=attach_tty, capture_output=capture_output, stdout=stdout, stderr=stderr) def mount_pkgbuilds(self, fail_if_mounted: bool = False) -> str: return self.mount( @@ -371,20 +375,22 @@ class Chroot(AbstractChroot): packages: list[str], refresh: bool = False, allow_fail: bool = True, + redirect_stderr: bool = True, ) -> dict[str, Union[int, subprocess.CompletedProcess]]: """Try installing packages, fall back to installing one by one""" results = {} + stderr = sys.stdout if redirect_stderr else sys.stderr if refresh: - results['refresh'] = self.run_cmd('pacman -Syy --noconfirm') + results['refresh'] = self.run_cmd('pacman -Syy --noconfirm', stderr=stderr) cmd = "pacman -S --noconfirm --needed --overwrite='/*'" - result = self.run_cmd(f'{cmd} -y {" ".join(packages)}') + result = self.run_cmd(f'{cmd} -y {" ".join(packages)}', stderr=stderr) assert isinstance(result, subprocess.CompletedProcess) results |= {package: result for package in packages} if result.returncode != 0 and allow_fail: results = {} logging.debug('Falling back to serial installation') for pkg in set(packages): - results[pkg] = self.run_cmd(f'{cmd} {pkg}') + results[pkg] = self.run_cmd(f'{cmd} {pkg}', stderr=stderr) return results diff --git a/chroot/base.py b/chroot/base.py index 37ed943..93b07e7 100644 --- a/chroot/base.py +++ b/chroot/base.py @@ -1,5 +1,6 @@ import logging import os +import sys from glob import glob from shutil import rmtree @@ -31,17 +32,20 @@ class BaseChroot(Chroot): logging.info(f'Pacstrapping chroot {self.name}: {", ".join(self.base_packages)}') - result = run_root_cmd([ - 'pacstrap', - '-C', - pacman_conf_target, - '-G', - self.path, - ] + self.base_packages + [ - '--needed', - '--overwrite=*', - '-yyuu', - ]) + result = run_root_cmd( + [ + 'pacstrap', + '-C', + pacman_conf_target, + '-G', + self.path, + *self.base_packages, + '--needed', + '--overwrite=*', + '-yyuu', + ], + stderr=sys.stdout, + ) if result.returncode != 0: raise Exception(f'Failed to initialize chroot "{self.name}"') self.initialized = True diff --git a/packages/build.py b/packages/build.py index 2a5a988..e01a230 100644 --- a/packages/build.py +++ b/packages/build.py @@ -3,6 +3,7 @@ import multiprocessing import os import shutil import subprocess +import sys from copy import deepcopy from urllib.error import HTTPError @@ -228,7 +229,7 @@ def add_file_to_repo(file_path: str, repo_name: str, arch: Arch, remove_original target_file, ] logging.debug(f'repo: running cmd: {cmd}') - result = run_cmd(cmd) + result = run_cmd(cmd, stderr=sys.stdout) assert isinstance(result, subprocess.CompletedProcess) if result.returncode != 0: raise Exception(f'Failed add package {target_file} to repo {repo_name}') @@ -474,7 +475,7 @@ def setup_sources(package: Pkgbuild, lazy: bool = True): assert config.runtime.arch chroot = setup_build_chroot(config.runtime.arch) logging.info(f'{package.path}: Setting up sources with makepkg') - result = chroot.run_cmd(makepkg_setup, cwd=dir, switch_user='kupfer') + result = chroot.run_cmd(makepkg_setup, cwd=dir, switch_user='kupfer', stderr=sys.stdout) assert isinstance(result, subprocess.CompletedProcess) if result.returncode != 0: raise Exception(f'{package.path}: Failed to setup sources, exit code: {result.returncode}') @@ -584,6 +585,7 @@ def build_package( inner_env=env, cwd=os.path.join(CHROOT_PATHS['pkgbuilds'], package.path), switch_user=build_user, + stderr=sys.stdout, ) assert isinstance(result, subprocess.CompletedProcess) if result.returncode != 0: @@ -829,6 +831,6 @@ def build_enable_qemu_binfmt(arch: Arch, repo: Optional[dict[str, Pkgbuild]] = N assert p.startswith(hostdir) _files.append(os.path.join(CHROOT_PATHS['packages'], p[len(hostdir):].lstrip('/'))) pkgfiles = _files - runcmd(['pacman', '-U', '--noconfirm', '--needed'] + pkgfiles) + runcmd(['pacman', '-U', '--noconfirm', '--needed'] + pkgfiles, stderr=sys.stdout) binfmt_register(arch, chroot=native_chroot) _qemu_enabled[arch] = True