Performs `a.join(b)`, except: - if `b` is an absolute path, then the resulting path will equal `/a/b` - if the prefix of `b` contains some `n` copies of a, then the resulting path will equal `/a/b`
(a: impl AsRef<Path>, b: impl AsRef<Path>)
| 10 | /// - if `b` is an absolute path, then the resulting path will equal `/a/b` |
| 11 | /// - if the prefix of `b` contains some `n` copies of a, then the resulting path will equal `/a/b` |
| 12 | pub(super) fn append(a: impl AsRef<Path>, b: impl AsRef<Path>) -> PathBuf { |
| 13 | let a_path = a.as_ref(); |
| 14 | let b_path = b.as_ref(); |
| 15 | |
| 16 | // Extract the non-prefix, non-root components of paths a and b for comparison |
| 17 | let a_normal_components: Vec<_> = a_path |
| 18 | .components() |
| 19 | .filter(|c| !matches!(c, Component::Prefix(_) | Component::RootDir)) |
| 20 | .collect(); |
| 21 | |
| 22 | // Create a version of b_path without prefix/root components |
| 23 | let mut b_normal_path = PathBuf::new(); |
| 24 | for comp in b_path.components() { |
| 25 | match comp { |
| 26 | Component::Prefix(_) | Component::RootDir => (), |
| 27 | _ => b_normal_path.push(comp.as_os_str()), |
| 28 | } |
| 29 | } |
| 30 | |
| 31 | // Iteratively strip a from the beginning of b |
| 32 | let mut cleaned_b = b_normal_path.clone(); |
| 33 | let mut done = false; |
| 34 | |
| 35 | while !done { |
| 36 | let b_normal_components: Vec<_> = cleaned_b.components().collect(); |
| 37 | |
| 38 | if b_normal_components.len() >= a_normal_components.len() { |
| 39 | // Check if the beginning of b matches a (case-insensitive on Windows) |
| 40 | let matches = a_normal_components |
| 41 | .iter() |
| 42 | .zip(b_normal_components.iter()) |
| 43 | .all(|(a_comp, b_comp)| { |
| 44 | // Case-insensitive comparison for Windows |
| 45 | a_comp.as_os_str().to_string_lossy().to_lowercase() |
| 46 | == b_comp.as_os_str().to_string_lossy().to_lowercase() |
| 47 | }); |
| 48 | |
| 49 | if matches { |
| 50 | // Create a new path with a's components removed from the beginning of b |
| 51 | let mut new_b = PathBuf::new(); |
| 52 | for comp in b_normal_components.iter().skip(a_normal_components.len()) { |
| 53 | new_b.push(comp.as_os_str()); |
| 54 | } |
| 55 | cleaned_b = new_b; |
| 56 | } else { |
| 57 | done = true; |
| 58 | } |
| 59 | } else { |
| 60 | done = true; |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | // Join the paths |
| 65 | a_path.join(cleaned_b) |
| 66 | } |
| 67 | |
| 68 | /// Creates a new symbolic link on the filesystem. |
| 69 | /// |