Skip to content

Commit 7cdb2d0

Browse files
Persist cache info when re-installing cached wheels (#15274)
## Summary I noticed that these paths aren't returning the cache information, so if you install through these paths, we actually don't write `uv_cache.json` at all. I'm not sure how a user would actually end up here, because assuming there are no bugs, we don't really ever use this path? The install plan indexes the cached wheels and marks the wheel as installed, which means it's typically a mistake if we're asking the `DistributionDatabase` for a wheel that's already available in the cache... But I did verify that if I _skip_ the install plan's cache lookup, we write a wheel without `uv_cache.json`, so this is definitely more correct.
1 parent c4e5984 commit 7cdb2d0

File tree

2 files changed

+74
-30
lines changed

2 files changed

+74
-30
lines changed

crates/uv-distribution/src/source/built_wheel_metadata.rs

Lines changed: 34 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,40 @@ pub(crate) struct BuiltWheelMetadata {
2727
}
2828

2929
impl BuiltWheelMetadata {
30+
/// Create a [`BuiltWheelMetadata`] from a [`BuiltWheelFile`].
31+
pub(crate) fn from_file(
32+
file: BuiltWheelFile,
33+
hashes: HashDigests,
34+
cache_info: CacheInfo,
35+
) -> Self {
36+
Self {
37+
path: file.path,
38+
target: file.target,
39+
filename: file.filename,
40+
hashes,
41+
cache_info,
42+
}
43+
}
44+
}
45+
46+
impl Hashed for BuiltWheelMetadata {
47+
fn hashes(&self) -> &[HashDigest] {
48+
self.hashes.as_slice()
49+
}
50+
}
51+
52+
/// The path to a built wheel file, along with its parsed filename.
53+
#[derive(Debug, Clone)]
54+
pub(crate) struct BuiltWheelFile {
55+
/// The path to the built wheel.
56+
pub(crate) path: Box<Path>,
57+
/// The expected path to the downloaded wheel's entry in the cache.
58+
pub(crate) target: Box<Path>,
59+
/// The parsed filename.
60+
pub(crate) filename: WheelFilename,
61+
}
62+
63+
impl BuiltWheelFile {
3064
/// Find a compatible wheel in the cache.
3165
pub(crate) fn find_in_cache(
3266
tags: &Tags,
@@ -51,26 +85,12 @@ impl BuiltWheelMetadata {
5185
target: cache_shard.join(filename.stem()).into_boxed_path(),
5286
path: path.into_boxed_path(),
5387
filename,
54-
cache_info: CacheInfo::default(),
55-
hashes: HashDigests::empty(),
5688
})
5789
}
5890

59-
#[must_use]
60-
pub(crate) fn with_hashes(mut self, hashes: HashDigests) -> Self {
61-
self.hashes = hashes;
62-
self
63-
}
64-
6591
/// Returns `true` if the wheel matches the given package name and version.
6692
pub(crate) fn matches(&self, name: Option<&PackageName>, version: Option<&Version>) -> bool {
6793
name.is_none_or(|name| self.filename.name == *name)
6894
&& version.is_none_or(|version| self.filename.version == *version)
6995
}
7096
}
71-
72-
impl Hashed for BuiltWheelMetadata {
73-
fn hashes(&self) -> &[HashDigest] {
74-
self.hashes.as_slice()
75-
}
76-
}

crates/uv-distribution/src/source/mod.rs

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use uv_workspace::pyproject::ToolUvSources;
4949
use crate::distribution_database::ManagedClient;
5050
use crate::error::Error;
5151
use crate::metadata::{ArchiveMetadata, GitWorkspaceMember, Metadata};
52-
use crate::source::built_wheel_metadata::BuiltWheelMetadata;
52+
use crate::source::built_wheel_metadata::{BuiltWheelFile, BuiltWheelMetadata};
5353
use crate::source::revision::Revision;
5454
use crate::{Reporter, RequiresDist};
5555

@@ -454,6 +454,10 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
454454
let cache_shard = cache_shard.shard(revision.id());
455455
let source_dist_entry = cache_shard.entry(SOURCE);
456456

457+
// We don't track any cache information for URL-based source distributions; they're assumed
458+
// to be immutable.
459+
let cache_info = CacheInfo::default();
460+
457461
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
458462
let config_settings = self.config_settings_for(source.name());
459463
let extra_build_deps = self.extra_build_dependencies_for(source.name());
@@ -472,12 +476,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
472476
};
473477

474478
// If the cache contains a compatible wheel, return it.
475-
if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard)
479+
if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard)
476480
.ok()
477481
.flatten()
478-
.filter(|built_wheel| built_wheel.matches(source.name(), source.version()))
482+
.filter(|file| file.matches(source.name(), source.version()))
479483
{
480-
return Ok(built_wheel.with_hashes(revision.into_hashes()));
484+
return Ok(BuiltWheelMetadata::from_file(
485+
file,
486+
revision.into_hashes(),
487+
cache_info,
488+
));
481489
}
482490

483491
// 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> {
540548
target: cache_shard.join(wheel_filename.stem()).into_boxed_path(),
541549
filename: wheel_filename,
542550
hashes: revision.into_hashes(),
543-
cache_info: CacheInfo::default(),
551+
cache_info,
544552
})
545553
}
546554

@@ -879,12 +887,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
879887
};
880888

881889
// If the cache contains a compatible wheel, return it.
882-
if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard)
890+
if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard)
883891
.ok()
884892
.flatten()
885-
.filter(|built_wheel| built_wheel.matches(source.name(), source.version()))
893+
.filter(|file| file.matches(source.name(), source.version()))
886894
{
887-
return Ok(built_wheel);
895+
return Ok(BuiltWheelMetadata::from_file(
896+
file,
897+
revision.into_hashes(),
898+
cache_info,
899+
));
888900
}
889901

890902
// Otherwise, we need to build a wheel, which requires a source distribution.
@@ -1201,12 +1213,16 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
12011213
};
12021214

12031215
// If the cache contains a compatible wheel, return it.
1204-
if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard)
1216+
if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard)
12051217
.ok()
12061218
.flatten()
1207-
.filter(|built_wheel| built_wheel.matches(source.name(), source.version()))
1219+
.filter(|file| file.matches(source.name(), source.version()))
12081220
{
1209-
return Ok(built_wheel);
1221+
return Ok(BuiltWheelMetadata::from_file(
1222+
file,
1223+
revision.into_hashes(),
1224+
cache_info,
1225+
));
12101226
}
12111227

12121228
// Otherwise, we need to build a wheel.
@@ -1594,6 +1610,14 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
15941610
// Acquire the advisory lock.
15951611
let _lock = cache_shard.lock().await.map_err(Error::CacheWrite)?;
15961612

1613+
// We don't track any cache information for Git-based source distributions; they're assumed
1614+
// to be immutable.
1615+
let cache_info = CacheInfo::default();
1616+
1617+
// We don't compute hashes for Git-based source distributions, since the Git commit SHA is
1618+
// used as the identifier.
1619+
let hashes = HashDigests::empty();
1620+
15971621
// If there are build settings or extra build dependencies, we need to scope to a cache shard.
15981622
let config_settings = self.config_settings_for(source.name());
15991623
let extra_build_deps = self.extra_build_dependencies_for(source.name());
@@ -1612,12 +1636,12 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
16121636
};
16131637

16141638
// If the cache contains a compatible wheel, return it.
1615-
if let Some(built_wheel) = BuiltWheelMetadata::find_in_cache(tags, &cache_shard)
1639+
if let Some(file) = BuiltWheelFile::find_in_cache(tags, &cache_shard)
16161640
.ok()
16171641
.flatten()
1618-
.filter(|built_wheel| built_wheel.matches(source.name(), source.version()))
1642+
.filter(|file| file.matches(source.name(), source.version()))
16191643
{
1620-
return Ok(built_wheel);
1644+
return Ok(BuiltWheelMetadata::from_file(file, hashes, cache_info));
16211645
}
16221646

16231647
let task = self
@@ -1650,8 +1674,8 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
16501674
path: cache_shard.join(&disk_filename).into_boxed_path(),
16511675
target: cache_shard.join(filename.stem()).into_boxed_path(),
16521676
filename,
1653-
hashes: HashDigests::empty(),
1654-
cache_info: CacheInfo::default(),
1677+
hashes,
1678+
cache_info,
16551679
})
16561680
}
16571681

0 commit comments

Comments
 (0)