From 391eebcd9f3382c140971613f127960e1f7c8a53 Mon Sep 17 00:00:00 2001 From: Daan De Meyer Date: Wed, 5 Jul 2023 09:38:57 +0200 Subject: [PATCH] Make BuildSources more flexible 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 | 6 ++++-- mkosi/__init__.py | 20 +++++++++++++++++--- mkosi/config.py | 35 +++++++++++++++++++---------------- 3 files changed, 40 insertions(+), 21 deletions(-) diff --git a/mkosi.md b/mkosi.md index e76fc0a72..86c48901a 100644 --- 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=` diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 37a779064..87de87a0f 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -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), diff --git a/mkosi/config.py b/mkosi/config.py index e1d86d95a..2bc181f37 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -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( -- 2.47.2