New watchdog command

This commit is contained in:
sagie gur ari 2020-01-26 18:32:59 +00:00
parent c7fc320fa5
commit b71223f5f5
9 changed files with 289 additions and 2 deletions

View file

@ -2,6 +2,7 @@
### v0.1.9
* New watchdog command.
* New pid command #73
* New whoami command.
* Alias based command implementations are not checked for variable leaks.

View file

@ -63,6 +63,7 @@
* [std::process::Execute (exec)](#std__process__Execute)
* [std::process::Exit (exit, quit, q)](#std__process__Exit)
* [std::process::ProcessID (pid, process_id)](#std__process__ProcessID)
* [std::process::Watchdog (watchdog)](#std__process__Watchdog)
* [std::scope::Clear (clear_scope)](#std__scope__Clear)
* [std::string::Concat (concat)](#std__string__Concat)
* [std::string::Contains (contains)](#std__string__Contains)
@ -2380,6 +2381,42 @@ id = pid
#### Aliases:
pid, process_id
<a name="std__process__Watchdog"></a>
## std::process::Watchdog
```sh
count = watchdog [--max-retries value] [--interval value] -- command [arguments]*
```
Executes the provided native command and arguments.<br>
In case the command existed it will be executed again up to the max retries provided.<br>
The watchdog will wait the specified time in milliseconds between invocations.<br>
In case of an invalid command, the watchdog will not reattempt the invocation and will exit without retries.
#### Parameters
* --max-retries - Positive value of max retries (excluding the first invocation). value <= 0 for unlimited retries. Default is unlimited.
* --interval - The amount in milliseconds between retries. 0 for no waiting between invocations. Default is no wait.
* The command to executed (preceded by a **--** separator).
* The command arguments.
#### Return Value
The amount of invocations or false in case of any error.
#### Examples
```sh
count = watchdog --max-retries 0 -- echo test
assert_eq ${count} 1
count = watchdog --max-retries 3 --interval 10 -- echo test
assert_eq ${count} 4
```
#### Aliases:
watchdog
<a name="std__scope__Clear"></a>
## std::scope::Clear
```sh

View file

@ -45,8 +45,9 @@ impl Command for CommandImpl {
_line: usize,
) -> CommandResult {
let allow_input = output_variable.is_some();
let print_output = !allow_input;
match exec::exec(&arguments, !allow_input, allow_input, 0) {
match exec::exec(&arguments, print_output, allow_input, 0) {
Ok((stdout, stderr, exit_code)) => {
match output_variable {
Some(name) => {

View file

@ -7,7 +7,6 @@ fn common_functions() {
test::test_common_command_functions(create(""));
}
#[test]
#[test]
fn run_no_args() {
test::run_script_and_error(vec![create("")], "out = exec", "out");

View file

@ -1,6 +1,7 @@
mod exec;
mod exit;
mod process_id;
mod watchdog;
use crate::utils::pckg;
use duckscript::types::command::Commands;
@ -14,6 +15,7 @@ pub(crate) fn load(commands: &mut Commands, parent: &str) -> Result<(), ScriptEr
commands.set(exec::create(&package))?;
commands.set(exit::create(&package))?;
commands.set(process_id::create(&package))?;
commands.set(watchdog::create(&package))?;
Ok(())
}

View file

@ -0,0 +1,29 @@
```sh
count = watchdog [--max-retries value] [--interval value] -- command [arguments]*
```
Executes the provided native command and arguments.<br>
In case the command existed it will be executed again up to the max retries provided.<br>
The watchdog will wait the specified time in milliseconds between invocations.<br>
In case of an invalid command, the watchdog will not reattempt the invocation and will exit without retries.
#### Parameters
* --max-retries - Positive value of max retries (excluding the first invocation). value <= 0 for unlimited retries. Default is unlimited.
* --interval - The amount in milliseconds between retries. 0 for no waiting between invocations. Default is no wait.
* The command to executed (preceded by a **--** separator).
* The command arguments.
#### Return Value
The amount of invocations or false in case of any error.
#### Examples
```sh
count = watchdog --max-retries 0 -- echo test
assert_eq ${count} 1
count = watchdog --max-retries 3 --interval 10 -- echo test
assert_eq ${count} 4
```

View file

@ -0,0 +1,131 @@
use crate::utils::{exec, pckg};
use duckscript::types::command::{Command, CommandResult};
use std::thread;
use std::time::Duration;
#[cfg(test)]
#[path = "./mod_test.rs"]
mod mod_test;
enum LookingFor {
Flag,
MaxRetries,
Interval,
}
#[derive(Clone)]
pub(crate) struct CommandImpl {
package: String,
}
impl Command for CommandImpl {
fn name(&self) -> String {
pckg::concat(&self.package, "Watchdog")
}
fn aliases(&self) -> Vec<String> {
vec!["watchdog".to_string()]
}
fn help(&self) -> String {
include_str!("help.md").to_string()
}
fn clone_and_box(&self) -> Box<dyn Command> {
Box::new((*self).clone())
}
fn run(&self, arguments: Vec<String>) -> CommandResult {
if arguments.is_empty() {
CommandResult::Error("Command not provided.".to_string())
} else {
let mut max_retries: isize = -1;
let mut interval: u64 = 0;
let mut command_start_index = 0;
let mut index = 0;
let mut looking_for = LookingFor::Flag;
for argument in &arguments {
index = index + 1;
match looking_for {
LookingFor::Flag => match argument.as_str() {
"--" => {
command_start_index = index;
break;
}
"--max-retries" => looking_for = LookingFor::MaxRetries,
"--interval" => looking_for = LookingFor::Interval,
_ => {
return CommandResult::Error(
format!("Unexpected argument: {} found", argument).to_string(),
);
}
},
LookingFor::MaxRetries => {
max_retries = match argument.parse() {
Ok(value) => value,
Err(_) => {
return CommandResult::Error(
format!(
"Max retries value must be positive number, found: {}",
argument
)
.to_string(),
);
}
};
looking_for = LookingFor::Flag;
}
LookingFor::Interval => {
interval = match argument.parse() {
Ok(value) => value,
Err(_) => {
return CommandResult::Error(
format!(
"Interval value must be positive number, found: {}",
argument
)
.to_string(),
);
}
};
looking_for = LookingFor::Flag;
}
}
}
if command_start_index == 0 {
CommandResult::Error("Command not provided.".to_string())
} else {
let millis = Duration::from_millis(interval);
let mut attempt = 0;
loop {
attempt = attempt + 1;
match exec::exec(&arguments, false, false, command_start_index) {
Ok(_) => (),
Err(error) => return CommandResult::Error(error),
}
if max_retries <= 0 || attempt > max_retries {
break;
} else if interval > 0 {
thread::sleep(millis);
}
}
CommandResult::Continue(Some(attempt.to_string()))
}
}
}
}
pub(crate) fn create(package: &str) -> Box<dyn Command> {
Box::new(CommandImpl {
package: package.to_string(),
})
}

View file

@ -0,0 +1,45 @@
use super::*;
use crate::test;
use crate::test::CommandValidation;
#[test]
fn common_functions() {
test::test_common_command_functions(create(""));
}
#[test]
fn run_no_args() {
test::run_script_and_error(vec![create("")], "out = watchdog", "out");
}
#[test]
fn run_no_command() {
test::run_script_and_error(
vec![create("")],
"out = watchdog --max-retries 0 --interval 0",
"out",
);
}
#[test]
fn run_without_retries() {
test::run_script_and_validate(
vec![create("")],
"out = watchdog --max-retries 0 --interval 0 -- echo 1 2 3",
CommandValidation::Match("out".to_string(), "1".to_string()),
);
}
#[test]
fn run_with_retries() {
test::run_script_and_validate(
vec![create("")],
"out = watchdog --max-retries 3 --interval 0 -- echo 1 2 3",
CommandValidation::Match("out".to_string(), "4".to_string()),
);
}
#[test]
fn run_error_code_with_output() {
test::run_script_and_error(vec![create("")], "out = watchdog badcommand", "out");
}

View file

@ -0,0 +1,42 @@
function test_no_retries
count = watchdog --max-retries 0 -- echo test
assert_eq ${count} 1
end
function test_with_retries
count = watchdog --max-retries 3 -- echo test
assert_eq ${count} 4
end
function test_with_retries_and_interval
count = watchdog --max-retries 3 --interval 10 -- echo test
assert_eq ${count} 4
end
function test_bad_command
count = watchdog --max-retries 3 --interval 10 -- badcommand
assert_eq ${count} false
end
function test_negatived_max_retries
count = watchdog --max-retries -3 --interval 10 -- echo test
assert_eq ${count} 1
end
function test_invalid_interval
count = watchdog --max-retries 3 --interval -10 -- echo test
assert_eq ${count} false
end
function test_missing_command_separator
count = watchdog --max-retries 0 echo test
assert_eq ${count} false
end