diff --git a/crates/uv-distribution/src/source/built_wheel_metadata.rs b/crates/uv-distribution/src/source/built_wheel_metadata.rs index 4d3a87c6f..e097a2f3c 100644 --- a/crates/uv-distribution/src/source/built_wheel_metadata.rs +++ b/crates/uv-distribution/src/source/built_wheel_metadata.rs @@ -27,6 +27,40 @@ pub(crate) struct BuiltWheelMetadata { } impl BuiltWheelMetadata { + /// Create a [`BuiltWheelMetadata`] from a [`BuiltWheelFile`]. + pub(crate) fn from_file( + file: BuiltWheelFile, + hashes: HashDigests, + cache_info: CacheInfo, + ) -> Self { + Self { + path: file.path, + target: file.target, + filename: file.filename, + hashes, + cache_info, + } + } +} + +impl Hashed for BuiltWheelMetadata { + fn hashes(&self) -> &[HashDigest] { + self.hashes.as_slice() + } +} + +/// The path to a built wheel file, along with its parsed filename. +#[derive(Debug, Clone)] +pub(crate) struct BuiltWheelFile { + /// The path to the built wheel. + pub(crate) path: Box, + /// The expected path to the downloaded wheel's entry in the cache. + pub(crate) target: Box, + /// The parsed filename. + pub(crate) filename: WheelFilename, +} + +impl BuiltWheelFile { /// Find a compatible wheel in the cache. pub(crate) fn find_in_cache( tags: &Tags, @@ -51,26 +85,12 @@ impl BuiltWheelMetadata { target: cache_shard.join(filename.stem()).into_boxed_path(), path: path.into_boxed_path(), filename, - cache_info: CacheInfo::default(), - hashes: HashDigests::empty(), }) } - #[must_use] - pub(crate) fn with_hashes(mut self, hashes: HashDigests) -> Self { - self.hashes = hashes; - self - } - /// Returns `true` if the wheel matches the given package name and version. pub(crate) fn matches(&self, name: Option<&PackageName>, version: Option<&Version>) -> bool { name.is_none_or(|name| self.filename.name == *name) && version.is_none_or(|version| self.filename.version == *version) } } - -impl Hashed for BuiltWheelMetadata { - fn hashes(&self) -> &[HashDigest] { - self.hashes.as_slice() - } -} diff --git a/crates/uv-distribution/src/source/mod.rs b/crates/uv-distribution/src/source/mod.rs index 2e0e6c224..08a88f87a 100644 --- a/crates/uv-distribution/src/source/mod.rs +++ b/crates/uv-distribution/src/source/mod.rs @@ -49,7 +49,7 @@ use uv_workspace::pyproject::ToolUvSources; use crate::distribution_database::ManagedClient; use crate::error::Error; use crate::metadata::{ArchiveMetadata, GitWorkspaceMember, Metadata}; -use crate::source::built_wheel_metadata::BuiltWheelMetadata; +use crate::source::built_wheel_metadata::{BuiltWheelFile, BuiltWheelMetadata}; use crate::source::revision::Revision; use crate::{Reporter, RequiresDist}; @@ -454,6 +454,10 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { let cache_shard = cache_shard.shard(revision.id()); let source_dist_entry = cache_shard.entry(SOURCE); + // We don't track any cache information for URL-based source distributions; they're assumed + // to be immutable. + let cache_info = CacheInfo::default(); + // If there are build settings or extra build dependencies, we need to scope to a cache shard. let config_settings = self.config_settings_for(source.name()); let extra_build_deps = self.extra_build_dependencies_for(source.name()); @@ -472,12 +476,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { }; // If the cache contains a compatible wheel, return it. - if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard) + if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard) .ok() .flatten() - .filter(|built_wheel| built_wheel.matches(source.name(), source.version())) + .filter(|file| file.matches(source.name(), source.version())) { - return Ok(built_wheel.with_hashes(revision.into_hashes())); + return Ok(BuiltWheelMetadata::from_file( + file, + revision.into_hashes(), + cache_info, + )); } // Otherwise, we need to build a wheel. Before building, ensure that the source is present. @@ -540,7 +548,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { target: cache_shard.join(wheel_filename.stem()).into_boxed_path(), filename: wheel_filename, hashes: revision.into_hashes(), - cache_info: CacheInfo::default(), + cache_info, }) } @@ -879,12 +887,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { }; // If the cache contains a compatible wheel, return it. - if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard) + if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard) .ok() .flatten() - .filter(|built_wheel| built_wheel.matches(source.name(), source.version())) + .filter(|file| file.matches(source.name(), source.version())) { - return Ok(built_wheel); + return Ok(BuiltWheelMetadata::from_file( + file, + revision.into_hashes(), + cache_info, + )); } // Otherwise, we need to build a wheel, which requires a source distribution. @@ -1201,12 +1213,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { }; // If the cache contains a compatible wheel, return it. - if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard) + if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard) .ok() .flatten() - .filter(|built_wheel| built_wheel.matches(source.name(), source.version())) + .filter(|file| file.matches(source.name(), source.version())) { - return Ok(built_wheel); + return Ok(BuiltWheelMetadata::from_file( + file, + revision.into_hashes(), + cache_info, + )); } // Otherwise, we need to build a wheel. @@ -1594,6 +1610,14 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { // Acquire the advisory lock. let _lock = cache_shard.lock().await.map_err(Error::CacheWrite)?; + // We don't track any cache information for Git-based source distributions; they're assumed + // to be immutable. + let cache_info = CacheInfo::default(); + + // We don't compute hashes for Git-based source distributions, since the Git commit SHA is + // used as the identifier. + let hashes = HashDigests::empty(); + // If there are build settings or extra build dependencies, we need to scope to a cache shard. let config_settings = self.config_settings_for(source.name()); let extra_build_deps = self.extra_build_dependencies_for(source.name()); @@ -1612,12 +1636,12 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { }; // If the cache contains a compatible wheel, return it. - if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard) + if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard) .ok() .flatten() - .filter(|built_wheel| built_wheel.matches(source.name(), source.version())) + .filter(|file| file.matches(source.name(), source.version())) { - return Ok(built_wheel); + return Ok(BuiltWheelMetadata::from_file(file, hashes, cache_info)); } let task = self @@ -1650,8 +1674,8 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { path: cache_shard.join(&disk_filename).into_boxed_path(), target: cache_shard.join(filename.stem()).into_boxed_path(), filename, - hashes: HashDigests::empty(), - cache_info: CacheInfo::default(), + hashes, + cache_info, }) }