From: Daan De Meyer Date: Tue, 26 Mar 2024 09:49:26 +0000 (+0100) Subject: Add support for configure scripts X-Git-Tag: v23~62^2 X-Git-Url: http://git.ipfire.org/gitweb/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F2552%2Fhead;p=thirdparty%2Fmkosi.git Add support for configure scripts These allow dynamically modifying the configuration. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 3046e5adc..2f5cc1914 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -423,6 +423,46 @@ def finalize_config_json(config: Config) -> Iterator[Path]: yield Path(f.name) +def run_configure_scripts(config: Config) -> Config: + if not config.configure_scripts: + return config + + for script in config.configure_scripts: + if not os.access(script, os.X_OK): + die(f"{script} is not executable") + + env = dict( + DISTRIBUTION=str(config.distribution), + RELEASE=config.release, + ARCHITECTURE=str(config.architecture), + SRCDIR="/work/src", + MKOSI_UID=str(INVOKING_USER.uid), + MKOSI_GID=str(INVOKING_USER.gid), + ) + + if config.profile: + env["PROFILE"] = config.profile + + with finalize_source_mounts(config, ephemeral=False) as sources: + for script in config.configure_scripts: + with complete_step(f"Running configure script {script}…"): + result = run( + ["/work/configure", "final"], + env=env | config.environment, + sandbox=config.sandbox( + tools=Path("/"), + mounts=[*sources, Mount(script, "/work/configure", ro=True)], + options=["--dir", "/work/src", "--chdir", "/work/src"] + ), + input=config.to_json(indent=None), + stdout=subprocess.PIPE, + ) + + config = Config.from_json(result.stdout) + + return config + + def run_sync_scripts(context: Context) -> None: if not context.config.sync_scripts: return @@ -1679,6 +1719,10 @@ def finalize_default_initrd( _, [config] = parse_config(cmdline + ["build"], resources=resources) + make_executable(*config.configure_scripts) + + run_configure_scripts(config) + make_executable( *config.prepare_scripts, *config.postinst_scripts, @@ -4183,12 +4227,15 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None: if args.verb == Verb.genkey: return generate_key_cert_pair(args) + if args.verb == Verb.bump: + return bump_image_version() + if all(config == Config.default() for config in images): die("No configuration found", hint="Make sure you're running mkosi from a directory with configuration files") - if args.verb == Verb.bump: - return bump_image_version() + for i, config in enumerate(images): + images[i] = run_configure_scripts(config) if args.verb == Verb.summary: if args.json: diff --git a/mkosi/config.py b/mkosi/config.py index 588058d57..9b54940e2 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -1324,6 +1324,7 @@ class Config: clean_package_metadata: ConfigFeature source_date_epoch: Optional[int] + configure_scripts: list[Path] sync_scripts: list[Path] prepare_scripts: list[Path] build_scripts: list[Path] @@ -1586,6 +1587,7 @@ class Config: network: bool = False, devices: bool = False, relaxed: bool = False, + tools: Optional[Path] = None, scripts: Optional[Path] = None, mounts: Sequence[Mount] = (), options: Sequence[PathString] = (), @@ -1603,7 +1605,7 @@ class Config: devices=devices, relaxed=relaxed, scripts=scripts, - tools=self.tools(), + tools=tools or self.tools(), mounts=mounts, options=options, ) @@ -2073,6 +2075,15 @@ SETTINGS = ( default_factory_depends=("environment",), help="Set the $SOURCE_DATE_EPOCH timestamp", ), + ConfigSetting( + dest="configure_scripts", + long="--configure-script", + metavar="PATH", + section="Content", + parse=config_make_list_parser(delimiter=",", parse=make_path_parser()), + paths=("mkosi.configure",), + help="Configure script to run before doing anything", + ), ConfigSetting( dest="sync_scripts", long="--sync-script", @@ -3732,6 +3743,7 @@ def summary(config: Config) -> str: Clean Package Manager Metadata: {config.clean_package_metadata} Source Date Epoch: {none_to_none(config.source_date_epoch)} + Configure Scripts: {line_join_list(config.configure_scripts)} Sync Scripts: {line_join_list(config.sync_scripts)} Prepare Scripts: {line_join_list(config.prepare_scripts)} Build Scripts: {line_join_list(config.build_scripts)} diff --git a/mkosi/resources/mkosi.md b/mkosi/resources/mkosi.md index 086722913..6e732346c 100644 --- a/mkosi/resources/mkosi.md +++ b/mkosi/resources/mkosi.md @@ -1026,6 +1026,12 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, package manager executable is *not* present at the end of the installation. +`ConfigureScripts=`, `--configure-script=` + +: Takes a comma-separated list of paths to executables that are used as + the configure scripts for this image. See the **Scripts** section for + more information. + `SyncScripts=`, `--sync-script=` : Takes a comma-separated list of paths to executables that are used as @@ -1907,6 +1913,7 @@ Then, for each image, we execute the following steps: 1. Copy package manager trees into the workspace 1. Sync the package manager repository metadata +1. Run sync scripts (`mkosi.sync`) 1. Copy base trees (`--base-tree=`) into the image 1. Reuse a cached image if one is available 1. Copy a snapshot of the package manager repository metadata into the @@ -1950,6 +1957,13 @@ are mounted into the current working directory before running the script in the current working directory. `$SRCDIR` is set to point to the current working directory. The following scripts are supported: +* If **`mkosi.configure`** (`ConfigureScripts=`) exists, it is executed + after parsing the configuration files. This script may be used to + dynamically modify the configuration. It receives the configuration + serialized as JSON on stdin and should output the modified + configuration serialized as JSON on stdout. Note that this script does + not use the tools tree even if one is configured. + * If **`mkosi.sync`** (`SyncScripts=`) exists, it is executed before the image is built. This script may be used to update various sources that are used to build the image. One use case is to run `git pull` on @@ -2078,30 +2092,30 @@ Scripts executed by mkosi receive the following environment variables: Consult this table for which script receives which environment variables: -| Variable | `mkosi.sync` | `mkosi.prepare` | `mkosi.build` | `mkosi.postinst` | `mkosi.finalize` | -|---------------------|--------------|-----------------|---------------|------------------|------------------| -| `ARCHITECTURE` | X | X | X | X | X | -| `DISTRIBUTION` | X | X | X | X | X | -| `RELEASE` | X | X | X | X | X | -| `PROFILE` | X | X | X | X | X | -| `CACHED` | X | | | | | -| `CHROOT_SCRIPT` | | X | X | X | X | -| `SRCDIR` | X | X | X | X | X | -| `CHROOT_SRCDIR` | | X | X | X | X | -| `BUILDDIR` | | | X | | | -| `CHROOT_BUILDDIR` | | | X | | | -| `DESTDIR` | | | X | | | -| `CHROOT_DESTDIR` | | | X | | | -| `OUTPUTDIR` | | | X | X | X | -| `CHROOT_OUTPUTDIR` | | | X | X | X | -| `BUILDROOT` | | X | X | X | X | -| `WITH_DOCS` | | X | X | | | -| `WITH_TESTS` | | X | X | | | -| `WITH_NETWORK` | | X | X | | | -| `SOURCE_DATE_EPOCH` | | X | X | X | X | -| `MKOSI_UID` | X | X | X | X | X | -| `MKOSI_GID` | X | X | X | X | X | -| `MKOSI_CONFIG` | X | X | X | X | X | +| Variable | `mkosi.configure` | `mkosi.sync` | `mkosi.prepare` | `mkosi.build` | `mkosi.postinst` | `mkosi.finalize` | +|---------------------|-------------------|--------------|-----------------|---------------|------------------|------------------| +| `ARCHITECTURE` | X | X | X | X | X | X | +| `DISTRIBUTION` | X | X | X | X | X | X | +| `RELEASE` | X | X | X | X | X | X | +| `PROFILE` | X | X | X | X | X | X | +| `CACHED` | | X | | | | | +| `CHROOT_SCRIPT` | | | X | X | X | X | +| `SRCDIR` | X | X | X | X | X | X | +| `CHROOT_SRCDIR` | | | X | X | X | X | +| `BUILDDIR` | | | | X | | | +| `CHROOT_BUILDDIR` | | | | X | | | +| `DESTDIR` | | | | X | | | +| `CHROOT_DESTDIR` | | | | X | | | +| `OUTPUTDIR` | | | | X | X | X | +| `CHROOT_OUTPUTDIR` | | | | X | X | X | +| `BUILDROOT` | | | X | X | X | X | +| `WITH_DOCS` | | | X | X | | | +| `WITH_TESTS` | | | X | X | | | +| `WITH_NETWORK` | | | X | X | | | +| `SOURCE_DATE_EPOCH` | | | X | X | X | X | +| `MKOSI_UID` | X | X | X | X | X | X | +| `MKOSI_GID` | X | X | X | X | X | X | +| `MKOSI_CONFIG` | | X | X | X | X | X | Additionally, when a script is executed, a few scripts are made available via `$PATH` to simplify common usecases. diff --git a/tests/test_json.py b/tests/test_json.py index 3cd112935..f9b0ad70e 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -114,6 +114,9 @@ def test_config() -> None: "CleanPackageMetadata": "auto", "CompressLevel": 3, "CompressOutput": "bz2", + "ConfigureScripts": [ + "/configure" + ], "Credentials": { "credkey": "credval" }, @@ -345,6 +348,7 @@ def test_config() -> None: clean_package_metadata = ConfigFeature.auto, compress_level = 3, compress_output = Compression.bz2, + configure_scripts = [Path("/configure")], credentials = {"credkey": "credval"}, dependencies = ("dep1",), distribution = Distribution.fedora,