From c90f462461261914e0e99f8bc83d3e5f18d484a8 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Fri, 28 Jul 2023 11:22:02 +0200 Subject: [PATCH] Separate out functions to get package manager commands + options --- mkosi/distributions/centos.py | 4 +-- mkosi/distributions/fedora.py | 5 ++- mkosi/installer/apt.py | 35 +++++++++--------- mkosi/installer/dnf.py | 67 ++++++++++++++++++----------------- mkosi/installer/pacman.py | 9 +++-- mkosi/installer/zypper.py | 27 +++++++------- 6 files changed, 75 insertions(+), 72 deletions(-) diff --git a/mkosi/distributions/centos.py b/mkosi/distributions/centos.py index 70fc495e6..1acd539d0 100644 --- a/mkosi/distributions/centos.py +++ b/mkosi/distributions/centos.py @@ -50,8 +50,8 @@ class CentosInstaller(DistributionInstaller): die("CentOS 7 or earlier variants are not supported") setup_dnf(state, cls.repositories(state.config, release)) - invoke_dnf(state, "install", packages, apivfs=apivfs, - env=dict(DNF_VAR_stream=f"{state.config.release}-stream")) + (state.pkgmngr / "etc/dnf/vars/stream").write_text(f"{state.config.release}-stream\n") + invoke_dnf(state, "install", packages, apivfs=apivfs) @classmethod def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: diff --git a/mkosi/distributions/fedora.py b/mkosi/distributions/fedora.py index 50ad25791..a68a89c0b 100644 --- a/mkosi/distributions/fedora.py +++ b/mkosi/distributions/fedora.py @@ -59,9 +59,8 @@ class FedoraInstaller(DistributionInstaller): if url: repos += [Repo(name, url, (gpgurl,))] - setup_dnf(state, repos) - invoke_dnf(state, "install", packages, apivfs=apivfs, - filelists=fedora_release_at_least(state.config.release, "38")) + setup_dnf(state, repos, filelists=fedora_release_at_least(state.config.release, "38")) + invoke_dnf(state, "install", packages, apivfs=apivfs) @classmethod def remove_packages(cls, state: MkosiState, packages: Sequence[str]) -> None: diff --git a/mkosi/installer/apt.py b/mkosi/installer/apt.py index 4499130d6..f2146e082 100644 --- a/mkosi/installer/apt.py +++ b/mkosi/installer/apt.py @@ -1,5 +1,4 @@ # SPDX-License-Identifier: LGPL-2.1+ -import os import shutil import textwrap from collections.abc import Sequence @@ -54,20 +53,7 @@ def setup_apt(state: MkosiState, repos: Sequence[str]) -> None: f.write(f"{repo}\n") -def invoke_apt( - state: MkosiState, - operation: str, - packages: Sequence[str] = (), - apivfs: bool = True, -) -> None: - env = dict( - APT_CONFIG=os.fspath(state.workspace / "apt.conf"), - DEBIAN_FRONTEND="noninteractive", - DEBCONF_INTERACTIVE_SEEN="true", - KERNEL_INSTALL_BYPASS="1", - INITRD="No", - ) - +def apt_cmd(state: MkosiState) -> list[str]: debarch = state.installer.architecture(state.config.architecture) trustedkeys = state.pkgmngr / "etc/apt/trusted.gpg" @@ -75,7 +61,13 @@ def invoke_apt( trustedkeys_dir = state.pkgmngr / "etc/apt/trusted.gpg.d" trustedkeys_dir = trustedkeys_dir if trustedkeys_dir.exists() else "/usr/share/keyrings" - options = [ + return [ + "env", + f"APT_CONFIG={state.workspace / 'apt.conf'}", + "DEBIAN_FRONTEND=noninteractive", + "DEBCONF_INTERACTIVE_SEEN=true", + "INITRD=No", + "apt-get", "-o", f"APT::Architecture={debarch}", "-o", f"APT::Architectures={debarch}", "-o", "APT::Immediate-Configure=off", @@ -102,6 +94,13 @@ def invoke_apt( "-o", "pkgCacheGen::ForceEssential=,", ] - bwrap(["apt-get", *options, operation, *packages], + +def invoke_apt( + state: MkosiState, + operation: str, + packages: Sequence[str] = (), + apivfs: bool = True, +) -> None: + bwrap(apt_cmd(state) + [operation, *packages], apivfs=state.root if apivfs else None, - env=env | state.config.environment) + env=dict(KERNEL_INSTALL_BYPASS="1") | state.config.environment) diff --git a/mkosi/installer/dnf.py b/mkosi/installer/dnf.py index f0e334028..4efc636e9 100644 --- a/mkosi/installer/dnf.py +++ b/mkosi/installer/dnf.py @@ -2,9 +2,9 @@ import os import shutil import textwrap -from collections.abc import Iterable, Mapping, Sequence +from collections.abc import Iterable, Sequence from pathlib import Path -from typing import Any, NamedTuple +from typing import NamedTuple from mkosi.run import bwrap from mkosi.state import MkosiState @@ -19,19 +19,36 @@ class Repo(NamedTuple): enabled: bool = True -def setup_dnf(state: MkosiState, repos: Sequence[Repo]) -> None: +def dnf_executable(state: MkosiState) -> str: + # dnf5 does not support building for foreign architectures yet (missing --forcearch) + dnf = shutil.which("dnf5") if state.config.architecture.is_native() else None + dnf = dnf or shutil.which("dnf") or "yum" + return dnf + + +def setup_dnf(state: MkosiState, repos: Sequence[Repo], filelists: bool = True) -> None: + state.pkgmngr.joinpath("etc/dnf/vars").mkdir(exist_ok=True, parents=True) + state.pkgmngr.joinpath("etc/yum.repos.d").mkdir(exist_ok=True, parents=True) + state.pkgmngr.joinpath("var/lib/dnf").mkdir(exist_ok=True, parents=True) + config = state.pkgmngr / "etc/dnf/dnf.conf" if not config.exists(): config.parent.mkdir(exist_ok=True, parents=True) - config.write_text( - textwrap.dedent( - """\ - [main] - install_weak_deps=0 - """ + with config.open("w") as f: + f.write( + textwrap.dedent( + """\ + [main] + install_weak_deps=0 + """ + ) ) - ) + + # Make sure we download filelists so all dependencies can be resolved. + # See https://bugzilla.redhat.com/show_bug.cgi?id=2180842 + if dnf_executable(state).endswith("dnf5") and filelists: + f.write("optional_metadata_types=filelists\n") repofile = state.pkgmngr / "etc/yum.repos.d/mkosi.repo" if not repofile.exists(): @@ -55,21 +72,8 @@ def setup_dnf(state: MkosiState, repos: Sequence[Repo]) -> None: f.write(f"{url}\n") -def invoke_dnf( - state: MkosiState, - command: str, - packages: Iterable[str], - env: Mapping[str, Any] = {}, - filelists: bool = True, - apivfs: bool = True -) -> None: - state.pkgmngr.joinpath("etc/dnf/vars").mkdir(exist_ok=True, parents=True) - state.pkgmngr.joinpath("etc/yum.repos.d").mkdir(exist_ok=True, parents=True) - state.pkgmngr.joinpath("var/lib/dnf").mkdir(exist_ok=True, parents=True) - - # dnf5 does not support building for foreign architectures yet (missing --forcearch) - dnf = shutil.which("dnf5") if state.config.architecture.is_native() else None - dnf = dnf or shutil.which("dnf") or "yum" +def dnf_cmd(state: MkosiState) -> list[str]: + dnf = dnf_executable(state) cmdline = [ dnf, @@ -87,11 +91,6 @@ def invoke_dnf( "--no-plugins" if dnf.endswith("dnf5") else "--noplugins", ] - # Make sure we download filelists so all dependencies can be resolved. - # See https://bugzilla.redhat.com/show_bug.cgi?id=2180842 - if dnf.endswith("dnf5") and filelists: - cmdline += ["--setopt=optional_metadata_types=filelists"] - if not state.config.repository_key_check: cmdline += ["--nogpgcheck"] @@ -109,11 +108,13 @@ def invoke_dnf( if not state.config.with_docs: cmdline += ["--no-docs" if dnf.endswith("dnf5") else "--nodocs"] - cmdline += [command, *sort_packages(packages)] + return cmdline + - bwrap(cmdline, +def invoke_dnf(state: MkosiState, command: str, packages: Iterable[str], apivfs: bool = True) -> None: + bwrap(dnf_cmd(state) + [command] + sort_packages(packages), apivfs=state.root if apivfs else None, - env=dict(KERNEL_INSTALL_BYPASS="1") | env | state.config.environment) + env=dict(KERNEL_INSTALL_BYPASS="1") | state.config.environment) fixup_rpmdb_location(state.root) diff --git a/mkosi/installer/pacman.py b/mkosi/installer/pacman.py index 5dda1d4d2..d4c79d5de 100644 --- a/mkosi/installer/pacman.py +++ b/mkosi/installer/pacman.py @@ -82,7 +82,7 @@ def setup_pacman(state: MkosiState) -> None: ) -def invoke_pacman(state: MkosiState, packages: Sequence[str], apivfs: bool = True) -> None: +def pacman_cmd(state: MkosiState) -> list[str]: gpgdir = state.pkgmngr / "etc/pacman.d/gnupg/" gpgdir = gpgdir if gpgdir.exists() else Path("/etc/pacman.d/gnupg/") @@ -98,7 +98,6 @@ def invoke_pacman(state: MkosiState, packages: Sequence[str], apivfs: bool = Tru "--color", "auto", "--noconfirm", "--needed", - "-Sy", *sort_packages(packages), ] # If we're generating a bootable image, we'll do so with a prebuilt initramfs, so no need for an @@ -106,6 +105,10 @@ def invoke_pacman(state: MkosiState, packages: Sequence[str], apivfs: bool = Tru if state.config.bootable != ConfigFeature.disabled: cmdline += ["--assume-installed", "initramfs"] - bwrap(cmdline, + return cmdline + + +def invoke_pacman(state: MkosiState, packages: Sequence[str], apivfs: bool = True) -> None: + bwrap(pacman_cmd(state) + ["-Sy"] + sort_packages(packages), apivfs=state.root if apivfs else None, env=dict(KERNEL_INSTALL_BYPASS="1") | state.config.environment) diff --git a/mkosi/installer/zypper.py b/mkosi/installer/zypper.py index 6304c0bb6..a536a1123 100644 --- a/mkosi/installer/zypper.py +++ b/mkosi/installer/zypper.py @@ -46,27 +46,28 @@ def setup_zypper(state: MkosiState, repos: Sequence[Repo]) -> None: f.write(f"{url}\n") -def invoke_zypper( - state: MkosiState, - verb: str, - packages: Sequence[str], - options: Sequence[str] = (), - apivfs: bool = True, -) -> None: - cmdline = [ +def zypper_cmd(state: MkosiState) -> list[str]: + return [ + "env", + f"ZYPP_CONF={state.pkgmngr / 'etc/zypp/zypp.conf'}", "zypper", f"--root={state.root}", f"--cache-dir={state.cache_dir}", f"--reposd-dir={state.pkgmngr / 'etc/zypp/repos.d'}", "--gpg-auto-import-keys" if state.config.repository_key_check else "--no-gpg-checks", "--non-interactive", - verb, - *options, - *packages, ] - bwrap(cmdline, + +def invoke_zypper( + state: MkosiState, + verb: str, + packages: Sequence[str], + options: Sequence[str] = (), + apivfs: bool = True, +) -> None: + bwrap(zypper_cmd(state) + [verb, *packages, *options], apivfs=state.root if apivfs else None, - env=dict(ZYPP_CONF=str(state.pkgmngr / "etc/zypp/zypp.conf"), KERNEL_INSTALL_BYPASS="1") | state.config.environment) + env=dict(KERNEL_INSTALL_BYPASS="1") | state.config.environment) fixup_rpmdb_location(state.root) -- 2.47.2