From b263fcff9c6c38c12c46919b6f5edd24881385b6 Mon Sep 17 00:00:00 2001 From: konsti Date: Tue, 14 May 2024 03:47:20 +0200 Subject: [PATCH] Preserve parsed url in ResolvedDist -> Requirement (#3457) Lose less information in the `ResolvedDist` -> `Requirement` conversion. --- crates/distribution-types/src/requirement.rs | 6 ++++- crates/distribution-types/src/resolution.rs | 27 ++++++++------------ crates/uv-installer/src/plan.rs | 7 ++++- crates/uv-installer/src/satisfies.rs | 23 ++++++++++++++--- crates/uv-requirements/src/lookahead.rs | 19 +++++++++----- crates/uv-requirements/src/pyproject.rs | 1 + crates/uv-resolver/src/resolver/urls.rs | 7 ++++- 7 files changed, 61 insertions(+), 29 deletions(-) diff --git a/crates/distribution-types/src/requirement.rs b/crates/distribution-types/src/requirement.rs index d5b33b27c..c0f7ad4a5 100644 --- a/crates/distribution-types/src/requirement.rs +++ b/crates/distribution-types/src/requirement.rs @@ -6,7 +6,7 @@ use url::Url; use pep440_rs::VersionSpecifiers; use pep508_rs::{MarkerEnvironment, MarkerTree, RequirementOrigin, VerbatimUrl, VersionOrUrl}; -use uv_git::GitReference; +use uv_git::{GitReference, GitSha}; use uv_normalize::{ExtraName, PackageName}; use crate::{ParsedUrl, ParsedUrlError}; @@ -102,6 +102,7 @@ impl Display for Requirement { url: _, repository, reference, + precise: _, subdirectory, } => { write!(f, " @ git+{repository}")?; @@ -158,6 +159,8 @@ pub enum RequirementSource { repository: Url, /// Optionally, the revision, tag, or branch to use. reference: GitReference, + /// The precise commit to use, if known. + precise: Option, /// The path to the source distribution if it is not in the repository root. subdirectory: Option, /// The PEP 508 style url in the format @@ -192,6 +195,7 @@ impl RequirementSource { url, repository: git.url.repository().clone(), reference: git.url.reference().clone(), + precise: git.url.precise(), subdirectory: git.subdirectory, }, ParsedUrl::Archive(archive) => RequirementSource::Url { diff --git a/crates/distribution-types/src/resolution.rs b/crates/distribution-types/src/resolution.rs index 0e9606329..4b73c358d 100644 --- a/crates/distribution-types/src/resolution.rs +++ b/crates/distribution-types/src/resolution.rs @@ -2,9 +2,7 @@ use rustc_hash::FxHashMap; use uv_normalize::PackageName; -use crate::{ - BuiltDist, Dist, Name, ParsedGitUrl, Requirement, RequirementSource, ResolvedDist, SourceDist, -}; +use crate::{BuiltDist, Dist, Name, Requirement, RequirementSource, ResolvedDist, SourceDist}; /// A set of packages pinned at specific versions. #[derive(Debug, Default, Clone)] @@ -88,7 +86,7 @@ impl From<&ResolvedDist> for Requirement { RequirementSource::Url { url: wheel.url.clone(), location, - subdirectory: None, + subdirectory: wheel.subdirectory.clone(), } } Dist::Built(BuiltDist::Path(wheel)) => RequirementSource::Path { @@ -108,19 +106,16 @@ impl From<&ResolvedDist> for Requirement { RequirementSource::Url { url: sdist.url.clone(), location, - subdirectory: None, - } - } - Dist::Source(SourceDist::Git(sdist)) => { - let git_url = ParsedGitUrl::try_from(sdist.url.to_url()) - .expect("urls must be valid at this point"); - RequirementSource::Git { - url: sdist.url.clone(), - repository: git_url.url.repository().clone(), - reference: git_url.url.reference().clone(), - subdirectory: git_url.subdirectory, + subdirectory: sdist.subdirectory.clone(), } } + Dist::Source(SourceDist::Git(sdist)) => RequirementSource::Git { + url: sdist.url.clone(), + repository: sdist.git.repository().clone(), + reference: sdist.git.reference().clone(), + precise: sdist.git.precise(), + subdirectory: sdist.subdirectory.clone(), + }, Dist::Source(SourceDist::Path(sdist)) => RequirementSource::Path { path: sdist.path.clone(), url: sdist.url.clone(), @@ -129,7 +124,7 @@ impl From<&ResolvedDist> for Requirement { Dist::Source(SourceDist::Directory(sdist)) => RequirementSource::Path { path: sdist.path.clone(), url: sdist.url.clone(), - editable: None, + editable: Some(sdist.editable), }, }, ResolvedDist::Installed(dist) => RequirementSource::Registry { diff --git a/crates/uv-installer/src/plan.rs b/crates/uv-installer/src/plan.rs index cfb1d2db5..ad2b9722f 100644 --- a/crates/uv-installer/src/plan.rs +++ b/crates/uv-installer/src/plan.rs @@ -312,12 +312,17 @@ impl<'a> Planner<'a> { RequirementSource::Git { repository, reference, + precise, subdirectory, url, } => { + let mut git = GitUrl::new(repository.clone(), reference.clone()); + if let Some(precise) = precise { + git = git.with_precise(*precise); + } let sdist = GitSourceDist { name: requirement.name.clone(), - git: Box::new(GitUrl::new(repository.clone(), reference.clone())), + git: Box::new(git), subdirectory: subdirectory.clone(), url: url.clone(), }; diff --git a/crates/uv-installer/src/satisfies.rs b/crates/uv-installer/src/satisfies.rs index e9c5634a8..5b1779ac4 100644 --- a/crates/uv-installer/src/satisfies.rs +++ b/crates/uv-installer/src/satisfies.rs @@ -92,6 +92,7 @@ impl RequirementSatisfaction { url: _, repository: requested_repository, reference: requested_reference, + precise: requested_precise, subdirectory: requested_subdirectory, } => { let InstalledDist::Url(InstalledDirectUrlDist { direct_url, .. }) = &distribution @@ -130,10 +131,12 @@ impl RequirementSatisfaction { return Ok(Self::Mismatch); } - if installed_reference.as_deref() != requested_reference.as_str() { + if installed_reference.as_deref() != requested_reference.as_str() + && installed_reference != &requested_precise.map(|git_sha| git_sha.to_string()) + { debug!( - "Reference mismatch: {:?} vs. {:?}", - installed_reference, requested_reference + "Reference mismatch: {:?} vs. {:?} and {:?}", + installed_reference, requested_reference, requested_precise ); return Ok(Self::OutOfDate); } @@ -160,17 +163,29 @@ impl RequirementSatisfaction { return Ok(Self::Mismatch); }; - if requested_editable != installed_editable { + if requested_editable.unwrap_or_default() != installed_editable.unwrap_or_default() + { + trace!( + "Editable mismatch: {:?} vs. {:?}", + requested_editable.unwrap_or_default(), + installed_editable.unwrap_or_default() + ); return Ok(Self::Mismatch); } if !CanonicalUrl::parse(installed_url) .is_ok_and(|installed_url| installed_url == CanonicalUrl::new(requested_url)) { + trace!( + "URL mismatch: {:?} vs. {:?}", + CanonicalUrl::parse(installed_url), + CanonicalUrl::new(requested_url) + ); return Ok(Self::Mismatch); } if !ArchiveTimestamp::up_to_date_with(path, ArchiveTarget::Install(distribution))? { + trace!("Out of date"); return Ok(Self::OutOfDate); } diff --git a/crates/uv-requirements/src/lookahead.rs b/crates/uv-requirements/src/lookahead.rs index fe4c1a370..188ee02a6 100644 --- a/crates/uv-requirements/src/lookahead.rs +++ b/crates/uv-requirements/src/lookahead.rs @@ -171,14 +171,21 @@ impl<'a, Context: BuildContext> LookaheadResolver<'a, Context> { RequirementSource::Git { repository, reference, + precise, subdirectory, url, - } => Dist::Source(SourceDist::Git(GitSourceDist { - name: requirement.name, - git: Box::new(GitUrl::new(repository, reference)), - subdirectory, - url, - })), + } => { + let mut git_url = GitUrl::new(repository, reference); + if let Some(precise) = precise { + git_url = git_url.with_precise(precise); + } + Dist::Source(SourceDist::Git(GitSourceDist { + name: requirement.name, + git: Box::new(git_url), + subdirectory, + url, + })) + } RequirementSource::Path { path, url, diff --git a/crates/uv-requirements/src/pyproject.rs b/crates/uv-requirements/src/pyproject.rs index fb8d27b6b..8f3b680a9 100644 --- a/crates/uv-requirements/src/pyproject.rs +++ b/crates/uv-requirements/src/pyproject.rs @@ -468,6 +468,7 @@ pub(crate) fn lower_requirement( url, repository, reference, + precise: None, subdirectory: subdirectory.map(PathBuf::from), } } diff --git a/crates/uv-resolver/src/resolver/urls.rs b/crates/uv-resolver/src/resolver/urls.rs index aff48f3bc..589a9bd37 100644 --- a/crates/uv-resolver/src/resolver/urls.rs +++ b/crates/uv-resolver/src/resolver/urls.rs @@ -104,12 +104,17 @@ impl Urls { RequirementSource::Git { repository, reference, + precise, subdirectory, url, } => { + let mut git_url = GitUrl::new(repository.clone(), reference.clone()); + if let Some(precise) = precise { + git_url = git_url.with_precise(*precise); + } let url = VerbatimParsedUrl { parsed_url: ParsedUrl::Git(ParsedGitUrl { - url: GitUrl::new(repository.clone(), reference.clone()), + url: git_url, subdirectory: subdirectory.clone(), }), verbatim: url.clone(),