Skip to content

Commit 78517a6

Browse files
committed
Merge branch 'fix/ceiling-directories-win'
2 parents 0506a1f + 8840b64 commit 78517a6

File tree

2 files changed

+44
-20
lines changed

2 files changed

+44
-20
lines changed

git-discover/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,5 @@ is_ci = "1.1.1"
2929
[target.'cfg(target_os = "macos")'.dev-dependencies]
3030
defer = "0.1.0"
3131

32-
[target.'cfg(unix)'.dev-dependencies]
32+
[target.'cfg(any(unix, windows))'.dev-dependencies]
3333
tempfile = "3.2.0"

git-discover/src/upwards/types.rs

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
use std::{borrow::Cow, env, path::PathBuf};
2-
3-
use bstr::{ByteSlice, ByteVec};
1+
use std::ffi::OsStr;
2+
use std::{env, path::PathBuf};
43

54
/// The error returned by [git_discover::upwards()][crate::upwards()].
65
#[derive(Debug, thiserror::Error)]
@@ -81,44 +80,40 @@ impl Options<'_> {
8180
// TODO: test
8281
pub fn apply_environment(mut self) -> Self {
8382
let name = "GIT_CEILING_DIRECTORIES";
84-
if let Some(ceiling_dirs) = env::var_os(name).and_then(|c| Vec::from_os_string(c).ok()) {
83+
if let Some(ceiling_dirs) = env::var_os(name) {
8584
self.ceiling_dirs = parse_ceiling_dirs(&ceiling_dirs);
8685
}
8786
self
8887
}
8988
}
9089

9190
/// Parse a byte-string of `:`-separated paths into `Vec<PathBuf>`.
91+
/// On Windows, paths are separated by `;`.
9292
/// Non-absolute paths are discarded.
9393
/// To match git, all paths are normalized, until an empty path is encountered.
94-
pub(crate) fn parse_ceiling_dirs(ceiling_dirs: &[u8]) -> Vec<PathBuf> {
94+
pub(crate) fn parse_ceiling_dirs(ceiling_dirs: &OsStr) -> Vec<PathBuf> {
9595
let mut should_normalize = true;
96-
let mut result = Vec::new();
97-
for ceiling_dir in ceiling_dirs.split_str(":") {
98-
if ceiling_dir.is_empty() {
96+
let mut out = Vec::new();
97+
for ceiling_dir in std::env::split_paths(ceiling_dirs) {
98+
if ceiling_dir.as_os_str().is_empty() {
9999
should_normalize = false;
100100
continue;
101101
}
102102

103-
// Paths that are invalid unicode can't be handled
104-
let mut dir = match ceiling_dir.to_path() {
105-
Ok(dir) => Cow::Borrowed(dir),
106-
Err(_) => continue,
107-
};
108-
109103
// Only absolute paths are allowed
110-
if dir.is_relative() {
104+
if ceiling_dir.is_relative() {
111105
continue;
112106
}
113107

108+
let mut dir = ceiling_dir;
114109
if should_normalize {
115110
if let Ok(normalized) = git_path::realpath(&dir) {
116-
dir = Cow::Owned(normalized);
111+
dir = normalized;
117112
}
118113
}
119-
result.push(dir.into_owned());
114+
out.push(dir);
120115
}
121-
result
116+
out
122117
}
123118

124119
#[cfg(test)]
@@ -141,7 +136,7 @@ mod tests {
141136
// Parse & build ceiling dirs string
142137
let symlink_str = symlink_path.to_str().expect("symlink path is valid utf8");
143138
let ceiling_dir_string = format!("{}:relative::{}", symlink_str, symlink_str);
144-
let ceiling_dirs = parse_ceiling_dirs(ceiling_dir_string.as_bytes());
139+
let ceiling_dirs = parse_ceiling_dirs(OsStr::new(ceiling_dir_string.as_str()));
145140

146141
assert_eq!(ceiling_dirs.len(), 2, "Relative path is discarded");
147142
assert_eq!(
@@ -156,4 +151,33 @@ mod tests {
156151

157152
dir.close()
158153
}
154+
155+
#[test]
156+
#[cfg(windows)]
157+
fn parse_ceiling_dirs_from_environment_format() -> std::io::Result<()> {
158+
use std::{fs, os::windows::fs::symlink_dir};
159+
160+
use super::*;
161+
162+
// Setup filesystem
163+
let dir = tempfile::tempdir().expect("success creating temp dir");
164+
let direct_path = dir.path().join("direct");
165+
let symlink_path = dir.path().join("symlink");
166+
fs::create_dir(&direct_path)?;
167+
symlink_dir(&direct_path, &symlink_path)?;
168+
169+
// Parse & build ceiling dirs string
170+
let symlink_str = symlink_path.to_str().expect("symlink path is valid utf8");
171+
let ceiling_dir_string = format!("{};relative;;{}", symlink_str, symlink_str);
172+
let ceiling_dirs = parse_ceiling_dirs(OsStr::new(ceiling_dir_string.as_str()));
173+
174+
assert_eq!(ceiling_dirs.len(), 2, "Relative path is discarded");
175+
assert_eq!(ceiling_dirs[0], direct_path, "Symlinks are resolved");
176+
assert_eq!(
177+
ceiling_dirs[1], symlink_path,
178+
"Symlink are not resolved after empty item"
179+
);
180+
181+
dir.close()
182+
}
159183
}

0 commit comments

Comments
 (0)