]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Rework --run-build-scripts 3585/head
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Thu, 6 Mar 2025 22:47:33 +0000 (23:47 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 7 Mar 2025 09:36:48 +0000 (10:36 +0100)
Instead of (optionally) building the image when this option is enabled,
let's insist that the image has already been built and cached. This allows
us to reuse the history of the previous build if History= is enabled. At
the same time, rename the option to --rerun-build-scripts to indicate more
clearly that the image needs to have been built once already.

This allows the option to be used in systemd's mkosi.clangd script to replace
"-t none" and "--incremental=strict" there.

mkosi/__init__.py
mkosi/config.py
mkosi/resources/man/mkosi.1.md
tests/test_json.py

index df59b1a7184de0c1549b0145e4c0a8ad625218b5..126d747189b86f12ee2b97b6b7bc14503087e4f7 100644 (file)
@@ -3928,10 +3928,7 @@ def build_image(context: Context) -> None:
         check_root_populated(context)
         run_build_scripts(context)
 
-        if context.config.output_format == OutputFormat.none or (
-            context.args.run_build_scripts
-            and (context.config.output_dir_or_cwd() / context.config.output).exists()
-        ):
+        if context.config.output_format == OutputFormat.none or context.args.rerun_build_scripts:
             return
 
         if wantrepo:
@@ -5106,6 +5103,13 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
             Verb.sandbox: run_sandbox,
         }[args.verb](args, last)
 
+    if last.output_format == OutputFormat.none:
+        if args.verb != Verb.build:
+            die(f"Cannot run '{args.verb}' verb on image with output format 'none'")
+
+        if args.rerun_build_scripts:
+            die("Cannot use --run-build-scripts on image with output format 'none'")
+
     output = last.output_dir_or_cwd() / last.output_with_compression
 
     if (
@@ -5114,11 +5118,17 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
         and output.exists()
         and not output.is_symlink()
         and last.output_format != OutputFormat.none
-        and not args.run_build_scripts
+        and not args.rerun_build_scripts
     ):
         logging.info(f"Output path {output} exists already. (Use --force to rebuild.)")
         return
 
+    if args.rerun_build_scripts and not output.exists():
+        die(
+            f"Image '{last.image}' must be built once before --rerun-build-scripts can be used",
+            hint="Build the image once with 'mkosi build'",
+        )
+
     if args.verb != Verb.build and not args.force and not output.exists():
         die(
             f"Image '{last.image}' has not been built yet",
@@ -5130,6 +5140,9 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
 
     check_workspace_directory(last)
 
+    if args.rerun_build_scripts and not last.is_incremental():
+        die("Incremental= must be enabled to be able to use --rerun-build-scripts")
+
     if last.is_incremental():
         for a, b in itertools.combinations(images, 2):
             if a.expand_key_specifiers(a.cache_key) == b.expand_key_specifiers(b.cache_key):
@@ -5138,21 +5151,24 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
                     hint="Add the &I specifier to the cache key to avoid this issue",
                 )
 
-    if last.is_incremental() and last.incremental == Incremental.strict:
+    if last.is_incremental() and (last.incremental == Incremental.strict or args.rerun_build_scripts):
         if args.force > 1:
             die(
                 "Cannot remove incremental caches when building with Incremental=strict",
                 hint="Build once with '-i yes' to update the image cache",
             )
 
-        for config in images:
-            if have_cache(config):
-                continue
-
-            die(
-                f"Strict incremental mode is enabled and cache for image {config.image} is out-of-date",
-                hint="Build once with '-i yes' to update the image cache",
-            )
+        if any((c := config).is_incremental() and not have_cache(config) for config in images):
+            if args.rerun_build_scripts:
+                die(
+                    f"Cannot use --rerun-build-scripts as the cache for image {c.image} is out-of-date",
+                    hint="Rebuild the image to update the image cache",
+                )
+            else:
+                die(
+                    f"Strict incremental mode is enabled and cache for image {c.image} is out-of-date",
+                    hint="Build once with '-i yes' to update the image cache",
+                )
 
     # First, process all directory removals because otherwise if different images share directories
     # a later image build could end up deleting the output generated by an earlier image build.
@@ -5179,7 +5195,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
         images = resolve_deps(images[:-1], last.dependencies) + [last]
 
     if (
-        args.run_build_scripts
+        args.rerun_build_scripts
         or last.output_format == OutputFormat.none
         or not (last.output_dir_or_cwd() / last.output).exists()
     ):
@@ -5231,7 +5247,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
                 # nothing to do so exit early.
                 if (
                     config.output_format == OutputFormat.none
-                    or (args.run_build_scripts and (config.output_dir_or_cwd() / config.output).exists())
+                    or (args.rerun_build_scripts and (config.output_dir_or_cwd() / config.output).exists())
                 ) and not config.build_scripts:
                     continue
 
@@ -5265,7 +5281,7 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
         if args.auto_bump:
             bump_image_version()
 
-        if last.history:
+        if last.history and not args.rerun_build_scripts:
             Path(".mkosi-private/history").mkdir(parents=True, exist_ok=True)
             Path(".mkosi-private/history/latest.json").write_text(
                 json.dumps(
index 152b757153a4ab889fbdb3ebff474fe0ceb3aca4..002b3e41bda018f2a80909330c462c1ff50a180f 100644 (file)
@@ -1697,7 +1697,7 @@ class Args:
     doc_format: DocFormat
     json: bool
     wipe_build_dir: bool
-    run_build_scripts: bool
+    rerun_build_scripts: bool
 
     @classmethod
     def default(cls) -> "Args":
@@ -4207,7 +4207,7 @@ def create_argument_parser(chdir: bool = True) -> argparse.ArgumentParser:
     )
     parser.add_argument(
         "-R",
-        "--run-build-scripts",
+        "--rerun-build-scripts",
         help="Run build scripts even if the image is not rebuilt",
         action="store_true",
         default=False,
@@ -4710,7 +4710,7 @@ def have_history(args: Args) -> bool:
     return (
         args.directory is not None
         and args.verb.needs_build()
-        and args.verb != Verb.build
+        and (args.verb != Verb.build or args.rerun_build_scripts)
         and not args.force
         and Path(".mkosi-private/history/latest.json").exists()
     )
@@ -4746,6 +4746,9 @@ def parse_config(
     if args.cmdline and not args.verb.supports_cmdline():
         die(f"Arguments after verb are not supported for {args.verb}.")
 
+    if args.rerun_build_scripts and args.force:
+        die("--force cannot be used together with --rerun-build-scripts")
+
     # If --debug was passed, apply it as soon as possible.
     if ARG_DEBUG.get():
         logging.getLogger().setLevel(logging.DEBUG)
index 0dee6cd9ec7d88973d9498bc3d9b60407e3f689c..17230a24c63562e3905a1676f7693bec47e741eb 100644 (file)
@@ -293,6 +293,12 @@ Those settings cannot be configured in the configuration files.
 `--wipe-build-dir`, `-w`
 :   Wipe the build directory if one is configured before building the image.
 
+`--rerun-build-scripts`, `-R`
+:   Rerun build scripts. Requires the `Incremental=` option to be
+    enabled and the image to have been built once already. If `History=`
+    is enabled, the config from the previous build will be reused and no
+    new history will be written.
+
 ## Supported output formats
 
 The following output formats are supported:
index 348ac8a0a238fed84b195647d976407186218321..1207459a3ca00be7a639802c61c25e1d07f96099 100644 (file)
@@ -67,7 +67,7 @@ def test_args(path: Optional[Path]) -> None:
             "GenkeyValidDays": "100",
             "Json": false,
             "Pager": true,
-            "RunBuildScripts": true,
+            "RerunBuildScripts": true,
             "Verb": "build",
             "WipeBuildDir": true
         }}
@@ -88,7 +88,7 @@ def test_args(path: Optional[Path]) -> None:
         genkey_valid_days="100",
         json=False,
         pager=True,
-        run_build_scripts=True,
+        rerun_build_scripts=True,
         verb=Verb.build,
         wipe_build_dir=True,
     )