mirror of
https://github.com/astral-sh/uv.git
synced 2025-08-03 10:33:49 +00:00
Enforce and backtrack on invalid versions in source metadata (#2954)
## Summary If we build a source distribution from the registry, and the version doesn't match that of the filename, we should error, just as we do for mismatched package names. However, we should also backtrack here, which we didn't previously. Closes https://github.com/astral-sh/uv/issues/2953. ## Test Plan Verified that `cargo run pip install docutils --verbose --no-cache --reinstall` installs `docutils==0.21` instead of the invalid `docutils==0.21.post1`. In the logs, I see: ``` WARN Unable to extract metadata for docutils: Package metadata version `0.21` does not match given version `0.21.post1` ```
This commit is contained in:
parent
997f3c9161
commit
c4472ebbb9
6 changed files with 105 additions and 32 deletions
|
@ -3,6 +3,7 @@ use tokio::task::JoinError;
|
|||
use zip::result::ZipError;
|
||||
|
||||
use distribution_filename::WheelFilenameError;
|
||||
use pep440_rs::Version;
|
||||
use uv_client::BetterReqwestError;
|
||||
use uv_normalize::PackageName;
|
||||
|
||||
|
@ -47,6 +48,8 @@ pub enum Error {
|
|||
given: PackageName,
|
||||
metadata: PackageName,
|
||||
},
|
||||
#[error("Package metadata version `{metadata}` does not match given version `{given}`")]
|
||||
VersionMismatch { given: Version, metadata: Version },
|
||||
#[error("Failed to parse metadata from built wheel")]
|
||||
Metadata(#[from] pypi_types::MetadataError),
|
||||
#[error("Failed to read `dist-info` metadata from built wheel")]
|
||||
|
|
|
@ -1109,14 +1109,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let metadata = read_wheel_metadata(&filename, cache_shard.join(&disk_filename))?;
|
||||
|
||||
// Validate the metadata.
|
||||
if let Some(name) = source.name() {
|
||||
if metadata.name != *name {
|
||||
return Err(Error::NameMismatch {
|
||||
metadata: metadata.name,
|
||||
given: name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
validate(source, &metadata)?;
|
||||
|
||||
debug!("Finished building: {source}");
|
||||
Ok((disk_filename, filename, metadata))
|
||||
|
@ -1138,14 +1131,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
debug!("Found static `PKG-INFO` for: {source}");
|
||||
|
||||
// Validate the metadata.
|
||||
if let Some(name) = source.name() {
|
||||
if metadata.name != *name {
|
||||
return Err(Error::NameMismatch {
|
||||
metadata: metadata.name,
|
||||
given: name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
validate(source, &metadata)?;
|
||||
|
||||
return Ok(Some(metadata));
|
||||
}
|
||||
|
@ -1161,14 +1147,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
debug!("Found static `pyproject.toml` for: {source}");
|
||||
|
||||
// Validate the metadata.
|
||||
if let Some(name) = source.name() {
|
||||
if metadata.name != *name {
|
||||
return Err(Error::NameMismatch {
|
||||
metadata: metadata.name,
|
||||
given: name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
validate(source, &metadata)?;
|
||||
|
||||
return Ok(Some(metadata));
|
||||
}
|
||||
|
@ -1208,14 +1187,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
let metadata = Metadata23::parse_metadata(&content)?;
|
||||
|
||||
// Validate the metadata.
|
||||
if let Some(name) = source.name() {
|
||||
if metadata.name != *name {
|
||||
return Err(Error::NameMismatch {
|
||||
metadata: metadata.name,
|
||||
given: name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
validate(source, &metadata)?;
|
||||
|
||||
Ok(Some(metadata))
|
||||
}
|
||||
|
@ -1278,6 +1250,29 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// Validate that the source distribution matches the built metadata.
|
||||
fn validate(source: &BuildableSource<'_>, metadata: &Metadata23) -> Result<(), Error> {
|
||||
if let Some(name) = source.name() {
|
||||
if metadata.name != *name {
|
||||
return Err(Error::NameMismatch {
|
||||
metadata: metadata.name.clone(),
|
||||
given: name.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(version) = source.version() {
|
||||
if metadata.version != *version {
|
||||
return Err(Error::VersionMismatch {
|
||||
metadata: metadata.version.clone(),
|
||||
given: version.clone(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read an existing HTTP-cached [`Revision`], if it exists.
|
||||
pub(crate) fn read_http_revision(cache_entry: &CacheEntry) -> Result<Option<Revision>, Error> {
|
||||
match fs_err::File::open(cache_entry.path()) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue