diff --git a/crates/uv-distribution/src/index/built_wheel_index.rs b/crates/uv-distribution/src/index/built_wheel_index.rs index 8d29f264c..300e7619c 100644 --- a/crates/uv-distribution/src/index/built_wheel_index.rs +++ b/crates/uv-distribution/src/index/built_wheel_index.rs @@ -10,10 +10,11 @@ use uv_distribution_types::{ }; use uv_normalize::PackageName; use uv_platform_tags::Tags; +use uv_pypi_types::HashDigests; use uv_types::HashStrategy; use crate::Error; -use crate::index::cached_wheel::CachedWheel; +use crate::index::cached_wheel::{CachedWheel, ResolvedWheel}; use crate::source::{HTTP_REVISION, HttpRevisionPointer, LOCAL_REVISION, LocalRevisionPointer}; /// A local index of built distributions for a specific source distribution. @@ -92,7 +93,9 @@ impl<'a> BuiltWheelIndex<'a> { ))) }; - Ok(self.find(&cache_shard)) + Ok(self.find(&cache_shard).map(|wheel| { + CachedWheel::from_entry(wheel, revision.into_hashes(), CacheInfo::default()) + })) } /// Return the most compatible [`CachedWheel`] for a given source distribution at a local path. pub fn path(&self, source_dist: &PathSourceDist) -> Result, Error> { @@ -141,7 +144,7 @@ impl<'a> BuiltWheelIndex<'a> { Ok(self .find(&cache_shard) - .map(|wheel| wheel.with_cache_info(cache_info))) + .map(|wheel| CachedWheel::from_entry(wheel, revision.into_hashes(), cache_info))) } /// Return the most compatible [`CachedWheel`] for a given source distribution built from a @@ -199,7 +202,7 @@ impl<'a> BuiltWheelIndex<'a> { Ok(self .find(&cache_shard) - .map(|wheel| wheel.with_cache_info(cache_info))) + .map(|wheel| CachedWheel::from_entry(wheel, revision.into_hashes(), cache_info))) } /// Return the most compatible [`CachedWheel`] for a given source distribution at a git URL. @@ -234,6 +237,7 @@ impl<'a> BuiltWheelIndex<'a> { }; self.find(&cache_shard) + .map(|wheel| CachedWheel::from_entry(wheel, HashDigests::empty(), CacheInfo::default())) } /// Find the "best" distribution in the index for a given source distribution. @@ -252,8 +256,8 @@ impl<'a> BuiltWheelIndex<'a> { /// ``` /// /// The `shard` should be `built-wheels-v0/pypi/django-allauth-0.51.0.tar.gz`. - fn find(&self, shard: &CacheShard) -> Option { - let mut candidate: Option = None; + fn find(&self, shard: &CacheShard) -> Option { + let mut candidate: Option = None; // Unzipped wheels are stored as symlinks into the archive directory. for wheel_dir in uv_fs::entries(shard).ok().into_iter().flatten() { @@ -265,7 +269,7 @@ impl<'a> BuiltWheelIndex<'a> { continue; } - match CachedWheel::from_built_source(&wheel_dir, self.cache) { + match ResolvedWheel::from_built_source(&wheel_dir, self.cache) { None => {} Some(dist_info) => { // Pick the wheel with the highest priority diff --git a/crates/uv-distribution/src/index/cached_wheel.rs b/crates/uv-distribution/src/index/cached_wheel.rs index d8808e9fc..83c614b92 100644 --- a/crates/uv-distribution/src/index/cached_wheel.rs +++ b/crates/uv-distribution/src/index/cached_wheel.rs @@ -12,6 +12,30 @@ use uv_pypi_types::{HashDigest, HashDigests, VerbatimParsedUrl}; use crate::archive::Archive; use crate::{HttpArchivePointer, LocalArchivePointer}; +#[derive(Debug, Clone)] +pub struct ResolvedWheel { + /// The filename of the wheel. + pub filename: WheelFilename, + /// The [`CacheEntry`] for the wheel. + pub entry: CacheEntry, +} + +impl ResolvedWheel { + /// Try to parse a distribution from a cached directory name (like `typing-extensions-4.8.0-py3-none-any`). + pub fn from_built_source(path: impl AsRef, cache: &Cache) -> Option { + let path = path.as_ref(); + + // Determine the wheel filename. + let filename = path.file_name()?.to_str()?; + let filename = WheelFilename::from_stem(filename).ok()?; + + // Convert to a cached wheel. + let archive = cache.resolve_link(path).ok()?; + let entry = CacheEntry::from_path(archive); + Some(Self { filename, entry }) + } +} + #[derive(Debug, Clone)] pub struct CachedWheel { /// The filename of the wheel. @@ -25,21 +49,62 @@ pub struct CachedWheel { } impl CachedWheel { - /// Try to parse a distribution from a cached directory name (like `typing-extensions-4.8.0-py3-none-any`). - pub fn from_built_source(path: impl AsRef, cache: &Cache) -> Option { + /// Create a [`CachedWheel`] from a [`ResolvedWheel`]. + pub fn from_entry(wheel: ResolvedWheel, hashes: HashDigests, cache_info: CacheInfo) -> Self { + Self { + filename: wheel.filename, + entry: wheel.entry, + hashes, + cache_info, + } + } + + /// Read a cached wheel from a `.http` pointer + pub fn from_http_pointer(path: impl AsRef, cache: &Cache) -> Option { let path = path.as_ref(); - // Determine the wheel filename. - let filename = path.file_name()?.to_str()?; - let filename = WheelFilename::from_stem(filename).ok()?; + // Read the pointer. + let pointer = HttpArchivePointer::read_from(path).ok()??; + let cache_info = pointer.to_cache_info(); + let archive = pointer.into_archive(); + + // Ignore stale pointers. + if !archive.exists(cache) { + return None; + } + + let Archive { id, hashes, .. } = archive; + let entry = cache.entry(CacheBucket::Archive, "", id); // Convert to a cached wheel. - let archive = cache.resolve_link(path).ok()?; - let entry = CacheEntry::from_path(archive); - let hashes = HashDigests::empty(); - let cache_info = CacheInfo::default(); Some(Self { - filename, + filename: archive.filename, + entry, + hashes, + cache_info, + }) + } + + /// Read a cached wheel from a `.rev` pointer + pub fn from_local_pointer(path: impl AsRef, cache: &Cache) -> Option { + let path = path.as_ref(); + + // Read the pointer. + let pointer = LocalArchivePointer::read_from(path).ok()??; + let cache_info = pointer.to_cache_info(); + let archive = pointer.into_archive(); + + // Ignore stale pointers. + if !archive.exists(cache) { + return None; + } + + let Archive { id, hashes, .. } = archive; + let entry = cache.entry(CacheBucket::Archive, "", id); + + // Convert to a cached wheel. + Some(Self { + filename: archive.filename, entry, hashes, cache_info, @@ -115,64 +180,6 @@ impl CachedWheel { cache_info: self.cache_info, } } - - /// Read a cached wheel from a `.http` pointer - pub fn from_http_pointer(path: impl AsRef, cache: &Cache) -> Option { - let path = path.as_ref(); - - // Read the pointer. - let pointer = HttpArchivePointer::read_from(path).ok()??; - let cache_info = pointer.to_cache_info(); - let archive = pointer.into_archive(); - - // Ignore stale pointers. - if !archive.exists(cache) { - return None; - } - - let Archive { id, hashes, .. } = archive; - let entry = cache.entry(CacheBucket::Archive, "", id); - - // Convert to a cached wheel. - Some(Self { - filename: archive.filename, - entry, - hashes, - cache_info, - }) - } - - /// Read a cached wheel from a `.rev` pointer - pub fn from_local_pointer(path: impl AsRef, cache: &Cache) -> Option { - let path = path.as_ref(); - - // Read the pointer. - let pointer = LocalArchivePointer::read_from(path).ok()??; - let cache_info = pointer.to_cache_info(); - let archive = pointer.into_archive(); - - // Ignore stale pointers. - if !archive.exists(cache) { - return None; - } - - let Archive { id, hashes, .. } = archive; - let entry = cache.entry(CacheBucket::Archive, "", id); - - // Convert to a cached wheel. - Some(Self { - filename: archive.filename, - entry, - hashes, - cache_info, - }) - } - - #[must_use] - pub fn with_cache_info(mut self, cache_info: CacheInfo) -> Self { - self.cache_info = cache_info; - self - } } impl Hashed for CachedWheel { diff --git a/crates/uv-distribution/src/index/registry_wheel_index.rs b/crates/uv-distribution/src/index/registry_wheel_index.rs index 2df5d4229..e62cf8214 100644 --- a/crates/uv-distribution/src/index/registry_wheel_index.rs +++ b/crates/uv-distribution/src/index/registry_wheel_index.rs @@ -4,6 +4,7 @@ use std::collections::hash_map::Entry; use rustc_hash::{FxHashMap, FxHashSet}; use uv_cache::{Cache, CacheBucket, WheelCache}; +use uv_cache_info::CacheInfo; use uv_cache_key::cache_digest; use uv_distribution_types::{ BuildVariables, CachedRegistryDist, ConfigSettings, ExtraBuildRequirement, ExtraBuildRequires, @@ -14,7 +15,7 @@ use uv_normalize::PackageName; use uv_platform_tags::Tags; use uv_types::HashStrategy; -use crate::index::cached_wheel::CachedWheel; +use crate::index::cached_wheel::{CachedWheel, ResolvedWheel}; use crate::source::{HTTP_REVISION, HttpRevisionPointer, LOCAL_REVISION, LocalRevisionPointer}; /// An entry in the [`RegistryWheelIndex`]. @@ -247,13 +248,18 @@ impl<'a> RegistryWheelIndex<'a> { continue; } - if let Some(wheel) = CachedWheel::from_built_source(wheel_dir, cache) { + if let Some(wheel) = ResolvedWheel::from_built_source(wheel_dir, cache) { if wheel.filename.compatibility(tags).is_compatible() { // Enforce hash-checking based on the source distribution. if revision.satisfies( hasher .get_package(&wheel.filename.name, &wheel.filename.version), ) { + let wheel = CachedWheel::from_entry( + wheel, + revision.hashes().into(), + CacheInfo::default(), + ); entries.push(IndexEntry { dist: wheel.into_registry_dist(), index,