]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
Remove all cached images if repository metadata will be synced
authorDaan De Meyer <daan@amutable.com>
Mon, 16 Feb 2026 08:05:54 +0000 (09:05 +0100)
committerDaan De Meyer <daan.j.demeyer@gmail.com>
Mon, 16 Feb 2026 09:25:50 +0000 (10:25 +0100)
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.

mkosi/__init__.py
mkosi/resources/man/mkosi.1.md

index 9c24ab6933dd5b872d0ea7ff1ca50387dcd3f7eb..b18c6ae4085988741152c3e2bdc0d5b596f74271 100644 (file)
@@ -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:
index 36f8c8debe4a40228e44c1e22b7c8b2688e8e02d..75582483cbb35842e8a63eebb08a9cb58cb9283b 100644 (file)
@@ -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.