2019-12-17 19:54:39 +01:00
|
|
|
use nu_test_support::fs::Stub::FileWithContentToBeTrimmed;
|
|
|
|
use nu_test_support::playground::Playground;
|
|
|
|
use nu_test_support::{nu, pipeline};
|
2019-12-15 17:15:06 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn table_to_tsv_text_and_from_tsv_text_back_into_table() {
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: "tests/fixtures/formats",
|
2022-09-29 00:08:17 +02:00
|
|
|
"open caco3_plastics.tsv | to tsv | from tsv | first | get origin"
|
2019-12-15 17:15:06 +01:00
|
|
|
);
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "SPAIN");
|
2019-12-15 17:15:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn table_to_tsv_text_and_from_tsv_text_back_into_table_using_csv_separator() {
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: "tests/fixtures/formats",
|
2023-03-16 23:49:46 +01:00
|
|
|
r#"open caco3_plastics.tsv | to tsv | from csv --separator "\t" | first | get origin"#
|
2019-12-15 17:15:06 +01:00
|
|
|
);
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "SPAIN");
|
2019-12-15 17:15:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn table_to_tsv_text() {
|
|
|
|
Playground::setup("filter_to_tsv_test_1", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2019-12-15 17:15:06 +01:00
|
|
|
"tsv_text_sample.txt",
|
|
|
|
r#"
|
|
|
|
importer shipper tariff_item name origin
|
|
|
|
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
|
|
|
|
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open tsv_text_sample.txt
|
|
|
|
| lines
|
2020-05-24 08:41:30 +02:00
|
|
|
| split column "\t" a b c d origin
|
2019-12-15 17:15:06 +01:00
|
|
|
| last 1
|
2020-05-04 10:44:33 +02:00
|
|
|
| to tsv
|
2019-12-15 17:15:06 +01:00
|
|
|
| lines
|
2022-02-09 15:59:40 +01:00
|
|
|
| select 1
|
2019-12-15 17:15:06 +01:00
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert!(actual.out.contains("Colombia"));
|
2019-12-15 17:15:06 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn table_to_tsv_text_skipping_headers_after_conversion() {
|
|
|
|
Playground::setup("filter_to_tsv_test_2", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2019-12-15 17:15:06 +01:00
|
|
|
"tsv_text_sample.txt",
|
|
|
|
r#"
|
|
|
|
importer shipper tariff_item name origin
|
|
|
|
Plasticos Rival Reverte 2509000000 Calcium carbonate Spain
|
|
|
|
Tigre Ecuador OMYA Andina 3824909999 Calcium carbonate Colombia
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open tsv_text_sample.txt
|
|
|
|
| lines
|
2020-05-24 08:41:30 +02:00
|
|
|
| split column "\t" a b c d origin
|
2019-12-15 17:15:06 +01:00
|
|
|
| last 1
|
2021-02-22 08:25:17 +01:00
|
|
|
| to tsv --noheaders
|
2019-12-15 17:15:06 +01:00
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert!(actual.out.contains("Colombia"));
|
2019-12-15 17:15:06 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_to_table() {
|
|
|
|
Playground::setup("filter_from_tsv_test_1", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2019-12-15 17:15:06 +01:00
|
|
|
"los_tres_amigos.txt",
|
|
|
|
r#"
|
|
|
|
first Name Last Name rusty_luck
|
|
|
|
Andrés Robalino 1
|
2023-03-15 06:54:55 +01:00
|
|
|
JT Turner 1
|
2019-12-15 17:15:06 +01:00
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_amigos.txt
|
2020-05-04 10:44:33 +02:00
|
|
|
| from tsv
|
2019-12-15 17:15:06 +01:00
|
|
|
| get rusty_luck
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2019-12-15 17:15:06 +01:00
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "3");
|
2019-12-15 17:15:06 +01:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
Replace `ExternalStream` with new `ByteStream` type (#12774)
# Description
This PR introduces a `ByteStream` type which is a `Read`-able stream of
bytes. Internally, it has an enum over three different byte stream
sources:
```rust
pub enum ByteStreamSource {
Read(Box<dyn Read + Send + 'static>),
File(File),
Child(ChildProcess),
}
```
This is in comparison to the current `RawStream` type, which is an
`Iterator<Item = Vec<u8>>` and has to allocate for each read chunk.
Currently, `PipelineData::ExternalStream` serves a weird dual role where
it is either external command output or a wrapper around `RawStream`.
`ByteStream` makes this distinction more clear (via `ByteStreamSource`)
and replaces `PipelineData::ExternalStream` in this PR:
```rust
pub enum PipelineData {
Empty,
Value(Value, Option<PipelineMetadata>),
ListStream(ListStream, Option<PipelineMetadata>),
ByteStream(ByteStream, Option<PipelineMetadata>),
}
```
The PR is relatively large, but a decent amount of it is just repetitive
changes.
This PR fixes #7017, fixes #10763, and fixes #12369.
This PR also improves performance when piping external commands. Nushell
should, in most cases, have competitive pipeline throughput compared to,
e.g., bash.
| Command | Before (MB/s) | After (MB/s) | Bash (MB/s) |
| -------------------------------------------------- | -------------:|
------------:| -----------:|
| `throughput \| rg 'x'` | 3059 | 3744 | 3739 |
| `throughput \| nu --testbin relay o> /dev/null` | 3508 | 8087 | 8136 |
# User-Facing Changes
- This is a breaking change for the plugin communication protocol,
because the `ExternalStreamInfo` was replaced with `ByteStreamInfo`.
Plugins now only have to deal with a single input stream, as opposed to
the previous three streams: stdout, stderr, and exit code.
- The output of `describe` has been changed for external/byte streams.
- Temporary breaking change: `bytes starts-with` no longer works with
byte streams. This is to keep the PR smaller, and `bytes ends-with`
already does not work on byte streams.
- If a process core dumped, then instead of having a `Value::Error` in
the `exit_code` column of the output returned from `complete`, it now is
a `Value::Int` with the negation of the signal number.
# After Submitting
- Update docs and book as necessary
- Release notes (e.g., plugin protocol changes)
- Adapt/convert commands to work with byte streams (high priority is
`str length`, `bytes starts-with`, and maybe `bytes ends-with`).
- Refactor the `tee` code, Devyn has already done some work on this.
---------
Co-authored-by: Devyn Cairns <devyn.cairns@gmail.com>
2024-05-16 16:11:18 +02:00
|
|
|
#[ignore = "csv crate has a bug when the last line is a comment: https://github.com/BurntSushi/rust-csv/issues/363"]
|
2023-03-16 23:49:46 +01:00
|
|
|
fn from_tsv_text_with_comments_to_table() {
|
2019-12-15 17:15:06 +01:00
|
|
|
Playground::setup("filter_from_tsv_test_2", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
# This is a comment
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
# This one too
|
|
|
|
Andrés Robalino 1
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
# This one also
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r##"
|
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from tsv --comment "#"
|
|
|
|
| get rusty_luck
|
|
|
|
| length
|
|
|
|
"##
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "3");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_with_custom_quotes_to_table() {
|
|
|
|
Playground::setup("filter_from_tsv_test_3", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
'And''rés' Robalino 1
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from tsv --quote "'"
|
|
|
|
| first
|
|
|
|
| get first_name
|
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "And'rés");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_with_custom_escapes_to_table() {
|
|
|
|
Playground::setup("filter_from_tsv_test_4", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
"And\"rés" Robalino 1
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
2023-09-01 00:08:27 +02:00
|
|
|
r"
|
2023-03-16 23:49:46 +01:00
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from tsv --escape '\'
|
|
|
|
| first
|
|
|
|
| get first_name
|
2023-09-01 00:08:27 +02:00
|
|
|
"
|
2023-03-16 23:49:46 +01:00
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "And\"rés");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_skipping_headers_to_table() {
|
|
|
|
Playground::setup("filter_from_tsv_test_5", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2019-12-15 17:15:06 +01:00
|
|
|
"los_tres_amigos.txt",
|
|
|
|
r#"
|
|
|
|
Andrés Robalino 1
|
2023-03-15 06:54:55 +01:00
|
|
|
JT Turner 1
|
2019-12-15 17:15:06 +01:00
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_amigos.txt
|
2021-02-22 08:25:17 +01:00
|
|
|
| from tsv --noheaders
|
2022-02-20 01:26:47 +01:00
|
|
|
| get column3
|
2021-03-13 22:46:40 +01:00
|
|
|
| length
|
2019-12-15 17:15:06 +01:00
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
2020-05-07 13:03:43 +02:00
|
|
|
assert_eq!(actual.out, "3");
|
2019-12-15 17:15:06 +01:00
|
|
|
})
|
|
|
|
}
|
2023-03-16 23:49:46 +01:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_with_missing_columns_to_table() {
|
|
|
|
Playground::setup("filter_from_tsv_test_6", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
Andrés Robalino
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from tsv --flexible
|
|
|
|
| get -i rusty_luck
|
|
|
|
| compact
|
|
|
|
| length
|
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
|
|
|
assert_eq!(actual.out, "2");
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_with_multiple_char_comment() {
|
|
|
|
Playground::setup("filter_from_tsv_test_7", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
Andrés Robalino 1
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from csv --comment "li"
|
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.err.contains("single character separator"));
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn from_tsv_text_with_wrong_type_comment() {
|
|
|
|
Playground::setup("filter_from_csv_test_8", |dirs, sandbox| {
|
2024-05-04 02:53:15 +02:00
|
|
|
sandbox.with_files(&[FileWithContentToBeTrimmed(
|
2023-03-16 23:49:46 +01:00
|
|
|
"los_tres_caballeros.txt",
|
|
|
|
r#"
|
|
|
|
first_name last_name rusty_luck
|
|
|
|
Andrés Robalino 1
|
|
|
|
Jonathan Turner 1
|
|
|
|
Yehuda Katz 1
|
|
|
|
"#,
|
|
|
|
)]);
|
|
|
|
|
|
|
|
let actual = nu!(
|
|
|
|
cwd: dirs.test(), pipeline(
|
|
|
|
r#"
|
|
|
|
open los_tres_caballeros.txt
|
|
|
|
| from csv --comment ('123' | into int)
|
|
|
|
"#
|
|
|
|
));
|
|
|
|
|
|
|
|
assert!(actual.err.contains("can't convert int to char"));
|
|
|
|
})
|
|
|
|
}
|