Use copy-on-write when normalizing paths (#9710)

This commit is contained in:
Charlie Marsh 2024-12-07 15:52:41 -05:00 committed by GitHub
parent f8e6a94893
commit 7df16af764
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 40 additions and 15 deletions

View File

@ -317,10 +317,10 @@ impl LoweredRequirement {
let source = if let Some(git_member) = &git_member { let source = if let Some(git_member) = &git_member {
// If the workspace comes from a Git dependency, all workspace // If the workspace comes from a Git dependency, all workspace
// members need to be Git dependencies, too. // members need to be Git dependencies, too.
let subdirectory = uv_fs::normalize_path( let subdirectory =
&uv_fs::relative_to(member.root(), git_member.fetch_root) uv_fs::relative_to(member.root(), git_member.fetch_root)
.expect("Workspace member must be relative"), .expect("Workspace member must be relative");
); let subdirectory = uv_fs::normalize_path_buf(subdirectory);
RequirementSource::Git { RequirementSource::Git {
repository: git_member.git_source.git.repository().clone(), repository: git_member.git_source.git.repository().clone(),
reference: git_member.git_source.git.reference().clone(), reference: git_member.git_source.git.reference().clone(),
@ -711,10 +711,9 @@ fn path_source(
}; };
if is_dir { if is_dir {
if let Some(git_member) = git_member { if let Some(git_member) = git_member {
let subdirectory = uv_fs::normalize_path( let subdirectory = uv_fs::relative_to(install_path, git_member.fetch_root)
&uv_fs::relative_to(install_path, git_member.fetch_root) .expect("Workspace member must be relative");
.expect("Workspace member must be relative"), let subdirectory = uv_fs::normalize_path_buf(subdirectory);
);
return Ok(RequirementSource::Git { return Ok(RequirementSource::Git {
repository: git_member.git_source.git.repository().clone(), repository: git_member.git_source.git.repository().clone(),
reference: git_member.git_source.git.reference().clone(), reference: git_member.git_source.git.reference().clone(),

View File

@ -199,7 +199,33 @@ pub fn normalize_absolute_path(path: &Path) -> Result<PathBuf, std::io::Error> {
Ok(ret) Ok(ret)
} }
/// Normalize a path, removing things like `.` and `..`. /// Normalize a [`Path`], removing things like `.` and `..`.
pub fn normalize_path(path: &Path) -> Cow<Path> {
// Fast path: if the path is already normalized, return it as-is.
if path.components().all(|component| match component {
Component::Prefix(_) | Component::RootDir | Component::Normal(_) => true,
Component::ParentDir | Component::CurDir => false,
}) {
Cow::Borrowed(path)
} else {
Cow::Owned(normalized(path))
}
}
/// Normalize a [`PathBuf`], removing things like `.` and `..`.
pub fn normalize_path_buf(path: PathBuf) -> PathBuf {
// Fast path: if the path is already normalized, return it as-is.
if path.components().all(|component| match component {
Component::Prefix(_) | Component::RootDir | Component::Normal(_) => true,
Component::ParentDir | Component::CurDir => false,
}) {
path
} else {
normalized(&path)
}
}
/// Normalize a [`Path`].
/// ///
/// Unlike [`normalize_absolute_path`], this works with relative paths and does never error. /// Unlike [`normalize_absolute_path`], this works with relative paths and does never error.
/// ///
@ -216,8 +242,7 @@ pub fn normalize_absolute_path(path: &Path) -> Result<PathBuf, std::io::Error> {
/// Out: `workspace-git-path-dep-test/packages/d` /// Out: `workspace-git-path-dep-test/packages/d`
/// ///
/// In: `./a/../../b` /// In: `./a/../../b`
/// Out: `../b` fn normalized(path: &Path) -> PathBuf {
pub fn normalize_path(path: &Path) -> PathBuf {
let mut normalized = PathBuf::new(); let mut normalized = PathBuf::new();
for component in path.components() { for component in path.components() {
match component { match component {

View File

@ -3749,7 +3749,8 @@ fn normalize_requirement(
ext, ext,
url: _, url: _,
} => { } => {
let install_path = uv_fs::normalize_path(&workspace.install_path().join(&install_path)); let install_path =
uv_fs::normalize_path_buf(workspace.install_path().join(&install_path));
let url = VerbatimUrl::from_absolute_path(&install_path) let url = VerbatimUrl::from_absolute_path(&install_path)
.map_err(LockErrorKind::RequirementVerbatimUrl)?; .map_err(LockErrorKind::RequirementVerbatimUrl)?;
@ -3772,7 +3773,8 @@ fn normalize_requirement(
r#virtual, r#virtual,
url: _, url: _,
} => { } => {
let install_path = uv_fs::normalize_path(&workspace.install_path().join(&install_path)); let install_path =
uv_fs::normalize_path_buf(workspace.install_path().join(&install_path));
let url = VerbatimUrl::from_absolute_path(&install_path) let url = VerbatimUrl::from_absolute_path(&install_path)
.map_err(LockErrorKind::RequirementVerbatimUrl)?; .map_err(LockErrorKind::RequirementVerbatimUrl)?;

View File

@ -65,8 +65,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
.as_deref() .as_deref()
.map(std::path::absolute) .map(std::path::absolute)
.transpose()? .transpose()?
.as_deref() .map(uv_fs::normalize_path_buf)
.map(uv_fs::normalize_path)
.map(Cow::Owned) .map(Cow::Owned)
.unwrap_or_else(|| Cow::Borrowed(&*CWD)); .unwrap_or_else(|| Cow::Borrowed(&*CWD));