Resolve issues with rm * globbing (#3516)

Using the `*` wildcard should not attempt to delete files with a leading dot
unless the more explicit `.*` is used. `rm *` should also not attempt to delete
the current directory or its parent directory (`.` and `..`). I have resolved
this bug as well in a less satisfactory way. I think it may be the case that we
can only disambiguate the `.` and `..` path segments by using `Path::display`.
Here is a short list of alternatives that I tried:

- `Path::ends_with()` can detect `/..` but not `/.`.
- `Path::iter()` and `Path::components()` leave out `/.`.
- `Path::file_name()` normalizes `/.` to the parent component's file name.

Fixes #3508
This commit is contained in:
Lily Mara 2021-05-29 20:36:36 -07:00 committed by GitHub
parent 6fdfc84904
commit 4b11b283ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 45 additions and 1 deletions

View File

@ -276,3 +276,33 @@ fn no_errors_if_attempting_to_delete_non_existent_file_with_f_flag() {
assert!(!actual.err.contains("no valid path"));
})
}
#[test]
fn rm_wildcard_keeps_dotfiles() {
Playground::setup("rm_test_15", |dirs, sandbox| {
sandbox.with_files(vec![EmptyFile("foo"), EmptyFile(".bar")]);
nu!(
cwd: dirs.test(),
r#"rm *"#
);
assert!(!files_exist_at(vec!["foo"], dirs.test()));
assert!(files_exist_at(vec![".bar"], dirs.test()));
})
}
#[test]
fn rm_wildcard_leading_dot_deletes_dotfiles() {
Playground::setup("rm_test_16", |dirs, sandbox| {
sandbox.with_files(vec![EmptyFile("foo"), EmptyFile(".bar")]);
nu!(
cwd: dirs.test(),
r#"rm .*"#
);
assert!(files_exist_at(vec!["foo"], dirs.test()));
assert!(!files_exist_at(vec![".bar"], dirs.test()));
})
}

View File

@ -643,11 +643,25 @@ impl Shell for FilesystemShell {
}
let path = path.join(&target.item);
match glob::glob(&path.to_string_lossy()) {
match glob::glob_with(
&path.to_string_lossy(),
glob::MatchOptions {
require_literal_leading_dot: true,
..Default::default()
},
) {
Ok(files) => {
for file in files {
match file {
Ok(ref f) => {
// It is not appropriate to try and remove the
// current directory or its parent when using
// glob patterns.
let name = format!("{}", f.display());
if name.ends_with("/.") || name.ends_with("/..") {
continue;
}
all_targets
.entry(f.clone())
.or_insert_with(|| target.tag.clone());