From: Daan De Meyer Date: Mon, 16 Feb 2026 08:05:54 +0000 (+0100) Subject: Remove all cached images if repository metadata will be synced X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4eac60f168f3dd4cddb419818512ef51e06e8301;p=thirdparty%2Fmkosi.git Remove all cached images if repository metadata will be synced If we don't do this, and packages are installed in postinstall scripts, we can end up in partial upgrade situations, where we install packages that depend on newer versions of libraries that are installed. This is particularly a problem on Arch Linux, which explicitly does not support partial upgrades. To solve the issue, if we decide we need to sync repository metadata, remove all cached images. To avoid removing syncing repository metadata (and thus removing all cached images) when a cached image is invalidated, CacheOnly=metadata can be configured for the image. --- diff --git a/mkosi/__init__.py b/mkosi/__init__.py index 9c24ab693..b18c6ae40 100644 --- a/mkosi/__init__.py +++ b/mkosi/__init__.py @@ -2788,6 +2788,9 @@ def check_inputs(config: Config) -> None: ), ) + if config.is_incremental() and config.cacheonly == Cacheonly.never: + die("Incremental=yes cannot be used with CacheOnly=never") + def check_tool(config: Config, *tools: PathString, reason: str, hint: Optional[str] = None) -> Path: tool = config.find_binary(*tools) @@ -4731,7 +4734,7 @@ def remove_cache_entries(config: Config) -> None: rmtree(*(p for p in cache_tree_paths(config) if p.exists()), sandbox=sandbox) -def run_clean(args: Args, config: Config) -> None: +def run_clean(args: Args, config: Config, repository_metadata_needs_sync: bool = False) -> None: # We remove any cached images if either the user used --force twice, or he/she called "clean" # with it passed once. Let's also remove the downloaded package cache if the user specified one # additional "--force". @@ -4752,7 +4755,7 @@ def run_clean(args: Args, config: Config) -> None: config.is_incremental() and not have_cache(config) ) remove_build_cache = args.force > 1 or args.wipe_build_dir - remove_image_cache = args.force > 1 or not have_cache(config) + remove_image_cache = args.force > 1 or not have_cache(config) or repository_metadata_needs_sync remove_package_cache = args.force > 2 if remove_outputs: @@ -4825,6 +4828,17 @@ def ensure_directories_exist(config: Config) -> None: config.build_subdir.chmod(stat.S_IMODE(st.st_mode) & ~(stat.S_ISGID | stat.S_ISUID)) +def repository_metadata_needs_sync(images: Sequence[Config]) -> bool: + for config in images: + if config.cacheonly == Cacheonly.never: + return True + + if config.cacheonly == Cacheonly.auto and not have_cache(config): + return True + + return False + + def sync_repository_metadata( args: Args, images: Sequence[Config], @@ -4872,14 +4886,8 @@ def sync_repository_metadata( (last.package_cache_dir_or_default() / "cache" / subdir).mkdir(parents=True, exist_ok=True) - def needs_sync(config: Config) -> bool: - if config.cacheonly != Cacheonly.auto: - return config.cacheonly == Cacheonly.never - - return not have_cache(config) - # Sync repository metadata unless explicitly disabled. - if any(needs_sync(config) for config in images): + if repository_metadata_needs_sync(images): with setup_workspace(args, last) as workspace: context = Context( args, @@ -5204,7 +5212,7 @@ def run_verb(args: Args, tools: Optional[Config], images: Sequence[Config], *, r # 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) + run_clean(args, config, repository_metadata_needs_sync(images)) for i, config in enumerate(images): if args.verb != Verb.build: diff --git a/mkosi/resources/man/mkosi.1.md b/mkosi/resources/man/mkosi.1.md index 36f8c8deb..75582483c 100644 --- a/mkosi/resources/man/mkosi.1.md +++ b/mkosi/resources/man/mkosi.1.md @@ -1564,7 +1564,7 @@ boolean argument: either `1`, `yes`, or `true` to enable, or `0`, `no`, as the package cache is already fully populated. If set to `metadata`, the package manager can still download packages, but we won't sync the repository metadata. If set to `auto`, the repository metadata is - synced unless the image is cached (see `Incremental=`) and packages can + synced unless all images are cached (see `Incremental=`) and packages can be downloaded during the build. If set to `never`, repository metadata is always synced and packages can be downloaded during the build.