]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
config: add PackageManagerTrees= option
authorJoerg Behrmann <behrmann@physik.fu-berlin.de>
Thu, 8 Jun 2023 13:01:23 +0000 (15:01 +0200)
committerJoerg Behrmann <behrmann@physik.fu-berlin.de>
Thu, 8 Jun 2023 14:45:42 +0000 (16:45 +0200)
mkosi.md
mkosi/__init__.py
mkosi/config.py
mkosi/distributions/arch.py
mkosi/distributions/fedora.py
tests/test_parse_load_args.py
tests/test_util.py

index b1bdb5724f89a00f1b87a7f24b2947218f894fe0..9deca903556cff75638069ea4a89e9a83ef51859 100644 (file)
--- a/mkosi.md
+++ b/mkosi.md
@@ -690,6 +690,19 @@ they should be specified with a boolean argument: either "1", "yes", or "true" t
   file may be provided too. `mkosi.skeleton.tar` will be automatically
   used if found in the local directory.
 
+`PackageManagerTrees=`, `--package-manager-tree=`
+
+: This option mirrors the above `SkeletonTrees=` option and defaults to the
+  same value if not configured otherwise, but installs the files to a
+  subdirectory of the workspace directory instead of the OS tree. This
+  subdirectory of the workspace is used to configure the package manager.
+
+: `SkeletonTrees=` and `PackageManagerTrees=` fulfill similar roles. Use
+  `SkeletonTrees=` if you want the files to be present in the final image. Use
+  `PackageManagerTrees=` if you don't want the files to be present in the final
+  image, e.g. when building an initrd or if you want to refer to paths outside
+  of the image in your repository configuration.
+
 `ExtraTrees=`, `--extra-tree=`
 
 : Takes a colon separated pair of paths. The first path refers to a
index 230385177414b51ca628976c2cc1dbd316cf5fe5..719d102c766d46d8ecee02abf9c455d29999bb30 100644 (file)
@@ -523,6 +523,24 @@ def install_skeleton_trees(state: MkosiState) -> None:
                 shutil.unpack_archive(source, t)
 
 
+def install_package_manager_trees(state: MkosiState) -> None:
+    if not state.config.package_manager_trees:
+        return
+
+    with complete_step("Copying in package maneger file trees…"):
+        for source, target in state.config.package_manager_trees:
+            t = state.workspace / "pkgmngr"
+            if target:
+                t = state.workspace / "pkgmngr" / target.relative_to("/")
+
+            t.parent.mkdir(mode=0o755, parents=True, exist_ok=True)
+
+            if source.is_dir() or target:
+                copy_path(source, t, preserve_owner=False)
+            else:
+                shutil.unpack_archive(source, t)
+
+
 def install_extra_trees(state: MkosiState) -> None:
     if not state.config.extra_trees:
         return
@@ -815,6 +833,7 @@ def install_unified_kernel(state: MkosiState, roothash: Optional[str]) -> None:
                 *(["--mirror", state.config.mirror] if state.config.mirror else []),
                 "--repository-key-check", yes_no(state.config.repository_key_check),
                 "--repositories", ",".join(state.config.repositories),
+                "--package-manager-tree", ",".join(format_source_target(s, t) for s, t in state.config.package_manager_trees),
                 *(["--compress-output", str(state.config.compress_output)] if state.config.compress_output else []),
                 "--with-network", yes_no(state.config.with_network),
                 "--cache-only", yes_no(state.config.cache_only),
@@ -1246,11 +1265,15 @@ def line_join_list(
     return "\n                                ".join(items)
 
 
+def format_source_target(source: Path, target: Optional[Path]) -> str:
+    return f"{source}:{target}" if target else f"{source}"
+
+
 def line_join_source_target_list(array: Sequence[tuple[Path, Optional[Path]]]) -> str:
     if not array:
         return "none"
 
-    items = [f"{source}:{target}" if target else f"{source}" for source, target in array]
+    items = [format_source_target(source, target) for source, target in array]
     return "\n                                ".join(items)
 
 
@@ -1299,6 +1322,7 @@ def summary(args: MkosiArgs, config: MkosiConfig) -> str:
                       Packages: {line_join_list(config.packages)}
             With Documentation: {yes_no(config.with_docs)}
                 Skeleton Trees: {line_join_source_target_list(config.skeleton_trees)}
+         Package Manager Trees: {line_join_source_target_list(config.package_manager_trees)}
                    Extra Trees: {line_join_source_target_list(config.extra_trees)}
         Clean Package Metadata: {yes_no_auto(config.clean_package_metadata)}
                   Remove Files: {line_join_list(config.remove_files)}
index 2a7f6e24fa63d11089fb0803c055a69d0c0c1438..b95a9eb2aec16d2a33d99dac86e3bb25e107ed83 100644 (file)
@@ -260,6 +260,10 @@ def config_default_mirror(namespace: argparse.Namespace) -> Optional[str]:
     return None
 
 
+def config_default_package_manager_tree(namespace: argparse.Namespace) -> list[tuple[Path, Optional[Path]]]:
+    return getattr(namespace, "skeleton_trees", [])
+
+
 def make_enum_parser(type: Type[enum.Enum]) -> Callable[[str], enum.Enum]:
     def parse_enum(value: str) -> enum.Enum:
         try:
@@ -600,6 +604,7 @@ class MkosiConfig:
     base_trees: list[Path]
     extra_trees: list[tuple[Path, Optional[Path]]]
     skeleton_trees: list[tuple[Path, Optional[Path]]]
+    package_manager_trees: list[tuple[Path, Optional[Path]]]
     clean_package_metadata: ConfigFeature
     remove_files: list[str]
     environment: dict[str, str]
@@ -927,6 +932,12 @@ class MkosiConfigParser:
             parse=config_make_list_parser(delimiter=",", parse=parse_source_target_paths),
             paths=("mkosi.skeleton", "mkosi.skeleton.tar"),
         ),
