mirror of
https://github.com/nushell/nushell.git
synced 2025-06-08 02:57:06 +02:00
fix(glob): Fix drive-letter glob expansion on Windows (#15871)
# Description This PR fixes drive-letter glob expansion on Windows. It adds a bit of pre-processing to play better with the wax crate. This change is following suggestions from this thread on the wax repo: https://github.com/olson-sean-k/wax/issues/34 fixes #15707 #7125
This commit is contained in:
parent
74e0e4f092
commit
ed7b2615c1
@ -168,6 +168,10 @@ impl Command for Glob {
|
||||
}),
|
||||
};
|
||||
|
||||
// paths starting with drive letters must be escaped on Windows
|
||||
#[cfg(windows)]
|
||||
let glob_pattern = patch_windows_glob_pattern(glob_pattern, glob_span)?;
|
||||
|
||||
if glob_pattern.is_empty() {
|
||||
return Err(ShellError::GenericError {
|
||||
error: "glob pattern must not be empty".into(),
|
||||
@ -280,6 +284,26 @@ impl Command for Glob {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn patch_windows_glob_pattern(glob_pattern: String, glob_span: Span) -> Result<String, ShellError> {
|
||||
let mut chars = glob_pattern.chars();
|
||||
match (chars.next(), chars.next(), chars.next()) {
|
||||
(Some(drive), Some(':'), Some('/' | '\\')) if drive.is_ascii_alphabetic() => {
|
||||
Ok(format!("{drive}\\:/{}", chars.as_str()))
|
||||
}
|
||||
(Some(drive), Some(':'), Some(_)) if drive.is_ascii_alphabetic() => {
|
||||
Err(ShellError::GenericError {
|
||||
error: "invalid Windows path format".into(),
|
||||
msg: "Windows paths with drive letters must include a path separator (/) after the colon".into(),
|
||||
span: Some(glob_span),
|
||||
help: Some("use format like 'C:/' instead of 'C:'".into()),
|
||||
inner: vec![],
|
||||
})
|
||||
}
|
||||
_ => Ok(glob_pattern),
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_patterns(columns: &[Value]) -> Result<Vec<String>, ShellError> {
|
||||
let res = columns
|
||||
.iter()
|
||||
@ -325,3 +349,53 @@ fn glob_to_value(
|
||||
|
||||
ListStream::new(result, span, signals.clone())
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
#[cfg(test)]
|
||||
mod windows_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn glob_pattern_with_drive_letter() {
|
||||
let pattern = "D:/*.mp4".to_string();
|
||||
let result = patch_windows_glob_pattern(pattern, Span::test_data()).unwrap();
|
||||
assert!(WaxGlob::new(&result).is_ok());
|
||||
|
||||
let pattern = "Z:/**/*.md".to_string();
|
||||
let result = patch_windows_glob_pattern(pattern, Span::test_data()).unwrap();
|
||||
assert!(WaxGlob::new(&result).is_ok());
|
||||
|
||||
let pattern = "C:/nested/**/escaped/path/<[_a-zA-Z\\-]>.md".to_string();
|
||||
let result = patch_windows_glob_pattern(pattern, Span::test_data()).unwrap();
|
||||
assert!(dbg!(WaxGlob::new(&result)).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn glob_pattern_without_drive_letter() {
|
||||
let pattern = "/usr/bin/*.sh".to_string();
|
||||
let result = patch_windows_glob_pattern(pattern.clone(), Span::test_data()).unwrap();
|
||||
assert_eq!(result, pattern);
|
||||
assert!(WaxGlob::new(&result).is_ok());
|
||||
|
||||
let pattern = "a".to_string();
|
||||
let result = patch_windows_glob_pattern(pattern.clone(), Span::test_data()).unwrap();
|
||||
assert_eq!(result, pattern);
|
||||
assert!(WaxGlob::new(&result).is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_path_format() {
|
||||
let invalid = "C:lol".to_string();
|
||||
let result = patch_windows_glob_pattern(invalid, Span::test_data());
|
||||
assert!(result.is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unpatched_patterns() {
|
||||
let unpatched = "C:/Users/*.txt".to_string();
|
||||
assert!(WaxGlob::new(&unpatched).is_err());
|
||||
|
||||
let patched = patch_windows_glob_pattern(unpatched, Span::test_data()).unwrap();
|
||||
assert!(WaxGlob::new(&patched).is_ok());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user