]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Make archive.py independent of Context
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 16 Jan 2024 13:21:52 +0000 (14:21 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Tue, 16 Jan 2024 13:59:56 +0000 (14:59 +0100)
Let's make these functions slightly more generic by passing in a
tools directory and a sandbox instead of the full Context object.

mkosi/__init__.py
mkosi/archive.py
mkosi/distributions/debian.py
mkosi/distributions/gentoo.py

index f00bc8e303eec90dd58ff602c8f4a55d660d7d9c..4264fef7e25b27a538d4720dc30fac28725e9c9e 100644 (file)
@@ -109,7 +109,11 @@ def mount_base_trees(context: Context) -> Iterator[None]:
             if path.is_dir():
                 bases += [path]
             elif path.suffix == ".tar":
-                extract_tar(context, path, d)
+                extract_tar(
+                    path, d,
+                    tools=context.config.tools(),
+                    sandbox=context.sandbox(options=["--bind", d, d]),
+                )
                 bases += [d]
             elif path.suffix == ".raw":
                 run(["systemd-dissect", "-M", path, d])
@@ -1344,7 +1348,12 @@ def install_tree(
     if src.is_dir() or (src.is_file() and target):
         copy()
     elif src.suffix == ".tar":
-        extract_tar(context, src, t)
+        extract_tar(
+            src, t,
+            tools=context.config.tools(),
+            # Make sure tar uses user/group information from the root directory instead of the host.
+            sandbox=context.sandbox(options=["--bind", dst, dst, *finalize_passwd_mounts(dst)]),
+        )
     elif src.suffix == ".raw":
         run(
             ["systemd-dissect", "--copy-from", src, "/", t],
@@ -1558,7 +1567,11 @@ def build_microcode_initrd(context: Context) -> Optional[Path]:
             for p in intel.iterdir():
                 f.write(p.read_bytes())
 
-    make_cpio(context, root, microcode)
+    make_cpio(
+        root, microcode,
+        tools=context.config.tools(),
+        sandbox=context.sandbox(options=["--ro-bind", root, root]),
+    )
 
     return microcode
 
@@ -1569,14 +1582,16 @@ def build_kernel_modules_initrd(context: Context, kver: str) -> Path:
         return kmods
 
     make_cpio(
-        context, context.root, kmods,
-        gen_required_kernel_modules(
+        context.root, kmods,
+        files=gen_required_kernel_modules(
             context.root, kver,
             include=context.config.kernel_modules_initrd_include,
             exclude=context.config.kernel_modules_initrd_exclude,
             host=context.config.kernel_modules_initrd_include_host,
             sandbox=context.sandbox(options=["--ro-bind", context.root, context.root]),
-        )
+        ),
+        tools=context.config.tools(),
+        sandbox=context.sandbox(options=["--ro-bind", context.root, context.root]),
     )
 
     # Debian/Ubuntu do not compress their kernel modules, so we compress the initramfs instead. Note that
@@ -1863,7 +1878,14 @@ def install_uki(context: Context, partitions: Sequence[Partition]) -> None:
 
 def make_uki(context: Context, stub: Path, kver: str, kimg: Path, output: Path) -> None:
     microcode = build_microcode_initrd(context)
-    make_cpio(context, context.root, context.workspace / "initrd")
+    make_cpio(
+        context.root, context.workspace / "initrd",
+        tools=context.config.tools(),
+        sandbox=context.sandbox(
+            # Make sure cpio uses user/group information from the root directory instead of the host.
+            options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)],
+        ),
+    )
     maybe_compress(context, context.config.compress_output, context.workspace / "initrd", context.workspace / "initrd")
 
     initrds = [microcode] if microcode else []
@@ -2901,9 +2923,23 @@ def build_image(args: Args, config: Config) -> None:
         copy_initrd(context)
 
         if context.config.output_format == OutputFormat.tar:
-            make_tar(context, context.root, context.staging / context.config.output_with_format)
+            make_tar(
+                context.root, context.staging / context.config.output_with_format,
+                tools=context.config.tools(),
+                # Make sure tar uses user/group information from the root directory instead of the host.
+                sandbox=context.sandbox(
+                    options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)],
+                ),
+            )
         elif context.config.output_format == OutputFormat.cpio:
-            make_cpio(context, context.root, context.staging / context.config.output_with_format)
+            make_cpio(
+                context.root, context.staging / context.config.output_with_format,
+                tools=context.config.tools(),
+                # Make sure cpio uses user/group information from the root directory instead of the host.
+                sandbox=context.sandbox(
+                    options=["--ro-bind", context.root, context.root, *finalize_passwd_mounts(context.root)],
+                ),
+            )
         elif context.config.output_format == OutputFormat.uki:
             assert stub and kver and kimg
             make_uki(context, stub, kver, kimg, context.staging / context.config.output_with_format)
index 4d420a85064c53d32bda5b01589a959140f2f56a..a681d5a1240ec767cae516d53c3e669194e092fa 100644 (file)
@@ -1,17 +1,16 @@
 # SPDX-License-Identifier: LGPL-2.1+
 
 import os
-from collections.abc import Iterable
+from collections.abc import Iterable, Sequence
 from pathlib import Path
 from typing import Optional
 
-from mkosi.context import Context
 from mkosi.log import log_step
 from mkosi.run import find_binary, run
-from mkosi.sandbox import finalize_passwd_mounts
+from mkosi.types import PathString
 
 
-def tar_binary(context: Context) -> str:
+def tar_binary(*, tools: Path = Path("/")) -> str:
     # Some distros (Mandriva) install BSD tar as "tar", hence prefer
     # "gtar" if it exists, which should be GNU tar wherever it exists.
     # We are interested in exposing same behaviour everywhere hence
@@ -19,11 +18,11 @@ def tar_binary(context: Context) -> str:
     # everywhere. In particular given the limited/different SELinux
     # support in BSD tar and the different command line syntax
     # compared to GNU tar.
-    return "gtar" if find_binary("gtar", root=context.config.tools()) else "tar"
+    return "gtar" if find_binary("gtar", root=tools) else "tar"
 
 
-def cpio_binary(context: Context) -> str:
-    return "gcpio" if find_binary("gcpio", root=context.config.tools()) else "cpio"
+def cpio_binary(*, tools: Path = Path("/")) -> str:
+    return "gcpio" if find_binary("gcpio", root=tools) else "cpio"
 
 
 def tar_exclude_apivfs_tmp() -> list[str]:
@@ -37,13 +36,13 @@ def tar_exclude_apivfs_tmp() -> list[str]:
     ]
 
 
-def make_tar(context: Context, src: Path, dst: Path) -> None:
+def make_tar(src: Path, dst: Path, *, tools: Path = Path("/"), sandbox: Sequence[PathString] = ()) -> None:
     log_step(f"Creating tar archive {dst}…")
 
     with dst.open("wb") as f:
         run(
             [
-                tar_binary(context),
+                tar_binary(tools=tools),
                 "--create",
                 "--file", "-",
                 "--directory", src,
@@ -60,19 +59,25 @@ def make_tar(context: Context, src: Path, dst: Path) -> None:
                 ".",
             ],
             stdout=f,
-            # Make sure tar uses user/group information from the root directory instead of the host.
-            sandbox=context.sandbox(options=["--ro-bind", src, src, *finalize_passwd_mounts(src)]),
+            sandbox=sandbox,
         )
 
 
-def extract_tar(context: Context, src: Path, dst: Path, log: bool = True) -> None:
+def extract_tar(
+    src: Path,
+    dst: Path,
+    *,
+    log: bool = True,
+    tools: Path = Path("/"),
+    sandbox: Sequence[PathString] = (),
+) -> None:
     if log:
         log_step(f"Extracting tar archive {src}…")
 
     with src.open("rb") as f:
         run(
             [
-                tar_binary(context),
+                tar_binary(tools=tools),
                 "--extract",
                 "--file", "-",
                 "--directory", dst,
@@ -88,12 +93,18 @@ def extract_tar(context: Context, src: Path, dst: Path, log: bool = True) -> Non
                 *tar_exclude_apivfs_tmp(),
             ],
             stdin=f,
-            # Make sure tar uses user/group information from the root directory instead of the host.
-            sandbox=context.sandbox(options=["--bind", dst, dst, *finalize_passwd_mounts(dst)]),
+            sandbox=sandbox,
         )
 
 
-def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[Path]] = None) -> None:
+def make_cpio(
+    src: Path,
+    dst: Path,
+    *,
+    files: Optional[Iterable[Path]] = None,
+    tools: Path = Path("/"),
+    sandbox: Sequence[PathString] = (),
+) -> None:
     if not files:
         files = src.rglob("*")
     files = sorted(files)
@@ -103,7 +114,7 @@ def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[P
     with dst.open("wb") as f:
         run(
             [
-                cpio_binary(context),
+                cpio_binary(tools=tools),
                 "--create",
                 "--reproducible",
                 "--null",
@@ -114,5 +125,5 @@ def make_cpio(context: Context, src: Path, dst: Path, files: Optional[Iterable[P
             input="\0".join(os.fspath(f.relative_to(src)) for f in files),
             stdout=f,
             # Make sure cpio uses user/group information from the root directory instead of the host.
-            sandbox=context.sandbox(options=["--ro-bind", src, src, *finalize_passwd_mounts(dst)]),
+            sandbox=sandbox,
         )
index 43314825f54624fe2694124c4e9146cb54a182d1..1001eb8d69e79a2be9ed9aae857316137c476f13 100644 (file)
@@ -12,6 +12,7 @@ from mkosi.distributions import Distribution, DistributionInstaller, PackageType
 from mkosi.installer.apt import createrepo_apt, invoke_apt, setup_apt
 from mkosi.log import die
 from mkosi.run import run
+from mkosi.sandbox import finalize_passwd_mounts
 from mkosi.util import umask
 
 
@@ -147,7 +148,15 @@ class Installer(DistributionInstaller):
                 tempfile.NamedTemporaryFile() as o
             ):
                 run(["dpkg-deb", "--fsys-tarfile", "/dev/stdin"], stdin=i, stdout=o, sandbox=context.sandbox())
-                extract_tar(context, Path(o.name), context.root, log=False)
+                extract_tar(
+                    Path(o.name), context.root,
+                    log=False,
+                    tools=context.config.tools(),
+                    # Make sure tar uses user/group information from the root directory instead of the host.
+                    sandbox=context.sandbox(
+                        options=["--bind", context.root, context.root, *finalize_passwd_mounts(context.root)],
+                    ),
+                )
 
         # Finally, run apt to properly install packages in the chroot without having to worry that maintainer
         # scripts won't find basic tools that they depend on.
index e6dfe95bc1b756110e10f789688ef26d1d2932c0..eca50d159d9c8b5f8c0c34d167373c5c48749758 100644 (file)
@@ -132,7 +132,11 @@ class Installer(DistributionInstaller):
 
         if not any(stage3.iterdir()):
             with complete_step(f"Extracting {stage3_tar.name} to {stage3}"):
-                extract_tar(context, stage3_tar, stage3)
+                extract_tar(
+                    stage3_tar, stage3,
+                    tools=context.config.tools(),
+                    sandbox=context.sandbox(options=["--bind", context.root, context.root]),
+                )
 
         for d in ("binpkgs", "distfiles", "repos/gentoo"):
             (context.cache_dir / d).mkdir(parents=True, exist_ok=True)