Unify glob behavior on open, rm, cp-old, mv, umv, cp and du commands (#11621)

# Description
This pr is a follow up to
[#11569](https://github.com/nushell/nushell/pull/11569#issuecomment-1902279587)
> Revert the logic in https://github.com/nushell/nushell/pull/10694 and
apply the logic in this pr to mv, cp, rv will require a larger change, I
need to think how to achieve the bahavior

And sorry @bobhy for reverting some of your changes.

This pr is going to unify glob behavior on the given commands:
* open
* rm
* cp-old
* mv
* umv
* cp
* du

So they have the same behavior to `ls`, which is:
If given parameter is quoted by single quote(`'`) or double quote(`"`),
don't auto-expand the glob pattern. If not quoted, auto-expand the glob
pattern.

Fixes: #9558  Fixes: #10211 Fixes: #9310 Fixes: #10364 

# TODO
But there is one thing remains: if we give a variable to the command, it
will always auto-expand the glob pattern, e.g:
```nushell
let path = "a[123]b"
rm $path
```
I don't think it's expected. But I also think user might want to
auto-expand the glob pattern in variables.

So I'll introduce a new command called `glob escape`, then if user
doesn't want to auto-expand the glob pattern, he can just do this: `rm
($path | glob escape)`

# User-Facing Changes
<!-- List of all changes that impact the user experience here. This
helps us keep track of breaking changes. -->

# Tests + Formatting
Done

# After Submitting
<!-- If your PR had any user-facing changes, update [the
documentation](https://github.com/nushell/nushell.github.io) after the
PR is merged, if necessary. This will help us keep the docs up to date.
-->

## NOTE
This pr changes the semantic of `GlobPattern`, before this pr, it will
`expand path` after evaluated, this makes `nu_engine::glob_from` have no
chance to glob things right if a path contains glob pattern.

e.g: [#9310
](https://github.com/nushell/nushell/issues/9310#issuecomment-1886824030)
#10211

I think changing the semantic is fine, because it makes glob works if
path contains something like '*'.

It maybe a breaking change if a custom command's argument are annotated
by `: glob`.
This commit is contained in:
WindSoilder
2024-01-26 21:57:35 +08:00
committed by GitHub
parent e43d893ea3
commit d646903161
28 changed files with 318 additions and 431 deletions

View File

@ -1,12 +1,11 @@
use crate::{DirBuilder, DirInfo, FileInfo};
use nu_cmd_base::arg_glob;
use nu_engine::{current_dir, CallExt};
use nu_glob::{GlobError, Pattern};
use nu_glob::Pattern;
use nu_protocol::{
ast::Call,
engine::{Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
Spanned, SyntaxShape, Type, Value,
Category, Example, IntoInterruptiblePipelineData, NuPath, PipelineData, ShellError, Signature,
Span, Spanned, SyntaxShape, Type, Value,
};
use serde::Deserialize;
@ -15,7 +14,7 @@ pub struct Du;
#[derive(Deserialize, Clone, Debug)]
pub struct DuArgs {
path: Option<Spanned<String>>,
path: Option<Spanned<NuPath>>,
all: bool,
deref: bool,
exclude: Option<Spanned<String>>,
@ -116,28 +115,26 @@ impl Command for Du {
let include_files = args.all;
let mut paths = match args.path {
Some(p) => arg_glob(&p, &current_dir)?,
Some(p) => nu_engine::glob_from(&p, &current_dir, call.head, None),
// The * pattern should never fail.
None => arg_glob(
None => nu_engine::glob_from(
&Spanned {
item: "*".into(),
item: NuPath::UnQuoted("*".into()),
span: Span::unknown(),
},
&current_dir,
)?,
call.head,
None,
),
}
.map(|f| f.1)?
.filter(move |p| {
if include_files {
true
} else {
match p {
Ok(f) if f.is_dir() => true,
Err(e) if e.path().is_dir() => true,
_ => false,
}
matches!(p, Ok(f) if f.is_dir())
}
})
.map(|v| v.map_err(glob_err_into));
});
let all = args.all;
let deref = args.deref;
@ -182,11 +179,6 @@ impl Command for Du {
}
}
fn glob_err_into(e: GlobError) -> ShellError {
let e = e.into_error();
ShellError::from(e)
}
#[cfg(test)]
mod tests {
use super::Du;