diff --git a/crates/nu-cli/src/commands.rs b/crates/nu-cli/src/commands.rs index 6447a1ed0f..9a9ff72292 100644 --- a/crates/nu-cli/src/commands.rs +++ b/crates/nu-cli/src/commands.rs @@ -18,7 +18,7 @@ pub fn evaluate_commands( input: PipelineData, is_perf_true: bool, table_mode: Option, -) -> Result<()> { +) -> Result> { // Run a command (or commands) given to us by the user let (block, delta) = { if let Some(ref t_mode) = table_mode { @@ -74,7 +74,7 @@ pub fn evaluate_commands( std::process::exit(1); } - match eval_block(engine_state, stack, &block, input, false, false) { + let exit_code = match eval_block(engine_state, stack, &block, input, false, false) { Ok(pipeline_data) => { crate::eval_file::print_table_or_error(engine_state, stack, pipeline_data, &mut config) } @@ -84,11 +84,11 @@ pub fn evaluate_commands( report_error(&working_set, &err); std::process::exit(1); } - } + }; if is_perf_true { info!("evaluate {}:{}:{}", file!(), line!(), column!()); } - Ok(()) + Ok(exit_code) } diff --git a/crates/nu-cli/src/eval_file.rs b/crates/nu-cli/src/eval_file.rs index 8c01289c9b..1b247d21e9 100644 --- a/crates/nu-cli/src/eval_file.rs +++ b/crates/nu-cli/src/eval_file.rs @@ -66,7 +66,7 @@ pub fn print_table_or_error( stack: &mut Stack, mut pipeline_data: PipelineData, config: &mut Config, -) { +) -> Option { let exit_code = match &mut pipeline_data { PipelineData::ExternalStream { exit_code, .. } => exit_code.take(), _ => None, @@ -130,6 +130,14 @@ pub fn print_table_or_error( // Make sure everything has finished if let Some(exit_code) = exit_code { - let _: Vec<_> = exit_code.into_iter().collect(); + let mut exit_code: Vec<_> = exit_code.into_iter().collect(); + exit_code + .pop() + .and_then(|last_exit_code| match last_exit_code { + Value::Int { val: code, .. } => Some(code), + _ => None, + }) + } else { + None } } diff --git a/src/main.rs b/src/main.rs index 5e84837a77..e063b813cb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -237,7 +237,11 @@ fn main() -> Result<()> { if is_perf_true() { info!("-c command execution {}:{}:{}", file!(), line!(), column!()); } - ret_val + match ret_val { + Ok(Some(exit_code)) => std::process::exit(exit_code as i32), + Ok(None) => Ok(()), + Err(e) => Err(e), + } } else if !script_name.is_empty() && binary_args.interactive_shell.is_none() { #[cfg(feature = "plugin")] read_plugin_file( diff --git a/tests/shell/pipeline/commands/external.rs b/tests/shell/pipeline/commands/external.rs index 1c351f774f..b573a18100 100644 --- a/tests/shell/pipeline/commands/external.rs +++ b/tests/shell/pipeline/commands/external.rs @@ -287,6 +287,8 @@ mod external_words { } mod nu_commands { + use nu_test_support::playground::Playground; + use super::nu; #[test] @@ -298,6 +300,18 @@ mod nu_commands { assert_eq!(actual.out, "foo"); } + #[test] + fn failed_with_proper_exit_code() { + Playground::setup("external failed", |dirs, _sandbox| { + let actual = nu!(cwd: dirs.test(), r#" + nu -c "cargo build; print $env.LAST_EXIT_CODE" + "#); + + // cargo for non rust project's exit code is 101. + assert_eq!(actual.out, "101") + }) + } + #[test] fn better_arg_quoting() { let actual = nu!(cwd: ".", r#"