with (
mount_build_overlay(context) if build else contextlib.nullcontext(),
- finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources,
+ finalize_source_mounts(
+ context.config,
+ ephemeral=bool(context.config.build_sources_ephemeral),
+ ) as sources,
finalize_config_json(context.config) as json,
):
if build:
env |= context.config.environment
with (
- finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources,
+ finalize_source_mounts(
+ context.config,
+ ephemeral=bool(context.config.build_sources_ephemeral),
+ ) as sources,
finalize_config_json(context.config) as json,
):
for script in context.config.postinst_scripts:
env |= context.config.environment
with (
- finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources,
+ finalize_source_mounts(
+ context.config,
+ ephemeral=bool(context.config.build_sources_ephemeral),
+ ) as sources,
finalize_config_json(context.config) as json,
):
for script in context.config.finalize_scripts:
env["PROFILES"] = " ".join(context.config.profiles)
with (
- finalize_source_mounts(context.config, ephemeral=context.config.build_sources_ephemeral) as sources,
+ finalize_source_mounts(
+ context.config,
+ ephemeral=bool(context.config.build_sources_ephemeral),
+ ) as sources,
finalize_config_json(context.config) as json,
):
for script in context.config.postoutput_scripts:
return self != Incremental.no
+class BuildSourcesEphemeral(StrEnum):
+ yes = enum.auto()
+ no = enum.auto()
+ buildcache = enum.auto()
+
+ def __bool__(self) -> bool:
+ return self != BuildSourcesEphemeral.no
+
+
class Architecture(StrEnum):
alpha = enum.auto()
arc = enum.auto()
repart_offline: bool
history: bool
build_sources: list[ConfigTree]
- build_sources_ephemeral: bool
+ build_sources_ephemeral: BuildSourcesEphemeral
environment: dict[str, str]
environment_files: list[Path]
with_tests: bool
),
ConfigSetting(
dest="build_sources_ephemeral",
- metavar="BOOL",
+ nargs="?",
section="Build",
- parse=config_parse_boolean,
+ parse=config_make_enum_parser_with_boolean(
+ BuildSourcesEphemeral, yes=BuildSourcesEphemeral.yes, no=BuildSourcesEphemeral.no
+ ),
+ default=BuildSourcesEphemeral.no,
help="Make build sources ephemeral when running scripts",
scope=SettingScope.universal,
+ choices=BuildSourcesEphemeral.values(),
),
ConfigSetting(
dest="environment",
Repart Offline: {yes_no(config.repart_offline)}
Save History: {yes_no(config.history)}
Build Sources: {line_join_list(config.build_sources)}
- Build Sources Ephemeral: {yes_no(config.build_sources_ephemeral)}
+ Build Sources Ephemeral: {config.build_sources_ephemeral}
Script Environment: {line_join_list(env)}
Environment Files: {line_join_list(config.environment_files)}
Run Tests in Build Scripts: {yes_no(config.with_tests)}
Firmware: enum_transformer,
SecureBootSignTool: enum_transformer,
Incremental: enum_transformer,
+ BuildSourcesEphemeral: enum_transformer,
Optional[Distribution]: optional_enum_transformer,
list[ManifestFormat]: enum_list_transformer,
Verb: enum_transformer,
import tempfile
from collections.abc import Iterator, Sequence
from pathlib import Path
-from typing import Optional
+from typing import Optional, Union
-from mkosi.config import Config
+from mkosi.config import BuildSourcesEphemeral, Config
+from mkosi.log import die
from mkosi.sandbox import OverlayOperation
from mkosi.util import PathString, flatten
@contextlib.contextmanager
-def finalize_source_mounts(config: Config, *, ephemeral: bool) -> Iterator[list[PathString]]:
+def finalize_source_mounts(
+ config: Config,
+ *,
+ ephemeral: Union[BuildSourcesEphemeral, bool],
+) -> Iterator[list[PathString]]:
with contextlib.ExitStack() as stack:
options: list[PathString] = []
src, dst = t.with_prefix("/work/src")
if ephemeral:
- upperdir = Path(stack.enter_context(tempfile.TemporaryDirectory(prefix="volatile-overlay")))
- os.chmod(upperdir, src.stat().st_mode)
+ if ephemeral == BuildSourcesEphemeral.buildcache:
+ if config.build_dir is None:
+ die(
+ "BuildSourcesEphemeral=buildcache was configured, but no build directory exists.", # noqa: E501
+ hint="Configure BuildDirectory= or create mkosi.builddir.",
+ )
+ assert config.build_dir
+ upperdir = config.build_dir / f"mkosi.buildovl.{src.name}"
+ upperdir.mkdir(mode=src.stat().st_mode, exist_ok=True)
+ else:
+ upperdir = Path(
+ stack.enter_context(tempfile.TemporaryDirectory(prefix="volatile-overlay."))
+ )
+ os.chmod(upperdir, src.stat().st_mode)
workdir = Path(
stack.enter_context(
- tempfile.TemporaryDirectory(dir=upperdir.parent, prefix=f"{upperdir.name}-workdir")
+ tempfile.TemporaryDirectory(dir=upperdir.parent, prefix=f"{upperdir.name}-workdir.")
)
)
working directory is mounted to `/work/src`.
`BuildSourcesEphemeral=`, `--build-sources-ephemeral=`
-: Takes a boolean. Disabled by default. Configures whether changes to
- source directories (the working directory and configured using
- `BuildSources=`) are persisted. If enabled, all source directories
- will be reset to their original state every time after running all
+: Takes a boolean or the special value `buildcache`. Disabled by default. Configures whether changes to
+ source directories, the working directory and configured using `BuildSources=`, are persisted. If
+ enabled, all source directories will be reset to their original state every time after running all
scripts of a specific type (except sync scripts).
+ 💥💣💥 If set to `buildcache` the overlay is not discarded when running build scripts, but saved to the
+ build directory, configured via `BuildDirectory=`, and will be reused on subsequent runs. The overlay is
+ still discarded for all other scripts. This option can be used to implement more advanced caching of
+ builds, but can lead to unexpected states of the source directory. When using this option, a build
+ directory must be configured. 💥💣💥
+
`Environment=`, `--environment=`
: Adds variables to the environment that package managers and the
prepare/build/postinstall/finalize scripts are executed with. Takes
ArtifactOutput,
BiosBootloader,
Bootloader,
+ BuildSourcesEphemeral,
Cacheonly,
CertificateSource,
CertificateSourceType,
"Target": "/frob"
}
],
- "BuildSourcesEphemeral": true,
+ "BuildSourcesEphemeral": "yes",
"CDROM": false,
"CPUs": 2,
"CacheDirectory": "/is/this/the/cachedir",
build_dir=None,
build_packages=["pkg1", "pkg2"],
build_scripts=[Path("/path/to/buildscript")],
- build_sources_ephemeral=True,
+ build_sources_ephemeral=BuildSourcesEphemeral.yes,
build_sources=[ConfigTree(Path("/qux"), Path("/frob"))],
cache_dir=Path("/is/this/the/cachedir"),
cacheonly=Cacheonly.always,