+        MkosiConfigSetting(
+            dest="package_manager_trees",
+            section="Content",
+            parse=config_make_list_parser(delimiter=",", parse=parse_source_target_paths),
+            default_factory=config_default_package_manager_tree,
+        ),
         MkosiConfigSetting(
             dest="clean_package_metadata",
             section="Content",
@@ -1630,6 +1641,13 @@ class MkosiConfigParser:
             dest="skeleton_trees",
             action=action,
         )
+        group.add_argument(
+            "--package-manager-tree",
+            metavar="PATH",
+            help="Use a package manager tree to configure the package manager",
+            dest="package_manager_trees",
+            action=action,
+        )
         group.add_argument(
             "--clean-package-metadata",
             metavar="FEATURE",
index b719f2574685f198b34be80ab0035adbfe8d5217..8016b2563ace2b65119d5b908dba7f59903d2767 100644 (file)
@@ -84,6 +84,15 @@ class ArchInstaller(DistributionInstaller):
                     )
                 )
 
+            if any(state.pkgmngr.joinpath("etc/pacman.d/").glob("*.conf")):
+                f.write(
+                    dedent(
+                        f"""\
+
+                        Include = {state.pkgmngr}/etc/pacman.d/*.conf
+                        """
+                    )
+                )
 
         return invoke_pacman(state, packages, apivfs=apivfs)
 
index 84a421be9131021b119a87dcdaa6cc169a1db115..a57d90f9b763ba8aa85b8a14f93c1a49beecfd8d 100644 (file)
@@ -174,6 +174,7 @@ def invoke_dnf(
         "--setopt=keepcache=1",
         "--setopt=install_weak_deps=0",
         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=logdir={state.pkgmngr / 'var/log'}",
         f"--setopt=persistdir={state.pkgmngr / 'var/lib/dnf'}",
index 362c9f014e77ba218a9d93e2508e8203c011b9ed..9d045089feb4c0479b5d29f0f0560e64162f4ce9 100644 (file)
@@ -12,8 +12,8 @@ from typing import Iterator, List, Optional
 
 import pytest
 
+from mkosi.config import MkosiArgs, MkosiConfig, MkosiConfigParser
 from mkosi.util import Compression, Distribution, Verb
-from mkosi.config import MkosiConfigParser, MkosiConfig, MkosiArgs
 
 
 @contextmanager
@@ -360,3 +360,28 @@ def test_match_imageversion(op: str, version: str) -> None:
         assert ("testpkg1" in conf.packages) == opfunc(123, version)
         assert ("testpkg2" in conf.packages) == opfunc(123, version)
         assert "testpkg3" not in conf.packages
+
+
+@pytest.mark.parametrize(
+    "skel,pkgmngr", itertools.product(
+        [None, Path("/foo"), Path("/bar")],
+        [None, Path("/foo"), Path("/bar")],
+    )
+)
+def test_package_manager_tree(skel: Optional[Path], pkgmngr: Optional[Path]) -> None:
+    with cd_temp_dir():
+        config = Path("mkosi.conf")
+        with config.open("w") as f:
+            f.write("[Content]\n")
+            if skel is not None:
+                f.write(f"SkeletonTrees={skel}\n")
+            if pkgmngr is not None:
+                f.write(f"PackageManagerTrees={pkgmngr}\n")
+
+        conf = parse([])[1][0]
+
+        skel_expected = [(skel, None)] if skel is not None else []
+        pkgmngr_expected = [(pkgmngr, None)] if pkgmngr is not None else skel_expected
+
+        assert conf.skeleton_trees == skel_expected
+        assert conf.package_manager_trees == pkgmngr_expected
index 758978b9aec938d649d571f9a34e739be0a63871..fa9717964e10a09d53f462c14e37f70ed68f79ff 100644 (file)
@@ -1,10 +1,7 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
-from mkosi.util import (
-    Compression,
-    Distribution,
-    PackageType,
-)
+from mkosi.util import Compression, Distribution, PackageType
+
 
 def test_distribution() -> None:
     assert Distribution.fedora.package_type == PackageType.rpm