Fix external extra (#4777)

* Fix empty table from externals

* Fix empty table from externals
This commit is contained in:
JT 2022-03-07 20:17:33 -05:00 committed by GitHub
parent 35ff1076f3
commit 299fea8538
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 138 additions and 41 deletions

View File

@ -18,7 +18,11 @@ pub fn print_pipeline_data(
let stdout = std::io::stdout(); let stdout = std::io::stdout();
if let PipelineData::ExternalStream { stdout: stream, .. } = input { if let PipelineData::ExternalStream {
stdout: Some(stream),
..
} = input
{
for s in stream { for s in stream {
let _ = stdout.lock().write_all(s?.as_binary()?); let _ = stdout.lock().write_all(s?.as_binary()?);
} }

View File

@ -99,7 +99,15 @@ fn into_binary(
let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?; let column_paths: Vec<CellPath> = call.rest(engine_state, stack, 0)?;
match input { match input {
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::Binary {
val: vec![],
span: head,
}
.into_pipeline_data()),
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
// TODO: in the future, we may want this to stream out, converting each to bytes // TODO: in the future, we may want this to stream out, converting each to bytes
let output = stream.into_bytes()?; let output = stream.into_bytes()?;
Ok(Value::Binary { Ok(Value::Binary {

View File

@ -150,7 +150,15 @@ fn string_helper(
} }
match input { match input {
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => Ok(Value::String {
val: String::new(),
span: head,
}
.into_pipeline_data()),
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
// TODO: in the future, we may want this to stream out, converting each to bytes // TODO: in the future, we may want this to stream out, converting each to bytes
let output = stream.into_string()?; let output = stream.into_string()?;
Ok(Value::String { Ok(Value::String {

View File

@ -121,11 +121,11 @@ impl Command for Open {
let buf_reader = BufReader::new(file); let buf_reader = BufReader::new(file);
let output = PipelineData::ExternalStream { let output = PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new(BufferedReader { input: buf_reader }), Box::new(BufferedReader { input: buf_reader }),
ctrlc, ctrlc,
call_span, call_span,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span: call_span, span: call_span,

View File

@ -169,7 +169,11 @@ impl Command for Each {
} }
}) })
.into_pipeline_data(ctrlc)), .into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: stream, .. } => Ok(stream PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => Ok(stream
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(move |(idx, x)| { .map(move |(idx, x)| {

View File

@ -213,7 +213,11 @@ impl Command for ParEach {
.into_iter() .into_iter()
.flatten() .flatten()
.into_pipeline_data(ctrlc)), .into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: stream, .. } => Ok(stream PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => Ok(stream
.enumerate() .enumerate()
.par_bridge() .par_bridge()
.map(move |(idx, x)| { .map(move |(idx, x)| {

View File

@ -77,7 +77,7 @@ impl Command for Skip {
match input { match input {
PipelineData::ExternalStream { PipelineData::ExternalStream {
stdout: stream, stdout: Some(stream),
span: bytes_span, span: bytes_span,
metadata, metadata,
.. ..

View File

@ -357,13 +357,13 @@ fn response_to_buffer(
let buffered_input = BufReader::new(response); let buffered_input = BufReader::new(response);
PipelineData::ExternalStream { PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new(BufferedReader { Box::new(BufferedReader {
input: buffered_input, input: buffered_input,
}), }),
engine_state.ctrlc.clone(), engine_state.ctrlc.clone(),
span, span,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span, span,

View File

@ -418,13 +418,13 @@ fn response_to_buffer(
let buffered_input = BufReader::new(response); let buffered_input = BufReader::new(response);
PipelineData::ExternalStream { PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new(BufferedReader { Box::new(BufferedReader {
input: buffered_input, input: buffered_input,
}), }),
engine_state.ctrlc.clone(), engine_state.ctrlc.clone(),
span, span,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span, span,

View File

@ -44,7 +44,11 @@ impl Command for Decode {
let encoding: Spanned<String> = call.req(engine_state, stack, 0)?; let encoding: Spanned<String> = call.req(engine_state, stack, 0)?;
match input { match input {
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(call.head)),
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
let bytes: Vec<u8> = stream.into_bytes()?.item; let bytes: Vec<u8> = stream.into_bytes()?.item;
let encoding = match Encoding::for_label(encoding.item.as_bytes()) { let encoding = match Encoding::for_label(encoding.item.as_bytes()) {

View File

@ -34,21 +34,24 @@ impl Command for Complete {
exit_code, exit_code,
.. ..
} => { } => {
let mut cols = vec!["stdout".to_string()]; let mut cols = vec![];
let mut vals = vec![]; let mut vals = vec![];
let stdout = stdout.into_bytes()?; if let Some(stdout) = stdout {
if let Ok(st) = String::from_utf8(stdout.item.clone()) { cols.push("stdout".to_string());
vals.push(Value::String { let stdout = stdout.into_bytes()?;
val: st, if let Ok(st) = String::from_utf8(stdout.item.clone()) {
span: stdout.span, vals.push(Value::String {
}) val: st,
} else { span: stdout.span,
vals.push(Value::Binary { })
val: stdout.item, } else {
span: stdout.span, vals.push(Value::Binary {
}) val: stdout.item,
}; span: stdout.span,
})
}
}
if let Some(stderr) = stderr { if let Some(stderr) = stderr {
cols.push("stderr".to_string()); cols.push("stderr".to_string());

View File

@ -307,7 +307,15 @@ impl ExternalCommand {
let exit_code_receiver = ValueReceiver::new(exit_code_rx); let exit_code_receiver = ValueReceiver::new(exit_code_rx);
Ok(PipelineData::ExternalStream { Ok(PipelineData::ExternalStream {
stdout: RawStream::new(Box::new(stdout_receiver), output_ctrlc.clone(), head), stdout: if redirect_stdout {
Some(RawStream::new(
Box::new(stdout_receiver),
output_ctrlc.clone(),
head,
))
} else {
None
},
stderr: Some(RawStream::new( stderr: Some(RawStream::new(
Box::new(stderr_receiver), Box::new(stderr_receiver),
output_ctrlc.clone(), output_ctrlc.clone(),

View File

@ -67,7 +67,7 @@ impl Command for Table {
PipelineData::ExternalStream { .. } => Ok(input), PipelineData::ExternalStream { .. } => Ok(input),
PipelineData::Value(Value::Binary { val, .. }, ..) => { PipelineData::Value(Value::Binary { val, .. }, ..) => {
Ok(PipelineData::ExternalStream { Ok(PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new( Box::new(
vec![Ok(format!("{}\n", nu_pretty_hex::pretty_hex(&val)) vec![Ok(format!("{}\n", nu_pretty_hex::pretty_hex(&val))
.as_bytes() .as_bytes()
@ -76,7 +76,7 @@ impl Command for Table {
), ),
ctrlc, ctrlc,
head, head,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span: head, span: head,
@ -269,7 +269,7 @@ fn handle_row_stream(
let head = call.head; let head = call.head;
Ok(PipelineData::ExternalStream { Ok(PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new(PagingTableCreator { Box::new(PagingTableCreator {
row_offset, row_offset,
config, config,
@ -279,7 +279,7 @@ fn handle_row_stream(
}), }),
ctrlc, ctrlc,
head, head,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span: head, span: head,

View File

@ -47,6 +47,7 @@ mod reverse;
mod rm; mod rm;
mod roll; mod roll;
mod rotate; mod rotate;
mod run_external;
mod save; mod save;
mod select; mod select;
mod semicolon; mod semicolon;

View File

@ -0,0 +1,15 @@
use nu_test_support::{nu, pipeline};
#[test]
fn better_empty_redirection() {
let actual = nu!(
cwd: "tests/fixtures/formats", pipeline(
r#"
ls | each { |it| nu --testbin cococo $it.name }
"#
));
eprintln!("out: {}", actual.out);
assert!(!actual.out.contains('2'));
}

View File

@ -36,7 +36,7 @@ pub enum PipelineData {
Value(Value, Option<PipelineMetadata>), Value(Value, Option<PipelineMetadata>),
ListStream(ListStream, Option<PipelineMetadata>), ListStream(ListStream, Option<PipelineMetadata>),
ExternalStream { ExternalStream {
stdout: RawStream, stdout: Option<RawStream>,
stderr: Option<RawStream>, stderr: Option<RawStream>,
exit_code: Option<ListStream>, exit_code: Option<ListStream>,
span: Span, span: Span,
@ -93,7 +93,11 @@ impl PipelineData {
vals: s.collect(), vals: s.collect(),
span, // FIXME? span, // FIXME?
}, },
PipelineData::ExternalStream { stdout: mut s, .. } => { PipelineData::ExternalStream { stdout: None, .. } => Value::Nothing { span },
PipelineData::ExternalStream {
stdout: Some(mut s),
..
} => {
let mut items = vec![]; let mut items = vec![];
for val in &mut s { for val in &mut s {
@ -157,7 +161,10 @@ impl PipelineData {
match self { match self {
PipelineData::Value(v, ..) => Ok(v.into_string(separator, config)), PipelineData::Value(v, ..) => Ok(v.into_string(separator, config)),
PipelineData::ListStream(s, ..) => Ok(s.into_string(separator, config)), PipelineData::ListStream(s, ..) => Ok(s.into_string(separator, config)),
PipelineData::ExternalStream { stdout: s, .. } => { PipelineData::ExternalStream { stdout: None, .. } => Ok(String::new()),
PipelineData::ExternalStream {
stdout: Some(s), ..
} => {
let mut items = vec![]; let mut items = vec![];
for val in s { for val in s {
@ -236,7 +243,13 @@ impl PipelineData {
Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc)) Ok(vals.into_iter().map(f).into_pipeline_data(ctrlc))
} }
PipelineData::ListStream(stream, ..) => Ok(stream.map(f).into_pipeline_data(ctrlc)), PipelineData::ListStream(stream, ..) => Ok(stream.map(f).into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span { start: 0, end: 0 }))
}
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
let collected = stream.into_bytes()?; let collected = stream.into_bytes()?;
if let Ok(st) = String::from_utf8(collected.clone().item) { if let Ok(st) = String::from_utf8(collected.clone().item) {
@ -283,7 +296,13 @@ impl PipelineData {
PipelineData::ListStream(stream, ..) => { PipelineData::ListStream(stream, ..) => {
Ok(stream.flat_map(f).into_pipeline_data(ctrlc)) Ok(stream.flat_map(f).into_pipeline_data(ctrlc))
} }
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span { start: 0, end: 0 }))
}
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
let collected = stream.into_bytes()?; let collected = stream.into_bytes()?;
if let Ok(st) = String::from_utf8(collected.clone().item) { if let Ok(st) = String::from_utf8(collected.clone().item) {
@ -324,7 +343,13 @@ impl PipelineData {
Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc)) Ok(vals.into_iter().filter(f).into_pipeline_data(ctrlc))
} }
PipelineData::ListStream(stream, ..) => Ok(stream.filter(f).into_pipeline_data(ctrlc)), PipelineData::ListStream(stream, ..) => Ok(stream.filter(f).into_pipeline_data(ctrlc)),
PipelineData::ExternalStream { stdout: stream, .. } => { PipelineData::ExternalStream { stdout: None, .. } => {
Ok(PipelineData::new(Span { start: 0, end: 0 }))
}
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => {
let collected = stream.into_bytes()?; let collected = stream.into_bytes()?;
if let Ok(st) = String::from_utf8(collected.clone().item) { if let Ok(st) = String::from_utf8(collected.clone().item) {
@ -414,7 +439,11 @@ impl Iterator for PipelineIterator {
PipelineData::Value(Value::Nothing { .. }, ..) => None, PipelineData::Value(Value::Nothing { .. }, ..) => None,
PipelineData::Value(v, ..) => Some(std::mem::take(v)), PipelineData::Value(v, ..) => Some(std::mem::take(v)),
PipelineData::ListStream(stream, ..) => stream.next(), PipelineData::ListStream(stream, ..) => stream.next(),
PipelineData::ExternalStream { stdout: stream, .. } => stream.next().map(|x| match x { PipelineData::ExternalStream { stdout: None, .. } => None,
PipelineData::ExternalStream {
stdout: Some(stream),
..
} => stream.next().map(|x| match x {
Ok(x) => x, Ok(x) => x,
Err(err) => Value::Error { error: err }, Err(err) => Value::Error { error: err },
}), }),

View File

@ -100,7 +100,12 @@ pub fn print_table_or_error(
); );
match table { match table {
Ok(table) => { Ok(mut table) => {
let exit_code = match &mut table {
PipelineData::ExternalStream { exit_code, .. } => exit_code.take(),
_ => None,
};
for item in table { for item in table {
let stdout = std::io::stdout(); let stdout = std::io::stdout();
@ -120,6 +125,10 @@ pub fn print_table_or_error(
Err(err) => eprintln!("{}", err), Err(err) => eprintln!("{}", err),
}; };
} }
if let Some(exit_code) = exit_code {
let _: Vec<_> = exit_code.into_iter().collect();
}
} }
Err(error) => { Err(error) => {
let working_set = StateWorkingSet::new(engine_state); let working_set = StateWorkingSet::new(engine_state);

View File

@ -172,11 +172,11 @@ fn main() -> Result<()> {
let buf_reader = BufReader::new(stdin); let buf_reader = BufReader::new(stdin);
PipelineData::ExternalStream { PipelineData::ExternalStream {
stdout: RawStream::new( stdout: Some(RawStream::new(
Box::new(BufferedReader::new(buf_reader)), Box::new(BufferedReader::new(buf_reader)),
Some(ctrlc), Some(ctrlc),
redirect_stdin.span, redirect_stdin.span,
), )),
stderr: None, stderr: None,
exit_code: None, exit_code: None,
span: redirect_stdin.span, span: redirect_stdin.span,