From cb7cd678a5928233f9bc15fc7b5a450c85012fb3 Mon Sep 17 00:00:00 2001 From: sagie gur ari Date: Thu, 4 Jun 2020 16:34:14 +0000 Subject: [PATCH] New Enable to error an exec command via new --fail-on-error flag #108 --- CHANGELOG.md | 4 ++ docs/sdk.md | 6 +- .../src/sdk/std/process/exec/help.md | 6 +- .../src/sdk/std/process/exec/mod.rs | 62 ++++++++++++------- .../src/sdk/std/process/exec/mod_test.rs | 14 +++++ duckscript_sdk/src/test/mod.rs | 11 ++-- test/std/process/exec_test.ds | 13 +++- 7 files changed, 85 insertions(+), 31 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3181244..aa666b3 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## CHANGELOG +### v0.4.1 + +* New Enable to error an exec command via new --fail-on-error flag #108 + ### v0.4.0 (2020-05-07) * New set_from_array command. diff --git a/docs/sdk.md b/docs/sdk.md index 87eaf28..a06edf0 100644 --- a/docs/sdk.md +++ b/docs/sdk.md @@ -4144,7 +4144,7 @@ wget ## std::process::Execute ```sh -exec command [args]* +exec [--fail-on-error] command [args]* output = exec command [args]* stdout = set ${output.stdout} @@ -4154,6 +4154,7 @@ exit_code = set ${output.code} Executes the provided native command and arguments.
If no output variable is set, the command output will be flushed to the main out/err stream of the parent process.
+In addition, in order to fail the command in case of the child process failed, add the --fail_on_error flag.
If an output variable is set, it will be used as a base variable name from which the command stout, stderr and exit code information can be pulled from.
The actual output variable name will not be modified, instead new variables will be created using that variable name as a baseline: @@ -4163,7 +4164,8 @@ The actual output variable name will not be modified, instead new variables will #### Parameters -The command to execute and its arguments. +* --fail-on-error - If no output variable is provided, it will cause an error in case the executed processed exists with an error exist code. +* The command to execute and its arguments. #### Return Value diff --git a/duckscript_sdk/src/sdk/std/process/exec/help.md b/duckscript_sdk/src/sdk/std/process/exec/help.md index 8133455..4502833 100644 --- a/duckscript_sdk/src/sdk/std/process/exec/help.md +++ b/duckscript_sdk/src/sdk/std/process/exec/help.md @@ -1,5 +1,5 @@ ```sh -exec command [args]* +exec [--fail-on-error] command [args]* output = exec command [args]* stdout = set ${output.stdout} @@ -9,6 +9,7 @@ exit_code = set ${output.code} Executes the provided native command and arguments.
If no output variable is set, the command output will be flushed to the main out/err stream of the parent process.
+In addition, in order to fail the command in case of the child process failed, add the --fail_on_error flag.
If an output variable is set, it will be used as a base variable name from which the command stout, stderr and exit code information can be pulled from.
The actual output variable name will not be modified, instead new variables will be created using that variable name as a baseline: @@ -18,7 +19,8 @@ The actual output variable name will not be modified, instead new variables will #### Parameters -The command to execute and its arguments. +* --fail-on-error - If no output variable is provided, it will cause an error in case the executed processed exists with an error exist code. +* The command to execute and its arguments. #### Return Value diff --git a/duckscript_sdk/src/sdk/std/process/exec/mod.rs b/duckscript_sdk/src/sdk/std/process/exec/mod.rs index 47d5741..7fd71ec 100755 --- a/duckscript_sdk/src/sdk/std/process/exec/mod.rs +++ b/duckscript_sdk/src/sdk/std/process/exec/mod.rs @@ -46,28 +46,48 @@ impl Command for CommandImpl { ) -> CommandResult { let allow_input = output_variable.is_some(); let print_output = !allow_input; - - match exec::exec(&arguments, print_output, allow_input, 0) { - Ok((stdout, stderr, exit_code)) => { - match output_variable { - Some(name) => { - let mut key = String::from(&name); - key.push_str(".stdout"); - variables.insert(key.clone(), stdout); - - key = String::from(&name); - key.push_str(".stderr"); - variables.insert(key.clone(), stderr); - - key = String::from(&name); - key.push_str(".code"); - variables.insert(key.clone(), exit_code.to_string()); - } - None => (), - }; - - CommandResult::Continue(None) + let (start_index, fail_on_error) = if !arguments.is_empty() { + if arguments[0] == "--fail-on-error" { + if output_variable.is_some() { + (1, true) + } else { + (1, false) + } + } else { + (0, false) } + } else { + (0, false) + }; + + match exec::exec(&arguments, print_output, allow_input, start_index) { + Ok((stdout, stderr, exit_code)) => match output_variable { + Some(name) => { + let mut key = String::from(&name); + key.push_str(".stdout"); + variables.insert(key.clone(), stdout); + + key = String::from(&name); + key.push_str(".stderr"); + variables.insert(key.clone(), stderr); + + key = String::from(&name); + key.push_str(".code"); + variables.insert(key.clone(), exit_code.to_string()); + + CommandResult::Continue(None) + } + None => { + if fail_on_error && exit_code != 0 { + CommandResult::Error( + format!("Error while executing command, exit code: {}", exit_code) + .to_string(), + ) + } else { + CommandResult::Continue(None) + } + } + }, Err(error) => CommandResult::Error(error), } } diff --git a/duckscript_sdk/src/sdk/std/process/exec/mod_test.rs b/duckscript_sdk/src/sdk/std/process/exec/mod_test.rs index edd1761..95cce87 100644 --- a/duckscript_sdk/src/sdk/std/process/exec/mod_test.rs +++ b/duckscript_sdk/src/sdk/std/process/exec/mod_test.rs @@ -17,6 +17,20 @@ fn run_no_output() { test::run_script_and_validate(vec![create("")], "exec echo test", CommandValidation::None); } +#[test] +fn run_no_output_with_fail_on_error_valid() { + test::run_script_and_validate( + vec![create("")], + "exec --fail-on-error echo test", + CommandValidation::None, + ); +} + +#[test] +fn run_no_output_with_fail_on_error_invalid() { + test::run_script_and_error(vec![create("")], "exec --fail-on-error badcommand", ""); +} + #[test] fn run_with_output() { let context = test::run_script_and_validate( diff --git a/duckscript_sdk/src/test/mod.rs b/duckscript_sdk/src/test/mod.rs index 42039cf..c3bc1c8 100644 --- a/duckscript_sdk/src/test/mod.rs +++ b/duckscript_sdk/src/test/mod.rs @@ -226,10 +226,13 @@ pub(crate) fn run_script_and_error( let result = run_command(commands, script); match result { Ok(context) => { - assert_eq!( - context.variables.get(&output_variable.to_string()).unwrap(), - "false" - ); + if !output_variable.is_empty() { + assert_eq!( + context.variables.get(&output_variable.to_string()).unwrap(), + "false" + ); + } + assert_eq!( context .variables diff --git a/test/std/process/exec_test.ds b/test/std/process/exec_test.ds index eb38117..34e88a4 100644 --- a/test/std/process/exec_test.ds +++ b/test/std/process/exec_test.ds @@ -1,12 +1,21 @@ -fn test_echo +fn test_echo_with_output output = exec echo hello world stdout = trim ${output.stdout} stderr = trim ${output.stderr} exit_code = set ${output.code} - + assert_eq ${stdout} "hello world" assert_eq ${stderr} "" assert_eq ${exit_code} 0 end + +fn test_echo_without_output + exec echo hello world +end + +fn test_echo_with_fail_on_error_flag + exec --fail-on-error echo hello world +end +