These allow dynamically modifying the configuration.
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
_, [config] = parse_config(cmdline + ["build"], resources=resources)
+ make_executable(*config.configure_scripts)
+
+ run_configure_scripts(config)
+
make_executable(
*config.prepare_scripts,
*config.postinst_scripts,
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:
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]
network: bool = False,
devices: bool = False,
relaxed: bool = False,
+ tools: Optional[Path] = None,
scripts: Optional[Path] = None,
mounts: Sequence[Mount] = (),
options: Sequence[PathString] = (),
devices=devices,
relaxed=relaxed,
scripts=scripts,
- tools=self.tools(),
+ tools=tools or self.tools(),
mounts=mounts,
options=options,
)
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",
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)}
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
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
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
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.
"CleanPackageMetadata": "auto",
"CompressLevel": 3,
"CompressOutput": "bz2",
+ "ConfigureScripts": [
+ "/configure"
+ ],
"Credentials": {
"credkey": "credval"
},
clean_package_metadata = ConfigFeature.auto,
compress_level = 3,
compress_output = Compression.bz2,
+ configure_scripts = [Path("/configure")],
credentials = {"credkey": "credval"},
dependencies = ("dep1",),
distribution = Distribution.fedora,