Include hashes for local source archives (#10080)

## Summary

Closes https://github.com/astral-sh/uv/issues/10077
This commit is contained in:
Charlie Marsh 2024-12-21 09:31:28 -05:00 committed by GitHub
parent 3da4fdeeb3
commit 19a6b5fe4b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 51 additions and 21 deletions

View file

@ -2905,11 +2905,16 @@ enum SourceDist {
#[serde(flatten)]
metadata: SourceDistMetadata,
},
Metadata {
#[serde(flatten)]
metadata: SourceDistMetadata,
},
}
impl SourceDist {
fn filename(&self) -> Option<Cow<str>> {
match self {
SourceDist::Metadata { .. } => None,
SourceDist::Url { url, .. } => url.filename().ok(),
SourceDist::Path { path, .. } => {
path.file_name().map(|filename| filename.to_string_lossy())
@ -2919,6 +2924,7 @@ impl SourceDist {
fn url(&self) -> Option<&UrlString> {
match &self {
SourceDist::Metadata { .. } => None,
SourceDist::Url { url, .. } => Some(url),
SourceDist::Path { .. } => None,
}
@ -2926,6 +2932,7 @@ impl SourceDist {
fn path(&self) -> Option<&Path> {
match &self {
SourceDist::Metadata { .. } => None,
SourceDist::Url { .. } => None,
SourceDist::Path { path, .. } => Some(path),
}
@ -2933,6 +2940,7 @@ impl SourceDist {
fn hash(&self) -> Option<&Hash> {
match &self {
SourceDist::Metadata { metadata } => metadata.hash.as_ref(),
SourceDist::Url { metadata, .. } => metadata.hash.as_ref(),
SourceDist::Path { metadata, .. } => metadata.hash.as_ref(),
}
@ -2940,6 +2948,7 @@ impl SourceDist {
fn size(&self) -> Option<u64> {
match &self {
SourceDist::Metadata { metadata } => metadata.size,
SourceDist::Url { metadata, .. } => metadata.size,
SourceDist::Path { metadata, .. } => metadata.size,
}
@ -2990,14 +2999,16 @@ impl SourceDist {
uv_distribution_types::SourceDist::Registry(ref reg_dist) => {
SourceDist::from_registry_dist(reg_dist, index)
}
uv_distribution_types::SourceDist::DirectUrl(ref direct_dist) => {
SourceDist::from_direct_dist(id, direct_dist, hashes).map(Some)
uv_distribution_types::SourceDist::DirectUrl(_) => {
SourceDist::from_direct_dist(id, hashes).map(Some)
}
uv_distribution_types::SourceDist::Path(_) => {
SourceDist::from_path_dist(id, hashes).map(Some)
}
// An actual sdist entry in the lockfile is only required when
// it's from a registry or a direct URL. Otherwise, it's strictly
// redundant with the information in all other kinds of `source`.
uv_distribution_types::SourceDist::Git(_)
| uv_distribution_types::SourceDist::Path(_)
| uv_distribution_types::SourceDist::Directory(_) => Ok(None),
}
}
@ -3046,11 +3057,7 @@ impl SourceDist {
}
}
fn from_direct_dist(
id: &PackageId,
direct_dist: &DirectUrlSourceDist,
hashes: &[HashDigest],
) -> Result<SourceDist, LockError> {
fn from_direct_dist(id: &PackageId, hashes: &[HashDigest]) -> Result<SourceDist, LockError> {
let Some(hash) = hashes.iter().max().cloned().map(Hash::from) else {
let kind = LockErrorKind::Hash {
id: id.clone(),
@ -3059,8 +3066,24 @@ impl SourceDist {
};
return Err(kind.into());
};
Ok(SourceDist::Url {
url: normalize_url(direct_dist.url.to_url()),
Ok(SourceDist::Metadata {
metadata: SourceDistMetadata {
hash: Some(hash),
size: None,
},
})
}
fn from_path_dist(id: &PackageId, hashes: &[HashDigest]) -> Result<SourceDist, LockError> {
let Some(hash) = hashes.iter().max().cloned().map(Hash::from) else {
let kind = LockErrorKind::Hash {
id: id.clone(),
artifact_type: "path source distribution",
expected: true,
};
return Err(kind.into());
};
Ok(SourceDist::Metadata {
metadata: SourceDistMetadata {
hash: Some(hash),
size: None,
@ -3082,6 +3105,10 @@ enum SourceDistWire {
#[serde(flatten)]
metadata: SourceDistMetadata,
},
Metadata {
#[serde(flatten)]
metadata: SourceDistMetadata,
},
}
impl SourceDist {
@ -3089,6 +3116,7 @@ impl SourceDist {
fn to_toml(&self) -> anyhow::Result<InlineTable> {
let mut table = InlineTable::new();
match &self {
SourceDist::Metadata { .. } => {}
SourceDist::Url { url, .. } => {
table.insert("url", Value::from(url.as_ref()));
}
@ -3116,6 +3144,7 @@ impl TryFrom<SourceDistWire> for SourceDist {
path: path.into(),
metadata,
}),
SourceDistWire::Metadata { metadata } => Ok(SourceDist::Metadata { metadata }),
}
}
}

View file

@ -1138,7 +1138,7 @@ fn lock_sdist_url() -> Result<()> {
{ name = "idna" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/db/4d/3970183622f0330d3c23d9b8a5f52e365e50381fd484d08e3285104333d3/anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" }
sdist = { hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6" }
[package.metadata]
requires-dist = [
@ -1307,7 +1307,7 @@ fn lock_sdist_url_subdirectory() -> Result<()> {
dependencies = [
{ name = "anyio" },
]
sdist = { url = "https://github.com/user-attachments/files/18216295/subdirectory-test.tar.gz", hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" }
sdist = { hash = "sha256:24b55efee28d08ad3cdc58903e359e820601baa6a4a4b3424311541ebcfb09d3" }
[package.metadata]
requires-dist = [{ name = "anyio" }]
@ -9556,7 +9556,7 @@ fn lock_sources_url() -> Result<()> {
dependencies = [
{ name = "anyio" },
]
sdist = { url = "https://github.com/user-attachments/files/16592193/workspace.zip", hash = "sha256:ba690a925dc3d1b53e0675201c9ec26ab59eeec72ab271562f53297bf1817263" }
sdist = { hash = "sha256:ba690a925dc3d1b53e0675201c9ec26ab59eeec72ab271562f53297bf1817263" }
[package.metadata]
requires-dist = [{ name = "anyio" }]
@ -9636,11 +9636,11 @@ fn lock_sources_archive() -> Result<()> {
let lock = context.read("uv.lock");
// insta::with_settings!({
// filters => context.filters(),
// }, {
assert_snapshot!(
lock, @r###"
insta::with_settings!({
filters => context.filters(),
}, {
assert_snapshot!(
lock, @r###"
version = 1
requires-python = ">=3.12"
@ -9696,12 +9696,13 @@ fn lock_sources_archive() -> Result<()> {
dependencies = [
{ name = "anyio" },
]
sdist = { hash = "sha256:ba690a925dc3d1b53e0675201c9ec26ab59eeec72ab271562f53297bf1817263" }
[package.metadata]
requires-dist = [{ name = "anyio" }]
"###
);
// });
);
});
// Re-run with `--locked`.
uv_snapshot!(context.filters(), context.lock().arg("--locked"), @r###"
@ -17496,7 +17497,7 @@ fn lock_multiple_sources() -> Result<()> {
resolution-markers = [
"sys_platform == 'win32'",
]
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" }
sdist = { hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3" }
[[package]]
name = "iniconfig"