From: Zbigniew Jędrzejewski-Szmek Date: Sun, 4 Nov 2018 13:17:55 +0000 (+0100) Subject: Call 'mkosi.finalize' script X-Git-Tag: v5~35^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F281%2Fhead;p=thirdparty%2Fmkosi.git Call 'mkosi.finalize' script This is similar to 'mkosi.postinst', but is called in the host. This makes it much easier to copy-in files. It is also much quicker when creating images for a foreign architecture. v2: - s/postinst2/finalize/g - call the script first with "build" too - pass the root directory as $BUILDROOT (like rpmbuild) and not as a positional argument. (This is easier to consume for scripts and also easier to extend with additional variables in the future.) - update to use args_find_path() --- diff --git a/README.md b/README.md index dfbb36d43..e364106ab 100644 --- a/README.md +++ b/README.md @@ -184,7 +184,7 @@ they exist in the local directory: `systemd-nspawn`), with `$SRCDIR` pointing to the *source* tree. `$DESTDIR` points to a directory where the script should place any files generated it would like to end up in the *final* - image. Note that `make`/`automake` based build systems generally + image. Note that `make`/`automake`/`meson` based build systems generally honour `$DESTDIR`, thus making it very natural to build *source* trees from the build script. After the *development* image was built and the build script ran inside of it, it is removed again. After @@ -205,16 +205,34 @@ they exist in the local directory: artifacts. * `mkosi.postinst` may be an executable script. If it exists it is - invoked as last step of preparing an image, from within the image - context. It is once called for the *development* image (if this is - enabled, see above) with the "build" command line parameter, right - before invoking the build script. It is called a second time for the - *final* image with the "final" command line parameter, right before - the image is considered complete. This script may be used to alter - the images without any restrictions, after all software packages and - built sources have been installed. Note that this script is executed - directly in the image context with the final root directory in - place, without any `$SRCDIR`/`$DESTDIR` setup. + invoked as the penultimate step of preparing an image, from within + the image context. It is once called for the *development* image (if + this is enabled, see above) with the "build" command line parameter, + right before invoking the build script. It is called a second time + for the *final* image with the "final" command line parameter, right + before the image is considered complete. This script may be used to + alter the images without any restrictions, after all software + packages and built sources have been installed. Note that this + script is executed directly in the image context with the final root + directory in place, without any `$SRCDIR`/`$DESTDIR` setup. + +* `mkosi.finalize` may be an executable script. If it exists it is + invoked as last step of preparing an image, from the host system. + It is once called for the *development* image (if this is enabled, + see above) with the "build" command line parameter, as the last step + before invoking the build script, after the `mkosi.postinst` script + is invoked. It is called the second time with the "final" command + line parameter as the last step before the image is considered + complete. The environment variable `$BUILDROOT` points to the root + directory of the installation image. Additional verbs may be added + in the future, the script should be prepared for that. This script + may be used to alter the images without any restrictions, after all + software packages and built sources have been installed. This script + is more flexible than `mkosi.postinst` in two regards: it has access + to the host file system so it's easier to copy in additional files + or to modify the image based on external configuration, and the + script is run in the host, so it can be used even without emulation + even if the image has a foreign architecture. * `mkosi.mksquashfs-tool` may be an executable script. If it exists is is called instead of `mksquashfs`. diff --git a/mkosi b/mkosi index f68c9f1f7..7a08bf5ff 100755 --- a/mkosi +++ b/mkosi @@ -1789,6 +1789,8 @@ def run_postinst_script(args, workspace, run_build_script, for_cache): if for_cache: return + verb = "build" if run_build_script else "final" + with complete_step('Running postinstall script'): # We copy the postinst script into the build tree. We'd prefer @@ -1799,9 +1801,18 @@ def run_postinst_script(args, workspace, run_build_script, for_cache): shutil.copy2(args.postinst_script, os.path.join(workspace, "root", "root/postinst")) - run_workspace_command(args, workspace, "/root/postinst", "build" if run_build_script else "final", network=args.with_network) + run_workspace_command(args, workspace, "/root/postinst", verb, network=args.with_network) os.unlink(os.path.join(workspace, "root", "root/postinst")) +def run_finalize_script(args: CommandLineArguments, workspace: str, *, verb: str): + if args.finalize_script is None: + return + + with complete_step('Running finalize script'): + buildroot = workspace + '/root' + env = collections.ChainMap({'BUILDROOT':buildroot}, os.environ) + run([args.finalize_script, verb], env=env, check=True) + def find_kernel_file(workspace_root, pattern): # Look for the vmlinuz file in the workspace workspace_pattern = os.path.join(workspace_root, pattern.lstrip('/')) @@ -2578,6 +2589,7 @@ def parse_args() -> CommandLineArguments: group.add_argument("--build-dir", help='Path to use as persistent build directory', metavar='PATH') group.add_argument("--build-package", action=CommaDelimitedListAction, dest='build_packages', default=[], help='Additional packages needed for build script', metavar='PACKAGE') group.add_argument("--postinst-script", help='Postinstall script to run inside image', metavar='PATH') + group.add_argument("--finalize-script", help='Postinstall script to run outside image', metavar='PATH') group.add_argument('--use-git-files', type=parse_boolean, help='Ignore any files that git itself ignores (default: guess)') group.add_argument('--git-files', choices=('cached', 'others'), @@ -2901,6 +2913,9 @@ def process_setting(args: CommandLineArguments, section: str, key: str, value: A elif key in {"PostinstallScript", "PostInstallationScript"}: if args.postinst_script is None: args.postinst_script = value + elif key == "FinalizeScript": + if args.finalize_script is None: + args.finalize_script = value elif key == "WithNetwork": if args.with_network is None: args.with_network = parse_boolean(value) @@ -3139,6 +3154,7 @@ def load_args() -> CommandLineArguments: args_find_path(args, 'build_sources', ".") args_find_path(args, 'build_dir', "mkosi.builddir/") args_find_path(args, 'postinst_script', "mkosi.postinst"); + args_find_path(args, 'finalize_script', "mkosi.finalize"); args_find_path(args, 'output_dir', "mkosi.output/"); args_find_path(args, 'mksquashfs_tool', "mkosi.mksquashfs-tool", type=lambda x: [x]) @@ -3291,6 +3307,9 @@ def load_args() -> CommandLineArguments: if args.postinst_script is not None: args.postinst_script = os.path.abspath(args.postinst_script) + if args.finalize_script is not None: + args.finalize_script = os.path.abspath(args.finalize_script) + if args.cache_path is not None: args.cache_path = os.path.abspath(args.cache_path) @@ -3460,6 +3479,7 @@ def print_summary(args: CommandLineArguments) -> None: sys.stderr.write(" Build Directory: " + none_to_none(args.build_dir) + "\n") sys.stderr.write(" Build Packages: " + line_join_list(args.build_packages) + "\n") sys.stderr.write(" Postinstall Script: " + none_to_none(args.postinst_script) + "\n") + sys.stderr.write(" Finalize Script: " + none_to_none(args.finalize_script) + "\n") sys.stderr.write(" Scripts with network: " + yes_no(args.with_network) + "\n") sys.stderr.write(" nspawn Settings: " + none_to_none(args.nspawn_settings) + "\n") @@ -3701,6 +3721,8 @@ def build_stuff(args: CommandLineArguments) -> None: args.cache_pre_inst) remove_artifacts(args, workspace.name, raw, tar, run_build_script=False) + run_finalize_script(args, workspace.name, verb='build') + if args.build_script: # Run the image builder for the first (develpoment) stage in preparation for the build script raw, tar, root_hash = build_image(args, workspace, run_build_script=True) @@ -3708,6 +3730,8 @@ def build_stuff(args: CommandLineArguments) -> None: run_build_script(args, workspace.name, raw) remove_artifacts(args, workspace.name, raw, tar, run_build_script=True) + run_finalize_script(args, workspace.name, verb='final') + # Run the image builder for the second (final) stage raw, tar, root_hash = build_image(args, workspace, run_build_script=False, cleanup=True)