raise
+@contextlib.contextmanager
+def lock_repository_metadata(config: Config) -> Iterator[None]:
+ subdir = config.distribution.package_manager(config).subdir(config)
+
+ with contextlib.ExitStack() as stack:
+ for d in ("cache", "lib"):
+ if (src := config.package_cache_dir_or_default() / d / subdir).exists():
+ stack.enter_context(flock(src))
+
+ yield
+
+
def copy_repository_metadata(context: Context) -> None:
if have_cache(context.config):
return
logging.debug(f"Found repository metadata in {context.package_cache_dir}, not copying repository metadata")
return
- for d in ("cache", "lib"):
- src = context.config.package_cache_dir_or_default() / d / subdir
- if not src.exists():
- logging.debug(f"{src} does not exist, not copying repository metadata from it")
- continue
+ with lock_repository_metadata(context.config):
+ for d in ("cache", "lib"):
+ src = context.config.package_cache_dir_or_default() / d / subdir
+ if not src.exists():
+ logging.debug(f"{src} does not exist, not copying repository metadata from it")
+ continue
- caches = context.config.distribution.package_manager(context.config).cache_subdirs(src) if d == "cache" else []
+ if d == "cache":
+ caches = context.config.distribution.package_manager(context.config).cache_subdirs(src)
+ else:
+ caches = []
- with tempfile.TemporaryDirectory() as tmp:
- os.chmod(tmp, 0o755)
+ with tempfile.TemporaryDirectory() as tmp:
+ os.chmod(tmp, 0o755)
- # 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, os.fspath(p)] for p in caches)
+ # 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, os.fspath(p)] for p in caches)
- dst = context.package_cache_dir / d / subdir
- with umask(~0o755):
- dst.mkdir(parents=True, exist_ok=True)
+ dst = context.package_cache_dir / d / subdir
+ with umask(~0o755):
+ dst.mkdir(parents=True, exist_ok=True)
- def sandbox(*, options: Sequence[PathString] = ()) -> list[PathString]:
- return context.sandbox(options=[*options, *exclude])
+ def sandbox(*, options: Sequence[PathString] = ()) -> list[PathString]:
+ return context.sandbox(options=[*options, *exclude])
- with flock(src):
copy_tree(
src, dst,
tools=context.config.tools(),
):
subdir = config.distribution.package_manager(config).subdir(config)
- with complete_step(f"Clearing out package cache of {config.name()} image…"):
+ with (
+ complete_step(f"Clearing out package cache of {config.name()} image…"),
+ lock_repository_metadata(config),
+ ):
rmtree(
*(
config.package_cache_dir_or_default() / d / subdir
if have_cache(context.config) or context.config.cacheonly != Cacheonly.none:
return
- with complete_step(f"Syncing package manager metadata for {context.config.name()} image"):
- subdir = context.config.distribution.package_manager(context.config).subdir(context.config)
-
- with (
- flock(context.config.package_cache_dir_or_default() / "cache" / subdir),
- flock(context.config.package_cache_dir_or_default() / "lib" / subdir),
- ):
- context.config.distribution.package_manager(context.config).sync(context)
+ with (
+ complete_step(f"Syncing package manager metadata for {context.config.name()} image"),
+ lock_repository_metadata(context.config),
+ ):
+ context.config.distribution.package_manager(context.config).sync(context)
def run_sync(args: Args, config: Config, *, resources: Path) -> None: