Skip to content

Commit 2fcc375

Browse files
committed
Auto merge of #14750 - epage:normalize, r=weihanglo
fix(util): Respect all `..`s in `normalize_path` ### What does this PR try to resolve? The fact that `normalize_path` was only designed for absolute paths bit us when working out #14497 and so I decided to make sure it worked. The other alternative I considered was having it assert that the path was absolute. Since I did try out the assert and Cargo tests hit it, this likely fixes something but I haven't dug through to be able to say what. ### How should we test and review this PR? ### Additional information
2 parents 7421ccf + 7a6eaf9 commit 2fcc375

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

crates/cargo-util/src/paths.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,18 @@ pub fn normalize_path(path: &Path) -> PathBuf {
9494
match component {
9595
Component::Prefix(..) => unreachable!(),
9696
Component::RootDir => {
97-
ret.push(component.as_os_str());
97+
ret.push(Component::RootDir);
9898
}
9999
Component::CurDir => {}
100100
Component::ParentDir => {
101-
ret.pop();
101+
if ret.ends_with(Component::ParentDir) {
102+
ret.push(Component::ParentDir);
103+
} else {
104+
let popped = ret.pop();
105+
if !popped && !ret.has_root() {
106+
ret.push(Component::ParentDir);
107+
}
108+
}
102109
}
103110
Component::Normal(c) => {
104111
ret.push(c);
@@ -856,9 +863,43 @@ fn exclude_from_time_machine(path: &Path) {
856863
#[cfg(test)]
857864
mod tests {
858865
use super::join_paths;
866+
use super::normalize_path;
859867
use super::write;
860868
use super::write_atomic;
861869

870+
#[test]
871+
fn test_normalize_path() {
872+
let cases = &[
873+
("", ""),
874+
(".", ""),
875+
(".////./.", ""),
876+
("/", "/"),
877+
("/..", "/"),
878+
("/foo/bar", "/foo/bar"),
879+
("/foo/bar/", "/foo/bar"),
880+
("/foo/bar/./././///", "/foo/bar"),
881+
("/foo/bar/..", "/foo"),
882+
("/foo/bar/../..", "/"),
883+
("/foo/bar/../../..", "/"),
884+
("foo/bar", "foo/bar"),
885+
("foo/bar/", "foo/bar"),
886+
("foo/bar/./././///", "foo/bar"),
887+
("foo/bar/..", "foo"),
888+
("foo/bar/../..", ""),
889+
("foo/bar/../../..", ".."),
890+
("../../foo/bar", "../../foo/bar"),
891+
("../../foo/bar/", "../../foo/bar"),
892+
("../../foo/bar/./././///", "../../foo/bar"),
893+
("../../foo/bar/..", "../../foo"),
894+
("../../foo/bar/../..", "../.."),
895+
("../../foo/bar/../../..", "../../.."),
896+
];
897+
for (input, expected) in cases {
898+
let actual = normalize_path(std::path::Path::new(input));
899+
assert_eq!(actual, std::path::Path::new(expected), "input: {input}");
900+
}
901+
}
902+
862903
#[test]
863904
fn write_works() {
864905
let original_contents = "[dependencies]\nfoo = 0.1.0";

0 commit comments

Comments
 (0)