Replace PyPI-internal Hashes representation with flat vector (#2925)

## Summary

Right now, we have a `Hashes` representation that looks like:

```rust
/// A dictionary mapping a hash name to a hex encoded digest of the file.
///
/// PEP 691 says multiple hashes can be included and the interpretation is left to the client.
#[derive(Debug, Clone, Eq, PartialEq, Default, Deserialize)]
pub struct Hashes {
    pub md5: Option<Box<str>>,
    pub sha256: Option<Box<str>>,
    pub sha384: Option<Box<str>>,
    pub sha512: Option<Box<str>>,
}
```

It stems from the PyPI API, which returns a dictionary of hashes.

We tend to pass these around as a vector of `Vec<Hashes>`. But it's a
bit strange because each entry in that vector could contain multiple
hashes. And it makes it difficult to ask questions like "Is
`sha256:ab21378ca980a8` in the set of hashes"?

This PR instead treats `Hashes` as the PyPI-internal type, and uses a
new `Vec<HashDigest>` everywhere in our own APIs.
This commit is contained in:
Charlie Marsh 2024-04-09 12:56:16 -04:00 committed by GitHub
parent 1512e07a2e
commit 13ae5ac8dc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 195 additions and 103 deletions

View file

@ -17,7 +17,7 @@ use distribution_types::{
use pep440_rs::Version;
use pep508_rs::VerbatimUrl;
use platform_tags::Tags;
use pypi_types::Hashes;
use uv_cache::{Cache, CacheBucket};
use uv_configuration::{NoBinary, NoBuild};
use uv_normalize::PackageName;
@ -236,9 +236,9 @@ impl<'a> FlatIndexClient<'a> {
};
let file = File {
dist_info_metadata: None,
dist_info_metadata: false,
filename: filename.to_string(),
hashes: Hashes::default(),
hashes: Vec::new(),
requires_python: None,
size: None,
upload_time_utc_ms: None,
@ -323,10 +323,10 @@ impl FlatIndex {
}));
match distributions.0.entry(version) {
Entry::Occupied(mut entry) => {
entry.get_mut().insert_built(dist, None, compatibility);
entry.get_mut().insert_built(dist, vec![], compatibility);
}
Entry::Vacant(entry) => {
entry.insert(PrioritizedDist::from_built(dist, None, compatibility));
entry.insert(PrioritizedDist::from_built(dist, vec![], compatibility));
}
}
}
@ -339,10 +339,10 @@ impl FlatIndex {
}));
match distributions.0.entry(filename.version) {
Entry::Occupied(mut entry) => {
entry.get_mut().insert_source(dist, None, compatibility);
entry.get_mut().insert_source(dist, vec![], compatibility);
}
Entry::Vacant(entry) => {
entry.insert(PrioritizedDist::from_source(dist, None, compatibility));
entry.insert(PrioritizedDist::from_source(dist, vec![], compatibility));
}
}
}

View file

@ -424,11 +424,7 @@ impl RegistryClient {
) -> Result<Metadata23, Error> {
// If the metadata file is available at its own url (PEP 658), download it from there.
let filename = WheelFilename::from_str(&file.filename).map_err(ErrorKind::WheelFilename)?;
if file
.dist_info_metadata
.as_ref()
.is_some_and(pypi_types::DistInfoMetadata::is_available)
{
if file.dist_info_metadata {
let mut url = url.clone();
url.set_path(&format!("{}.metadata", url.path()));