mirror of
https://github.com/nushell/nushell
synced 2024-12-28 14:03:09 +00:00
run_external.rs: use pathdiff::diff_path to handle relative path (#13056)
# Description This pr is going to use `pathdiff::diff_path`, so we don't need to handle for relative path by ourselves. This is also the behavior before the rewritten of run_external.rs It's a follow up to https://github.com/nushell/nushell/pull/13028 # User-Facing Changes NaN # Tests + Formatting No need to add tests
This commit is contained in:
parent
e3a20e90b0
commit
83cf212e20
1 changed files with 39 additions and 49 deletions
|
@ -8,6 +8,7 @@ use nu_protocol::{
|
||||||
};
|
};
|
||||||
use nu_system::ForegroundChild;
|
use nu_system::ForegroundChild;
|
||||||
use nu_utils::IgnoreCaseExt;
|
use nu_utils::IgnoreCaseExt;
|
||||||
|
use pathdiff::diff_paths;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
io::Write,
|
io::Write,
|
||||||
|
@ -343,61 +344,54 @@ fn expand_glob(
|
||||||
// We must use `nu_engine::glob_from` here, in order to ensure we get paths from the correct
|
// We must use `nu_engine::glob_from` here, in order to ensure we get paths from the correct
|
||||||
// dir
|
// dir
|
||||||
let glob = NuGlob::Expand(arg.to_owned()).into_spanned(span);
|
let glob = NuGlob::Expand(arg.to_owned()).into_spanned(span);
|
||||||
let Ok((_prefix, paths)) = nu_engine::glob_from(&glob, cwd, span, None) else {
|
if let Ok((prefix, matches)) = nu_engine::glob_from(&glob, cwd, span, None) {
|
||||||
// If an error occurred, return the original input
|
let mut result = vec![];
|
||||||
return Ok(vec![arg.into()]);
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the first component of the original `arg` string path was '.', that should be preserved
|
for m in matches {
|
||||||
let relative_to_dot = Path::new(arg).starts_with(".");
|
if nu_utils::ctrl_c::was_pressed(interrupt) {
|
||||||
|
return Err(ShellError::InterruptedByUser { span: Some(span) });
|
||||||
let paths = paths
|
|
||||||
// Skip over glob failures. These are usually just inaccessible paths.
|
|
||||||
.flat_map(|path_result| match path_result {
|
|
||||||
Ok(path) => Some(path),
|
|
||||||
Err(err) => {
|
|
||||||
// But internally log them just in case we need to debug this.
|
|
||||||
log::warn!("Error in run_external::expand_glob(): {}", err);
|
|
||||||
None
|
|
||||||
}
|
}
|
||||||
})
|
if let Ok(arg) = m {
|
||||||
// Make the paths relative to the cwd
|
let arg = resolve_globbed_path_to_cwd_relative(arg, prefix.as_ref(), cwd);
|
||||||
.map(|path| {
|
result.push(arg.to_string_lossy().to_string());
|
||||||
path.strip_prefix(cwd)
|
|
||||||
.map(|path| path.to_owned())
|
|
||||||
.unwrap_or(path)
|
|
||||||
})
|
|
||||||
// Add './' to relative paths if the original pattern had it
|
|
||||||
.map(|path| {
|
|
||||||
if relative_to_dot && path.is_relative() {
|
|
||||||
Path::new(".").join(path)
|
|
||||||
} else {
|
} else {
|
||||||
path
|
result.push(arg.into());
|
||||||
}
|
}
|
||||||
})
|
}
|
||||||
// Convert the paths returned to UTF-8 strings.
|
|
||||||
//
|
|
||||||
// FIXME: this fails to return the correct results for non-UTF-8 paths, but we don't support
|
|
||||||
// those in Nushell yet.
|
|
||||||
.map(|path| path.to_string_lossy().into_owned())
|
|
||||||
// Abandon if ctrl-c is pressed
|
|
||||||
.map(|path| {
|
|
||||||
if !nu_utils::ctrl_c::was_pressed(interrupt) {
|
|
||||||
Ok(path)
|
|
||||||
} else {
|
|
||||||
Err(ShellError::InterruptedByUser { span: Some(span) })
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<String>, ShellError>>()?;
|
|
||||||
|
|
||||||
if !paths.is_empty() {
|
// FIXME: do we want to special-case this further? We might accidentally expand when they don't
|
||||||
Ok(paths)
|
// intend to
|
||||||
|
if result.is_empty() {
|
||||||
|
result.push(arg.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
} else {
|
} else {
|
||||||
// If we failed to match, return the original input
|
|
||||||
Ok(vec![arg.into()])
|
Ok(vec![arg.into()])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn resolve_globbed_path_to_cwd_relative(
|
||||||
|
path: PathBuf,
|
||||||
|
prefix: Option<&PathBuf>,
|
||||||
|
cwd: &Path,
|
||||||
|
) -> PathBuf {
|
||||||
|
if let Some(prefix) = prefix {
|
||||||
|
if let Ok(remainder) = path.strip_prefix(prefix) {
|
||||||
|
let new_prefix = if let Some(pfx) = diff_paths(prefix, cwd) {
|
||||||
|
pfx
|
||||||
|
} else {
|
||||||
|
prefix.to_path_buf()
|
||||||
|
};
|
||||||
|
new_prefix.join(remainder)
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Transforms `--option="value"` into `--option=value`. `value` can be quoted
|
/// Transforms `--option="value"` into `--option=value`. `value` can be quoted
|
||||||
/// with double quotes, single quotes, or backticks. Only removes the outermost
|
/// with double quotes, single quotes, or backticks. Only removes the outermost
|
||||||
/// pair of quotes after the equal sign.
|
/// pair of quotes after the equal sign.
|
||||||
|
@ -716,10 +710,6 @@ mod test {
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
|
||||||
let actual = expand_glob("./*.txt", cwd, Span::unknown(), &None).unwrap();
|
let actual = expand_glob("./*.txt", cwd, Span::unknown(), &None).unwrap();
|
||||||
let expected = vec![
|
|
||||||
Path::new(".").join("a.txt").to_string_lossy().into_owned(),
|
|
||||||
Path::new(".").join("b.txt").to_string_lossy().into_owned(),
|
|
||||||
];
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
|
|
||||||
let actual = expand_glob("'*.txt'", cwd, Span::unknown(), &None).unwrap();
|
let actual = expand_glob("'*.txt'", cwd, Span::unknown(), &None).unwrap();
|
||||||
|
|
Loading…
Reference in a new issue