]> git.ipfire.org Git - thirdparty/mkosi.git/commitdiff
dnf: Share package cache between repositories with different baseurl=
authorDaanDeMeyer <daan.j.demeyer@gmail.com>
Sat, 5 Jul 2025 22:05:05 +0000 (00:05 +0200)
committerDaanDeMeyer <daan.j.demeyer@gmail.com>
Fri, 22 Aug 2025 19:54:52 +0000 (21:54 +0200)
Currently, the dnf5 package is not shared between repositories with the
same id but different baseurl=. For building images this is not ideal,
we do not want to have to redownload all packages when switching the
baseurl= or similar for a repository, so let's fix this by having
package_subdirs() return a tuple of source and destination path, and
in dnf's implementation of it, use the same package cache directory
for all repositories with the same id, regardless of the baseurl= used.

Note that this only applies to the package cache directory, the repository
metadata is still cached in the cache directory that is keyed by the baseurl=
or equivalent setting.

mkosi/__init__.py
mkosi/installer/__init__.py
mkosi/installer/apt.py
mkosi/installer/dnf.py
mkosi/installer/pacman.py
mkosi/installer/zypper.py

index 9d654a13f7477ca0974665db8d60c098aef3e414..5334e484c6c39599716eb1ae7fe493f7dd6b02f9 100644 (file)
@@ -3922,8 +3922,8 @@ def copy_repository_metadata(config: Config, dst: Path) -> None:
                 # cp doesn't support excluding directories but we can imitate it by bind mounting
                 # an empty directory over the directories we want to exclude.
                 exclude = flatten(
-                    ("--ro-bind", tmp, workdir(cachedir / p))
-                    for p in config.distribution.package_manager(config).package_subdirs(cachedir)
+                    ("--ro-bind", tmp, workdir(cachedir / srcsubdir))
+                    for srcsubdir, _ in config.distribution.package_manager(config).package_subdirs(cachedir)
                 )
 
                 subdst = dst / "cache" / subdir
@@ -4895,8 +4895,8 @@ def sync_repository_metadata(
                 )
 
     src = last.package_cache_dir_or_default() / "cache" / subdir
-    for p in last.distribution.package_manager(last).package_subdirs(src):
-        (src / p).mkdir(parents=True, exist_ok=True)
+    for srcsubdir, _ in last.distribution.package_manager(last).package_subdirs(src):
+        (src / srcsubdir).mkdir(parents=True, exist_ok=True)
 
     # If we're in incremental mode and caching metadata is not explicitly disabled, cache the keyring and the
     # synced repository metadata so we can reuse them later.
index 92d5a49b89313bcbd56a56c6b789428b4978c9ca..64e3ce75d6cce1487ff14bed03f77e0532e039c2 100644 (file)
@@ -22,7 +22,7 @@ class PackageManager:
         return Path("custom")
 
     @classmethod
-    def package_subdirs(cls, cache: Path) -> list[Path]:
+    def package_subdirs(cls, cache: Path) -> list[tuple[Path, Path]]:
         return []
 
     @classmethod
@@ -89,13 +89,11 @@ class PackageManager:
                 mounts += flatten(
                     (
                         "--bind",
-                        context.config.package_cache_dir_or_default() / d / subdir / p,
-                        Path("/var") / d / subdir / p,
+                        context.config.package_cache_dir_or_default() / d / subdir / srcsubdir,
+                        Path("/var") / d / subdir / dstsubdir,
                     )
-                    for p in caches
-                    if (
-                        context.config.package_cache_dir_or_default() / d / subdir / p
-                    ).exists()
+                    for srcsubdir, dstsubdir in caches
+                    if (context.config.package_cache_dir_or_default() / d / subdir / srcsubdir).exists()
                 )
 
         return mounts
index 16816ac33c5c102cdf886a3e396a06c4f569b395..966c9a1c7bfacabd1557508dbb93312ea0a436f3 100644 (file)
@@ -54,8 +54,8 @@ class Apt(PackageManager):
         return Path("apt")
 
     @classmethod
-    def package_subdirs(cls, cache: Path) -> list[Path]:
-        return [Path("archives")]
+    def package_subdirs(cls, cache: Path) -> list[tuple[Path, Path]]:
+        return [(Path("archives"), Path("archives"))]
 
     @classmethod
     def state_subdirs(cls, state: Path) -> list[Path]:
index 9e65cff2e03ae6e4879561c938ba53d6ace136f8..7a3d01102ad97a89951c78ffe46a176638d74055 100644 (file)
@@ -25,9 +25,18 @@ class Dnf(PackageManager):
         return Path("libdnf5" if cls.executable(config) == "dnf5" else "dnf")
 
     @classmethod
-    def package_subdirs(cls, cache: Path) -> list[Path]:
+    def package_subdirs(cls, cache: Path) -> list[tuple[Path, Path]]:
+        dirs = [p for p in cache.iterdir() if p.is_dir() and "-" in p.name and "mkosi" not in p.name]
         return [
-            (p / "packages").relative_to(cache) for p in cache.iterdir() if p.is_dir() and "-" in p.name and "mkosi" not in p.name
+            (
+                d.relative_to(cache) / "packages"
+                if cache == Path("/var")
+                # Cache directories look like <repo-id>-<baseurl-hash> so let's strip off the hash to reuse
+                # the same package cache directory regardless of baseurl.
+                else Path("packages") / d.name[: d.name.rfind("-")],
+                d.relative_to(cache) / "packages",
+            )
+            for d in dirs
         ]
 
     @classmethod
index 0d85fdcc753d7d2d75414bc6c108d67fc1d1f64d..cd142b686824bd32c5757fed783ce9a0dabdcb59 100644 (file)
@@ -35,8 +35,8 @@ class Pacman(PackageManager):
         return Path("pacman")
 
     @classmethod
-    def package_subdirs(cls, cache: Path) -> list[Path]:
-        return [Path("pkg")]
+    def package_subdirs(cls, cache: Path) -> list[tuple[Path, Path]]:
+        return [(Path("pkg"), Path("pkg"))]
 
     @classmethod
     def state_subdirs(cls, state: Path) -> list[Path]:
index d513f23bfbe14e33eb3beab8a1a2b2cc77a1155b..78704815b8c442f685104771f9394ea23d96acdf 100644 (file)
@@ -23,8 +23,8 @@ class Zypper(PackageManager):
         return Path("zypp")
 
     @classmethod
-    def package_subdirs(cls, cache: Path) -> list[Path]:
-        return [Path("packages")]
+    def package_subdirs(cls, cache: Path) -> list[tuple[Path, Path]]:
+        return [(Path("packages"), Path("packages"))]
 
     @classmethod
     def scripts(cls, context: Context) -> dict[str, list[PathString]]: