diff --git a/crates/uv-distribution/src/archive.rs b/crates/uv-distribution/src/archive.rs index 3d02d9e851c7..eb4258bf7dc7 100644 --- a/crates/uv-distribution/src/archive.rs +++ b/crates/uv-distribution/src/archive.rs @@ -1,6 +1,6 @@ use distribution_types::Hashed; use pypi_types::HashDigest; -use uv_cache::ArchiveId; +use uv_cache::{ArchiveId, Cache}; /// An archive (unzipped wheel) that exists in the local cache. #[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] @@ -16,6 +16,11 @@ impl Archive { pub(crate) fn new(id: ArchiveId, hashes: Vec) -> Self { Self { id, hashes } } + + /// Returns `true` if the archive exists in the cache. + pub(crate) fn exists(&self, cache: &Cache) -> bool { + cache.archive(&self.id).exists() + } } impl Hashed for Archive { diff --git a/crates/uv-distribution/src/distribution_database.rs b/crates/uv-distribution/src/distribution_database.rs index c227580d604c..f8e1e848a82e 100644 --- a/crates/uv-distribution/src/distribution_database.rs +++ b/crates/uv-distribution/src/distribution_database.rs @@ -596,8 +596,12 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> { CachedClientError::Client(err) => Error::Client(err), })?; - // If the archive is missing the required hashes, force a refresh. - let archive = if archive.has_digests(hashes) { + // If the archive is missing the required hashes, or has since been removed, force a refresh. + let archive = Some(archive) + .filter(|archive| archive.has_digests(hashes)) + .filter(|archive| archive.exists(self.build_context.cache())); + + let archive = if let Some(archive) = archive { archive } else { self.client @@ -746,12 +750,16 @@ impl<'a, Context: BuildContext> DistributionDatabase<'a, Context> { CachedClientError::Client(err) => Error::Client(err), })?; - // If the archive is missing the required hashes, force a refresh. - let archive = if archive.has_digests(hashes) { + // If the archive is missing the required hashes, or has since been removed, force a refresh. + let archive = Some(archive) + .filter(|archive| archive.has_digests(hashes)) + .filter(|archive| archive.exists(self.build_context.cache())); + + let archive = if let Some(archive) = archive { archive } else { self.client - .managed(|client| async move { + .managed(|client| async { client .cached_client() .skip_cache(self.request(url)?, &http_entry, download)