]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Make BuildSources more flexible 1666/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Wed, 5 Jul 2023 07:38:57 +0000 (09:38 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 6 Jul 2023 10:23:36 +0000 (12:23 +0200)
Currently, when you want to build multiple projects together, you
have to make the other projects subdirectories of the one with the
mkosi config, which is inconvenient. To make this more flexible, let's
allow specifying multiple source trees and where to mount them under
/work/src so that multiple projects can be mounted in a fixed location
regardless of their location on the host.

mkosi.md
mkosi/__init__.py
mkosi/config.py

index e76fc0a728704e67ce671b4659b16564c2d30d22..86c48901a1aee1a57d4898f02fe8f90a64b3ed2b 100644 (file)
--- a/mkosi.md
+++ b/mkosi.md
@@ -725,8 +725,10 @@ they should be specified with a boolean argument: either "1", "yes", or "true" t
 
 `BuildSources=`, `--build-sources=`
 
-: Takes a path to a source tree to mount into the development image, if
-  the build script is used.
+: Takes a list of colon-separated pairs of paths to source trees and where to mount them in the development
+  image, if the build script is used. Every target path is prefixed with `/work/src` and all build sources
+  are sorted lexicographically by mount target before mounting so that top level paths are mounted first. By
+  default, the current working directory is mounted to `/work/src`.
 
 `BuildPackages=`, `--build-package=`
 
index 37a779064f74e585975b3a31a164551e59f8d509..87de87a0fb328ea42eb35f09f3123b8b5f4bd07a 100644 (file)
@@ -294,6 +294,16 @@ def mount_build_overlay(state: MkosiState, read_only: bool = False) -> ContextMa
     return mount_overlay([state.root], state.workspace / "build-overlay", state.root, read_only)
 
 
+def finalize_sources(config: MkosiConfig) -> list[tuple[Path, Path]]:
+    sources = [
+        (src, Path("work/src") / (str(target).lstrip("/") if target else "."))
+        for src, target
+        in config.build_sources
+    ]
+
+    return sorted(sources, key=lambda s: s[1])
+
+
 def run_prepare_script(state: MkosiState, build: bool) -> None:
     if state.config.prepare_script is None:
         return
@@ -301,11 +311,13 @@ def run_prepare_script(state: MkosiState, build: bool) -> None:
         return
 
     bwrap: list[PathString] = [
-        "--bind", state.config.build_sources, "/work/src",
         "--bind", state.config.prepare_script, "/work/prepare",
         "--chdir", "/work/src",
     ]
 
+    for src, target in finalize_sources(state.config):
+        bwrap += ["--bind", src, Path("/") / target]
+
     if build:
         with complete_step("Running prepare script in build overlay…"), mount_build_overlay(state):
             run_workspace_command(
@@ -1355,7 +1367,7 @@ def summary(args: MkosiArgs, config: MkosiConfig) -> str:
         Clean Package Metadata: {yes_no_auto(config.clean_package_metadata)}
                   Remove Files: {line_join_list(config.remove_files)}
                Remove Packages: {line_join_list(config.remove_packages)}
-                 Build Sources: {config.build_sources}
+                 Build Sources: {line_join_source_target_list(config.build_sources)}
                 Build Packages: {line_join_list(config.build_packages)}
                   Build Script: {path_or_none(config.build_script, check_script_input)}
      Run Tests in Build Script: {yes_no(config.with_tests)}
@@ -1849,13 +1861,15 @@ def run_build_script(state: MkosiState) -> None:
 
     with complete_step("Running build script…"), mount_build_overlay(state, read_only=True):
         bwrap: list[PathString] = [
-            "--bind", state.config.build_sources, "/work/src",
             "--bind", state.config.build_script, "/work/build-script",
             "--bind", state.install_dir, "/work/dest",
             "--bind", state.staging, "/work/out",
             "--chdir", "/work/src",
         ]
 
+        for src, target in finalize_sources(state.config):
+            bwrap += ["--bind", src, Path("/") / target]
+
         env = dict(
             WITH_DOCS=one_zero(state.config.with_docs),
             WITH_TESTS=one_zero(state.config.with_tests),
index e1d86d95a094161436b9dabd3035a1133d28c4a5..2bc181f3745ce8ca84620722a3f683abd83f2341 100644 (file)
@@ -116,16 +116,19 @@ def parse_path(value: str,
     return path
 
 
-def parse_source_target_paths(value: str) -> tuple[Path, Optional[Path]]:
-    src, sep, target = value.partition(':')
-    src_path = parse_path(src, required=False)
-    if sep:
-        target_path = parse_path(target, required=False, absolute=False, expanduser=False)
-        if not target_path.is_absolute():
-            die("Target path must be absolute")
-    else:
-        target_path = None
-    return src_path, target_path
+def make_source_target_paths_parser(absolute: bool = True) -> Callable[[str], tuple[Path, Optional[Path]]]:
+    def parse_source_target_paths(value: str) -> tuple[Path, Optional[Path]]:
+        src, sep, target = value.partition(':')
+        src_path = parse_path(src, required=False)
+        if sep:
+            target_path = parse_path(target, required=False, absolute=False, expanduser=False)
+            if absolute and not target_path.is_absolute():
+                die("Target path must be absolute")
+        else:
+            target_path = None
+        return src_path, target_path
+
+    return parse_source_target_paths
 
 
 def config_parse_string(dest: str, value: Optional[str], namespace: argparse.Namespace) -> Optional[str]:
@@ -619,7 +622,7 @@ class MkosiConfig:
     clean_package_metadata: ConfigFeature
     remove_files: list[str]
     environment: dict[str, str]
-    build_sources: Path
+    build_sources: list[tuple[Path, Optional[Path]]]
     build_dir: Optional[Path]
     build_packages: list[str]
     build_script: Optional[Path]
@@ -1010,7 +1013,7 @@ class MkosiConfigParser:
             long="--extra-tree",
             metavar="PATH",
             section="Content",
-            parse=config_make_list_parser(delimiter=",", parse=parse_source_target_paths),
+            parse=config_make_list_parser(delimiter=",", parse=make_source_target_paths_parser()),
             paths=("mkosi.extra", "mkosi.extra.tar"),
             help="Copy an extra tree on top of image",
         ),
@@ -1019,7 +1022,7 @@ class MkosiConfigParser:
             long="--skeleton-tree",
             metavar="PATH",
             section="Content",
-            parse=config_make_list_parser(delimiter=",", parse=parse_source_target_paths),
+            parse=config_make_list_parser(delimiter=",", parse=make_source_target_paths_parser()),
             paths=("mkosi.skeleton", "mkosi.skeleton.tar"),
             help="Use a skeleton tree to bootstrap the image before installing anything",
         ),
@@ -1028,7 +1031,7 @@ class MkosiConfigParser:
             long="--package-manager-tree",
             metavar="PATH",
             section="Content",
-            parse=config_make_list_parser(delimiter=",", parse=parse_source_target_paths),
+            parse=config_make_list_parser(delimiter=",", parse=make_source_target_paths_parser()),
             default_factory=config_default_package_manager_tree,
             help="Use a package manager tree to configure the package manager",
         ),
@@ -1058,8 +1061,8 @@ class MkosiConfigParser:
             dest="build_sources",
             metavar="PATH",
             section="Content",
-            parse=config_make_path_parser(),
-            default=Path("."),
+            parse=config_make_list_parser(delimiter=",", parse=make_source_target_paths_parser(absolute=False)),
+            default=[(Path("."), None)],
             help="Path for sources to build",
         ),
         MkosiConfigSetting(