2019-12-17 19:54:39 +01:00
|
|
|
use nu_test_support::fs::Stub::EmptyFile;
|
2021-03-15 08:26:30 +01:00
|
|
|
use nu_test_support::playground::Playground;
|
2020-05-07 13:03:43 +02:00
|
|
|
use nu_test_support::{nu, pipeline};
|
2019-08-02 11:23:39 +02:00
|
|
|
|
|
|
|
#[test]
|
2019-12-15 17:15:06 +01:00
|
|
|
fn lists_regular_files() {
|
2019-08-29 02:32:42 +02:00
|
|
|
Playground::setup("ls_test_1", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2019-10-15 12:16:47 +02:00
|
|
|
EmptyFile("yehuda.txt"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jttxt"),
|
2019-10-15 12:16:47 +02:00
|
|
|
EmptyFile("andres.txt"),
|
2019-08-29 02:32:42 +02:00
|
|
|
]);
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2019-08-29 02:32:42 +02:00
|
|
|
let actual = nu!(
|
2019-12-15 17:15:06 +01:00
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-09-03 02:49:51 +02:00
|
|
|
ls
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-08-29 02:32:42 +02:00
|
|
|
));
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "3");
|
2019-08-28 19:01:16 +02:00
|
|
|
})
|
2019-08-02 11:23:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2019-12-15 17:15:06 +01:00
|
|
|
fn lists_regular_files_using_asterisk_wildcard() {
|
2019-08-29 02:32:42 +02:00
|
|
|
Playground::setup("ls_test_2", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2019-10-15 12:16:47 +02:00
|
|
|
EmptyFile("los.txt"),
|
|
|
|
EmptyFile("tres.txt"),
|
|
|
|
EmptyFile("amigos.txt"),
|
|
|
|
EmptyFile("arepas.clu"),
|
2019-08-29 02:32:42 +02:00
|
|
|
]);
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2019-08-29 02:32:42 +02:00
|
|
|
let actual = nu!(
|
2019-12-15 17:15:06 +01:00
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-09-03 02:49:51 +02:00
|
|
|
ls *.txt
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-08-29 02:32:42 +02:00
|
|
|
));
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "3");
|
2019-08-28 19:01:16 +02:00
|
|
|
})
|
2019-08-02 11:23:39 +02:00
|
|
|
}
|
|
|
|
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
#[cfg(not(target_os = "windows"))]
|
|
|
|
#[test]
|
|
|
|
fn lists_regular_files_in_special_folder() {
|
|
|
|
Playground::setup("ls_test_3", |dirs, sandbox| {
|
|
|
|
sandbox
|
|
|
|
.mkdir("[abcd]")
|
|
|
|
.mkdir("[bbcd]")
|
|
|
|
.mkdir("abcd]")
|
|
|
|
.mkdir("abcd")
|
|
|
|
.mkdir("abcd/*")
|
|
|
|
.mkdir("abcd/?")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("[abcd]/test.txt")])
|
|
|
|
.with_files(&[EmptyFile("abcd]/test.txt")])
|
|
|
|
.with_files(&[EmptyFile("abcd/*/test.txt")])
|
|
|
|
.with_files(&[EmptyFile("abcd/?/test.txt")])
|
|
|
|
.with_files(&[EmptyFile("abcd/?/test2.txt")]);
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd]"), format!(r#"ls | length"#));
|
|
|
|
assert_eq!(actual.out, "1");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), format!(r#"ls abcd] | length"#));
|
|
|
|
assert_eq!(actual.out, "1");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("[abcd]"), format!(r#"ls | length"#));
|
|
|
|
assert_eq!(actual.out, "1");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("[bbcd]"), format!(r#"ls | length"#));
|
|
|
|
assert_eq!(actual.out, "0");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/*"), format!(r#"ls | length"#));
|
|
|
|
assert_eq!(actual.out, "1");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/?"), format!(r#"ls | length"#));
|
|
|
|
assert_eq!(actual.out, "2");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/*"), format!(r#"ls -D ../* | length"#));
|
|
|
|
assert_eq!(actual.out, "2");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/*"), format!(r#"ls ../* | length"#));
|
2024-05-06 08:01:32 +02:00
|
|
|
assert_eq!(actual.out, "2");
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/?"), format!(r#"ls -D ../* | length"#));
|
|
|
|
assert_eq!(actual.out, "2");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("abcd/?"), format!(r#"ls ../* | length"#));
|
2024-05-06 08:01:32 +02:00
|
|
|
assert_eq!(actual.out, "2");
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[rstest::rstest]
|
|
|
|
#[case("j?.??.txt", 1)]
|
|
|
|
#[case("j????.txt", 2)]
|
|
|
|
#[case("?????.txt", 3)]
|
|
|
|
#[case("????c.txt", 1)]
|
|
|
|
#[case("ye??da.10.txt", 1)]
|
|
|
|
#[case("yehuda.?0.txt", 1)]
|
|
|
|
#[case("??????.10.txt", 2)]
|
|
|
|
#[case("[abcd]????.txt", 1)]
|
|
|
|
#[case("??[ac.]??.txt", 3)]
|
|
|
|
#[case("[ab]bcd/??.txt", 2)]
|
|
|
|
#[case("?bcd/[xy]y.txt", 2)]
|
|
|
|
#[case("?bcd/[xy]y.t?t", 2)]
|
|
|
|
#[case("[[]abcd[]].txt", 1)]
|
|
|
|
#[case("[[]?bcd[]].txt", 2)]
|
|
|
|
#[case("??bcd[]].txt", 2)]
|
|
|
|
#[case("??bcd].txt", 2)]
|
|
|
|
#[case("[[]?bcd].txt", 2)]
|
|
|
|
#[case("[[]abcd].txt", 1)]
|
|
|
|
#[case("[[][abcd]bcd[]].txt", 2)]
|
do not attempt to glob expand if the file path is wrapped in quotes (#11569)
# Description
Fixes: #11455
### For arguments which is annotated with `:path/:directory/:glob`
To fix the issue, we need to have a way to know if a path is originally
quoted during runtime. So the information needed to be added at several
levels:
* parse time (from user input to expression)
We need to add quoted information into `Expr::Filepath`,
`Expr::Directory`, `Expr::GlobPattern`
* eval time
When convert from `Expr::Filepath`, `Expr::Directory`,
`Expr::GlobPattern` to `Value::String` during runtime, we won't auto
expanded the path if it's quoted
### For `ls`
It's really special, because it accepts a `String` as a pattern, and it
generates `glob` expression inside the command itself.
So the idea behind the change is introducing a special SyntaxShape to
ls: `SyntaxShape::LsGlobPattern`. So we can track if the pattern is
originally quoted easier, and we don't auto expand the path either.
Then when constructing a glob pattern inside ls, we check if input
pattern is quoted, if so: we escape the input pattern, so we can run `ls
a[123]b`, because it's already escaped.
Finally, to accomplish the checking process, we also need to introduce a
new value type called `Value::QuotedString` to differ from
`Value::String`, it's used to generate an enum called `NuPath`, which is
finally used in `ls` function. `ls` learned from `NuPath` to know if
user input is quoted.
# User-Facing Changes
Actually it contains several changes
### For arguments which is annotated with `:path/:directory/:glob`
#### Before
```nushell
> def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
> def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
> def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a')
/home/windsoilder/a
/home/windsoilder/a
```
#### After
```nushell
> def foo [p: path] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
> def foo [p: directory] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
> def foo [p: glob] { echo $p }; print (foo "~/a"); print (foo '~/a')
~/a
~/a
```
### For ls command
`touch '[uwu]'`
#### Before
```
❯ ls -D "[uwu]"
Error: × No matches found for [uwu]
╭─[entry #6:1:1]
1 │ ls -D "[uwu]"
· ───┬───
· ╰── Pattern, file or folder not found
╰────
help: no matches found
```
#### After
```
❯ ls -D "[uwu]"
╭───┬───────┬──────┬──────┬──────────╮
│ # │ name │ type │ size │ modified │
├───┼───────┼──────┼──────┼──────────┤
│ 0 │ [uwu] │ file │ 0 B │ now │
╰───┴───────┴──────┴──────┴──────────╯
```
# Tests + Formatting
Done
# After Submitting
NaN
2024-01-21 16:22:25 +01:00
|
|
|
#[case("'[abcd].txt'", 1)]
|
|
|
|
#[case("'[bbcd].txt'", 1)]
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
fn lists_regular_files_using_question_mark(#[case] command: &str, #[case] expected: usize) {
|
|
|
|
Playground::setup("ls_test_3", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.mkdir("abcd").mkdir("bbcd").with_files(&[
|
treat path contains '?' as pattern (#10142)
Fix https://github.com/nushell/nushell/issues/10136
# Description
Current nushell only handle path containing '*' as match pattern and
treat '?' as just normal path.
This pr makes path containing '?' is also processed as pattern.
🔴 **Concerns: Need to design/comfirm a consistent rule to handle
dirs/files with '?' in their names.**
Currently:
- if no dir has exactly same name with pattern, it will print the list
of matched directories
- if pattern exactly matches an empty dir's name, it will just print the
empty dir's content ( i.e. `[]`)
- if pattern exactly matches an dir's name, it will perform pattern
match and print all the dir contains
e.g.
```bash
mkdir src
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ | --------------------------------------------- |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir src
mkdir scc
mkdir scs
ls s?c
```
| name | type | size | modified |
| ---- | ---- | ------ |
------------------------------------------------ |
| scc | dir | 64 B | Tue, 29 Aug 2023 16:55:31 +0900 (14 seconds ago) |
| src | dir | 1.1 KB | Tue, 29 Aug 2023 07:39:41 +0900 (9 hours ago) |
-----------
```bash
mkdir s?c
ls s?c
```
print empty (i.e. ls of dir `s?c`)
-----------
```bash
mkdir -p s?c/test
ls s?c
```
|name|type|size|modified|
|-|-|-|-|
|s?c/test|dir|64 B|Tue, 29 Aug 2023 16:47:53 +0900 (2 minutes ago)|
|src/bytes|dir|480 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/charting|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
|src/conversions|dir|160 B|Fri, 25 Aug 2023 17:43:52 +0900 (3 days ago)|
-----------
# User-Facing Changes
User will be able to use '?' to match directory/file.
# Tests + Formatting
- :green_circle: `toolkit fmt`
- :green_circle: `toolkit clippy`
- :green_circle: `toolkit test`
- :green_circle: `toolkit test stdlib`
# After Submitting
None
---------
Co-authored-by: Horasal <horsal@horsal.dev>
2023-09-04 02:25:00 +02:00
|
|
|
EmptyFile("abcd/xy.txt"),
|
|
|
|
EmptyFile("bbcd/yy.txt"),
|
|
|
|
EmptyFile("[abcd].txt"),
|
|
|
|
EmptyFile("[bbcd].txt"),
|
|
|
|
EmptyFile("yehuda.10.txt"),
|
|
|
|
EmptyFile("jt.10.txt"),
|
|
|
|
EmptyFile("jtabc.txt"),
|
|
|
|
EmptyFile("abcde.txt"),
|
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), format!(r#"ls {command} | length"#));
|
|
|
|
assert_eq!(actual.out, expected.to_string());
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-02 11:23:39 +02:00
|
|
|
#[test]
|
2019-12-15 17:15:06 +01:00
|
|
|
fn lists_regular_files_using_question_mark_wildcard() {
|
2019-08-29 02:32:42 +02:00
|
|
|
Playground::setup("ls_test_3", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2019-09-11 16:36:50 +02:00
|
|
|
EmptyFile("yehuda.10.txt"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jt.10.txt"),
|
2019-09-11 16:36:50 +02:00
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
2019-08-29 02:32:42 +02:00
|
|
|
]);
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2019-08-29 02:32:42 +02:00
|
|
|
let actual = nu!(
|
2019-12-15 17:15:06 +01:00
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-09-03 02:49:51 +02:00
|
|
|
ls *.??.txt
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2019-08-29 02:32:42 +02:00
|
|
|
));
|
2019-08-02 11:23:39 +02:00
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "3");
|
2019-08-28 19:01:16 +02:00
|
|
|
})
|
2019-08-02 11:23:39 +02:00
|
|
|
}
|
2020-01-19 03:25:07 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lists_all_files_in_directories_from_stream() {
|
|
|
|
Playground::setup("ls_test_4", |dirs, sandbox| {
|
2020-01-22 04:56:12 +01:00
|
|
|
sandbox
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("root1.txt"), EmptyFile("root2.txt")])
|
2020-01-22 04:56:12 +01:00
|
|
|
.within("dir_a")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("yehuda.10.txt"), EmptyFile("jt10.txt")])
|
2020-01-22 04:56:12 +01:00
|
|
|
.within("dir_b")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-01-22 04:56:12 +01:00
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
|
|
|
]);
|
2020-01-19 03:25:07 +01:00
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-01-19 03:25:07 +01:00
|
|
|
echo dir_a dir_b
|
2022-02-17 12:40:24 +01:00
|
|
|
| each { |it| ls $it }
|
2022-02-04 21:32:13 +01:00
|
|
|
| flatten | length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-01-19 03:25:07 +01:00
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "4");
|
2020-01-19 03:25:07 +01:00
|
|
|
})
|
|
|
|
}
|
2020-02-01 09:34:34 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn does_not_fail_if_glob_matches_empty_directory() {
|
|
|
|
Playground::setup("ls_test_5", |dirs, sandbox| {
|
|
|
|
sandbox.within("dir_a");
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-02-01 09:34:34 +01:00
|
|
|
ls dir_a
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-02-01 09:34:34 +01:00
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "0");
|
2020-02-01 09:34:34 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn fails_when_glob_doesnt_match() {
|
|
|
|
Playground::setup("ls_test_5", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[EmptyFile("root1.txt"), EmptyFile("root2.txt")]);
|
2020-02-01 09:34:34 +01:00
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
let actual = nu!(
|
2020-02-01 09:34:34 +01:00
|
|
|
cwd: dirs.test(),
|
|
|
|
"ls root3*"
|
|
|
|
);
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert!(actual.err.contains("no matches found"));
|
2020-02-01 09:34:34 +01:00
|
|
|
})
|
|
|
|
}
|
2020-04-06 13:28:56 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_files_from_two_parents_up_using_multiple_dots() {
|
|
|
|
Playground::setup("ls_test_6", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2020-04-06 13:28:56 +02:00
|
|
|
EmptyFile("yahuda.yaml"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jtjson"),
|
2020-04-06 13:28:56 +02:00
|
|
|
EmptyFile("andres.xml"),
|
|
|
|
EmptyFile("kevin.txt"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
sandbox.within("foo").mkdir("bar");
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("foo/bar"),
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2021-03-13 22:46:40 +01:00
|
|
|
ls ... | length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-04-06 13:28:56 +02:00
|
|
|
);
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "5");
|
2024-05-06 08:01:32 +02:00
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join("foo/bar"),
|
|
|
|
r#"ls ... | sort-by name | get name.0 | str replace -a '\' '/'"#
|
|
|
|
);
|
|
|
|
assert_eq!(actual.out, "../../andres.xml");
|
2020-04-06 13:28:56 +02:00
|
|
|
})
|
|
|
|
}
|
2020-07-04 22:17:36 +02:00
|
|
|
|
2020-08-22 03:49:34 +02:00
|
|
|
#[test]
|
|
|
|
fn lists_hidden_file_when_explicitly_specified() {
|
|
|
|
Playground::setup("ls_test_7", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2020-08-22 03:49:34 +02:00
|
|
|
EmptyFile("los.txt"),
|
|
|
|
EmptyFile("tres.txt"),
|
|
|
|
EmptyFile("amigos.txt"),
|
|
|
|
EmptyFile("arepas.clu"),
|
|
|
|
EmptyFile(".testdotfile"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-08-22 03:49:34 +02:00
|
|
|
ls .testdotfile
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-08-22 03:49:34 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "1");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lists_all_hidden_files_when_glob_contains_dot() {
|
|
|
|
Playground::setup("ls_test_8", |dirs, sandbox| {
|
|
|
|
sandbox
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-08-22 03:49:34 +02:00
|
|
|
EmptyFile("root1.txt"),
|
|
|
|
EmptyFile("root2.txt"),
|
|
|
|
EmptyFile(".dotfile1"),
|
|
|
|
])
|
|
|
|
.within("dir_a")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-08-22 03:49:34 +02:00
|
|
|
EmptyFile("yehuda.10.txt"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jt10.txt"),
|
2020-08-22 03:49:34 +02:00
|
|
|
EmptyFile(".dotfile2"),
|
|
|
|
])
|
|
|
|
.within("dir_b")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-08-22 03:49:34 +02:00
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
|
|
|
EmptyFile(".dotfile3"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-08-22 03:49:34 +02:00
|
|
|
ls **/.*
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-08-22 03:49:34 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "3");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-04 21:32:58 +02:00
|
|
|
#[test]
|
|
|
|
// TODO Remove this cfg value when we have an OS-agnostic way
|
|
|
|
// of creating hidden files using the playground.
|
|
|
|
#[cfg(unix)]
|
|
|
|
fn lists_all_hidden_files_when_glob_does_not_contain_dot() {
|
|
|
|
Playground::setup("ls_test_8", |dirs, sandbox| {
|
|
|
|
sandbox
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-09-04 21:32:58 +02:00
|
|
|
EmptyFile("root1.txt"),
|
|
|
|
EmptyFile("root2.txt"),
|
|
|
|
EmptyFile(".dotfile1"),
|
|
|
|
])
|
|
|
|
.within("dir_a")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-09-04 21:32:58 +02:00
|
|
|
EmptyFile("yehuda.10.txt"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jt10.txt"),
|
2020-09-04 21:32:58 +02:00
|
|
|
EmptyFile(".dotfile2"),
|
|
|
|
])
|
|
|
|
.within(".dir_b")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[
|
2020-09-04 21:32:58 +02:00
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
|
|
|
EmptyFile(".dotfile3"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-09-04 21:32:58 +02:00
|
|
|
ls **/*
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-09-04 21:32:58 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "5");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-05-31 02:13:27 +02:00
|
|
|
#[test]
|
|
|
|
// TODO Remove this cfg value when we have an OS-agnostic way
|
|
|
|
// of creating hidden files using the playground.
|
|
|
|
#[cfg(unix)]
|
|
|
|
fn glob_with_hidden_directory() {
|
|
|
|
Playground::setup("ls_test_8", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.within(".dir_b").with_files(&[
|
2022-05-31 02:13:27 +02:00
|
|
|
EmptyFile("andres.10.txt"),
|
|
|
|
EmptyFile("chicken_not_to_be_picked_up.100.txt"),
|
|
|
|
EmptyFile(".dotfile3"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-31 02:13:27 +02:00
|
|
|
ls **/*
|
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-31 02:13:27 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "");
|
|
|
|
assert!(actual.err.contains("No matches found"));
|
|
|
|
|
|
|
|
// will list files if provide `-a` flag.
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-31 02:13:27 +02:00
|
|
|
ls -a **/*
|
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-31 02:13:27 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "4");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-03-31 08:52:39 +02:00
|
|
|
#[test]
|
|
|
|
#[cfg(unix)]
|
|
|
|
fn fails_with_ls_to_dir_without_permission() {
|
|
|
|
Playground::setup("ls_test_1", |dirs, sandbox| {
|
2023-03-15 06:54:55 +01:00
|
|
|
sandbox
|
|
|
|
.within("dir_a")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("yehuda.11.txt"), EmptyFile("jt10.txt")]);
|
2021-03-31 08:52:39 +02:00
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2021-03-31 08:52:39 +02:00
|
|
|
chmod 000 dir_a; ls dir_a
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2021-03-31 08:52:39 +02:00
|
|
|
));
|
2022-05-21 04:48:36 +02:00
|
|
|
|
|
|
|
let check_not_root = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-21 04:48:36 +02:00
|
|
|
id -u
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-05-21 04:48:36 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert!(
|
|
|
|
actual
|
|
|
|
.err
|
|
|
|
.contains("The permissions of 0 do not allow access for this user")
|
|
|
|
|| check_not_root.out == "0"
|
|
|
|
);
|
2021-03-31 08:52:39 +02:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-09-21 09:56:37 +02:00
|
|
|
#[test]
|
|
|
|
fn lists_files_including_starting_with_dot() {
|
|
|
|
Playground::setup("ls_test_9", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2020-09-21 09:56:37 +02:00
|
|
|
EmptyFile("yehuda.txt"),
|
2023-03-15 06:54:55 +01:00
|
|
|
EmptyFile("jttxt"),
|
2020-09-21 09:56:37 +02:00
|
|
|
EmptyFile("andres.txt"),
|
|
|
|
EmptyFile(".hidden1.txt"),
|
|
|
|
EmptyFile(".hidden2.txt"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-09-21 09:56:37 +02:00
|
|
|
ls -a
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2020-09-21 09:56:37 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "5");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-07-04 22:17:36 +02:00
|
|
|
#[test]
|
|
|
|
fn list_all_columns() {
|
2021-03-15 08:26:30 +01:00
|
|
|
Playground::setup("ls_test_all_columns", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2021-03-15 08:26:30 +01:00
|
|
|
EmptyFile("Leonardo.yaml"),
|
|
|
|
EmptyFile("Raphael.json"),
|
|
|
|
EmptyFile("Donatello.xml"),
|
|
|
|
EmptyFile("Michelangelo.txt"),
|
|
|
|
]);
|
|
|
|
// Normal Operation
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(),
|
2022-02-04 21:32:13 +01:00
|
|
|
"ls | columns | to md"
|
2021-03-15 08:26:30 +01:00
|
|
|
);
|
|
|
|
let expected = ["name", "type", "size", "modified"].join("");
|
|
|
|
assert_eq!(actual.out, expected, "column names are incorrect for ls");
|
|
|
|
// Long
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(),
|
2022-02-04 21:32:13 +01:00
|
|
|
"ls -l | columns | to md"
|
2021-03-15 08:26:30 +01:00
|
|
|
);
|
|
|
|
let expected = {
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
[
|
|
|
|
"name",
|
|
|
|
"type",
|
|
|
|
"target",
|
2022-02-04 03:01:45 +01:00
|
|
|
"readonly",
|
|
|
|
"mode",
|
2022-02-04 21:32:13 +01:00
|
|
|
"num_links",
|
|
|
|
"inode",
|
2023-06-11 18:02:08 +02:00
|
|
|
"user",
|
2021-03-15 08:26:30 +01:00
|
|
|
"group",
|
|
|
|
"size",
|
|
|
|
"created",
|
|
|
|
"accessed",
|
|
|
|
"modified",
|
|
|
|
]
|
|
|
|
.join("")
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
|
|
|
[
|
|
|
|
"name", "type", "target", "readonly", "size", "created", "accessed", "modified",
|
|
|
|
]
|
|
|
|
.join("")
|
|
|
|
}
|
|
|
|
};
|
|
|
|
assert_eq!(
|
|
|
|
actual.out, expected,
|
|
|
|
"column names are incorrect for ls long"
|
|
|
|
);
|
|
|
|
});
|
2020-07-04 22:17:36 +02:00
|
|
|
}
|
2022-06-03 18:37:27 +02:00
|
|
|
|
2022-07-08 21:15:34 +02:00
|
|
|
#[test]
|
|
|
|
fn lists_with_directory_flag() {
|
|
|
|
Playground::setup("ls_test_flag_directory_1", |dirs, sandbox| {
|
|
|
|
sandbox
|
|
|
|
.within("dir_files")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("nushell.json")])
|
2022-07-08 21:15:34 +02:00
|
|
|
.within("dir_empty");
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
cd dir_empty;
|
|
|
|
['.' '././.' '..' '../dir_files' '../dir_files/*']
|
`open`, `rm`, `umv`, `cp`, `rm` and `du`: Don't globs if inputs are variables or string interpolation (#11886)
# Description
This is a follow up to
https://github.com/nushell/nushell/pull/11621#issuecomment-1937484322
Also Fixes: #11838
## About the code change
It applys the same logic when we pass variables to external commands:
https://github.com/nushell/nushell/blob/0487e9ffcbc57c2d5feca606e10c3f8221ff5e00/crates/nu-command/src/system/run_external.rs#L162-L170
That is: if user input dynamic things(like variables, sub-expression, or
string interpolation), it returns a quoted `NuPath`, then user input
won't be globbed
# User-Facing Changes
Given two input files: `a*c.txt`, `abc.txt`
* `let f = "a*c.txt"; rm $f` will remove one file: `a*c.txt`.
~* `let f = "a*c.txt"; rm --glob $f` will remove `a*c.txt` and
`abc.txt`~
* `let f: glob = "a*c.txt"; rm $f` will remove `a*c.txt` and `abc.txt`
## Rules about globbing with *variable*
Given two files: `a*c.txt`, `abc.txt`
| Cmd Type | example | Result |
| ----- | ------------------ | ------ |
| builtin | let f = "a*c.txt"; rm $f | remove `a*c.txt` |
| builtin | let f: glob = "a*c.txt"; rm $f | remove `a*c.txt` and
`abc.txt`
| builtin | let f = "a*c.txt"; rm ($f \| into glob) | remove `a*c.txt`
and `abc.txt`
| custom | def crm [f: glob] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt` and `abc.txt`
| custom | def crm [f: glob] { rm ($f \| into string) }; let f =
"a*c.txt"; crm $f | remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm $f |
remove `a*c.txt`
| custom | def crm [f: string] { rm $f }; let f = "a*c.txt"; crm ($f \|
into glob) | remove `a*c.txt` and `abc.txt`
In general, if a variable is annotated with `glob` type, nushell will
expand glob pattern. Or else, we need to use `into | glob` to expand
glob pattern
# Tests + Formatting
Done
# After Submitting
I think `str glob-escape` command will be no-longer required. We can
remove it.
2024-02-23 02:17:09 +01:00
|
|
|
| each { |it| ls --directory ($it | into glob) }
|
2022-07-08 21:15:34 +02:00
|
|
|
| flatten
|
|
|
|
| get name
|
|
|
|
| to text
|
|
|
|
"#
|
|
|
|
));
|
|
|
|
let expected = [".", ".", "..", "../dir_files", "../dir_files/nushell.json"].join("");
|
|
|
|
#[cfg(windows)]
|
2022-08-11 18:54:54 +02:00
|
|
|
let expected = expected.replace('/', "\\");
|
2022-07-08 21:15:34 +02:00
|
|
|
assert_eq!(
|
|
|
|
actual.out, expected,
|
|
|
|
"column names are incorrect for ls --directory (-D)"
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn lists_with_directory_flag_without_argument() {
|
|
|
|
Playground::setup("ls_test_flag_directory_2", |dirs, sandbox| {
|
|
|
|
sandbox
|
|
|
|
.within("dir_files")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("nushell.json")])
|
2022-07-08 21:15:34 +02:00
|
|
|
.within("dir_empty");
|
|
|
|
// Test if there are some files in the current directory
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-07-08 21:15:34 +02:00
|
|
|
cd dir_files;
|
|
|
|
ls --directory
|
|
|
|
| get name
|
|
|
|
| to text
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-07-08 21:15:34 +02:00
|
|
|
));
|
|
|
|
let expected = ".";
|
|
|
|
assert_eq!(
|
|
|
|
actual.out, expected,
|
|
|
|
"column names are incorrect for ls --directory (-D)"
|
|
|
|
);
|
|
|
|
// Test if there is no file in the current directory
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-07-08 21:15:34 +02:00
|
|
|
cd dir_empty;
|
|
|
|
ls -D
|
|
|
|
| get name
|
|
|
|
| to text
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-07-08 21:15:34 +02:00
|
|
|
));
|
|
|
|
let expected = ".";
|
|
|
|
assert_eq!(
|
|
|
|
actual.out, expected,
|
|
|
|
"column names are incorrect for ls --directory (-D)"
|
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2022-06-03 18:37:27 +02:00
|
|
|
/// Rust's fs::metadata function is unable to read info for certain system files on Windows,
|
|
|
|
/// like the `C:\Windows\System32\Configuration` folder. https://github.com/rust-lang/rust/issues/96980
|
|
|
|
/// This test confirms that Nu can work around this successfully.
|
|
|
|
#[test]
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn can_list_system_folder() {
|
|
|
|
// the awkward `ls Configuration* | where name == "Configuration"` thing is for speed;
|
|
|
|
// listing the entire System32 folder is slow and `ls Configuration*` alone
|
|
|
|
// might return more than 1 file someday
|
|
|
|
let file_type = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
|
|
|
r#"ls Configuration* | where name == "Configuration" | get type.0"#
|
|
|
|
));
|
|
|
|
assert_eq!(file_type.out, "dir");
|
|
|
|
|
|
|
|
let file_size = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
|
|
|
r#"ls Configuration* | where name == "Configuration" | get size.0"#
|
|
|
|
));
|
2023-01-15 03:03:32 +01:00
|
|
|
assert_ne!(file_size.out.trim(), "");
|
2022-06-03 18:37:27 +02:00
|
|
|
|
|
|
|
let file_modified = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
|
|
|
r#"ls Configuration* | where name == "Configuration" | get modified.0"#
|
|
|
|
));
|
2023-01-15 03:03:32 +01:00
|
|
|
assert_ne!(file_modified.out.trim(), "");
|
2022-06-03 18:37:27 +02:00
|
|
|
|
|
|
|
let file_accessed = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
|
|
|
r#"ls -l Configuration* | where name == "Configuration" | get accessed.0"#
|
|
|
|
));
|
2023-01-15 03:03:32 +01:00
|
|
|
assert_ne!(file_accessed.out.trim(), "");
|
2022-06-03 18:37:27 +02:00
|
|
|
|
|
|
|
let file_created = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
|
|
|
r#"ls -l Configuration* | where name == "Configuration" | get created.0"#
|
|
|
|
));
|
2023-01-15 03:03:32 +01:00
|
|
|
assert_ne!(file_created.out.trim(), "");
|
2022-06-03 18:37:27 +02:00
|
|
|
|
|
|
|
let ls_with_filter = nu!(
|
|
|
|
cwd: "C:\\Windows\\System32", pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"ls | where size > 10mb"
|
2022-06-03 18:37:27 +02:00
|
|
|
));
|
|
|
|
assert_eq!(ls_with_filter.err, "");
|
|
|
|
}
|
2022-07-27 17:53:00 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_a_directory_not_exists() {
|
|
|
|
Playground::setup("ls_test_directory_not_exists", |dirs, _sandbox| {
|
|
|
|
let actual = nu!(cwd: dirs.test(), "ls a_directory_not_exists");
|
|
|
|
assert!(actual.err.contains("directory not found"));
|
|
|
|
})
|
|
|
|
}
|
2022-08-04 03:59:57 +02:00
|
|
|
|
2024-02-17 20:04:59 +01:00
|
|
|
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
2022-08-04 03:59:57 +02:00
|
|
|
#[test]
|
|
|
|
fn list_directory_contains_invalid_utf8() {
|
|
|
|
use std::ffi::OsStr;
|
|
|
|
use std::os::unix::ffi::OsStrExt;
|
|
|
|
|
|
|
|
Playground::setup(
|
|
|
|
"ls_test_directory_contains_invalid_utf8",
|
|
|
|
|dirs, _sandbox| {
|
|
|
|
let v: [u8; 4] = [7, 196, 144, 188];
|
|
|
|
let s = OsStr::from_bytes(&v);
|
|
|
|
|
|
|
|
let cwd = dirs.test();
|
|
|
|
let path = cwd.join(s);
|
|
|
|
|
2022-11-04 21:11:17 +01:00
|
|
|
std::fs::create_dir_all(path).expect("failed to create directory");
|
2022-08-04 03:59:57 +02:00
|
|
|
|
2022-08-13 04:13:50 +02:00
|
|
|
let actual = nu!(cwd: cwd, "ls");
|
2022-08-04 03:59:57 +02:00
|
|
|
|
|
|
|
assert!(actual.out.contains("warning: get non-utf8 filename"));
|
|
|
|
assert!(actual.err.contains("No matches found for"));
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2022-08-04 13:59:20 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_ignores_ansi() {
|
|
|
|
Playground::setup("ls_test_ansi", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2022-08-04 13:59:20 +02:00
|
|
|
EmptyFile("los.txt"),
|
|
|
|
EmptyFile("tres.txt"),
|
|
|
|
EmptyFile("amigos.txt"),
|
|
|
|
EmptyFile("arepas.clu"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
Restrict closure expression to be something like `{|| ...}` (#8290)
# Description
As title, closes: #7921 closes: #8273
# User-Facing Changes
when define a closure without pipe, nushell will raise error for now:
```
❯ let x = {ss ss}
Error: nu::parser::closure_missing_pipe
× Missing || inside closure
╭─[entry #2:1:1]
1 │ let x = {ss ss}
· ───┬───
· ╰── Parsing as a closure, but || is missing
╰────
help: Try add || to the beginning of closure
```
`any`, `each`, `all`, `where` command accepts closure, it forces user
input closure like `{||`, or parse error will returned.
```
❯ {major:2, minor:1, patch:4} | values | each { into string }
Error: nu::parser::closure_missing_pipe
× Missing || inside closure
╭─[entry #4:1:1]
1 │ {major:2, minor:1, patch:4} | values | each { into string }
· ───────┬───────
· ╰── Parsing as a closure, but || is missing
╰────
help: Try add || to the beginning of closure
```
`with-env`, `do`, `def`, `try` are special, they still remain the same,
although it says that it accepts a closure, but they don't need to be
written like `{||`, it's more likely a block but can capture variable
outside of scope:
```
❯ def test [input] { echo [0 1 2] | do { do { echo $input } } }; test aaa
aaa
```
Just realize that It's a big breaking change, we need to update config
and scripts...
# Tests + Formatting
Don't forget to add tests that cover your changes.
Make sure you've run and fixed any issues with these commands:
- `cargo fmt --all -- --check` to check standard code formatting (`cargo
fmt --all` applies these changes)
- `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used -A
clippy::needless_collect` to check that you're using the standard code
style
- `cargo test --workspace` to check that all tests pass
# 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.
2023-03-17 13:36:28 +01:00
|
|
|
ls | find .txt | each {|| ls $in.name }
|
2023-07-21 17:32:37 +02:00
|
|
|
"
|
2022-08-04 13:59:20 +02:00
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.err.is_empty());
|
|
|
|
})
|
|
|
|
}
|
2022-12-13 13:45:33 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_unknown_flag() {
|
2023-07-17 18:43:51 +02:00
|
|
|
let actual = nu!("ls -r");
|
2022-12-13 13:45:33 +01:00
|
|
|
|
|
|
|
assert!(actual
|
|
|
|
.err
|
|
|
|
.contains("Available flags: --help(-h), --all(-a),"));
|
|
|
|
}
|
2024-01-11 16:19:48 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_flag_false() {
|
|
|
|
// Check that ls flags respect explicit values
|
|
|
|
Playground::setup("ls_test_false_flag", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2024-01-11 16:19:48 +01:00
|
|
|
EmptyFile(".hidden"),
|
|
|
|
EmptyFile("normal"),
|
|
|
|
EmptyFile("another_normal"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
// TODO Remove this cfg value when we have an OS-agnostic way
|
|
|
|
// of creating hidden files using the playground.
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
"
|
|
|
|
ls --all=false | length
|
|
|
|
"
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "2");
|
|
|
|
}
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
"
|
|
|
|
ls --long=false | columns | length
|
|
|
|
"
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "4");
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
"
|
|
|
|
ls --full-paths=false | get name | any { $in =~ / }
|
|
|
|
"
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "false");
|
|
|
|
})
|
|
|
|
}
|
2024-03-08 22:49:41 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_empty_string() {
|
|
|
|
Playground::setup("ls_empty_string", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[EmptyFile("yehuda.txt")]);
|
2024-03-08 22:49:41 +01:00
|
|
|
|
|
|
|
let actual = nu!(cwd: dirs.test(), "ls ''");
|
|
|
|
assert!(actual.err.contains("does not exist"));
|
|
|
|
})
|
|
|
|
}
|
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
2024-03-25 03:08:38 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_with_tilde() {
|
|
|
|
Playground::setup("ls_tilde", |dirs, sandbox| {
|
|
|
|
sandbox
|
|
|
|
.within("~tilde")
|
2024-05-04 02:53:15 +02:00
|
|
|
.with_files(&[EmptyFile("f1.txt"), EmptyFile("f2.txt")]);
|
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
2024-03-25 03:08:38 +01:00
|
|
|
|
|
|
|
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"));
|
|
|
|
})
|
|
|
|
}
|
2024-04-13 17:03:17 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_with_multiple_path() {
|
|
|
|
Playground::setup("ls_multiple_path", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[
|
2024-04-13 17:03:17 +02:00
|
|
|
EmptyFile("f1.txt"),
|
|
|
|
EmptyFile("f2.txt"),
|
|
|
|
EmptyFile("f3.txt"),
|
|
|
|
]);
|
|
|
|
|
|
|
|
let actual = nu!(cwd: dirs.test(), "ls f1.txt f2.txt");
|
|
|
|
assert!(actual.out.contains("f1.txt"));
|
|
|
|
assert!(actual.out.contains("f2.txt"));
|
|
|
|
assert!(!actual.out.contains("f3.txt"));
|
|
|
|
assert!(actual.status.success());
|
|
|
|
|
|
|
|
// report errors if one path not exists
|
|
|
|
let actual = nu!(cwd: dirs.test(), "ls asdf f1.txt");
|
|
|
|
assert!(actual.err.contains("directory not found"));
|
|
|
|
assert!(!actual.status.success());
|
|
|
|
|
|
|
|
// ls with spreading empty list should returns nothing.
|
|
|
|
let actual = nu!(cwd: dirs.test(), "ls ...[] | length");
|
|
|
|
assert_eq!(actual.out, "0");
|
|
|
|
})
|
|
|
|
}
|
2024-05-06 08:01:32 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_inside_glob_metachars_dir() {
|
|
|
|
Playground::setup("list_files_inside_glob_metachars_dir", |dirs, sandbox| {
|
|
|
|
let sub_dir = "test[]";
|
|
|
|
sandbox
|
|
|
|
.within(sub_dir)
|
|
|
|
.with_files(&[EmptyFile("test_file.txt")]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join(sub_dir),
|
|
|
|
"ls test_file.txt | get name.0 | path basename",
|
|
|
|
);
|
|
|
|
assert!(actual.out.contains("test_file.txt"));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_inside_tilde_glob_metachars_dir() {
|
|
|
|
Playground::setup(
|
|
|
|
"list_files_inside_tilde_glob_metachars_dir",
|
|
|
|
|dirs, sandbox| {
|
|
|
|
let sub_dir = "~test[]";
|
|
|
|
sandbox
|
|
|
|
.within(sub_dir)
|
|
|
|
.with_files(&[EmptyFile("test_file.txt")]);
|
|
|
|
|
|
|
|
// need getname.0 | path basename because the output path
|
|
|
|
// might be too long to output as a single line.
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test().join(sub_dir),
|
|
|
|
"ls test_file.txt | get name.0 | path basename",
|
|
|
|
);
|
|
|
|
assert!(actual.out.contains("test_file.txt"));
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(),
|
|
|
|
"ls '~test[]' | get name.0 | path basename"
|
|
|
|
);
|
|
|
|
assert!(actual.out.contains("test_file.txt"));
|
|
|
|
},
|
|
|
|
);
|
|
|
|
}
|