From: Daan De Meyer Date: Fri, 23 Aug 2024 16:44:04 +0000 (+0200) Subject: Simplify run_verb() logic X-Git-Tag: v25~342^2~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0e2e5383dc3b389eec5b2beecc86eab006dddd38;p=thirdparty%2Fmkosi.git Simplify run_verb() logic - 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 --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 014c04237..73a651a92 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -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