mirror of
https://github.com/nushell/nushell.git
synced 2025-05-30 06:39:33 +02:00
Eval external command result immediately when using do
command with -c
(#6645)
* make capture error works better in do command * remove into string test because we have no way to generate Value::Error for now
This commit is contained in:
parent
6f59167960
commit
530ff3893e
@ -2,7 +2,8 @@ use nu_engine::{eval_block, CallExt};
|
|||||||
use nu_protocol::ast::Call;
|
use nu_protocol::ast::Call;
|
||||||
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
use nu_protocol::engine::{CaptureBlock, Command, EngineState, Stack};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
Category, Example, IntoPipelineData, PipelineData, Signature, SyntaxShape, Value,
|
Category, Example, ListStream, PipelineData, RawStream, ShellError, Signature, SyntaxShape,
|
||||||
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -102,9 +103,75 @@ impl Command for Do {
|
|||||||
Err(_) => Ok(PipelineData::new(call.head)),
|
Err(_) => Ok(PipelineData::new(call.head)),
|
||||||
}
|
}
|
||||||
} else if capture_errors {
|
} else if capture_errors {
|
||||||
|
// collect stdout and stderr and check exit code.
|
||||||
|
// if exit code is not 0, return back ShellError.
|
||||||
match result {
|
match result {
|
||||||
Ok(x) => Ok(x),
|
Ok(PipelineData::ExternalStream {
|
||||||
Err(err) => Ok((Value::Error { error: err }).into_pipeline_data()),
|
stdout,
|
||||||
|
stderr,
|
||||||
|
exit_code,
|
||||||
|
span,
|
||||||
|
metadata,
|
||||||
|
}) => {
|
||||||
|
// collect all output first.
|
||||||
|
let mut stderr_ctrlc = None;
|
||||||
|
let stderr_msg = match stderr {
|
||||||
|
None => "".to_string(),
|
||||||
|
Some(stderr_stream) => {
|
||||||
|
stderr_ctrlc = stderr_stream.ctrlc.clone();
|
||||||
|
stderr_stream.into_string().map(|s| s.item)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut stdout_ctrlc = None;
|
||||||
|
let stdout_msg = match stdout {
|
||||||
|
None => "".to_string(),
|
||||||
|
Some(stdout_stream) => {
|
||||||
|
stdout_ctrlc = stdout_stream.ctrlc.clone();
|
||||||
|
stdout_stream.into_string().map(|s| s.item)?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut exit_code_ctrlc = None;
|
||||||
|
let exit_code: Vec<Value> = match exit_code {
|
||||||
|
None => vec![],
|
||||||
|
Some(exit_code_stream) => {
|
||||||
|
exit_code_ctrlc = exit_code_stream.ctrlc.clone();
|
||||||
|
exit_code_stream.into_iter().collect()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if let Some(Value::Int { val: code, .. }) = exit_code.last() {
|
||||||
|
// if exit_code is not 0, it indicates error occured, return back Err.
|
||||||
|
if *code != 0 {
|
||||||
|
return Err(ShellError::ExternalCommand(
|
||||||
|
"External command runs to failed".to_string(),
|
||||||
|
stderr_msg,
|
||||||
|
span,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// construct pipeline data to our caller
|
||||||
|
Ok(PipelineData::ExternalStream {
|
||||||
|
stdout: Some(RawStream::new(
|
||||||
|
Box::new(vec![Ok(stdout_msg.into_bytes())].into_iter()),
|
||||||
|
stdout_ctrlc,
|
||||||
|
span,
|
||||||
|
)),
|
||||||
|
stderr: Some(RawStream::new(
|
||||||
|
Box::new(vec![Ok(stderr_msg.into_bytes())].into_iter()),
|
||||||
|
stderr_ctrlc,
|
||||||
|
span,
|
||||||
|
)),
|
||||||
|
exit_code: Some(ListStream::from_stream(
|
||||||
|
exit_code.into_iter(),
|
||||||
|
exit_code_ctrlc,
|
||||||
|
)),
|
||||||
|
span,
|
||||||
|
metadata,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Ok(other) => Ok(other),
|
||||||
|
Err(e) => Err(e),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
|
@ -5,11 +5,47 @@ fn capture_errors_works() {
|
|||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
cwd: ".", pipeline(
|
cwd: ".", pipeline(
|
||||||
r#"
|
r#"
|
||||||
do -c {$env.use} | describe
|
do -c {$env.use}
|
||||||
"#
|
"#
|
||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(actual.out, "error");
|
assert!(actual.err.contains("column_not_found"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capture_errors_works_for_external() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
do -c {nu --testbin fail}
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
assert!(actual.err.contains("External command runs to failed"));
|
||||||
|
assert_eq!(actual.out, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capture_errors_works_for_external_with_pipeline() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
do -c {nu --testbin fail} | echo `text`
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
assert!(actual.err.contains("External command runs to failed"));
|
||||||
|
assert_eq!(actual.out, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn capture_errors_works_for_external_with_semicolon() {
|
||||||
|
let actual = nu!(
|
||||||
|
cwd: ".", pipeline(
|
||||||
|
r#"
|
||||||
|
do -c {nu --testbin fail}; echo `text`
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
assert!(actual.err.contains("External command runs to failed"));
|
||||||
|
assert_eq!(actual.out, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -172,18 +172,6 @@ fn from_nothing() {
|
|||||||
assert_eq!(actual.out, "");
|
assert_eq!(actual.out, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn from_error() {
|
|
||||||
let actual = nu!(
|
|
||||||
cwd: ".", pipeline(
|
|
||||||
r#"
|
|
||||||
do -c {$env.use} | into string
|
|
||||||
"#
|
|
||||||
));
|
|
||||||
|
|
||||||
assert_eq!(actual.out, "nu::shell::column_not_found");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn int_into_string() {
|
fn int_into_string() {
|
||||||
let actual = nu!(
|
let actual = nu!(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user