]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Simplify run_verb() logic
authorDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 23 Aug 2024 16:44:04 +0000 (18:44 +0200)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Fri, 23 Aug 2024 19:44:11 +0000 (21:44 +0200)
- Handle Verb.clean separately from builds
- Move most checks to the front before we clean up the previous results.
- Get rid of check_outputs()
- If main image needs a build, clean all subimages as well

mkosi/__init__.py

index 014c04237ada054dd2b2b2cb2bd84c0e00144d91..73a651a927ce67bd5625d2b7db2188c9a3c1121c 100644 (file)
@@ -2880,16 +2880,6 @@ def check_inputs(config: Config) -> None:
             die(f"{script} is not executable")
 
 
-def check_outputs(config: Config) -> None:
-    if config.output_format == OutputFormat.none:
-        return
-
-    f = config.output_dir_or_cwd() / config.output_with_compression
-
-    if f.exists() and not f.is_symlink():
-        logging.info(f"Output path {f} exists already. (Use --force to rebuild.)")
-
-
 def check_tool(config: Config, *tools: PathString, reason: str, hint: Optional[str] = None) -> Path:
     tool = config.find_binary(*tools)
     if not tool:
@@ -4510,9 +4500,8 @@ def run_clean_scripts(config: Config) -> None:
                 )
 
 
-def needs_clean(args: Args, config: Config, force: int = 1) -> bool:
+def needs_build(args: Args, config: Config, force: int = 1) -> bool:
     return (
-        args.verb == Verb.clean or
         args.force >= force or
         not (config.output_dir_or_cwd() / config.output_with_compression).exists() or
         # When the output is a directory, its name is the same as the symlink we create that points to the actual
@@ -4741,6 +4730,11 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
         page(text, args.pager)
         return
 
+    last = images[-1]
+
+    if (minversion := last.minimum_version) and minversion > __version__:
+        die(f"mkosi {minversion} or newer is required by this configuration (found {__version__})")
+
     if args.verb in (Verb.journalctl, Verb.coredumpctl, Verb.ssh):
         # We don't use a tools tree for verbs that don't need an image build.
         last = dataclasses.replace(images[-1], tools_tree=None)
@@ -4750,108 +4744,110 @@ def run_verb(args: Args, images: Sequence[Config], *, resources: Path) -> None:
             Verb.coredumpctl: run_coredumpctl,
         }[args.verb](args, last)
 
-    assert args.verb.needs_build() or args.verb == Verb.clean
-
-    for config in images:
-        if args.verb == Verb.build and not args.force:
-            check_outputs(config)
-
-    last = images[-1]
-
     if last.tools_tree and last.tools_tree == Path("default"):
         tools = finalize_default_tools(args, last, resources=resources)
-
-        # If we're doing an incremental build and the cache is not out of date, don't clean up the tools tree
-        # so that we can reuse the previous one.
-        if (
-            not tools.incremental or
-            ((args.verb == Verb.build or args.force > 0) and not have_cache(tools)) or
-            needs_clean(args, tools, force=2)
-        ):
-            run_clean(args, tools, resources=resources)
     else:
         tools = None
 
-    # 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.
-    for config in images:
-        if needs_clean(args, config) or args.wipe_build_dir:
+    if args.verb == Verb.clean:
+        if tools:
+            run_clean(args, tools, resources=resources)
+
+        for config in images:
             run_clean(args, config, resources=resources)
 
-    if args.verb == Verb.clean:
         return
 
-    for config in images:
-        if (minversion := config.minimum_version) and minversion > __version__:
-            die(f"mkosi {minversion} or newer is required to build this configuration (found {__version__})")
+    assert args.verb.needs_build()
 
-        if not config.repart_offline and os.getuid() != 0:
-            die(f"Must be root to build {config.name()} image configured with RepartOffline=no")
+    if (
+        tools and
+        not (tools.output_dir_or_cwd() / tools.output).exists() and
+        args.verb != Verb.build and
+        not args.force
+    ):
+        die(f"Default tools tree requested for image '{last.name()}' but it has not been built yet",
+            hint="Make sure to build the image first with 'mkosi build' or use '--force'")
 
-        check_workspace_directory(config)
+    if not last.repart_offline and os.getuid() != 0:
+        die(f"Must be root to build {last.name()} image configured with RepartOffline=no")
 
