From: Daan De Meyer Date: Tue, 9 May 2023 09:09:26 +0000 (+0200) Subject: Add some very basic cache invalidation X-Git-Tag: v15~174^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=008e16d57e993ac9485e04bea87fca62cf6dab1b;p=thirdparty%2Fmkosi.git Add some very basic cache invalidation Let's compare the packages, build packages, repositories and the contents of the prepare script. This doesn't cover everything but should be sufficient to catch most changes without having to run with "-ff". --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 16c2b9abc..643da964b 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -1032,7 +1032,7 @@ def unlink_output(args: MkosiArgs, config: MkosiConfig) -> None: if remove_build_cache: for p in cache_tree_paths(config): if p.exists(): - with complete_step(f"Removing cache directory {p}…"): + with complete_step(f"Removing cache entry {p}…"): unlink_try_hard(p) if config.build_dir and config.build_dir.exists() and any(config.build_dir.iterdir()): @@ -1049,9 +1049,13 @@ def unlink_output(args: MkosiArgs, config: MkosiConfig) -> None: empty_directory(config.cache_dir) -def cache_tree_paths(config: MkosiConfig) -> tuple[Path, Path]: +def cache_tree_paths(config: MkosiConfig) -> tuple[Path, Path, Path]: assert config.cache_dir - return config.cache_dir / f"{config.output}.cache", config.cache_dir / f"{config.output}.build.cache" + return ( + config.cache_dir / f"{config.output}.cache", + config.cache_dir / f"{config.output}.build.cache", + config.cache_dir / f"{config.output}.manifest", + ) def check_tree_input(path: Optional[Path]) -> None: @@ -1456,7 +1460,7 @@ def save_cache(state: MkosiState) -> None: if not state.config.incremental: return - final, build = cache_tree_paths(state.config) + final, build, manifest = cache_tree_paths(state.config) with complete_step("Installing cache copies"): unlink_try_hard(final) @@ -1472,15 +1476,22 @@ def save_cache(state: MkosiState) -> None: unlink_try_hard(build) shutil.move(state.workspace / "build-overlay", build) + manifest.write_text(json.dumps(state.config.cache_manifest())) + def reuse_cache(state: MkosiState) -> bool: if not state.config.incremental: return False - final, build = cache_tree_paths(state.config) + final, build, manifest = cache_tree_paths(state.config) if not final.exists() or (state.config.build_script and not build.exists()): return False + if manifest.exists(): + prev = json.loads(manifest.read_text()) + if prev != state.config.cache_manifest(): + return False + with complete_step("Copying cached trees"): btrfs_maybe_snapshot_subvolume(state.config, final, state.root) if state.config.build_script: diff --git a/mkosi/config.py b/mkosi/config.py index 55220ec87..ebd4871ce 100644 --- a/mkosi/config.py +++ b/mkosi/config.py @@ -1,4 +1,5 @@ import argparse +import base64 import configparser import copy import dataclasses @@ -716,6 +717,18 @@ class MkosiConfig: def output_changelog(self) -> str: return f"{self.output_with_version}.changelog" + def cache_manifest(self) -> dict[str, Any]: + manifest: dict[str, Any] = { + "packages": self.packages, + "build_packages": self.build_packages, + "repositories": self.repositories, + } + + if self.prepare_script: + manifest["prepare_script"] = base64.b64encode(self.prepare_script.read_bytes()).decode() + + return manifest + class MkosiConfigParser: SETTINGS = (