From: Georges Discry Date: Fri, 15 Sep 2023 20:19:41 +0000 (+0200) Subject: Convert script settings to lists X-Git-Tag: v18~36^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F1903%2Fhead;p=thirdparty%2Fmkosi.git Convert script settings to lists With `mkosi.conf.d`, `mkosi.presets` and/or `[Match]`, it's become really easy to split the configuration of an image in logical parts. It might be done to isolate some settings that go together or to share the same configuration across several images. However, for each `mkosi.prepare`, `mkosi.build`, `mkosi.postinst` and `mkosi.finalize` step, only one script could be executed as the one with highest priority overrides the others. Each script is now managed as a list of executables so that it's also possible to split them if desired. Backward compatibility is kind of maintained by keeping the same options on the command line and by introducing aliases for the renamed INI settings (with a deprecation warning). These aliases also parse the settings as a list, so compatibility is still broken when a script was expected to override a previously defined one, as they are now both executed. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 8ab118191..5b3d6f04b 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -260,10 +260,10 @@ def finalize_mounts(config: MkosiConfig) -> list[PathString]: return flatten(["--bind", src, target] for src, target in sorted(set(sources), key=lambda s: s[1])) -def run_prepare_script(state: MkosiState, build: bool) -> None: - if state.config.prepare_script is None: +def run_prepare_scripts(state: MkosiState, build: bool) -> None: + if not state.config.prepare_scripts: return - if build and state.config.build_script is None: + if build and not state.config.build_scripts: return env = dict( @@ -276,43 +276,41 @@ def run_prepare_script(state: MkosiState, build: bool) -> None: MKOSI_GID=str(state.gid), ) - chroot: list[PathString] = chroot_cmd( - state.root, - options=[ - "--bind", state.config.prepare_script, "/work/prepare", - "--bind", Path.cwd(), "/work/src", - "--chdir", "/work/src", - "--setenv", "SRCDIR", "/work/src", - "--setenv", "BUILDROOT", "/", - ], - ) - - if build: - with complete_step("Running prepare script in build overlay…"), mount_build_overlay(state): - bwrap( - [state.config.prepare_script, "build"], - network=True, - readonly=True, - options=finalize_mounts(state.config), - scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), - env=env | state.config.environment, - stdin=sys.stdin, - ) - else: - with complete_step("Running prepare script…"): - bwrap( - [state.config.prepare_script, "final"], - network=True, - readonly=True, - options=finalize_mounts(state.config), - scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), - env=env | state.config.environment, - stdin=sys.stdin, + with contextlib.ExitStack() as stack: + if build: + stack.enter_context(mount_build_overlay(state)) + step_msg = "Running prepare script {} in build overlay…" + arg = "build" + else: + step_msg = "Running prepare script {}…" + arg = "final" + + for script in state.config.prepare_scripts: + chroot: list[PathString] = chroot_cmd( + state.root, + options=[ + "--bind", script, "/work/prepare", + "--bind", Path.cwd(), "/work/src", + "--chdir", "/work/src", + "--setenv", "SRCDIR", "/work/src", + "--setenv", "BUILDROOT", "/", + ], ) + with complete_step(step_msg.format(script)): + bwrap( + [script, arg], + network=True, + readonly=True, + options=finalize_mounts(state.config), + scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), + env=env | state.config.environment, + stdin=sys.stdin, + ) + -def run_build_script(state: MkosiState) -> None: - if state.config.build_script is None: +def run_build_scripts(state: MkosiState) -> None: + if not state.config.build_scripts: return env = dict( @@ -338,40 +336,40 @@ def run_build_script(state: MkosiState) -> None: CHROOT_BUILDDIR="/work/build", ) - chroot = chroot_cmd( - state.root, - options=[ - "--bind", state.config.build_script, "/work/build-script", - "--bind", state.install_dir, "/work/dest", - "--bind", state.staging, "/work/out", - "--bind", Path.cwd(), "/work/src", - *(["--bind", str(state.config.build_dir), "/work/build"] if state.config.build_dir else []), - "--chdir", "/work/src", - "--setenv", "SRCDIR", "/work/src", - "--setenv", "DESTDIR", "/work/dest", - "--setenv", "OUTPUTDIR", "/work/out", - "--setenv", "BUILDROOT", "/", - *(["--setenv", "BUILDDIR", "/work/build"] if state.config.build_dir else []), - "--remount-ro", "/", - ], - ) + with mount_build_overlay(state), mount_passwd(state.name, state.uid, state.gid, state.root): + for script in state.config.build_scripts: + chroot = chroot_cmd( + state.root, + options=[ + "--bind", script, "/work/build-script", + "--bind", state.install_dir, "/work/dest", + "--bind", state.staging, "/work/out", + "--bind", Path.cwd(), "/work/src", + *(["--bind", str(state.config.build_dir), "/work/build"] if state.config.build_dir else []), + "--chdir", "/work/src", + "--setenv", "SRCDIR", "/work/src", + "--setenv", "DESTDIR", "/work/dest", + "--setenv", "OUTPUTDIR", "/work/out", + "--setenv", "BUILDROOT", "/", + *(["--setenv", "BUILDDIR", "/work/build"] if state.config.build_dir else []), + "--remount-ro", "/", + ], + ) - with complete_step("Running build script…"),\ - mount_build_overlay(state),\ - mount_passwd(state.name, state.uid, state.gid, state.root): - bwrap( - [state.config.build_script, *(state.args.cmdline if state.args.verb == Verb.build else [])], - network=state.config.with_network, - readonly=True, - options=finalize_mounts(state.config), - scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), - env=env | state.config.environment, - stdin=sys.stdin, - ) + with complete_step(f"Running build script {script}…"): + bwrap( + [script, *(state.args.cmdline if state.args.verb == Verb.build else [])], + network=state.config.with_network, + readonly=True, + options=finalize_mounts(state.config), + scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), + env=env | state.config.environment, + stdin=sys.stdin, + ) -def run_postinst_script(state: MkosiState) -> None: - if state.config.postinst_script is None: +def run_postinst_scripts(state: MkosiState) -> None: + if not state.config.postinst_scripts: return env = dict( @@ -386,33 +384,34 @@ def run_postinst_script(state: MkosiState) -> None: MKOSI_GID=str(state.gid), ) - chroot = chroot_cmd( - state.root, - options=[ - "--bind", state.config.postinst_script, "/work/postinst", - "--bind", state.staging, "/work/out", - "--bind", Path.cwd(), "/work/src", - "--chdir", "/work/src", - "--setenv", "SRCDIR", "/work/src", - "--setenv", "OUTPUTDIR", "/work/out", - "--setenv", "BUILDROOT", "/", - ], - ) - - with complete_step("Running postinstall script…"): - bwrap( - [state.config.postinst_script, "final"], - network=state.config.with_network, - readonly=True, - options=finalize_mounts(state.config), - scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), - env=env | state.config.environment, - stdin=sys.stdin, + for script in state.config.postinst_scripts: + chroot = chroot_cmd( + state.root, + options=[ + "--bind", script, "/work/postinst", + "--bind", state.staging, "/work/out", + "--bind", Path.cwd(), "/work/src", + "--chdir", "/work/src", + "--setenv", "SRCDIR", "/work/src", + "--setenv", "OUTPUTDIR", "/work/out", + "--setenv", "BUILDROOT", "/", + ], ) + with complete_step(f"Running postinstall script {script}…"): + bwrap( + [script, "final"], + network=state.config.with_network, + readonly=True, + options=finalize_mounts(state.config), + scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), + env=env | state.config.environment, + stdin=sys.stdin, + ) + -def run_finalize_script(state: MkosiState) -> None: - if state.config.finalize_script is None: +def run_finalize_scripts(state: MkosiState) -> None: + if not state.config.finalize_scripts: return env = dict( @@ -427,30 +426,31 @@ def run_finalize_script(state: MkosiState) -> None: MKOSI_GID=str(state.gid), ) - chroot = chroot_cmd( - state.root, - options=[ - "--bind", state.config.finalize_script, "/work/finalize", - "--bind", state.staging, "/work/out", - "--bind", Path.cwd(), "/work/src", - "--chdir", "/work/src", - "--setenv", "SRCDIR", "/work/src", - "--setenv", "OUTPUTDIR", "/work/out", - "--setenv", "BUILDROOT", "/", - ], - ) - - with complete_step("Running finalize script…"): - bwrap( - [state.config.finalize_script], - network=state.config.with_network, - readonly=True, - options=finalize_mounts(state.config), - scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), - env=env | state.config.environment, - stdin=sys.stdin, + for script in state.config.finalize_scripts: + chroot = chroot_cmd( + state.root, + options=[ + "--bind", script, "/work/finalize", + "--bind", state.staging, "/work/out", + "--bind", Path.cwd(), "/work/src", + "--chdir", "/work/src", + "--setenv", "SRCDIR", "/work/src", + "--setenv", "OUTPUTDIR", "/work/out", + "--setenv", "BUILDROOT", "/", + ], ) + with complete_step(f"Running finalize script {script}…"): + bwrap( + [script], + network=state.config.with_network, + readonly=True, + options=finalize_mounts(state.config), + scripts={"mkosi-chroot": chroot} | package_manager_scripts(state), + env=env | state.config.environment, + stdin=sys.stdin, + ) + def run_openssl(args: Sequence[PathString], stdout: _FILE = None) -> CompletedProcess: with tempfile.NamedTemporaryFile(prefix="mkosi-openssl.cnf") as config: @@ -1661,7 +1661,7 @@ def run_selinux_relabel(state: MkosiState) -> None: def need_build_packages(config: MkosiConfig) -> bool: - return config.build_script is not None and len(config.build_packages) > 0 + return bool(config.build_scripts and config.build_packages) def save_cache(state: MkosiState) -> None: @@ -1879,14 +1879,14 @@ def build_image(args: MkosiArgs, config: MkosiConfig, name: str, uid: int, gid: if not cached: with mount_cache_overlay(state): install_distribution(state) - run_prepare_script(state, build=False) + run_prepare_scripts(state, build=False) install_build_packages(state) - run_prepare_script(state, build=True) + run_prepare_scripts(state, build=True) save_cache(state) reuse_cache(state) - run_build_script(state) + run_build_scripts(state) if state.config.output_format == OutputFormat.none: # Touch an empty file to indicate the image was built. @@ -1896,7 +1896,7 @@ def build_image(args: MkosiArgs, config: MkosiConfig, name: str, uid: int, gid: install_build_dest(state) install_extra_trees(state) - run_postinst_script(state) + run_postinst_scripts(state) configure_autologin(state) configure_initrd(state) @@ -1918,7 +1918,7 @@ def build_image(args: MkosiArgs, config: MkosiConfig, name: str, uid: int, gid: clean_package_manager_metadata(state) remove_files(state) run_selinux_relabel(state) - run_finalize_script(state) + run_finalize_scripts(state) normalize_mtime(state.root, state.config.source_date_epoch) partitions = make_image(state, skip=("esp", "xbootldr")) diff --git a/mkosi/config.py b/mkosi/config.py index de2d283bb..46e2452aa 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -151,6 +151,7 @@ def parse_path(value: str, *, required: bool = True, resolve: bool = True, + executable: bool = False, expanduser: bool = True, expandvars: bool = True, secret: bool = False) -> Path: @@ -170,6 +171,9 @@ def parse_path(value: str, if resolve: path = path.resolve() + if executable and not os.access(path, os.X_OK): + die(f"{value} is not executable") + if secret and path.exists(): mode = path.stat().st_mode & 0o777 if mode & 0o007: @@ -210,17 +214,6 @@ def config_make_string_matcher(allow_globs: bool = False) -> ConfigMatchCallback return config_match_string -def config_parse_script(value: Optional[str], old: Optional[Path]) -> Optional[Path]: - if not value: - return None - - path = parse_path(value) - if not os.access(path, os.X_OK): - die(f"{value} is not executable") - - return path - - def config_parse_boolean(value: Optional[str], old: Optional[bool]) -> Optional[bool]: if value is None: return False @@ -425,6 +418,7 @@ def config_match_version(match: str, value: str) -> bool: def make_path_parser(*, required: bool = True, resolve: bool = True, + executable: bool = False, expanduser: bool = True, expandvars: bool = True, secret: bool = False) -> Callable[[str], Path]: @@ -432,6 +426,7 @@ def make_path_parser(*, parse_path, required=required, resolve=resolve, + executable=executable, expanduser=expanduser, expandvars=expandvars, secret=secret, @@ -441,6 +436,7 @@ def make_path_parser(*, def config_make_path_parser(*, required: bool = True, resolve: bool = True, + executable: bool = False, expanduser: bool = True, expandvars: bool = True, secret: bool = False) -> ConfigParseCallback: @@ -452,6 +448,7 @@ def config_make_path_parser(*, value, required=required, resolve=resolve, + executable=executable, expanduser=expanduser, expandvars=expandvars, secret=secret, @@ -716,10 +713,10 @@ class MkosiConfig: clean_package_metadata: ConfigFeature source_date_epoch: Optional[int] - prepare_script: Optional[Path] - build_script: Optional[Path] - postinst_script: Optional[Path] - finalize_script: Optional[Path] + prepare_scripts: list[Path] + build_scripts: list[Path] + postinst_scripts: list[Path] + finalize_scripts: list[Path] build_sources: list[tuple[Path, Optional[Path]]] environment: dict[str, str] with_tests: bool @@ -859,17 +856,16 @@ class MkosiConfig: return f"{self.output_with_version}.changelog" def cache_manifest(self) -> dict[str, Any]: - manifest: dict[str, Any] = { + return { "packages": self.packages, "build_packages": self.build_packages, "repositories": self.repositories, + "prepare_scripts": [ + base64.b64encode(script.read_bytes()).decode() + for script in self.prepare_scripts + ] } - if self.prepare_script: - manifest["prepare_script"] = base64.b64encode(self.prepare_script.read_bytes()).decode() - - return manifest - def parse_ini(path: Path, only_sections: Sequence[str] = ()) -> Iterator[tuple[str, str, str]]: """ @@ -1169,7 +1165,7 @@ SETTINGS = ( metavar="PACKAGE", section="Content", parse=config_make_list_parser(delimiter=","), - help="Additional packages needed for build script", + help="Additional packages needed for build scripts", ), MkosiConfigSetting( dest="with_docs", @@ -1249,37 +1245,49 @@ SETTINGS = ( help="Set the $SOURCE_DATE_EPOCH timestamp", ), MkosiConfigSetting( - dest="prepare_script", + dest="prepare_scripts", + long="--prepare-script", metavar="PATH", section="Content", - parse=config_parse_script, + parse=config_make_list_parser(delimiter=",", parse=make_path_parser(executable=True)), paths=("mkosi.prepare",), + path_default=False, help="Prepare script to run inside the image before it is cached", + compat_names=("PrepareScript",), ), MkosiConfigSetting( - dest="build_script", + dest="build_scripts", + long="--build-script", metavar="PATH", section="Content", - parse=config_parse_script, + parse=config_make_list_parser(delimiter=",", parse=make_path_parser(executable=True)), paths=("mkosi.build",), + path_default=False, help="Build script to run inside image", + compat_names=("BuildScript",), ), MkosiConfigSetting( - dest="postinst_script", + dest="postinst_scripts", + long="--postinst-script", metavar="PATH", - name="PostInstallationScript", + name="PostInstallationScripts", section="Content", - parse=config_parse_script, + parse=config_make_list_parser(delimiter=",", parse=make_path_parser(executable=True)), paths=("mkosi.postinst",), + path_default=False, help="Postinstall script to run inside image", + compat_names=("PostInstallationScript",), ), MkosiConfigSetting( - dest="finalize_script", + dest="finalize_scripts", + long="--finalize-script", metavar="PATH", section="Content", - parse=config_parse_script, + parse=config_make_list_parser(delimiter=",", parse=make_path_parser(executable=True)), paths=("mkosi.finalize",), + path_default=False, help="Postinstall script to run outside image", + compat_names=("FinalizeScript",), ), MkosiConfigSetting( dest="build_sources", @@ -1305,7 +1313,7 @@ SETTINGS = ( section="Content", parse=config_parse_boolean, default=True, - help="Do not run tests as part of build script, if supported", + help="Do not run tests as part of build scripts, if supported", ), MkosiConfigSetting( dest="with_network", @@ -2310,7 +2318,7 @@ def load_config(args: argparse.Namespace) -> MkosiConfig: # For unprivileged builds we need the userxattr OverlayFS mount option, which is only available # in Linux v5.11 and later. if ( - (args.build_script is not None or args.base_trees) and + (args.build_scripts or args.base_trees) and GenericVersion(platform.release()) < GenericVersion("5.11") and os.geteuid() != 0 ): @@ -2424,13 +2432,13 @@ def summary(args: MkosiArgs, config: MkosiConfig) -> str: Clean Package Manager Metadata: {yes_no_auto(config.clean_package_metadata)} Source Date Epoch: {none_to_none(config.source_date_epoch)} - Prepare Script: {none_to_none(config.prepare_script)} - Build Script: {none_to_none(config.build_script)} - Postinstall Script: {none_to_none(config.postinst_script)} - Finalize Script: {none_to_none(config.finalize_script)} + Prepare Scripts: {line_join_list(config.prepare_scripts)} + Build Scripts: {line_join_list(config.build_scripts)} + Postinstall Scripts: {line_join_list(config.postinst_scripts)} + Finalize Scripts: {line_join_list(config.finalize_scripts)} Build Sources: {line_join_source_target_list(config.build_sources)} Script Environment: {line_join_list(env)} - Run Tests in Build Script: {yes_no(config.with_tests)} + Run Tests in Build Scripts: {yes_no(config.with_tests)} Scripts With Network: {yes_no(config.with_network)} Bootable: {yes_no_auto(config.bootable)} diff --git a/mkosi/resources/mkosi.md b/mkosi/resources/mkosi.md index 1c8f6089b..a41d2e6dc 100644 --- a/mkosi/resources/mkosi.md +++ b/mkosi/resources/mkosi.md @@ -226,7 +226,7 @@ The following output formats are supported: The output format may also be set to *none* to have mkosi produce no image at all. This can be useful if you only want to use the image to -produce another output in the build script (e.g. build an rpm). +produce another output in the build scripts (e.g. build an rpm). When a *GPT* disk image is created, repart partition definition files may be placed in `mkosi.repart/` to configure the generated disk image. @@ -509,10 +509,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, systems that support out-of-tree builds (such as Meson). The directory used this way is shared between repeated builds, and allows the build system to reuse artifacts (such as object files, executable, …) - generated on previous invocations. The build script can find the path + generated on previous invocations. The build scripts can find the path to this directory in the `$BUILDDIR` environment variable. This directory is mounted into the image's root directory when - `mkosi-chroot` is invoked during execution of the build script. If + `mkosi-chroot` is invoked during execution of the build scripts. If this option is not specified, but a directory `mkosi.builddir/` exists in the local directory it is automatically used for this purpose (also see the **Files** section below). @@ -616,8 +616,8 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, option may be used multiple times in which case the specified package lists are combined. Use `BuildPackages=` to specify packages that shall only be installed in an overlay that is mounted when the prepare - script is executed with the `build` argument and when the build script - is executed. + scripts are executed with the `build` argument and when the build scripts + are executed. : The types and syntax of *package specifications* that are allowed depend on the package installer (e.g. `dnf` for `rpm`-based distros or @@ -648,10 +648,10 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : Similar to `Packages=`, but configures packages to install only in an overlay that is made available on top of the image to the prepare - script when executed with the `build` argument and the build script. + scripts when executed with the `build` argument and the build scripts. This option should be used to list packages containing header files, compilers, build systems, linkers and other build tools the - `mkosi.build` script requires to operate. Note that packages listed + `mkosi.build` scripts require to operate. Note that packages listed here will be absent in the final image. `WithDocs=`, `--with-docs` @@ -659,7 +659,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : Include documentation in the image built. By default if the underlying distribution package manager supports it documentation is not included in the image built. The `$WITH_DOCS` environment - variable passed to the `mkosi.build` script indicates whether this + variable passed to the `mkosi.build` scripts indicates whether this option was used or not. `BaseTrees=`, `--base-tree=` @@ -742,25 +742,29 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, package manager executable is *not* present at the end of the installation. -`PrepareScript=`, `--prepare-script=` +`PrepareScripts=`, `--prepare-script=` -: Takes a path to an executable that is used as the prepare script for - this image. See the **Scripts** section for more information. +: Takes a comma-separated list of paths to executables that are used as + the prepare scripts for this image. See the **Scripts** section for + more information. -`BuildScript=`, `--build-script=` +`BuildScripts=`, `--build-script=` -: Takes a path to an executable that is used as build script for this - image. See the **Scripts** section for more information. +: Takes a comma-separated list of paths to executables that are used as + the build scripts for this image. See the **Scripts** section for more + information. -`PostInstallationScript=`, `--postinst-script=` +`PostInstallationScripts=`, `--postinst-script=` -: Takes a path to an executable that is used as the post-installation - script for this image. See the **Scripts** section for more information. +: Takes a comma-separated list of paths to executables that are used as + the post-installation scripts for this image. See the **Scripts** section + for more information. -`FinalizeScript=`, `--finalize-script=` +`FinalizeScripts=`, `--finalize-script=` -: Takes a path to an executable that is used as the finalize script for - this image. See the **Scripts** section for more information. +: Takes a comma-separated list of paths to executables that are used as + the finalize scripts for this image. See the **Scripts** section for more + information. `BuildSources=`, `--build-sources=` @@ -788,17 +792,17 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : If set to false (or when the command-line option is used), the `$WITH_TESTS` environment variable is set to `0` when the - `mkosi.build` script is invoked. This is supposed to be used by the - build script to bypass any unit or integration tests that are + `mkosi.build` scripts are invoked. This is supposed to be used by the + build scripts to bypass any unit or integration tests that are normally run during the source build process. Note that this option - has no effect unless the `mkosi.build` build script honors it. + has no effect unless the `mkosi.build` build scripts honor it. `WithNetwork=`, `--with-network=` -: When true, enables network connectivity while the build script - `mkosi.build` is invoked. By default, the build script runs with +: When true, enables network connectivity while the build scripts + `mkosi.build` are invoked. By default, the build scripts run with networking turned off. The `$WITH_NETWORK` environment variable is - passed to the `mkosi.build` build script indicating whether the + passed to the `mkosi.build` build scripts indicating whether the build is done with or without network. `Bootable=`, `--bootable=` @@ -1009,7 +1013,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, : Enable incremental build mode. In this mode, a copy of the OS image is created immediately after all OS packages are installed and the - prepare script has executed but before the `mkosi.build` script is + prepare scripts have executed but before the `mkosi.build` scripts are invoked (or anything that happens after it). On subsequent invocations of `mkosi` with the `-i` switch this cached image may be used to skip the OS package installation, thus drastically speeding up repetitive @@ -1244,16 +1248,16 @@ Then, for each preset, we execute the following steps: 8. Copy skeleton trees (`mkosi.skeleton`) into image 9. Install distribution and packages into image or use cache tree if available -10. Run prepare script on image with the `final` argument (`mkosi.prepare`) -11. Install build packages in overlay if a build script is configured -12. Run prepare script on overlay with the `build` argument if a build - script is configured (`mkosi.prepare`) +10. Run prepare scripts on image with the `final` argument (`mkosi.prepare`) +11. Install build packages in overlay if any build scripts are configured +12. Run prepare scripts on overlay with the `build` argument if any build + scripts are configured (`mkosi.prepare`) 13. Cache the image if configured (`--incremental`) -14. Run build script on image + overlay if a build script is configured (`mkosi.build`) +14. Run build scripts on image + overlay if any build scripts are configured (`mkosi.build`) 15. Finalize the build if the output format `none` is configured -16. Copy the build script outputs into the image +16. Copy the build scripts outputs into the image 17. Copy the extra trees into the image (`mkosi.extra`) -18. Run post-install script (`mkosi.postinst`) +18. Run post-install scripts (`mkosi.postinst`) 19. Write config files required for `Ssh=`, `Autologin=` and `MakeInitrd=` 20. Install systemd-boot and configure secure boot if configured (`--secure-boot`) 21. Run `systemd-sysusers` @@ -1263,7 +1267,7 @@ Then, for each preset, we execute the following steps: 25. Run `systemd-hwdb` 26. Remove packages and files (`RemovePackages=`, `RemoveFiles=`) 27. Run SELinux relabel is a SELinux policy is installed -28. Run finalize script (`mkosi.finalize`) +28. Run finalize scripts (`mkosi.finalize`) 29. Generate unified kernel image if configured to do so 30. Generate final output format @@ -1280,7 +1284,7 @@ are mounted into the current working directory before running the script and `$SRCDIR` is set to point to the current working directory. The following scripts are supported: -* If **`mkosi.prepare`** (`PrepareScript=`) exists, it is first called +* If **`mkosi.prepare`** (`PrepareScripts=`) exists, it is first called with the `final` argument, right after the software packages are installed. It is called a second time with the `build` command line parameter, right after the build packages are installed and the build @@ -1295,7 +1299,7 @@ following scripts are supported: easily be thrown away and rebuilt so there's no risk of conflicting dependencies and no risk of polluting the host system. -* If **`mkosi.build`** (`BuildScript=`) exists, it is executed with the +* If **`mkosi.build`** (`BuildScripts=`) exists, it is executed with the build overlay mounted on top of the image's root directory. When running the build script, `$DESTDIR` points to a directory where the script should place any files generated it would like to end up in the @@ -1304,13 +1308,13 @@ following scripts are supported: *source* trees from the build script. After running the build script, the contents of `$DESTDIR` are copied into the image. -* If **`mkosi.postinst`** (`PostInstallationScript=`) exists, it is +* If **`mkosi.postinst`** (`PostInstallationScripts=`) exists, it is executed after the (optional) build tree and extra trees have been installed. This script may be used to alter the images without any restrictions, after all software packages and built sources have been installed. -* If **`mkosi.finalize`** (`FinalizeScript=`) exists, it is executed as +* If **`mkosi.finalize`** (`FinalizeScripts=`) exists, it is executed as the last step of preparing an image. Scripts executed by mkosi receive the following environment variables: @@ -1332,8 +1336,8 @@ Scripts executed by mkosi receive the following environment variables: will have after invoking `mkosi-chroot`. * `$DESTDIR` is a directory into which any installed software generated - by the build script may be placed. This variable is only set when - executing the build script. `$CHROOT_DESTDIR` contains the value that + by a build script may be placed. This variable is only set when + executing a build script. `$CHROOT_DESTDIR` contains the value that `$DESTDIR` will have after invoking `mkosi-chroot`. * `$OUTPUTDIR` points to the staging directory used to store build @@ -1346,18 +1350,18 @@ Scripts executed by mkosi receive the following environment variables: * `$WITH_DOCS` is either `0` or `1` depending on whether a build without or with installed documentation was requested - (`WithDocs=yes`). The build script should suppress installation of + (`WithDocs=yes`). A build script should suppress installation of any package documentation to `$DESTDIR` in case `$WITH_DOCS` is set to `0`. * `$WITH_TESTS` is either `0`or `1` depending on whether a build without or with running the test suite was requested - (`WithTests=no`). The build script should avoid running any unit or + (`WithTests=no`). A build script should avoid running any unit or integration tests in case `$WITH_TESTS` is `0`. * `$WITH_NETWORK` is either `0`or `1` depending on whether a build without or with networking is being executed (`WithNetwork=no`). - The build script should avoid any network communication in case + A build script should avoid any network communication in case `$WITH_NETWORK` is `0`. * `$SOURCE_DATE_EPOCH` is defined if requested (`SourceDateEpoch=TIMESTAMP`, @@ -1446,14 +1450,14 @@ local directory: to speed repeated runs of the tool. * The **`mkosi.builddir/`** directory, if it exists, is automatically used as out-of-tree build directory, if - the build commands in the `mkosi.build` script support it. Specifically, this directory will be mounted - into the build container, and the `$BUILDDIR` environment variable will be set to it when the build script - is invoked. The build script may then use this directory as build directory, for automake-style or + the build commands in the `mkosi.build` scripts support it. Specifically, this directory will be mounted + into the build container, and the `$BUILDDIR` environment variable will be set to it when the build scripts + are invoked. A build script may then use this directory as build directory, for automake-style or ninja-style out-of-tree builds. This speeds up builds considerably, in particular when `mkosi` is used in incremental mode (`-i`): not only the image and build overlay, but also the build tree is reused between subsequent invocations. Note that if this directory does not exist the `$BUILDDIR` environment variable is - not set, and it is up to build script to decide whether to do in in-tree or an out-of-tree build, and which - build directory to use. + not set, and it is up to the build scripts to decide whether to do in in-tree or an out-of-tree build, and + which build directory to use. * The **`mkosi.rootpw`** file can be used to provide the password for the root user of the image. If the password is prefixed with `hashed:` it is treated as an already hashed root password. The password may @@ -1557,7 +1561,7 @@ re-building of images. Specifically: be shared, using the `mkosi.builddir/` directory. This directory allows build systems such as Meson to reuse already compiled sources from a previous built, thus speeding up the build process - of the `mkosi.build` build script. + of a `mkosi.build` build script. The package cache and incremental mode are unconditionally useful. The final cache only apply to uses of `mkosi` with a source tree and build