diff --git a/crates/distribution-types/src/cached.rs b/crates/distribution-types/src/cached.rs index 946286001304..596b03bee256 100644 --- a/crates/distribution-types/src/cached.rs +++ b/crates/distribution-types/src/cached.rs @@ -7,11 +7,9 @@ use pep508_rs::VerbatimUrl; use pypi_types::HashDigest; use uv_normalize::PackageName; -use crate::direct_url::{LocalFileUrl, ParsedUrl}; -use crate::hash::Hashed; use crate::{ - BuiltDist, Dist, DistributionMetadata, InstalledMetadata, InstalledVersion, Name, SourceDist, - VersionOrUrl, + BuiltDist, Dist, DistributionMetadata, Hashed, InstalledMetadata, InstalledVersion, Name, + ParsedLocalFileUrl, ParsedUrl, SourceDist, VersionOrUrl, }; /// A built distribution (wheel) that exists in the local cache. @@ -111,7 +109,7 @@ impl CachedDist { Self::Url(dist) => { if dist.editable { assert_eq!(dist.url.scheme(), "file", "{}", dist.url); - Ok(Some(ParsedUrl::LocalFile(LocalFileUrl { + Ok(Some(ParsedUrl::LocalFile(ParsedLocalFileUrl { url: dist.url.raw().clone(), editable: dist.editable, }))) diff --git a/crates/distribution-types/src/lib.rs b/crates/distribution-types/src/lib.rs index 6007455861b3..e88155db4448 100644 --- a/crates/distribution-types/src/lib.rs +++ b/crates/distribution-types/src/lib.rs @@ -47,7 +47,6 @@ use uv_normalize::PackageName; pub use crate::any::*; pub use crate::buildable::*; pub use crate::cached::*; -pub use crate::direct_url::*; pub use crate::editable::*; pub use crate::error::*; pub use crate::file::*; @@ -55,6 +54,7 @@ pub use crate::hash::*; pub use crate::id::*; pub use crate::index_url::*; pub use crate::installed::*; +pub use crate::parsed_url::*; pub use crate::prioritized_distribution::*; pub use crate::resolution::*; pub use crate::resolved::*; @@ -63,7 +63,6 @@ pub use crate::traits::*; mod any; mod buildable; mod cached; -mod direct_url; mod editable; mod error; mod file; @@ -71,6 +70,7 @@ mod hash; mod id; mod index_url; mod installed; +mod parsed_url; mod prioritized_distribution; mod resolution; mod resolved; diff --git a/crates/distribution-types/src/direct_url.rs b/crates/distribution-types/src/parsed_url.rs similarity index 83% rename from crates/distribution-types/src/direct_url.rs rename to crates/distribution-types/src/parsed_url.rs index b1aa247c7250..c9539ef1bf3f 100644 --- a/crates/distribution-types/src/direct_url.rs +++ b/crates/distribution-types/src/parsed_url.rs @@ -6,7 +6,7 @@ use url::Url; use uv_git::{GitSha, GitUrl}; #[derive(Debug, Error)] -pub enum DirectUrlError { +pub enum ParsedUrlError { #[error("Unsupported URL prefix `{prefix}` in URL: `{url}`")] UnsupportedUrlPrefix { prefix: String, url: Url }, #[error("Invalid path in file URL: `{0}`")] @@ -28,11 +28,11 @@ pub enum DirectUrlError { #[derive(Debug)] pub enum ParsedUrl { /// The direct URL is a path to a local directory or file. - LocalFile(LocalFileUrl), + LocalFile(ParsedLocalFileUrl), /// The direct URL is path to a Git repository. - Git(DirectGitUrl), + Git(ParsedGitUrl), /// The direct URL is a URL to an archive. - Archive(DirectArchiveUrl), + Archive(ParsedArchiveUrl), } /// A local path url @@ -40,7 +40,7 @@ pub enum ParsedUrl { /// Examples: /// * `file:///home/ferris/my_project` #[derive(Debug)] -pub struct LocalFileUrl { +pub struct ParsedLocalFileUrl { pub url: Url, pub editable: bool, } @@ -51,7 +51,7 @@ pub struct LocalFileUrl { /// * `git+https://git.example.com/MyProject.git` /// * `git+https://git.example.com/MyProject.git@v1.0#egg=pkg&subdirectory=pkg_dir` #[derive(Debug)] -pub struct DirectGitUrl { +pub struct ParsedGitUrl { pub url: GitUrl, pub subdirectory: Option, } @@ -63,13 +63,13 @@ pub struct DirectGitUrl { /// * source dist, correctly named: `https://files.pythonhosted.org/packages/62/06/d5604a70d160f6a6ca5fd2ba25597c24abd5c5ca5f437263d177ac242308/tqdm-4.66.1.tar.gz` /// * source dist, only extension recognizable: `https://github.com/foo-labs/foo/archive/master.zip#egg=pkg&subdirectory=packages/bar` #[derive(Debug)] -pub struct DirectArchiveUrl { +pub struct ParsedArchiveUrl { pub url: Url, pub subdirectory: Option, } -impl TryFrom<&Url> for DirectGitUrl { - type Error = DirectUrlError; +impl TryFrom<&Url> for ParsedGitUrl { + type Error = ParsedUrlError; fn try_from(url_in: &Url) -> Result { let subdirectory = get_subdirectory(url_in); @@ -77,15 +77,15 @@ impl TryFrom<&Url> for DirectGitUrl { let url = url_in .as_str() .strip_prefix("git+") - .ok_or_else(|| DirectUrlError::MissingUrlPrefix(url_in.clone()))?; - let url = Url::parse(url).map_err(|err| DirectUrlError::UrlParse(url.to_string(), err))?; + .ok_or_else(|| ParsedUrlError::MissingUrlPrefix(url_in.clone()))?; + let url = Url::parse(url).map_err(|err| ParsedUrlError::UrlParse(url.to_string(), err))?; let url = GitUrl::try_from(url) - .map_err(|err| DirectUrlError::GitShaParse(url_in.clone(), err))?; + .map_err(|err| ParsedUrlError::GitShaParse(url_in.clone(), err))?; Ok(Self { url, subdirectory }) } } -impl From<&Url> for DirectArchiveUrl { +impl From<&Url> for ParsedArchiveUrl { fn from(url: &Url) -> Self { Self { url: url.clone(), @@ -110,29 +110,29 @@ fn get_subdirectory(url: &Url) -> Option { /// Return the Git reference of the given URL, if it exists. pub fn git_reference(url: &Url) -> Result, Error> { - let DirectGitUrl { url, .. } = DirectGitUrl::try_from(url)?; + let ParsedGitUrl { url, .. } = ParsedGitUrl::try_from(url)?; Ok(url.precise()) } impl TryFrom<&Url> for ParsedUrl { - type Error = DirectUrlError; + type Error = ParsedUrlError; fn try_from(url: &Url) -> Result { if let Some((prefix, ..)) = url.scheme().split_once('+') { match prefix { - "git" => Ok(Self::Git(DirectGitUrl::try_from(url)?)), - _ => Err(DirectUrlError::UnsupportedUrlPrefix { + "git" => Ok(Self::Git(ParsedGitUrl::try_from(url)?)), + _ => Err(ParsedUrlError::UnsupportedUrlPrefix { prefix: prefix.to_string(), url: url.clone(), }), } } else if url.scheme().eq_ignore_ascii_case("file") { - Ok(Self::LocalFile(LocalFileUrl { + Ok(Self::LocalFile(ParsedLocalFileUrl { url: url.clone(), editable: false, })) } else { - Ok(Self::Archive(DirectArchiveUrl::from(url))) + Ok(Self::Archive(ParsedArchiveUrl::from(url))) } } } @@ -149,10 +149,10 @@ impl TryFrom<&ParsedUrl> for pypi_types::DirectUrl { } } -impl TryFrom<&LocalFileUrl> for pypi_types::DirectUrl { +impl TryFrom<&ParsedLocalFileUrl> for pypi_types::DirectUrl { type Error = Error; - fn try_from(value: &LocalFileUrl) -> Result { + fn try_from(value: &ParsedLocalFileUrl) -> Result { Ok(Self::LocalDirectory { url: value.url.to_string(), dir_info: pypi_types::DirInfo { @@ -162,10 +162,10 @@ impl TryFrom<&LocalFileUrl> for pypi_types::DirectUrl { } } -impl TryFrom<&DirectArchiveUrl> for pypi_types::DirectUrl { +impl TryFrom<&ParsedArchiveUrl> for pypi_types::DirectUrl { type Error = Error; - fn try_from(value: &DirectArchiveUrl) -> Result { + fn try_from(value: &ParsedArchiveUrl) -> Result { Ok(Self::ArchiveUrl { url: value.url.to_string(), archive_info: pypi_types::ArchiveInfo { @@ -177,10 +177,10 @@ impl TryFrom<&DirectArchiveUrl> for pypi_types::DirectUrl { } } -impl TryFrom<&DirectGitUrl> for pypi_types::DirectUrl { +impl TryFrom<&ParsedGitUrl> for pypi_types::DirectUrl { type Error = Error; - fn try_from(value: &DirectGitUrl) -> Result { + fn try_from(value: &ParsedGitUrl) -> Result { Ok(Self::VcsUrl { url: value.url.repository().to_string(), vcs_info: pypi_types::VcsInfo { @@ -203,14 +203,14 @@ impl From for Url { } } -impl From for Url { - fn from(value: LocalFileUrl) -> Self { +impl From for Url { + fn from(value: ParsedLocalFileUrl) -> Self { value.url } } -impl From for Url { - fn from(value: DirectArchiveUrl) -> Self { +impl From for Url { + fn from(value: ParsedArchiveUrl) -> Self { let mut url = value.url; if let Some(subdirectory) = value.subdirectory { url.set_fragment(Some(&format!("subdirectory={}", subdirectory.display()))); @@ -219,8 +219,8 @@ impl From for Url { } } -impl From for Url { - fn from(value: DirectGitUrl) -> Self { +impl From for Url { + fn from(value: ParsedGitUrl) -> Self { let mut url = Self::parse(&format!("{}{}", "git+", Self::from(value.url).as_str())) .expect("Git URL is invalid"); if let Some(subdirectory) = value.subdirectory { @@ -235,7 +235,7 @@ mod tests { use anyhow::Result; use url::Url; - use crate::direct_url::ParsedUrl; + use crate::parsed_url::ParsedUrl; #[test] fn direct_url_from_url() -> Result<()> { diff --git a/crates/uv-distribution/src/error.rs b/crates/uv-distribution/src/error.rs index bcdcc07618c1..94de2b0b457f 100644 --- a/crates/uv-distribution/src/error.rs +++ b/crates/uv-distribution/src/error.rs @@ -3,7 +3,7 @@ use tokio::task::JoinError; use zip::result::ZipError; use distribution_filename::WheelFilenameError; -use distribution_types::DirectUrlError; +use distribution_types::ParsedUrlError; use pep440_rs::Version; use pypi_types::HashDigest; use uv_client::BetterReqwestError; @@ -24,7 +24,7 @@ pub enum Error { #[error("Git operation failed")] Git(#[source] anyhow::Error), #[error(transparent)] - DirectUrl(#[from] Box), + DirectUrl(#[from] Box), #[error(transparent)] Reqwest(#[from] BetterReqwestError), #[error(transparent)] diff --git a/crates/uv-distribution/src/git.rs b/crates/uv-distribution/src/git.rs index 8391299ac17f..ff47a56cafd8 100644 --- a/crates/uv-distribution/src/git.rs +++ b/crates/uv-distribution/src/git.rs @@ -9,7 +9,7 @@ use tracing::debug; use url::Url; use cache_key::{CanonicalUrl, RepositoryUrl}; -use distribution_types::DirectGitUrl; +use distribution_types::ParsedGitUrl; use uv_cache::{Cache, CacheBucket}; use uv_fs::LockedFile; use uv_git::{Fetch, GitReference, GitSha, GitSource, GitUrl}; @@ -67,7 +67,7 @@ pub(crate) async fn fetch_git_archive( ) .map_err(Error::CacheWrite)?; - let DirectGitUrl { url, subdirectory } = DirectGitUrl::try_from(url).map_err(Box::new)?; + let ParsedGitUrl { url, subdirectory } = ParsedGitUrl::try_from(url).map_err(Box::new)?; // Fetch the Git repository. let source = if let Some(reporter) = reporter { @@ -95,7 +95,7 @@ pub(crate) async fn resolve_precise( cache: &Cache, reporter: Option<&Arc>, ) -> Result, Error> { - let DirectGitUrl { url, subdirectory } = DirectGitUrl::try_from(url).map_err(Box::new)?; + let ParsedGitUrl { url, subdirectory } = ParsedGitUrl::try_from(url).map_err(Box::new)?; // If the Git reference already contains a complete SHA, short-circuit. if url.precise().is_some() { @@ -107,7 +107,7 @@ pub(crate) async fn resolve_precise( let resolved_git_refs = RESOLVED_GIT_REFS.lock().unwrap(); let reference = RepositoryReference::new(&url); if let Some(precise) = resolved_git_refs.get(&reference) { - return Ok(Some(Url::from(DirectGitUrl { + return Ok(Some(Url::from(ParsedGitUrl { url: url.with_precise(*precise), subdirectory, }))); @@ -136,7 +136,7 @@ pub(crate) async fn resolve_precise( } // Re-encode as a URL. - Ok(Some(Url::from(DirectGitUrl { + Ok(Some(Url::from(ParsedGitUrl { url: git, subdirectory, }))) @@ -154,11 +154,11 @@ pub(crate) async fn resolve_precise( /// This method will only return precise URLs for URLs that have already been resolved via /// [`resolve_precise`]. pub fn to_precise(url: &Url) -> Option { - let DirectGitUrl { url, subdirectory } = DirectGitUrl::try_from(url).ok()?; + let ParsedGitUrl { url, subdirectory } = ParsedGitUrl::try_from(url).ok()?; let resolved_git_refs = RESOLVED_GIT_REFS.lock().unwrap(); let reference = RepositoryReference::new(&url); let precise = resolved_git_refs.get(&reference)?; - Some(Url::from(DirectGitUrl { + Some(Url::from(ParsedGitUrl { url: url.with_precise(*precise), subdirectory, })) @@ -182,12 +182,12 @@ fn is_same_reference_impl<'a>( resolved_refs: &FxHashMap, ) -> bool { // Convert `a` to a Git URL, if possible. - let Ok(a_git) = DirectGitUrl::try_from(&Url::from(CanonicalUrl::new(a))) else { + let Ok(a_git) = ParsedGitUrl::try_from(&Url::from(CanonicalUrl::new(a))) else { return false; }; // Convert `b` to a Git URL, if possible. - let Ok(b_git) = DirectGitUrl::try_from(&Url::from(CanonicalUrl::new(b))) else { + let Ok(b_git) = ParsedGitUrl::try_from(&Url::from(CanonicalUrl::new(b))) else { return false; }; diff --git a/crates/uv-distribution/src/source/mod.rs b/crates/uv-distribution/src/source/mod.rs index 474211f4c429..9d7e04c15d7d 100644 --- a/crates/uv-distribution/src/source/mod.rs +++ b/crates/uv-distribution/src/source/mod.rs @@ -16,8 +16,8 @@ use zip::ZipArchive; use distribution_filename::WheelFilename; use distribution_types::{ - BuildableSource, DirectArchiveUrl, Dist, FileLocation, GitSourceUrl, HashPolicy, Hashed, - LocalEditable, PathSourceDist, PathSourceUrl, RemoteSource, SourceDist, SourceUrl, + BuildableSource, Dist, FileLocation, GitSourceUrl, HashPolicy, Hashed, LocalEditable, + ParsedArchiveUrl, PathSourceDist, PathSourceUrl, RemoteSource, SourceDist, SourceUrl, }; use install_wheel_rs::metadata::read_archive_metadata; use platform_tags::Tags; @@ -135,7 +135,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { } BuildableSource::Dist(SourceDist::DirectUrl(dist)) => { let filename = dist.filename().expect("Distribution must have a filename"); - let DirectArchiveUrl { url, subdirectory } = DirectArchiveUrl::from(dist.url.raw()); + let ParsedArchiveUrl { url, subdirectory } = ParsedArchiveUrl::from(dist.url.raw()); // For direct URLs, cache directly under the hash of the URL itself. let cache_shard = self @@ -186,7 +186,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { .url .filename() .expect("Distribution must have a filename"); - let DirectArchiveUrl { url, subdirectory } = DirectArchiveUrl::from(resource.url); + let ParsedArchiveUrl { url, subdirectory } = ParsedArchiveUrl::from(resource.url); // For direct URLs, cache directly under the hash of the URL itself. let cache_shard = self @@ -284,7 +284,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { } BuildableSource::Dist(SourceDist::DirectUrl(dist)) => { let filename = dist.filename().expect("Distribution must have a filename"); - let DirectArchiveUrl { url, subdirectory } = DirectArchiveUrl::from(dist.url.raw()); + let ParsedArchiveUrl { url, subdirectory } = ParsedArchiveUrl::from(dist.url.raw()); // For direct URLs, cache directly under the hash of the URL itself. let cache_shard = self @@ -328,7 +328,7 @@ impl<'a, T: BuildContext> SourceDistributionBuilder<'a, T> { .url .filename() .expect("Distribution must have a filename"); - let DirectArchiveUrl { url, subdirectory } = DirectArchiveUrl::from(resource.url); + let ParsedArchiveUrl { url, subdirectory } = ParsedArchiveUrl::from(resource.url); // For direct URLs, cache directly under the hash of the URL itself. let cache_shard = self