Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 3 additions & 5 deletions crates/uv-distribution-types/src/requirement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::str::FromStr;
use thiserror::Error;
use uv_cache_key::{CacheKey, CacheKeyHasher};
use uv_distribution_filename::DistExtension;
use uv_fs::{CWD, PortablePath, PortablePathBuf, relative_to};
use uv_fs::{CWD, PortablePath, PortablePathBuf, try_relative_to_if};
use uv_git_types::{GitLfs, GitOid, GitReference, GitUrl, GitUrlParseError, OidParseError};
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep440::VersionSpecifiers;
Expand Down Expand Up @@ -694,8 +694,7 @@ impl RequirementSource {
ext,
url,
} => Ok(Self::Path {
install_path: relative_to(&install_path, path)
.or_else(|_| std::path::absolute(install_path))?
install_path: try_relative_to_if(&install_path, path, !url.was_given_absolute())?
.into_boxed_path(),
ext,
url,
Expand All @@ -707,8 +706,7 @@ impl RequirementSource {
url,
..
} => Ok(Self::Directory {
install_path: relative_to(&install_path, path)
.or_else(|_| std::path::absolute(install_path))?
install_path: try_relative_to_if(&install_path, path, !url.was_given_absolute())?
.into_boxed_path(),
editable,
r#virtual,
Expand Down
14 changes: 14 additions & 0 deletions crates/uv-fs/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,20 @@ pub fn relative_to(
Ok(up.join(stripped))
}

/// Try to compute a path relative to `base` if `should_relativize` is true, otherwise return
/// the absolute path. Falls back to absolute if relativization fails.
pub fn try_relative_to_if(
path: impl AsRef<Path>,
base: impl AsRef<Path>,
should_relativize: bool,
) -> Result<PathBuf, std::io::Error> {
if should_relativize {
relative_to(&path, &base).or_else(|_| std::path::absolute(path.as_ref()))
} else {
std::path::absolute(path.as_ref())
}
}

/// A path that can be serialized and deserialized in a portable way by converting Windows-style
/// backslashes to forward slashes, and using a `.` for an empty path.
///
Expand Down
15 changes: 15 additions & 0 deletions crates/uv-pep508/src/verbatim_url.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,21 @@ impl VerbatimUrl {
self.given.as_deref()
}

/// Returns `true` if the `given` input was an absolute path or file URL.
pub fn was_given_absolute(&self) -> bool {
let Some(given) = &self.given else {
return false;
};

if let Some((scheme, _)) = split_scheme(given) {
if let Some(parsed_scheme) = Scheme::parse(scheme) {
return parsed_scheme.is_file();
}
}

Path::new(given.as_str()).is_absolute()
}

/// Return the underlying [`DisplaySafeUrl`].
pub fn raw(&self) -> &DisplaySafeUrl {
&self.url
Expand Down
54 changes: 34 additions & 20 deletions crates/uv-resolver/src/lock/export/pylock_toml.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;
use std::ffi::OsStr;
use std::path::Path;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::sync::Arc;

Expand All @@ -27,7 +27,7 @@ use uv_distribution_types::{
RegistryBuiltDist, RegistryBuiltWheel, RegistrySourceDist, RemoteSource, RequiresPython,
Resolution, ResolvedDist, SourceDist, ToUrlError, UrlString,
};
use uv_fs::{PortablePathBuf, relative_to};
use uv_fs::{PortablePathBuf, try_relative_to_if};
use uv_git::{RepositoryReference, ResolvedRepositoryReference};
use uv_git_types::{GitLfs, GitOid, GitReference, GitUrl, GitUrlParseError};
use uv_normalize::{ExtraName, GroupName, PackageName};
Expand Down Expand Up @@ -411,9 +411,13 @@ impl<'lock> PylockToml {
});
}
Dist::Built(BuiltDist::Path(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
let path = try_relative_to_if(
&dist.install_path,
install_path,
!dist.url.was_given_absolute(),
)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.archive = Some(PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(path)),
Expand Down Expand Up @@ -477,9 +481,13 @@ impl<'lock> PylockToml {
});
}
Dist::Source(SourceDist::Directory(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
let path = try_relative_to_if(
&dist.install_path,
install_path,
!dist.url.was_given_absolute(),
)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.directory = Some(PylockTomlDirectory {
path: PortablePathBuf::from(path),
editable: dist.editable,
Expand All @@ -499,9 +507,13 @@ impl<'lock> PylockToml {
});
}
Dist::Source(SourceDist::Path(dist)) => {
let path = relative_to(&dist.install_path, install_path)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
let path = try_relative_to_if(
&dist.install_path,
install_path,
!dist.url.was_given_absolute(),
)
.map(Box::<Path>::from)
.unwrap_or_else(|_| dist.install_path.clone());
package.archive = Some(PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(path)),
Expand Down Expand Up @@ -761,8 +773,11 @@ impl<'lock> PylockToml {
let directory = match &sdist {
Some(SourceDist::Directory(sdist)) => Some(PylockTomlDirectory {
path: PortablePathBuf::from(
relative_to(&sdist.install_path, target.install_path())
.unwrap_or_else(|_| sdist.install_path.to_path_buf())
sdist
.url
.given()
.map(PathBuf::from)
.unwrap_or_else(|| sdist.install_path.to_path_buf())
.into_boxed_path(),
),
editable: match editable {
Expand Down Expand Up @@ -804,8 +819,11 @@ impl<'lock> PylockToml {
Some(SourceDist::Path(sdist)) => Some(PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(
relative_to(&sdist.install_path, target.install_path())
.unwrap_or_else(|_| sdist.install_path.to_path_buf())
sdist
.url
.given()
.map(PathBuf::from)
.unwrap_or_else(|| sdist.install_path.to_path_buf())
.into_boxed_path(),
)),
size,
Expand All @@ -817,11 +835,7 @@ impl<'lock> PylockToml {
Source::Registry(..) => None,
Source::Path(source) => package.wheels.first().map(|wheel| PylockTomlArchive {
url: None,
path: Some(PortablePathBuf::from(
relative_to(source, target.install_path())
.unwrap_or_else(|_| source.to_path_buf())
.into_boxed_path(),
)),
path: Some(PortablePathBuf::from(source.clone())),
size: wheel.size,
upload_time: None,
subdirectory: None,
Expand Down
Loading
Loading