mirror of
https://github.com/nushell/nushell.git
synced 2024-11-25 01:43:47 +01:00
ls, rm, cp, open, touch, mkdir: Don't expand tilde if input path is quoted string or a variable. (#12232)
# Description Fixes: #11887 Fixes: #11626 This pr unify the tilde expand behavior over several filesystem relative commands. It follows the same rule with glob expansion: | command | result | | ----------- | ------ | | ls ~/aaa | expand tilde | ls "~/aaa" | don't expand tilde | let f = "~/aaa"; ls $f | don't expand tilde, if you want to: use `ls ($f \| path expand)` | let f: glob = "~/aaa"; ls $f | expand tilde, they don't expand on `mkdir`, `touch` comamnd. Actually I'm not sure for 4th item, currently it's expanding is just because it followes the same rule with glob expansion. ### About the change It changes `expand_path_with` to accept a new argument called `expand_tilde`, if it's true, expand it, if not, just keep it as `~` itself. # User-Facing Changes After this change, `ls "~/aaa"` won't expand tilde. # Tests + Formatting Done
This commit is contained in:
parent
e7bdd08a04
commit
87c5f6e455
@ -734,7 +734,7 @@ fn parse_operation(
|
|||||||
orig = trim_quotes_str(&orig).to_string()
|
orig = trim_quotes_str(&orig).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
let path = nu_path::expand_path_with(&orig, &cwd);
|
let path = nu_path::expand_path_with(&orig, &cwd, true);
|
||||||
if looks_like_path(&orig) && path.is_dir() && tokens.0.len() == 1 {
|
if looks_like_path(&orig) && path.is_dir() && tokens.0.len() == 1 {
|
||||||
Ok(ReplOperation::AutoCd {
|
Ok(ReplOperation::AutoCd {
|
||||||
cwd,
|
cwd,
|
||||||
|
2
crates/nu-command/src/env/load_env.rs
vendored
2
crates/nu-command/src/env/load_env.rs
vendored
@ -70,7 +70,7 @@ impl Command for LoadEnv {
|
|||||||
if env_var == "PWD" {
|
if env_var == "PWD" {
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let rhs = rhs.coerce_into_string()?;
|
let rhs = rhs.coerce_into_string()?;
|
||||||
let rhs = nu_path::expand_path_with(rhs, cwd);
|
let rhs = nu_path::expand_path_with(rhs, cwd, true);
|
||||||
stack.add_env_var(
|
stack.add_env_var(
|
||||||
env_var,
|
env_var,
|
||||||
Value::string(rhs.to_string_lossy(), call.head),
|
Value::string(rhs.to_string_lossy(), call.head),
|
||||||
|
@ -118,12 +118,14 @@ impl Command for Ls {
|
|||||||
let (path, p_tag, absolute_path, quoted) = match pattern_arg {
|
let (path, p_tag, absolute_path, quoted) = match pattern_arg {
|
||||||
Some(pat) => {
|
Some(pat) => {
|
||||||
let p_tag = pat.span;
|
let p_tag = pat.span;
|
||||||
let p = expand_to_real_path(pat.item.as_ref());
|
let expanded = nu_path::expand_path_with(
|
||||||
|
pat.item.as_ref(),
|
||||||
let expanded = nu_path::expand_path_with(&p, &cwd);
|
&cwd,
|
||||||
|
matches!(pat.item, NuGlob::Expand(..)),
|
||||||
|
);
|
||||||
// Avoid checking and pushing "*" to the path when directory (do not show contents) flag is true
|
// Avoid checking and pushing "*" to the path when directory (do not show contents) flag is true
|
||||||
if !directory && expanded.is_dir() {
|
if !directory && expanded.is_dir() {
|
||||||
if permission_denied(&p) {
|
if permission_denied(&expanded) {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
let error_msg = format!(
|
let error_msg = format!(
|
||||||
"The permissions of {:o} do not allow access for this user",
|
"The permissions of {:o} do not allow access for this user",
|
||||||
@ -151,9 +153,17 @@ impl Command for Ls {
|
|||||||
}
|
}
|
||||||
extra_star_under_given_directory = true;
|
extra_star_under_given_directory = true;
|
||||||
}
|
}
|
||||||
let absolute_path = p.is_absolute();
|
|
||||||
|
// it's absolute path if:
|
||||||
|
// 1. pattern is absolute.
|
||||||
|
// 2. pattern can be expanded, and after expands to real_path, it's absolute.
|
||||||
|
// here `expand_to_real_path` call is required, because `~/aaa` should be absolute
|
||||||
|
// path.
|
||||||
|
let absolute_path = Path::new(pat.item.as_ref()).is_absolute()
|
||||||
|
|| (pat.item.is_expand()
|
||||||
|
&& expand_to_real_path(pat.item.as_ref()).is_absolute());
|
||||||
(
|
(
|
||||||
p,
|
expanded,
|
||||||
p_tag,
|
p_tag,
|
||||||
absolute_path,
|
absolute_path,
|
||||||
matches!(pat.item, NuGlob::DoNotExpand(_)),
|
matches!(pat.item, NuGlob::DoNotExpand(_)),
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
use super::util::get_rest_for_glob_pattern;
|
use super::util::get_rest_for_glob_pattern;
|
||||||
use nu_engine::{current_dir, get_eval_block, CallExt};
|
use nu_engine::{current_dir, get_eval_block, CallExt};
|
||||||
use nu_path::expand_to_real_path;
|
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::util::BufferedReader;
|
use nu_protocol::util::BufferedReader;
|
||||||
@ -153,7 +152,6 @@ impl Command for Open {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let buf_reader = BufReader::new(file);
|
let buf_reader = BufReader::new(file);
|
||||||
let real_path = expand_to_real_path(path);
|
|
||||||
|
|
||||||
let file_contents = PipelineData::ExternalStream {
|
let file_contents = PipelineData::ExternalStream {
|
||||||
stdout: Some(RawStream::new(
|
stdout: Some(RawStream::new(
|
||||||
@ -166,7 +164,7 @@ impl Command for Open {
|
|||||||
exit_code: None,
|
exit_code: None,
|
||||||
span: call_span,
|
span: call_span,
|
||||||
metadata: Some(PipelineMetadata {
|
metadata: Some(PipelineMetadata {
|
||||||
data_source: DataSource::FilePath(real_path),
|
data_source: DataSource::FilePath(path.to_path_buf()),
|
||||||
}),
|
}),
|
||||||
trim_end_newline: false,
|
trim_end_newline: false,
|
||||||
};
|
};
|
||||||
|
@ -157,7 +157,7 @@ fn rm(
|
|||||||
|
|
||||||
for (idx, path) in paths.clone().into_iter().enumerate() {
|
for (idx, path) in paths.clone().into_iter().enumerate() {
|
||||||
if let Some(ref home) = home {
|
if let Some(ref home) = home {
|
||||||
if expand_path_with(path.item.as_ref(), ¤tdir_path)
|
if expand_path_with(path.item.as_ref(), ¤tdir_path, path.item.is_expand())
|
||||||
.to_string_lossy()
|
.to_string_lossy()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
== home.as_str()
|
== home.as_str()
|
||||||
@ -242,7 +242,11 @@ fn rm(
|
|||||||
let mut all_targets: HashMap<PathBuf, Span> = HashMap::new();
|
let mut all_targets: HashMap<PathBuf, Span> = HashMap::new();
|
||||||
|
|
||||||
for target in paths {
|
for target in paths {
|
||||||
let path = expand_path_with(target.item.as_ref(), ¤tdir_path);
|
let path = expand_path_with(
|
||||||
|
target.item.as_ref(),
|
||||||
|
¤tdir_path,
|
||||||
|
target.item.is_expand(),
|
||||||
|
);
|
||||||
if currentdir_path.to_string_lossy() == path.to_string_lossy()
|
if currentdir_path.to_string_lossy() == path.to_string_lossy()
|
||||||
|| currentdir_path.starts_with(format!("{}{}", target.item, std::path::MAIN_SEPARATOR))
|
|| currentdir_path.starts_with(format!("{}{}", target.item, std::path::MAIN_SEPARATOR))
|
||||||
{
|
{
|
||||||
@ -281,7 +285,11 @@ fn rm(
|
|||||||
}
|
}
|
||||||
|
|
||||||
all_targets
|
all_targets
|
||||||
.entry(nu_path::expand_path_with(f, ¤tdir_path))
|
.entry(nu_path::expand_path_with(
|
||||||
|
f,
|
||||||
|
¤tdir_path,
|
||||||
|
target.item.is_expand(),
|
||||||
|
))
|
||||||
.or_insert_with(|| target.span);
|
.or_insert_with(|| target.span);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -92,14 +92,14 @@ impl Command for Save {
|
|||||||
|
|
||||||
let path_arg = call.req::<Spanned<PathBuf>>(engine_state, stack, 0)?;
|
let path_arg = call.req::<Spanned<PathBuf>>(engine_state, stack, 0)?;
|
||||||
let path = Spanned {
|
let path = Spanned {
|
||||||
item: expand_path_with(path_arg.item, &cwd),
|
item: expand_path_with(path_arg.item, &cwd, true),
|
||||||
span: path_arg.span,
|
span: path_arg.span,
|
||||||
};
|
};
|
||||||
|
|
||||||
let stderr_path = call
|
let stderr_path = call
|
||||||
.get_flag::<Spanned<PathBuf>>(engine_state, stack, "stderr")?
|
.get_flag::<Spanned<PathBuf>>(engine_state, stack, "stderr")?
|
||||||
.map(|arg| Spanned {
|
.map(|arg| Spanned {
|
||||||
item: expand_path_with(arg.item, cwd),
|
item: expand_path_with(arg.item, cwd, true),
|
||||||
span: arg.span,
|
span: arg.span,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ impl Command for UCp {
|
|||||||
target.item.to_string(),
|
target.item.to_string(),
|
||||||
));
|
));
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let target_path = nu_path::expand_path_with(target_path, &cwd);
|
let target_path = nu_path::expand_path_with(target_path, &cwd, target.item.is_expand());
|
||||||
if target.item.as_ref().ends_with(PATH_SEPARATOR) && !target_path.is_dir() {
|
if target.item.as_ref().ends_with(PATH_SEPARATOR) && !target_path.is_dir() {
|
||||||
return Err(ShellError::GenericError {
|
return Err(ShellError::GenericError {
|
||||||
error: "is not a directory".into(),
|
error: "is not a directory".into(),
|
||||||
@ -196,7 +196,7 @@ impl Command for UCp {
|
|||||||
|
|
||||||
// paths now contains the sources
|
// paths now contains the sources
|
||||||
|
|
||||||
let mut sources: Vec<PathBuf> = Vec::new();
|
let mut sources: Vec<(Vec<PathBuf>, bool)> = Vec::new();
|
||||||
|
|
||||||
for mut p in paths {
|
for mut p in paths {
|
||||||
p.item = p.item.strip_ansi_string_unlikely();
|
p.item = p.item.strip_ansi_string_unlikely();
|
||||||
@ -230,16 +230,19 @@ impl Command for UCp {
|
|||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sources.append(&mut app_vals);
|
sources.push((app_vals, p.item.is_expand()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to send absolute paths to avoid uu_cp looking for cwd in std::env which is not
|
// Make sure to send absolute paths to avoid uu_cp looking for cwd in std::env which is not
|
||||||
// supported in Nushell
|
// supported in Nushell
|
||||||
for src in sources.iter_mut() {
|
for (sources, need_expand_tilde) in sources.iter_mut() {
|
||||||
if !src.is_absolute() {
|
for src in sources.iter_mut() {
|
||||||
*src = nu_path::expand_path_with(&src, &cwd);
|
if !src.is_absolute() {
|
||||||
|
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let sources: Vec<PathBuf> = sources.into_iter().flat_map(|x| x.0).collect();
|
||||||
|
|
||||||
let attributes = make_attributes(preserve)?;
|
let attributes = make_attributes(preserve)?;
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use nu_engine::env::current_dir;
|
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
use uu_mkdir::mkdir;
|
use uu_mkdir::mkdir;
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -60,11 +60,10 @@ impl Command for UMkdir {
|
|||||||
call: &Call,
|
call: &Call,
|
||||||
_input: PipelineData,
|
_input: PipelineData,
|
||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let cwd = current_dir(engine_state, stack)?;
|
|
||||||
let mut directories = call
|
let mut directories = call
|
||||||
.rest::<String>(engine_state, stack, 0)?
|
.rest::<String>(engine_state, stack, 0)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|dir| nu_path::expand_path_with(dir, &cwd))
|
.map(PathBuf::from)
|
||||||
.peekable();
|
.peekable();
|
||||||
|
|
||||||
let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
|
let is_verbose = call.has_flag(engine_state, stack, "verbose")?;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use super::util::get_rest_for_glob_pattern;
|
use super::util::get_rest_for_glob_pattern;
|
||||||
use nu_engine::current_dir;
|
use nu_engine::current_dir;
|
||||||
use nu_engine::CallExt;
|
use nu_engine::CallExt;
|
||||||
use nu_path::{expand_path_with, expand_to_real_path};
|
use nu_path::expand_path_with;
|
||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{Command, EngineState, Stack};
|
use nu_protocol::engine::{Command, EngineState, Stack};
|
||||||
|
use nu_protocol::NuGlob;
|
||||||
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
use nu_protocol::{Category, Example, PipelineData, ShellError, Signature, SyntaxShape, Type};
|
||||||
use std::ffi::OsString;
|
use std::ffi::OsString;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
@ -98,7 +99,8 @@ impl Command for UMv {
|
|||||||
error: "Missing destination path".into(),
|
error: "Missing destination path".into(),
|
||||||
msg: format!(
|
msg: format!(
|
||||||
"Missing destination path operand after {}",
|
"Missing destination path operand after {}",
|
||||||
expand_path_with(paths[0].item.as_ref(), cwd).to_string_lossy()
|
expand_path_with(paths[0].item.as_ref(), cwd, paths[0].item.is_expand())
|
||||||
|
.to_string_lossy()
|
||||||
),
|
),
|
||||||
span: Some(paths[0].span),
|
span: Some(paths[0].span),
|
||||||
help: None,
|
help: None,
|
||||||
@ -112,7 +114,7 @@ impl Command for UMv {
|
|||||||
label: "Missing file operand".into(),
|
label: "Missing file operand".into(),
|
||||||
span: call.head,
|
span: call.head,
|
||||||
})?;
|
})?;
|
||||||
let mut files: Vec<PathBuf> = Vec::new();
|
let mut files: Vec<(Vec<PathBuf>, bool)> = Vec::new();
|
||||||
for mut p in paths {
|
for mut p in paths {
|
||||||
p.item = p.item.strip_ansi_string_unlikely();
|
p.item = p.item.strip_ansi_string_unlikely();
|
||||||
let exp_files: Vec<Result<PathBuf, ShellError>> =
|
let exp_files: Vec<Result<PathBuf, ShellError>> =
|
||||||
@ -134,22 +136,26 @@ impl Command for UMv {
|
|||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
files.append(&mut app_vals);
|
files.push((app_vals, p.item.is_expand()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure to send absolute paths to avoid uu_cp looking for cwd in std::env which is not
|
// Make sure to send absolute paths to avoid uu_cp looking for cwd in std::env which is not
|
||||||
// supported in Nushell
|
// supported in Nushell
|
||||||
for src in files.iter_mut() {
|
for (files, need_expand_tilde) in files.iter_mut() {
|
||||||
if !src.is_absolute() {
|
for src in files.iter_mut() {
|
||||||
*src = nu_path::expand_path_with(&src, &cwd);
|
if !src.is_absolute() {
|
||||||
|
*src = nu_path::expand_path_with(&src, &cwd, *need_expand_tilde);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut files: Vec<PathBuf> = files.into_iter().flat_map(|x| x.0).collect();
|
||||||
|
|
||||||
// Add back the target after globbing
|
// Add back the target after globbing
|
||||||
let expanded_target = expand_to_real_path(nu_utils::strip_ansi_string_unlikely(
|
let abs_target_path = expand_path_with(
|
||||||
spanned_target.item.to_string(),
|
nu_utils::strip_ansi_string_unlikely(spanned_target.item.to_string()),
|
||||||
));
|
&cwd,
|
||||||
let abs_target_path = expand_path_with(expanded_target, &cwd);
|
matches!(spanned_target.item, NuGlob::Expand(..)),
|
||||||
|
);
|
||||||
files.push(abs_target_path.clone());
|
files.push(abs_target_path.clone());
|
||||||
let files = files
|
let files = files
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
@ -137,7 +137,7 @@ fn exists(path: &Path, span: Span, args: &Arguments) -> Value {
|
|||||||
if path.as_os_str().is_empty() {
|
if path.as_os_str().is_empty() {
|
||||||
return Value::bool(false, span);
|
return Value::bool(false, span);
|
||||||
}
|
}
|
||||||
let path = expand_path_with(path, &args.pwd);
|
let path = expand_path_with(path, &args.pwd, true);
|
||||||
let exists = if args.not_follow_symlink {
|
let exists = if args.not_follow_symlink {
|
||||||
// symlink_metadata returns true if the file/folder exists
|
// symlink_metadata returns true if the file/folder exists
|
||||||
// whether it is a symbolic link or not. Sorry, but returns Err
|
// whether it is a symbolic link or not. Sorry, but returns Err
|
||||||
|
@ -152,7 +152,10 @@ fn expand(path: &Path, span: Span, args: &Arguments) -> Value {
|
|||||||
match canonicalize_with(path, &args.cwd) {
|
match canonicalize_with(path, &args.cwd) {
|
||||||
Ok(p) => {
|
Ok(p) => {
|
||||||
if args.not_follow_symlink {
|
if args.not_follow_symlink {
|
||||||
Value::string(expand_path_with(path, &args.cwd).to_string_lossy(), span)
|
Value::string(
|
||||||
|
expand_path_with(path, &args.cwd, true).to_string_lossy(),
|
||||||
|
span,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
Value::string(p.to_string_lossy(), span)
|
Value::string(p.to_string_lossy(), span)
|
||||||
}
|
}
|
||||||
@ -171,12 +174,18 @@ fn expand(path: &Path, span: Span, args: &Arguments) -> Value {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
} else if args.not_follow_symlink {
|
} else if args.not_follow_symlink {
|
||||||
Value::string(expand_path_with(path, &args.cwd).to_string_lossy(), span)
|
Value::string(
|
||||||
|
expand_path_with(path, &args.cwd, true).to_string_lossy(),
|
||||||
|
span,
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
canonicalize_with(path, &args.cwd)
|
canonicalize_with(path, &args.cwd)
|
||||||
.map(|p| Value::string(p.to_string_lossy(), span))
|
.map(|p| Value::string(p.to_string_lossy(), span))
|
||||||
.unwrap_or_else(|_| {
|
.unwrap_or_else(|_| {
|
||||||
Value::string(expand_path_with(path, &args.cwd).to_string_lossy(), span)
|
Value::string(
|
||||||
|
expand_path_with(path, &args.cwd, true).to_string_lossy(),
|
||||||
|
span,
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -711,3 +711,25 @@ fn list_empty_string() {
|
|||||||
assert!(actual.err.contains("does not exist"));
|
assert!(actual.err.contains("does not exist"));
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn list_with_tilde() {
|
||||||
|
Playground::setup("ls_tilde", |dirs, sandbox| {
|
||||||
|
sandbox
|
||||||
|
.within("~tilde")
|
||||||
|
.with_files(vec![EmptyFile("f1.txt"), EmptyFile("f2.txt")]);
|
||||||
|
|
||||||
|
let actual = nu!(cwd: dirs.test(), "ls '~tilde'");
|
||||||
|
assert!(actual.out.contains("f1.txt"));
|
||||||
|
assert!(actual.out.contains("f2.txt"));
|
||||||
|
assert!(actual.out.contains("~tilde"));
|
||||||
|
let actual = nu!(cwd: dirs.test(), "ls ~tilde");
|
||||||
|
assert!(actual.err.contains("does not exist"));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde'; ls $f");
|
||||||
|
assert!(actual.out.contains("f1.txt"));
|
||||||
|
assert!(actual.out.contains("f2.txt"));
|
||||||
|
assert!(actual.out.contains("~tilde"));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -2,6 +2,7 @@ use nu_test_support::fs::{files_exist_at, Stub::EmptyFile, Stub::FileWithContent
|
|||||||
use nu_test_support::nu;
|
use nu_test_support::nu;
|
||||||
use nu_test_support::playground::Playground;
|
use nu_test_support::playground::Playground;
|
||||||
use rstest::rstest;
|
use rstest::rstest;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn moves_a_file() {
|
fn moves_a_file() {
|
||||||
@ -656,3 +657,33 @@ fn test_cp_inside_glob_metachars_dir() {
|
|||||||
assert!(files_exist_at(vec!["test_file.txt"], dirs.test()));
|
assert!(files_exist_at(vec!["test_file.txt"], dirs.test()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mv_with_tilde() {
|
||||||
|
Playground::setup("mv_tilde", |dirs, sandbox| {
|
||||||
|
sandbox.within("~tilde").with_files(vec![
|
||||||
|
EmptyFile("f1.txt"),
|
||||||
|
EmptyFile("f2.txt"),
|
||||||
|
EmptyFile("f3.txt"),
|
||||||
|
]);
|
||||||
|
sandbox.within("~tilde2");
|
||||||
|
|
||||||
|
// mv file
|
||||||
|
let actual = nu!(cwd: dirs.test(), "mv '~tilde/f1.txt' ./");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(!files_exist_at(
|
||||||
|
vec![Path::new("f1.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
assert!(files_exist_at(vec![Path::new("f1.txt")], dirs.test()));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde/f2.txt'; mv $f ./");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(!files_exist_at(
|
||||||
|
vec![Path::new("f2.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
assert!(files_exist_at(vec![Path::new("f1.txt")], dirs.test()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -538,3 +538,34 @@ fn force_rm_suppress_error() {
|
|||||||
assert!(actual.err.is_empty());
|
assert!(actual.err.is_empty());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rm_with_tilde() {
|
||||||
|
Playground::setup("rm_tilde", |dirs, sandbox| {
|
||||||
|
sandbox.within("~tilde").with_files(vec![
|
||||||
|
EmptyFile("f1.txt"),
|
||||||
|
EmptyFile("f2.txt"),
|
||||||
|
EmptyFile("f3.txt"),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let actual = nu!(cwd: dirs.test(), "rm '~tilde/f1.txt'");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(!files_exist_at(
|
||||||
|
vec![Path::new("f1.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde/f2.txt'; rm $f");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(!files_exist_at(
|
||||||
|
vec![Path::new("f2.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
|
||||||
|
// remove directory
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde'; rm -r $f");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(!files_exist_at(vec![Path::new("~tilde")], dirs.test()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use chrono::{DateTime, Local};
|
use chrono::{DateTime, Local};
|
||||||
use nu_test_support::fs::Stub;
|
use nu_test_support::fs::{files_exist_at, Stub};
|
||||||
use nu_test_support::nu;
|
use nu_test_support::nu;
|
||||||
use nu_test_support::playground::Playground;
|
use nu_test_support::playground::Playground;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
// Use 1 instead of 0 because 0 has a special meaning in Windows
|
// Use 1 instead of 0 because 0 has a special meaning in Windows
|
||||||
const TIME_ONE: filetime::FileTime = filetime::FileTime::from_unix_time(1, 0);
|
const TIME_ONE: filetime::FileTime = filetime::FileTime::from_unix_time(1, 0);
|
||||||
@ -487,3 +488,17 @@ fn change_dir_atime_to_reference() {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_a_file_with_tilde() {
|
||||||
|
Playground::setup("touch with tilde", |dirs, _| {
|
||||||
|
let actual = nu!(cwd: dirs.test(), "touch '~tilde'");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(vec![Path::new("~tilde")], dirs.test()));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde2'; touch $f");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(vec![Path::new("~tilde2")], dirs.test()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -1174,6 +1174,42 @@ fn test_cp_to_customized_home_directory() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn cp_with_tilde() {
|
||||||
|
Playground::setup("cp_tilde", |dirs, sandbox| {
|
||||||
|
sandbox.within("~tilde").with_files(vec![
|
||||||
|
EmptyFile("f1.txt"),
|
||||||
|
EmptyFile("f2.txt"),
|
||||||
|
EmptyFile("f3.txt"),
|
||||||
|
]);
|
||||||
|
sandbox.within("~tilde2");
|
||||||
|
// cp directory
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: dirs.test(),
|
||||||
|
"let f = '~tilde'; cp -r $f '~tilde2'; ls '~tilde2/~tilde' | length"
|
||||||
|
);
|
||||||
|
assert_eq!(actual.out, "3");
|
||||||
|
|
||||||
|
// cp file
|
||||||
|
let actual = nu!(cwd: dirs.test(), "cp '~tilde/f1.txt' ./");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(
|
||||||
|
vec![Path::new("f1.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
assert!(files_exist_at(vec![Path::new("f1.txt")], dirs.test()));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde/f2.txt'; cp $f ./");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(
|
||||||
|
vec![Path::new("f2.txt")],
|
||||||
|
dirs.test().join("~tilde")
|
||||||
|
));
|
||||||
|
assert!(files_exist_at(vec![Path::new("f1.txt")], dirs.test()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy_file_with_update_flag() {
|
fn copy_file_with_update_flag() {
|
||||||
copy_file_with_update_flag_impl(false);
|
copy_file_with_update_flag_impl(false);
|
||||||
|
@ -145,3 +145,17 @@ fn mkdir_umask_permission() {
|
|||||||
);
|
);
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn mkdir_with_tilde() {
|
||||||
|
Playground::setup("mkdir with tilde", |dirs, _| {
|
||||||
|
let actual = nu!(cwd: dirs.test(), "mkdir '~tilde'");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(vec![Path::new("~tilde")], dirs.test()));
|
||||||
|
|
||||||
|
// pass variable
|
||||||
|
let actual = nu!(cwd: dirs.test(), "let f = '~tilde2'; mkdir $f");
|
||||||
|
assert!(actual.err.is_empty());
|
||||||
|
assert!(files_exist_at(vec![Path::new("~tilde2")], dirs.test()));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
@ -328,7 +328,7 @@ fn eval_redirection<D: DebugContext>(
|
|||||||
let cwd = current_dir(engine_state, stack)?;
|
let cwd = current_dir(engine_state, stack)?;
|
||||||
let value = eval_expression::<D>(engine_state, stack, expr)?;
|
let value = eval_expression::<D>(engine_state, stack, expr)?;
|
||||||
let path = Spanned::<PathBuf>::from_value(value)?.item;
|
let path = Spanned::<PathBuf>::from_value(value)?.item;
|
||||||
let path = expand_path_with(path, cwd);
|
let path = expand_path_with(path, cwd, true);
|
||||||
|
|
||||||
let mut options = OpenOptions::new();
|
let mut options = OpenOptions::new();
|
||||||
if *append {
|
if *append {
|
||||||
@ -634,7 +634,7 @@ impl Eval for EvalRuntime {
|
|||||||
Ok(Value::string(path, span))
|
Ok(Value::string(path, span))
|
||||||
} else {
|
} else {
|
||||||
let cwd = current_dir_str(engine_state, stack)?;
|
let cwd = current_dir_str(engine_state, stack)?;
|
||||||
let path = expand_path_with(path, cwd);
|
let path = expand_path_with(path, cwd, true);
|
||||||
|
|
||||||
Ok(Value::string(path.to_string_lossy(), span))
|
Ok(Value::string(path.to_string_lossy(), span))
|
||||||
}
|
}
|
||||||
@ -653,7 +653,7 @@ impl Eval for EvalRuntime {
|
|||||||
Ok(Value::string(path, span))
|
Ok(Value::string(path, span))
|
||||||
} else {
|
} else {
|
||||||
let cwd = current_dir_str(engine_state, stack)?;
|
let cwd = current_dir_str(engine_state, stack)?;
|
||||||
let path = expand_path_with(path, cwd);
|
let path = expand_path_with(path, cwd, true);
|
||||||
|
|
||||||
Ok(Value::string(path.to_string_lossy(), span))
|
Ok(Value::string(path.to_string_lossy(), span))
|
||||||
}
|
}
|
||||||
|
@ -58,13 +58,13 @@ pub fn glob_from(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now expand `p` to get full prefix
|
// Now expand `p` to get full prefix
|
||||||
let path = expand_path_with(p, cwd);
|
let path = expand_path_with(p, cwd, pattern.item.is_expand());
|
||||||
let escaped_prefix = PathBuf::from(nu_glob::Pattern::escape(&path.to_string_lossy()));
|
let escaped_prefix = PathBuf::from(nu_glob::Pattern::escape(&path.to_string_lossy()));
|
||||||
|
|
||||||
(Some(path), escaped_prefix.join(just_pattern))
|
(Some(path), escaped_prefix.join(just_pattern))
|
||||||
} else {
|
} else {
|
||||||
let path = PathBuf::from(&pattern.item.as_ref());
|
let path = PathBuf::from(&pattern.item.as_ref());
|
||||||
let path = expand_path_with(path, cwd);
|
let path = expand_path_with(path, cwd, pattern.item.is_expand());
|
||||||
let is_symlink = match fs::symlink_metadata(&path) {
|
let is_symlink = match fs::symlink_metadata(&path) {
|
||||||
Ok(attr) => attr.file_type().is_symlink(),
|
Ok(attr) => attr.file_type().is_symlink(),
|
||||||
Err(_) => false,
|
Err(_) => false,
|
||||||
|
@ -6,7 +6,7 @@ use super::helpers;
|
|||||||
use super::tilde::expand_tilde;
|
use super::tilde::expand_tilde;
|
||||||
|
|
||||||
// Join a path relative to another path. Paths starting with tilde are considered as absolute.
|
// Join a path relative to another path. Paths starting with tilde are considered as absolute.
|
||||||
fn join_path_relative<P, Q>(path: P, relative_to: Q) -> PathBuf
|
fn join_path_relative<P, Q>(path: P, relative_to: Q, expand_tilde: bool) -> PathBuf
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
Q: AsRef<Path>,
|
Q: AsRef<Path>,
|
||||||
@ -19,7 +19,7 @@ where
|
|||||||
// more ugly - so we don't do anything, which should result in an equal
|
// more ugly - so we don't do anything, which should result in an equal
|
||||||
// path on all supported systems.
|
// path on all supported systems.
|
||||||
relative_to.into()
|
relative_to.into()
|
||||||
} else if path.to_string_lossy().as_ref().starts_with('~') {
|
} else if path.to_string_lossy().as_ref().starts_with('~') && expand_tilde {
|
||||||
// do not end up with "/some/path/~" or "/some/path/~user"
|
// do not end up with "/some/path/~" or "/some/path/~user"
|
||||||
path.into()
|
path.into()
|
||||||
} else {
|
} else {
|
||||||
@ -45,13 +45,18 @@ where
|
|||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
Q: AsRef<Path>,
|
Q: AsRef<Path>,
|
||||||
{
|
{
|
||||||
let path = join_path_relative(path, relative_to);
|
let path = join_path_relative(path, relative_to, true);
|
||||||
|
|
||||||
canonicalize(path)
|
canonicalize(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expand_path(path: impl AsRef<Path>) -> PathBuf {
|
fn expand_path(path: impl AsRef<Path>, need_expand_tilde: bool) -> PathBuf {
|
||||||
let path = expand_to_real_path(path);
|
let path = if need_expand_tilde {
|
||||||
|
expand_tilde(path)
|
||||||
|
} else {
|
||||||
|
PathBuf::from(path.as_ref())
|
||||||
|
};
|
||||||
|
let path = expand_ndots(path);
|
||||||
expand_dots(path)
|
expand_dots(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,14 +69,14 @@ fn expand_path(path: impl AsRef<Path>) -> PathBuf {
|
|||||||
///
|
///
|
||||||
/// Does not convert to absolute form nor does it resolve symlinks.
|
/// Does not convert to absolute form nor does it resolve symlinks.
|
||||||
/// The input path is specified relative to another path
|
/// The input path is specified relative to another path
|
||||||
pub fn expand_path_with<P, Q>(path: P, relative_to: Q) -> PathBuf
|
pub fn expand_path_with<P, Q>(path: P, relative_to: Q, expand_tilde: bool) -> PathBuf
|
||||||
where
|
where
|
||||||
P: AsRef<Path>,
|
P: AsRef<Path>,
|
||||||
Q: AsRef<Path>,
|
Q: AsRef<Path>,
|
||||||
{
|
{
|
||||||
let path = join_path_relative(path, relative_to);
|
let path = join_path_relative(path, relative_to, expand_tilde);
|
||||||
|
|
||||||
expand_path(path)
|
expand_path(path, expand_tilde)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve to a path that is accepted by the system and no further - tilde is expanded, and ndot path components are expanded.
|
/// Resolve to a path that is accepted by the system and no further - tilde is expanded, and ndot path components are expanded.
|
||||||
|
@ -20,6 +20,10 @@ impl NuGlob {
|
|||||||
NuGlob::Expand(s) => NuGlob::Expand(nu_utils::strip_ansi_string_unlikely(s)),
|
NuGlob::Expand(s) => NuGlob::Expand(nu_utils::strip_ansi_string_unlikely(s)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_expand(&self) -> bool {
|
||||||
|
matches!(self, NuGlob::Expand(..))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<str> for NuGlob {
|
impl AsRef<str> for NuGlob {
|
||||||
|
@ -12,8 +12,8 @@ fn expand_path_with_and_without_relative() {
|
|||||||
|
|
||||||
let cwd = std::env::current_dir().expect("Could not get current directory");
|
let cwd = std::env::current_dir().expect("Could not get current directory");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
expand_path_with(full_path, cwd),
|
expand_path_with(full_path, cwd, true),
|
||||||
expand_path_with(path, relative_to),
|
expand_path_with(path, relative_to, true),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,7 +22,10 @@ fn expand_path_with_relative() {
|
|||||||
let relative_to = "/foo/bar";
|
let relative_to = "/foo/bar";
|
||||||
let path = "../..";
|
let path = "../..";
|
||||||
|
|
||||||
assert_eq!(PathBuf::from("/"), expand_path_with(path, relative_to),);
|
assert_eq!(
|
||||||
|
PathBuf::from("/"),
|
||||||
|
expand_path_with(path, relative_to, true),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
@ -31,7 +34,7 @@ fn expand_path_no_change() {
|
|||||||
let path = "/foo/bar";
|
let path = "/foo/bar";
|
||||||
|
|
||||||
let cwd = std::env::current_dir().expect("Could not get current directory");
|
let cwd = std::env::current_dir().expect("Could not get current directory");
|
||||||
let actual = expand_path_with(path, cwd);
|
let actual = expand_path_with(path, cwd, true);
|
||||||
|
|
||||||
assert_eq!(actual, PathBuf::from(path));
|
assert_eq!(actual, PathBuf::from(path));
|
||||||
}
|
}
|
||||||
@ -43,7 +46,7 @@ fn expand_unicode_path_no_change() {
|
|||||||
spam.push("🚒.txt");
|
spam.push("🚒.txt");
|
||||||
|
|
||||||
let cwd = std::env::current_dir().expect("Could not get current directory");
|
let cwd = std::env::current_dir().expect("Could not get current directory");
|
||||||
let actual = expand_path_with(spam, cwd);
|
let actual = expand_path_with(spam, cwd, true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("🚒.txt");
|
expected.push("🚒.txt");
|
||||||
|
|
||||||
@ -60,7 +63,7 @@ fn expand_non_utf8_path() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_relative_to() {
|
fn expand_path_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("spam.txt", dirs.test());
|
let actual = expand_path_with("spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -74,7 +77,7 @@ fn expand_unicode_path_relative_to_unicode_path_with_spaces() {
|
|||||||
let mut relative_to = dirs.test().to_owned();
|
let mut relative_to = dirs.test().to_owned();
|
||||||
relative_to.push("e-$ èрт🚒♞中片-j");
|
relative_to.push("e-$ èрт🚒♞中片-j");
|
||||||
|
|
||||||
let actual = expand_path_with("🚒.txt", relative_to);
|
let actual = expand_path_with("🚒.txt", relative_to, true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("e-$ èрт🚒♞中片-j/🚒.txt");
|
expected.push("e-$ èрт🚒♞中片-j/🚒.txt");
|
||||||
|
|
||||||
@ -94,7 +97,7 @@ fn expand_absolute_path_relative_to() {
|
|||||||
let mut absolute_path = dirs.test().to_owned();
|
let mut absolute_path = dirs.test().to_owned();
|
||||||
absolute_path.push("spam.txt");
|
absolute_path.push("spam.txt");
|
||||||
|
|
||||||
let actual = expand_path_with(&absolute_path, "non/existent/directory");
|
let actual = expand_path_with(&absolute_path, "non/existent/directory", true);
|
||||||
let expected = absolute_path;
|
let expected = absolute_path;
|
||||||
|
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
@ -104,7 +107,7 @@ fn expand_absolute_path_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_dot_relative_to() {
|
fn expand_path_with_dot_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("./spam.txt", dirs.test());
|
let actual = expand_path_with("./spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -115,7 +118,7 @@ fn expand_path_with_dot_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_many_dots_relative_to() {
|
fn expand_path_with_many_dots_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("././/.//////./././//.////spam.txt", dirs.test());
|
let actual = expand_path_with("././/.//////./././//.////spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -126,7 +129,7 @@ fn expand_path_with_many_dots_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_double_dot_relative_to() {
|
fn expand_path_with_double_dot_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("foo/../spam.txt", dirs.test());
|
let actual = expand_path_with("foo/../spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -137,7 +140,7 @@ fn expand_path_with_double_dot_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_many_double_dots_relative_to() {
|
fn expand_path_with_many_double_dots_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("foo/bar/baz/../../../spam.txt", dirs.test());
|
let actual = expand_path_with("foo/bar/baz/../../../spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -148,7 +151,7 @@ fn expand_path_with_many_double_dots_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_3_ndots_relative_to() {
|
fn expand_path_with_3_ndots_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("foo/bar/.../spam.txt", dirs.test());
|
let actual = expand_path_with("foo/bar/.../spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -162,6 +165,7 @@ fn expand_path_with_many_3_ndots_relative_to() {
|
|||||||
let actual = expand_path_with(
|
let actual = expand_path_with(
|
||||||
"foo/bar/baz/eggs/sausage/bacon/.../.../.../spam.txt",
|
"foo/bar/baz/eggs/sausage/bacon/.../.../.../spam.txt",
|
||||||
dirs.test(),
|
dirs.test(),
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
@ -173,7 +177,7 @@ fn expand_path_with_many_3_ndots_relative_to() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn expand_path_with_4_ndots_relative_to() {
|
fn expand_path_with_4_ndots_relative_to() {
|
||||||
Playground::setup("nu_path_test_1", |dirs, _| {
|
Playground::setup("nu_path_test_1", |dirs, _| {
|
||||||
let actual = expand_path_with("foo/bar/baz/..../spam.txt", dirs.test());
|
let actual = expand_path_with("foo/bar/baz/..../spam.txt", dirs.test(), true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -187,6 +191,7 @@ fn expand_path_with_many_4_ndots_relative_to() {
|
|||||||
let actual = expand_path_with(
|
let actual = expand_path_with(
|
||||||
"foo/bar/baz/eggs/sausage/bacon/..../..../spam.txt",
|
"foo/bar/baz/eggs/sausage/bacon/..../..../spam.txt",
|
||||||
dirs.test(),
|
dirs.test(),
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
@ -201,7 +206,11 @@ fn expand_path_with_way_too_many_dots_relative_to() {
|
|||||||
let mut relative_to = dirs.test().to_owned();
|
let mut relative_to = dirs.test().to_owned();
|
||||||
relative_to.push("foo/bar/baz/eggs/sausage/bacon/vikings");
|
relative_to.push("foo/bar/baz/eggs/sausage/bacon/vikings");
|
||||||
|
|
||||||
let actual = expand_path_with("././..////././...///././.....///spam.txt", relative_to);
|
let actual = expand_path_with(
|
||||||
|
"././..////././...///././.....///spam.txt",
|
||||||
|
relative_to,
|
||||||
|
true,
|
||||||
|
);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("spam.txt");
|
expected.push("spam.txt");
|
||||||
|
|
||||||
@ -215,7 +224,7 @@ fn expand_unicode_path_with_way_too_many_dots_relative_to_unicode_path_with_spac
|
|||||||
let mut relative_to = dirs.test().to_owned();
|
let mut relative_to = dirs.test().to_owned();
|
||||||
relative_to.push("foo/áčěéí +šř=é/baz/eggs/e-$ èрт🚒♞中片-j/bacon/öäöä öäöä");
|
relative_to.push("foo/áčěéí +šř=é/baz/eggs/e-$ èрт🚒♞中片-j/bacon/öäöä öäöä");
|
||||||
|
|
||||||
let actual = expand_path_with("././..////././...///././.....///🚒.txt", relative_to);
|
let actual = expand_path_with("././..////././...///././.....///🚒.txt", relative_to, true);
|
||||||
let mut expected = dirs.test().to_owned();
|
let mut expected = dirs.test().to_owned();
|
||||||
expected.push("🚒.txt");
|
expected.push("🚒.txt");
|
||||||
|
|
||||||
@ -228,7 +237,7 @@ fn expand_path_tilde() {
|
|||||||
let tilde_path = "~";
|
let tilde_path = "~";
|
||||||
|
|
||||||
let cwd = std::env::current_dir().expect("Could not get current directory");
|
let cwd = std::env::current_dir().expect("Could not get current directory");
|
||||||
let actual = expand_path_with(tilde_path, cwd);
|
let actual = expand_path_with(tilde_path, cwd, true);
|
||||||
|
|
||||||
assert!(actual.is_absolute());
|
assert!(actual.is_absolute());
|
||||||
assert!(!actual.starts_with("~"));
|
assert!(!actual.starts_with("~"));
|
||||||
@ -238,7 +247,7 @@ fn expand_path_tilde() {
|
|||||||
fn expand_path_tilde_relative_to() {
|
fn expand_path_tilde_relative_to() {
|
||||||
let tilde_path = "~";
|
let tilde_path = "~";
|
||||||
|
|
||||||
let actual = expand_path_with(tilde_path, "non/existent/path");
|
let actual = expand_path_with(tilde_path, "non/existent/path", true);
|
||||||
|
|
||||||
assert!(actual.is_absolute());
|
assert!(actual.is_absolute());
|
||||||
assert!(!actual.starts_with("~"));
|
assert!(!actual.starts_with("~"));
|
||||||
|
Loading…
Reference in New Issue
Block a user