`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
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`.
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
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('/'))
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'),
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)
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])
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)
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")
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)
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)