mirror of https://github.com/astral-sh/uv
Make metadata deserialization failures non-fatal in the cache (#11105)
## Summary If we fail to deserialize cached metadata in the cache, we should just ignore it, rather than failing. Ideally, this never happens. If it does, it means we missed a cache version bump. But if it does happen, it should still be non-fatal. Closes https://github.com/astral-sh/uv/issues/11043. Closes https://github.com/astral-sh/uv/issues/11101. ## Test Plan Prior to this PR, the following would fail: - `uvx uv@0.5.25 venv --python 3.12 --cache-dir foo` - `uvx uv@0.5.25 pip install ./scripts/packages/hatchling_dynamic --no-deps --python 3.12 --cache-dir foo` - `uvx uv@0.5.18 venv --python 3.12 --cache-dir foo` - `uvx uv@0.5.18 pip install ./scripts/packages/hatchling_dynamic --no-deps --python 3.12 --cache-dir foo` We can't go back and fix 0.5.18, but this will prevent such regressions in the future.
This commit is contained in:
parent
1dfa650ab4
commit
d106ab1a9a
|
|
@ -793,7 +793,7 @@ impl CacheBucket {
|
||||||
match self {
|
match self {
|
||||||
// Note that when bumping this, you'll also need to bump it
|
// Note that when bumping this, you'll also need to bump it
|
||||||
// in crates/uv/tests/cache_prune.rs.
|
// in crates/uv/tests/cache_prune.rs.
|
||||||
Self::SourceDistributions => "sdists-v6",
|
Self::SourceDistributions => "sdists-v7",
|
||||||
Self::FlatIndex => "flat-index-v2",
|
Self::FlatIndex => "flat-index-v2",
|
||||||
Self::Git => "git-v0",
|
Self::Git => "git-v0",
|
||||||
Self::Interpreter => "interpreter-v4",
|
Self::Interpreter => "interpreter-v4",
|
||||||
|
|
|
||||||
|
|
@ -551,16 +551,22 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
|
|
||||||
// If the cache contains compatible metadata, return it.
|
// If the cache contains compatible metadata, return it.
|
||||||
let metadata_entry = cache_shard.entry(METADATA);
|
let metadata_entry = cache_shard.entry(METADATA);
|
||||||
if let Some(metadata) = CachedMetadata::read(&metadata_entry)
|
match CachedMetadata::read(&metadata_entry).await {
|
||||||
.await?
|
Ok(Some(metadata)) => {
|
||||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
if metadata.matches(source.name(), source.version()) {
|
||||||
{
|
|
||||||
debug!("Using cached metadata for: {source}");
|
debug!("Using cached metadata for: {source}");
|
||||||
return Ok(ArchiveMetadata {
|
return Ok(ArchiveMetadata {
|
||||||
metadata: Metadata::from_metadata23(metadata.into()),
|
metadata: Metadata::from_metadata23(metadata.into()),
|
||||||
hashes: revision.into_hashes(),
|
hashes: revision.into_hashes(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
debug!("Cached metadata does not match expected name and version for: {source}");
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Failed to deserialize cached metadata for: {source} ({err})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, we need a wheel.
|
// Otherwise, we need a wheel.
|
||||||
let revision = if source_dist_entry.path().is_dir() {
|
let revision = if source_dist_entry.path().is_dir() {
|
||||||
|
|
@ -882,16 +888,22 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
|
|
||||||
// If the cache contains compatible metadata, return it.
|
// If the cache contains compatible metadata, return it.
|
||||||
let metadata_entry = cache_shard.entry(METADATA);
|
let metadata_entry = cache_shard.entry(METADATA);
|
||||||
if let Some(metadata) = CachedMetadata::read(&metadata_entry)
|
match CachedMetadata::read(&metadata_entry).await {
|
||||||
.await?
|
Ok(Some(metadata)) => {
|
||||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
if metadata.matches(source.name(), source.version()) {
|
||||||
{
|
|
||||||
debug!("Using cached metadata for: {source}");
|
debug!("Using cached metadata for: {source}");
|
||||||
return Ok(ArchiveMetadata {
|
return Ok(ArchiveMetadata {
|
||||||
metadata: Metadata::from_metadata23(metadata.into()),
|
metadata: Metadata::from_metadata23(metadata.into()),
|
||||||
hashes: revision.into_hashes(),
|
hashes: revision.into_hashes(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
debug!("Cached metadata does not match expected name and version for: {source}");
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Failed to deserialize cached metadata for: {source} ({err})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Otherwise, we need a source distribution.
|
// Otherwise, we need a source distribution.
|
||||||
let revision = if source_entry.path().is_dir() {
|
let revision = if source_entry.path().is_dir() {
|
||||||
|
|
@ -1183,10 +1195,11 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
|
|
||||||
// If the cache contains compatible metadata, return it.
|
// If the cache contains compatible metadata, return it.
|
||||||
let metadata_entry = cache_shard.entry(METADATA);
|
let metadata_entry = cache_shard.entry(METADATA);
|
||||||
if let Some(metadata) = CachedMetadata::read(&metadata_entry)
|
match CachedMetadata::read(&metadata_entry).await {
|
||||||
.await?
|
Ok(Some(metadata)) => {
|
||||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
if metadata.matches(source.name(), source.version()) {
|
||||||
{
|
debug!("Using cached metadata for: {source}");
|
||||||
|
|
||||||
// If necessary, mark the metadata as dynamic.
|
// If necessary, mark the metadata as dynamic.
|
||||||
let metadata = if dynamic {
|
let metadata = if dynamic {
|
||||||
ResolutionMetadata {
|
ResolutionMetadata {
|
||||||
|
|
@ -1196,7 +1209,6 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
} else {
|
} else {
|
||||||
metadata.into()
|
metadata.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(ArchiveMetadata::from(
|
return Ok(ArchiveMetadata::from(
|
||||||
Metadata::from_workspace(
|
Metadata::from_workspace(
|
||||||
metadata,
|
metadata,
|
||||||
|
|
@ -1209,6 +1221,13 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await?,
|
.await?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
debug!("Cached metadata does not match expected name and version for: {source}");
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Failed to deserialize cached metadata for: {source} ({err})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If the backend supports `prepare_metadata_for_build_wheel`, use it.
|
// If the backend supports `prepare_metadata_for_build_wheel`, use it.
|
||||||
if let Some(metadata) = self
|
if let Some(metadata) = self
|
||||||
|
|
@ -1635,16 +1654,15 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.map_err(Error::CacheRead)?
|
.map_err(Error::CacheRead)?
|
||||||
.is_fresh()
|
.is_fresh()
|
||||||
{
|
{
|
||||||
if let Some(metadata) = CachedMetadata::read(&metadata_entry)
|
match CachedMetadata::read(&metadata_entry).await {
|
||||||
.await?
|
Ok(Some(metadata)) => {
|
||||||
.filter(|metadata| metadata.matches(source.name(), source.version()))
|
if metadata.matches(source.name(), source.version()) {
|
||||||
{
|
debug!("Using cached metadata for: {source}");
|
||||||
|
|
||||||
let git_member = GitWorkspaceMember {
|
let git_member = GitWorkspaceMember {
|
||||||
fetch_root: fetch.path(),
|
fetch_root: fetch.path(),
|
||||||
git_source: resource,
|
git_source: resource,
|
||||||
};
|
};
|
||||||
|
|
||||||
debug!("Using cached metadata for: {source}");
|
|
||||||
return Ok(ArchiveMetadata::from(
|
return Ok(ArchiveMetadata::from(
|
||||||
Metadata::from_workspace(
|
Metadata::from_workspace(
|
||||||
metadata.into(),
|
metadata.into(),
|
||||||
|
|
@ -1657,6 +1675,15 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
||||||
.await?,
|
.await?,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
debug!(
|
||||||
|
"Cached metadata does not match expected name and version for: {source}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Ok(None) => {}
|
||||||
|
Err(err) => {
|
||||||
|
debug!("Failed to deserialize cached metadata for: {source} ({err})");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the backend supports `prepare_metadata_for_build_wheel`, use it.
|
// If the backend supports `prepare_metadata_for_build_wheel`, use it.
|
||||||
|
|
|
||||||
|
|
@ -348,7 +348,7 @@ fn prune_stale_revision() -> Result<()> {
|
||||||
----- stderr -----
|
----- stderr -----
|
||||||
DEBUG uv [VERSION] ([COMMIT] DATE)
|
DEBUG uv [VERSION] ([COMMIT] DATE)
|
||||||
Pruning cache at: [CACHE_DIR]/
|
Pruning cache at: [CACHE_DIR]/
|
||||||
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v6/[ENTRY]
|
DEBUG Removing dangling source revision: [CACHE_DIR]/sdists-v7/[ENTRY]
|
||||||
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
|
DEBUG Removing dangling cache archive: [CACHE_DIR]/archive-v0/[ENTRY]
|
||||||
Removed [N] files ([SIZE])
|
Removed [N] files ([SIZE])
|
||||||
"###);
|
"###);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue