We put this in a new "installer" submodule as well.
from mkosi.config import MkosiConfig
from mkosi.distributions.centos import CentosInstaller
-from mkosi.distributions.fedora import Repo
+from mkosi.installer.dnf import Repo
class AlmaInstaller(CentosInstaller):
from mkosi.architecture import Architecture
from mkosi.config import MkosiConfig
from mkosi.distributions import DistributionInstaller
-from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf
+from mkosi.installer.dnf import Repo, invoke_dnf, setup_dnf
from mkosi.log import complete_step, die
from mkosi.state import MkosiState
from mkosi.tree import rmtree
# SPDX-License-Identifier: LGPL-2.1+
-import os
-import shutil
-from collections.abc import Iterable, Mapping, Sequence
-from pathlib import Path
-from textwrap import dedent
-from typing import Any, NamedTuple
+from collections.abc import Sequence
from mkosi.architecture import Architecture
from mkosi.distributions import DistributionInstaller
+from mkosi.installer.dnf import Repo, invoke_dnf, setup_dnf
from mkosi.log import die
-from mkosi.run import bwrap
from mkosi.state import MkosiState
-from mkosi.tree import rmtree
-from mkosi.util import sort_packages
class FedoraInstaller(DistributionInstaller):
return False
# If neither is 'rawhide', both must be integers
return int(release) >= int(threshold)
-
-
-class Repo(NamedTuple):
- id: str
- url: str
- gpgurls: tuple[str, ...]
- enabled: bool = True
-
-
-def setup_dnf(state: MkosiState, repos: Sequence[Repo]) -> None:
- config = state.pkgmngr / "etc/dnf/dnf.conf"
-
- if not config.exists():
- config.parent.mkdir(exist_ok=True, parents=True)
- config.write_text(
- dedent(
- """\
- [main]
- install_weak_deps=0
- """
- )
- )
-
- repofile = state.pkgmngr / "etc/yum.repos.d/mkosi.repo"
- if not repofile.exists():
- repofile.parent.mkdir(exist_ok=True, parents=True)
- with repofile.open("w") as f:
- for repo in repos:
- f.write(
- dedent(
- f"""\
- [{repo.id}]
- name={repo.id}
- {repo.url}
- gpgcheck=1
- enabled={int(repo.enabled)}
- """
- )
- )
-
- for i, url in enumerate(repo.gpgurls):
- f.write("gpgkey=" if i == 0 else len("gpgkey=") * " ")
- 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"
-
- cmdline = [
- dnf,
- "--assumeyes",
- f"--config={state.pkgmngr / 'etc/dnf/dnf.conf'}",
- "--best",
- f"--releasever={state.config.release}",
- f"--installroot={state.root}",
- "--setopt=keepcache=1",
- f"--setopt=cachedir={state.cache_dir}",
- f"--setopt=reposdir={state.pkgmngr / 'etc/yum.repos.d'}",
- f"--setopt=varsdir={state.pkgmngr / 'etc/dnf/vars'}",
- f"--setopt=persistdir={state.pkgmngr / 'var/lib/dnf'}",
- "--setopt=check_config_file_age=0",
- "--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"]
-
- if state.config.repositories:
- opt = "--enable-repo" if dnf.endswith("dnf5") else "--enablerepo"
- cmdline += [f"{opt}={repo}" for repo in state.config.repositories]
-
- # TODO: this breaks with a local, offline repository created with 'createrepo'
- if state.config.cache_only and not state.config.local_mirror:
- cmdline += ["--cacheonly"]
-
- if not state.config.architecture.is_native():
- cmdline += [f"--forcearch={state.installer.architecture(state.config.architecture)}"]
-
- if not state.config.with_docs:
- cmdline += ["--no-docs" if dnf.endswith("dnf5") else "--nodocs"]
-
- cmdline += [command, *sort_packages(packages)]
-
- bwrap(cmdline,
- apivfs=state.root if apivfs else None,
- env=dict(KERNEL_INSTALL_BYPASS="1") | env | state.config.environment)
-
- fixup_rpmdb_location(state.root)
-
- # The log directory is always interpreted relative to the install root so there's nothing we can do but
- # to remove the log files from the install root afterwards.
- for p in (state.root / "var/log").iterdir():
- if any(p.name.startswith(prefix) for prefix in ("dnf", "hawkey", "yum")):
- p.unlink()
-
-
-def fixup_rpmdb_location(root: Path) -> None:
- # On Debian, rpm/dnf ship with a patch to store the rpmdb under ~/ so it needs to be copied back in the
- # right location, otherwise the rpmdb will be broken. See: https://bugs.debian.org/1004863. We also
- # replace it with a symlink so that any further rpm operations immediately use the correct location.
- rpmdb_home = root / "root/.rpmdb"
- if not rpmdb_home.exists() or rpmdb_home.is_symlink():
- return
-
- # Take into account the new location in F36
- rpmdb = root / "usr/lib/sysimage/rpm"
- if not rpmdb.exists():
- rpmdb = root / "var/lib/rpm"
- rmtree(rpmdb)
- shutil.move(rpmdb_home, rpmdb)
- rpmdb_home.symlink_to(os.path.relpath(rpmdb, start=rpmdb_home.parent))
from mkosi.architecture import Architecture
from mkosi.distributions import DistributionInstaller
-from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf
+from mkosi.installer.dnf import Repo, invoke_dnf, setup_dnf
from mkosi.log import die
from mkosi.state import MkosiState
from mkosi.architecture import Architecture
from mkosi.distributions import DistributionInstaller
-from mkosi.distributions.fedora import Repo, invoke_dnf, setup_dnf
+from mkosi.installer.dnf import Repo, invoke_dnf, setup_dnf
from mkosi.log import die
from mkosi.state import MkosiState
from mkosi.architecture import Architecture
from mkosi.distributions import DistributionInstaller
-from mkosi.distributions.fedora import Repo, fixup_rpmdb_location, invoke_dnf, setup_dnf
+from mkosi.installer.dnf import Repo, fixup_rpmdb_location, invoke_dnf, setup_dnf
from mkosi.log import die
from mkosi.run import bwrap
from mkosi.state import MkosiState
from mkosi.config import MkosiConfig
from mkosi.distributions.centos import CentosInstaller
-from mkosi.distributions.fedora import Repo
+from mkosi.installer.dnf import Repo
class RockyInstaller(CentosInstaller):
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1+
--- /dev/null
+# SPDX-License-Identifier: LGPL-2.1+
+import os
+import shutil
+import textwrap
+from collections.abc import Iterable, Mapping, Sequence
+from pathlib import Path
+from typing import Any, NamedTuple
+
+from mkosi.run import bwrap
+from mkosi.state import MkosiState
+from mkosi.tree import rmtree
+from mkosi.util import sort_packages
+
+
+class Repo(NamedTuple):
+ id: str
+ url: str
+ gpgurls: tuple[str, ...]
+ enabled: bool = True
+
+
+def setup_dnf(state: MkosiState, repos: Sequence[Repo]) -> None:
+ 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
+ """
+ )
+ )
+
+ repofile = state.pkgmngr / "etc/yum.repos.d/mkosi.repo"
+ if not repofile.exists():
+ repofile.parent.mkdir(exist_ok=True, parents=True)
+ with repofile.open("w") as f:
+ for repo in repos:
+ f.write(
+ textwrap.dedent(
+ f"""\
+ [{repo.id}]
+ name={repo.id}
+ {repo.url}
+ gpgcheck=1
+ enabled={int(repo.enabled)}
+ """
+ )
+ )
+
+ for i, url in enumerate(repo.gpgurls):
+ f.write("gpgkey=" if i == 0 else len("gpgkey=") * " ")
+ 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"
+
+ cmdline = [
+ dnf,
+ "--assumeyes",
+ f"--config={state.pkgmngr / 'etc/dnf/dnf.conf'}",
+ "--best",
+ f"--releasever={state.config.release}",
+ f"--installroot={state.root}",
+ "--setopt=keepcache=1",
+ f"--setopt=cachedir={state.cache_dir}",
+ f"--setopt=reposdir={state.pkgmngr / 'etc/yum.repos.d'}",
+ f"--setopt=varsdir={state.pkgmngr / 'etc/dnf/vars'}",
+ f"--setopt=persistdir={state.pkgmngr / 'var/lib/dnf'}",
+ "--setopt=check_config_file_age=0",
+ "--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"]
+
+ if state.config.repositories:
+ opt = "--enable-repo" if dnf.endswith("dnf5") else "--enablerepo"
+ cmdline += [f"{opt}={repo}" for repo in state.config.repositories]
+
+ # TODO: this breaks with a local, offline repository created with 'createrepo'
+ if state.config.cache_only and not state.config.local_mirror:
+ cmdline += ["--cacheonly"]
+
+ if not state.config.architecture.is_native():
+ cmdline += [f"--forcearch={state.installer.architecture(state.config.architecture)}"]
+
+ if not state.config.with_docs:
+ cmdline += ["--no-docs" if dnf.endswith("dnf5") else "--nodocs"]
+
+ cmdline += [command, *sort_packages(packages)]
+
+ bwrap(cmdline,
+ apivfs=state.root if apivfs else None,
+ env=dict(KERNEL_INSTALL_BYPASS="1") | env | state.config.environment)
+
+ fixup_rpmdb_location(state.root)
+
+ # The log directory is always interpreted relative to the install root so there's nothing we can do but
+ # to remove the log files from the install root afterwards.
+ for p in (state.root / "var/log").iterdir():
+ if any(p.name.startswith(prefix) for prefix in ("dnf", "hawkey", "yum")):
+ p.unlink()
+
+
+def fixup_rpmdb_location(root: Path) -> None:
+ # On Debian, rpm/dnf ship with a patch to store the rpmdb under ~/ so it needs to be copied back in the
+ # right location, otherwise the rpmdb will be broken. See: https://bugs.debian.org/1004863. We also
+ # replace it with a symlink so that any further rpm operations immediately use the correct location.
+ rpmdb_home = root / "root/.rpmdb"
+ if not rpmdb_home.exists() or rpmdb_home.is_symlink():
+ return
+
+ # Take into account the new location in F36
+ rpmdb = root / "usr/lib/sysimage/rpm"
+ if not rpmdb.exists():
+ rpmdb = root / "var/lib/rpm"
+ rmtree(rpmdb)
+ shutil.move(rpmdb_home, rpmdb)
+ rpmdb_home.symlink_to(os.path.relpath(rpmdb, start=rpmdb_home.parent))