From cf040726e342e531e4a382c1d0fb31e72e9ec7a4 Mon Sep 17 00:00:00 2001 From: Tobias Fischer Date: Fri, 13 Nov 2026 14:25:25 +1000 Subject: [PATCH] Keep downloaded conda-forge-pinning versions in a cache A version's contents don't change, so download_pinning_package keeps it in $VINCA_CACHE_DIR (default ~/.cache/vinca) and every later render of the same version (e.g. every distribution of a repository) reads it from there. RoboStack's humble render: 2.0 s, then 0.6 s. Co-Authored-By: Claude Opus 5.5 --- vinca/pinning.py | 65 +++++++++++++++++++++++++++++++------------ vinca/test_pinning.py | 20 +++++++++++++ 2 files changed, 67 insertions(+), 18 deletions(-) diff --git a/vinca/pinning.py b/vinca/pinning.py index e1d689e..443807f 100644 --- a/vinca/pinning.py +++ b/vinca/pinning.py @@ -87,28 +87,57 @@ def get_pinning_distribution(version: str) -> str: return _newest_pinning_record(f"{PINNING_PACKAGE}=={version}").url +def pinning_cache_dir() -> Path: + """Where downloaded conda-forge-pinning versions are kept: ``$VINCA_CACHE_DIR``, + or ``vinca`` in the user's cache directory.""" + if cache := os.environ.get("VINCA_CACHE_DIR"): + return Path(cache) / "conda-forge-pinning" + base = os.environ.get("XDG_CACHE_HOME") or Path.home() / ".cache" + return Path(base) / "vinca" / "conda-forge-pinning" + + +def _extract_pinning(url: str, dest: Path) -> None: + try: + asyncio.run(download_and_extract(rattler.Client(), url, dest)) + except (ExtractError, OSError) as exc: + raise PinningError(f"Could not download {url}: {exc}") from exc + if not (dest / "conda_build_config.yaml").is_file(): + raise PinningError("conda_build_config.yaml is missing from pinning artifact") + + +def _read_pinning(path: Path) -> tuple[bytes, dict[str, bytes]]: + migrations = { + migration.stem: migration.read_bytes() + for migration in (path / "share/conda-forge/migrations").glob("*.yaml") + } + return (path / "conda_build_config.yaml").read_bytes(), migrations + + def download_pinning_package( version: str, *, artifact_url: Optional[str] = None ) -> tuple[bytes, dict[str, bytes]]: """Download a versioned pinning artifact, or the supplied artifact URL, into its - base config and named migrations.""" - url = artifact_url or get_pinning_distribution(version) - with tempfile.TemporaryDirectory() as tmp: - dest = Path(tmp) - try: - asyncio.run(download_and_extract(rattler.Client(), url, dest)) - except (ExtractError, OSError) as exc: - raise PinningError(f"Could not download {url}: {exc}") from exc - base = dest / "conda_build_config.yaml" - if not base.is_file(): - raise PinningError( - "conda_build_config.yaml is missing from pinning artifact" - ) - migrations = { - path.stem: path.read_bytes() - for path in (dest / "share/conda-forge/migrations").glob("*.yaml") - } - return base.read_bytes(), migrations + base config and named migrations. + + A version is downloaded once and kept in :func:`pinning_cache_dir` (a version's + contents don't change): rendering every distribution, or rendering again, needs + no download.""" + if artifact_url: + with tempfile.TemporaryDirectory() as tmp: + _extract_pinning(artifact_url, Path(tmp)) + return _read_pinning(Path(tmp)) + cached = pinning_cache_dir() / version + if not (cached / "conda_build_config.yaml").is_file(): + cached.parent.mkdir(parents=True, exist_ok=True) + # extracted next to the cache entry, then moved: never a partial entry + with tempfile.TemporaryDirectory(dir=cached.parent) as tmp: + _extract_pinning(get_pinning_distribution(version), Path(tmp) / "pkg") + try: + (Path(tmp) / "pkg").rename(cached) + except OSError: + if not (cached / "conda_build_config.yaml").is_file(): + raise # not a concurrent download of the same version + return _read_pinning(cached) def _pinning_spec_fields( diff --git a/vinca/test_pinning.py b/vinca/test_pinning.py index 5b7658c..3ef1a52 100644 --- a/vinca/test_pinning.py +++ b/vinca/test_pinning.py @@ -78,6 +78,26 @@ def test_download_pinning_package_that_does_not_exist(tmp_path): download_pinning_package("1", artifact_url=url) +def test_download_pinning_package_downloads_a_version_once(tmp_path, monkeypatch): + url = _pinning_package( + tmp_path / "conda-forge-pinning-1-0.tar.bz2", + { + "conda_build_config.yaml": BASE_CONFIG, + "share/conda-forge/migrations/libboost190.yaml": BOOST_MIGRATION, + }, + ) + monkeypatch.setenv("VINCA_CACHE_DIR", str(tmp_path / "cache")) + with patch("vinca.pinning.get_pinning_distribution", return_value=url) as lookup: + first = download_pinning_package("1") + second = download_pinning_package("1") + + assert first == second == (BASE_CONFIG, {"libboost190": BOOST_MIGRATION}) + assert lookup.call_count == 1 + assert ( + tmp_path / "cache" / "conda-forge-pinning" / "1" / "conda_build_config.yaml" + ).is_file() + + def test_render_applies_base_migration_then_override(tmp_path): config_path = tmp_path / "vinca_pinning.yaml" config_path.write_text(