Skip to content

Commit 0093404

Browse files
Backtrack on distributions with invalid metadata (#2834)
## Summary Closes #2821.
1 parent f0b0e19 commit 0093404

File tree

15 files changed

+229
-73
lines changed

15 files changed

+229
-73
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/uv-client/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ pub enum ErrorKind {
132132

133133
/// Dist-info error
134134
#[error(transparent)]
135-
InstallWheel(#[from] install_wheel_rs::Error),
135+
DistInfo(#[from] install_wheel_rs::Error),
136136

137137
#[error("{0} isn't available locally, but making network requests to registries was banned.")]
138138
NoIndex(String),

crates/uv-client/src/registry_client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ async fn read_metadata_async_seek(
632632
.enumerate()
633633
.filter_map(|(index, entry)| Some((index, entry.filename().as_str().ok()?))),
634634
)
635-
.map_err(ErrorKind::InstallWheel)?;
635+
.map_err(ErrorKind::DistInfo)?;
636636

637637
// Read the contents of the `METADATA` file.
638638
let mut contents = Vec::new();

crates/uv-client/src/remote_metadata.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ pub(crate) async fn wheel_metadata_from_remote_zip(
7575
.enumerate()
7676
.filter_map(|(idx, e)| Some(((idx, e), e.filename().as_str().ok()?))),
7777
)
78-
.map_err(ErrorKind::InstallWheel)?;
78+
.map_err(ErrorKind::DistInfo)?;
7979

8080
let offset = metadata_entry.header_offset();
8181
let size = metadata_entry.compressed_size()

crates/uv-requirements/src/lookahead.rs

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use pep508_rs::{MarkerEnvironment, Requirement, VersionOrUrl};
1111
use pypi_types::Metadata23;
1212
use uv_client::RegistryClient;
1313
use uv_distribution::{DistributionDatabase, Reporter};
14-
use uv_resolver::InMemoryIndex;
14+
use uv_resolver::{InMemoryIndex, MetadataResponse};
1515
use uv_types::{BuildContext, Constraints, Overrides, RequestedRequirements};
1616

1717
/// A resolver for resolving lookahead requirements from direct URLs.
@@ -134,7 +134,18 @@ impl<'a, Context: BuildContext + Send + Sync> LookaheadResolver<'a, Context> {
134134
// Fetch the metadata for the distribution.
135135
let requires_dist = {
136136
let id = dist.package_id();
137-
if let Some(metadata) = self.index.get_metadata(&id) {
137+
if let Some(metadata) = self
138+
.index
139+
.get_metadata(&id)
140+
.as_deref()
141+
.and_then(|response| {
142+
if let MetadataResponse::Found(metadata) = response {
143+
Some(metadata)
144+
} else {
145+
None
146+
}
147+
})
148+
{
138149
// If the metadata is already in the index, return it.
139150
metadata.requires_dist.clone()
140151
} else {
@@ -151,7 +162,8 @@ impl<'a, Context: BuildContext + Send + Sync> LookaheadResolver<'a, Context> {
151162
let requires_dist = metadata.requires_dist.clone();
152163

153164
// Insert the metadata into the index.
154-
self.index.insert_metadata(id, metadata);
165+
self.index
166+
.insert_metadata(id, MetadataResponse::Found(metadata));
155167

156168
requires_dist
157169
}

crates/uv-requirements/src/source_tree.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use std::borrow::Cow;
2-
use std::ops::Deref;
2+
33
use std::path::{Path, PathBuf};
44

55
use anyhow::{Context, Result};
@@ -11,7 +11,7 @@ use pep508_rs::Requirement;
1111
use uv_client::RegistryClient;
1212
use uv_distribution::{DistributionDatabase, Reporter};
1313
use uv_fs::Simplified;
14-
use uv_resolver::InMemoryIndex;
14+
use uv_resolver::{InMemoryIndex, MetadataResponse};
1515
use uv_types::BuildContext;
1616

1717
use crate::ExtrasSpecification;
@@ -87,16 +87,28 @@ impl<'a, Context: BuildContext + Send + Sync> SourceTreeResolver<'a, Context> {
8787
// Fetch the metadata for the distribution.
8888
let metadata = {
8989
let id = PackageId::from_url(source.url());
90-
if let Some(metadata) = self.index.get_metadata(&id) {
90+
if let Some(metadata) = self
91+
.index
92+
.get_metadata(&id)
93+
.as_deref()
94+
.and_then(|response| {
95+
if let MetadataResponse::Found(metadata) = response {
96+
Some(metadata)
97+
} else {
98+
None
99+
}
100+
})
101+
{
91102
// If the metadata is already in the index, return it.
92-
metadata.deref().clone()
103+
metadata.clone()
93104
} else {
94105
// Run the PEP 517 build process to extract metadata from the source distribution.
95106
let source = BuildableSource::Url(source);
96107
let metadata = self.database.build_wheel_metadata(&source).await?;
97108

98109
// Insert the metadata into the index.
99-
self.index.insert_metadata(id, metadata.clone());
110+
self.index
111+
.insert_metadata(id, MetadataResponse::Found(metadata.clone()));
100112

101113
metadata
102114
}

crates/uv-requirements/src/unnamed.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use pypi_types::Metadata10;
2020
use uv_client::RegistryClient;
2121
use uv_distribution::{DistributionDatabase, Reporter};
2222
use uv_normalize::PackageName;
23-
use uv_resolver::InMemoryIndex;
23+
use uv_resolver::{InMemoryIndex, MetadataResponse};
2424
use uv_types::BuildContext;
2525

2626
/// Like [`RequirementsSpecification`], but with concrete names for all requirements.
@@ -236,7 +236,13 @@ impl<'a, Context: BuildContext + Send + Sync> NamedRequirementsResolver<'a, Cont
236236
// Fetch the metadata for the distribution.
237237
let name = {
238238
let id = PackageId::from_url(source.url());
239-
if let Some(metadata) = index.get_metadata(&id) {
239+
if let Some(metadata) = index.get_metadata(&id).as_deref().and_then(|response| {
240+
if let MetadataResponse::Found(metadata) = response {
241+
Some(metadata)
242+
} else {
243+
None
244+
}
245+
}) {
240246
// If the metadata is already in the index, return it.
241247
metadata.name.clone()
242248
} else {
@@ -247,7 +253,7 @@ impl<'a, Context: BuildContext + Send + Sync> NamedRequirementsResolver<'a, Cont
247253
let name = metadata.name.clone();
248254

249255
// Insert the metadata into the index.
250-
index.insert_metadata(id, metadata);
256+
index.insert_metadata(id, MetadataResponse::Found(metadata));
251257

252258
name
253259
}

crates/uv-resolver/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ workspace = true
1616
cache-key = { workspace = true }
1717
distribution-filename = { workspace = true, features = ["serde"] }
1818
distribution-types = { workspace = true }
19+
install-wheel-rs = { workspace = true }
1920
once-map = { workspace = true }
2021
pep440_rs = { workspace = true }
2122
pep508_rs = { workspace = true }

crates/uv-resolver/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub use python_requirement::PythonRequirement;
99
pub use resolution::{AnnotationStyle, Diagnostic, DisplayResolutionGraph, ResolutionGraph};
1010
pub use resolution_mode::ResolutionMode;
1111
pub use resolver::{
12-
BuildId, DefaultResolverProvider, InMemoryIndex, PackageVersionsResult,
12+
BuildId, DefaultResolverProvider, InMemoryIndex, MetadataResponse, PackageVersionsResult,
1313
Reporter as ResolverReporter, Resolver, ResolverProvider, VersionsResponse,
1414
WheelMetadataResult,
1515
};

crates/uv-resolver/src/resolution.rs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use distribution_types::{
1818
use once_map::OnceMap;
1919
use pep440_rs::Version;
2020
use pep508_rs::MarkerEnvironment;
21-
use pypi_types::{Hashes, Metadata23};
21+
use pypi_types::Hashes;
2222
use uv_distribution::to_precise;
2323
use uv_normalize::{ExtraName, PackageName};
2424

@@ -28,7 +28,7 @@ use crate::pins::FilePins;
2828
use crate::preferences::Preferences;
2929
use crate::pubgrub::{PubGrubDistribution, PubGrubPackage};
3030
use crate::redirect::apply_redirect;
31-
use crate::resolver::{InMemoryIndex, VersionsResponse};
31+
use crate::resolver::{InMemoryIndex, MetadataResponse, VersionsResponse};
3232
use crate::{Manifest, ResolveError};
3333

3434
/// Indicate the style of annotation comments, used to indicate the dependencies that requested each
@@ -66,7 +66,7 @@ impl ResolutionGraph {
6666
selection: &SelectedDependencies<UvDependencyProvider>,
6767
pins: &FilePins,
6868
packages: &OnceMap<PackageName, VersionsResponse>,
69-
distributions: &OnceMap<PackageId, Metadata23>,
69+
distributions: &OnceMap<PackageId, MetadataResponse>,
7070
state: &State<UvDependencyProvider>,
7171
preferences: &Preferences,
7272
editables: Editables,
@@ -164,13 +164,20 @@ impl ResolutionGraph {
164164
});
165165
}
166166
} else {
167-
let metadata = distributions.get(&dist.package_id()).unwrap_or_else(|| {
167+
let response = distributions.get(&dist.package_id()).unwrap_or_else(|| {
168168
panic!(
169169
"Every package should have metadata: {:?}",
170170
dist.package_id()
171171
)
172172
});
173173

174+
let MetadataResponse::Found(metadata) = &*response else {
175+
panic!(
176+
"Every package should have metadata: {:?}",
177+
dist.package_id()
178+
)
179+
};
180+
174181
if metadata.provides_extras.contains(extra) {
175182
extras
176183
.entry(package_name.clone())
@@ -211,13 +218,20 @@ impl ResolutionGraph {
211218
});
212219
}
213220
} else {
214-
let metadata = distributions.get(&dist.package_id()).unwrap_or_else(|| {
221+
let response = distributions.get(&dist.package_id()).unwrap_or_else(|| {
215222
panic!(
216223
"Every package should have metadata: {:?}",
217224
dist.package_id()
218225
)
219226
});
220227

228+
let MetadataResponse::Found(metadata) = &*response else {
229+
panic!(
230+
"Every package should have metadata: {:?}",
231+
dist.package_id()
232+
)
233+
};
234+
221235
if metadata.provides_extras.contains(extra) {
222236
extras
223237
.entry(package_name.clone())
@@ -417,10 +431,16 @@ impl ResolutionGraph {
417431
}
418432
VersionOrUrl::Url(verbatim_url) => PackageId::from_url(verbatim_url.raw()),
419433
};
420-
let md = index
434+
let res = index
421435
.distributions
422436
.get(&package_id)
423437
.expect("every package in resolution graph has metadata");
438+
let MetadataResponse::Found(md) = &*res else {
439+
panic!(
440+
"Every package should have metadata: {:?}",
441+
dist.package_id()
442+
)
443+
};
424444
for req in manifest.apply(&md.requires_dist) {
425445
let Some(ref marker_tree) = req.marker else {
426446
continue;

0 commit comments

Comments
 (0)