Skip to content

Commit

Permalink
Add option to save the BuildSourcesEphemeral overlay.
Browse files Browse the repository at this point in the history
  • Loading branch information
behrmann authored and DaanDeMeyer committed Jan 23, 2025
1 parent 81590b5 commit bcaaccc
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 20 deletions.
20 changes: 16 additions & 4 deletions mkosi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,10 @@ def run_prepare_scripts(context: Context, build: bool) -> None:

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:
Expand Down Expand Up @@ -871,7 +874,10 @@ def run_postinst_scripts(context: Context) -> None:
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:
Expand Down Expand Up @@ -937,7 +943,10 @@ def run_finalize_scripts(context: Context) -> None:
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:
Expand Down Expand Up @@ -989,7 +998,10 @@ def run_postoutput_scripts(context: Context) -> None:
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:
Expand Down
22 changes: 18 additions & 4 deletions mkosi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,15 @@ def __bool__(self) -> bool:
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()
Expand Down Expand Up @@ -1897,7 +1906,7 @@ class Config:
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
Expand Down Expand Up @@ -3360,11 +3369,15 @@ def parse_ini(path: Path, only_sections: Collection[str] = ()) -> Iterator[tuple
),
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",
Expand Down Expand Up @@ -4943,7 +4956,7 @@ def summary(config: Config) -> str:
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)}
Expand Down Expand Up @@ -5134,6 +5147,7 @@ def uki_profile_transformer(
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,
Expand Down
29 changes: 23 additions & 6 deletions mkosi/mounts.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@
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

Expand Down Expand Up @@ -56,20 +57,36 @@ def mount_overlay(


@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] = []

for t in config.build_sources:
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.")
)
)

Expand Down
13 changes: 9 additions & 4 deletions mkosi/resources/man/mkosi.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -1476,12 +1476,17 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`,
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
Expand Down
5 changes: 3 additions & 2 deletions tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
ArtifactOutput,
BiosBootloader,
Bootloader,
BuildSourcesEphemeral,
Cacheonly,
CertificateSource,
CertificateSourceType,
Expand Down Expand Up @@ -117,7 +118,7 @@ def test_config() -> None:
"Target": "/frob"
}
],
"BuildSourcesEphemeral": true,
"BuildSourcesEphemeral": "yes",
"CDROM": false,
"CPUs": 2,
"CacheDirectory": "/is/this/the/cachedir",
Expand Down Expand Up @@ -424,7 +425,7 @@ def test_config() -> None:
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,
Expand Down

0 comments on commit bcaaccc

Please sign in to comment.