Use canonical URLs in satisfaction check (#3373)

## Summary

Closes https://github.com/astral-sh/uv/issues/3367.
This commit is contained in:
Charlie Marsh 2024-05-04 08:44:25 -04:00 committed by GitHub
parent 8adf5b11ab
commit 69e99b3502
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 62 additions and 8 deletions

1
Cargo.lock generated
View file

@ -4862,6 +4862,7 @@ version = "0.0.1"
dependencies = [
"anyhow",
"async-channel",
"cache-key",
"distribution-filename",
"distribution-types",
"fs-err",

View file

@ -13,6 +13,7 @@ license = { workspace = true }
workspace = true
[dependencies]
cache-key = { workspace = true }
distribution-filename = { workspace = true }
distribution-types = { workspace = true }
install-wheel-rs = { workspace = true, default-features = false }

View file

@ -1,5 +1,7 @@
use anyhow::Result;
use cache_key::{CanonicalUrl, RepositoryUrl};
use std::fmt::Debug;
use tracing::log::debug;
use tracing::trace;
use distribution_types::{InstalledDirectUrlDist, InstalledDist, RequirementSource};
@ -61,8 +63,12 @@ impl RequirementSatisfaction {
return Ok(Self::Mismatch);
}
if &requested_url.to_string() != installed_url
|| requested_subdirectory != installed_subdirectory
if requested_subdirectory != installed_subdirectory {
return Ok(Self::Mismatch);
}
if !CanonicalUrl::parse(installed_url)
.is_ok_and(|installed_url| installed_url == CanonicalUrl::new(requested_url))
{
return Ok(Self::Mismatch);
}
@ -105,12 +111,30 @@ impl RequirementSatisfaction {
else {
return Ok(Self::Mismatch);
};
if &requested_repository.to_string() != installed_url
|| requested_subdirectory != installed_subdirectory
{
if requested_subdirectory != installed_subdirectory {
debug!(
"Subdirectory mismatch: {:?} vs. {:?}",
installed_subdirectory, requested_subdirectory
);
return Ok(Self::Mismatch);
}
if !RepositoryUrl::parse(installed_url).is_ok_and(|installed_url| {
installed_url == RepositoryUrl::new(requested_repository)
}) {
debug!(
"Repository mismatch: {:?} vs. {:?}",
installed_url, requested_repository
);
return Ok(Self::Mismatch);
}
if installed_reference.as_deref() != requested_reference.as_str() {
debug!(
"Reference mismatch: {:?} vs. {:?}",
installed_reference, requested_reference
);
return Ok(Self::OutOfDate);
}
@ -136,9 +160,12 @@ impl RequirementSatisfaction {
return Ok(Self::Mismatch);
};
if &requested_url.to_string() != installed_url
|| requested_editable.unwrap_or_default()
!= installed_editable.unwrap_or_default()
if requested_editable != installed_editable {
return Ok(Self::Mismatch);
}
if !CanonicalUrl::parse(installed_url)
.is_ok_and(|installed_url| installed_url == CanonicalUrl::new(requested_url))
{
return Ok(Self::Mismatch);
}

View file

@ -4093,6 +4093,31 @@ fn already_installed_remote_url() {
context.assert_installed("uv_public_pypackage", "0.1.0");
// Request installation again with a different URL, but the same _canonical_ URL. We should
// resolve the package (since we installed a specific commit, but are now requesting the default
// branch), but not reinstall the package.
uv_snapshot!(context.filters(), context.install().arg("uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Audited 1 package in [TIME]
"###);
// Request installation again with a different URL, but the same _canonical_ URL and the same
// commit. We should neither resolve nor reinstall the package, since it's already installed
// at this precise commit.
uv_snapshot!(context.filters(), context.install().arg("uv-public-pypackage @ git+https://github.com/astral-test/uv-public-pypackage.git@b270df1a2fb5d012294e9aaf05e7e0bab1e6a389"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Audited 1 package in [TIME]
"###);
// Request installation again with just the name
// We should just audit the URL package since it fulfills this requirement
uv_snapshot!(