-    if tools and not (tools.output_dir_or_cwd() / tools.output).exists():
-        if args.verb == Verb.build or args.force > 0:
-            with prepend_to_environ_path(tools):
-                check_tools(tools, Verb.build)
-                run_sync(args, tools, resources=resources)
-                fork_and_wait(run_build, args, tools, resources=resources)
-        else:
-            die(f"Default tools tree requested for image '{last.name()}' but it has not been built yet",
-                hint="Make sure to build the image first with 'mkosi build' or use '--force'")
+    output = last.output_dir_or_cwd() / last.output_with_compression
 
-    build = False
+    if args.verb == Verb.build and not args.force and output.exists() and not output.is_symlink():
+        logging.info(f"Output path {output} exists already. (Use --force to rebuild.)")
+        return
 
-    with tempfile.TemporaryDirectory(dir=last.workspace_dir_or_default(), prefix="mkosi-packages-") as package_dir:
-        for i, config in enumerate(images):
-            images[i] = config = dataclasses.replace(
-                config,
-                tools_tree=(
-                    tools.output_dir_or_cwd() / tools.output
-                    if tools and config.tools_tree == Path("default")
-                    else config.tools_tree
-                )
-            )
+    if args.verb != Verb.build and not args.force and not output.exists():
+        die(f"Image '{last.name()}' has not been built yet",
+            hint="Make sure to build the image first with 'mkosi build' or use '--force'")
 
-            with prepend_to_environ_path(config):
-                check_tools(config, args.verb)
-                images[i] = config = run_configure_scripts(config)
+    check_workspace_directory(last)
 
-                if args.verb != Verb.build and args.force == 0:
-                    continue
+    # If we're doing an incremental build and the cache is not out of date, don't clean up the tools tree
+    # so that we can reuse the previous one.
+    if (
+        tools and
+        (
+            not tools.incremental or
+            ((args.verb == Verb.build or args.force > 0) and not have_cache(tools)) or
+            needs_build(args, tools, force=2)
+        )
+    ):
+        run_clean(args, tools, resources=resources)
 
-                if (
-                    config.output_format != OutputFormat.none and
-                    (config.output_dir_or_cwd() / config.output_with_compression).exists()
-                ):
-                    continue
+    # 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.
+    if needs_build(args, last) or args.wipe_build_dir:
+        for config in images:
+            run_clean(args, config, resources=resources)
 
+    if tools and not (tools.output_dir_or_cwd() / tools.output).exists():
+        with prepend_to_environ_path(tools):
+            check_tools(tools, Verb.build)
+            run_sync(args, tools, resources=resources)
+            fork_and_wait(run_build, args, tools, resources=resources)
+
+    for i, config in enumerate(images):
+        images[i] = config = dataclasses.replace(
+            config,
+            tools_tree=(
+                tools.output_dir_or_cwd() / tools.output
+                if tools and config.tools_tree == Path("default")
+                else config.tools_tree
+            )
+        )
+
+        with prepend_to_environ_path(config):
+            check_tools(config, args.verb)
+            images[i] = config = run_configure_scripts(config)
+
+    # The images array has been modified so we need to reevaluate last again.
+    last = images[-1]
+
+    if not (last.output_dir_or_cwd() / last.output).exists():
+        with (
+            tempfile.TemporaryDirectory(dir=last.workspace_dir_or_default(), prefix="mkosi-packages-") as package_dir,
+        ):
+            for config in images:
                 # If the output format is "none" and there are no build scripts, there's nothing to do so exit early.
                 if config.output_format == OutputFormat.none and not config.build_scripts:
-                    return
-
-                if args.verb != Verb.build:
-                    check_tools(config, Verb.build)
+                    continue
 
-                check_inputs(config)
-                run_sync(args, config, resources=resources)
-                fork_and_wait(run_build, args, config, resources=resources, package_dir=Path(package_dir))
+                with prepend_to_environ_path(config):
+                    if args.verb != Verb.build:
+                        check_tools(config, Verb.build)
 
-                build = True
+                    check_inputs(config)
+                    run_sync(args, last, resources=resources)
+                    fork_and_wait(run_build, args, config, resources=resources, package_dir=Path(package_dir))
 
-    if build and args.auto_bump:
-        bump_image_version()
+            if args.auto_bump:
+                bump_image_version()
 
     if args.verb == Verb.build:
         return
 
-    # The images array has been modified so we need to reevaluate last again.
-    last = images[-1]
-
-    if not (last.output_dir_or_cwd() / last.output_with_compression).exists():
-        die(f"Image '{last.name()}' has not been built yet",
-            hint="Make sure to build the image first with 'mkosi build' or use '--force'")
-
     if (
         last.output_format == OutputFormat.directory and
         (last.output_dir_or_cwd() / last.output).stat().st_uid == 0 and