mirror of
https://github.com/sagiegurari/duckscript
synced 2024-10-06 08:02:06 +00:00
New watchdog command
This commit is contained in:
parent
c7fc320fa5
commit
b71223f5f5
|
@ -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.
|
||||
|
|
37
docs/sdk.md
37
docs/sdk.md
|
@ -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
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
|
|
29
duckscript_sdk/src/sdk/std/process/watchdog/help.md
Normal file
29
duckscript_sdk/src/sdk/std/process/watchdog/help.md
Normal 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
|
||||
```
|
131
duckscript_sdk/src/sdk/std/process/watchdog/mod.rs
Executable file
131
duckscript_sdk/src/sdk/std/process/watchdog/mod.rs
Executable 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(),
|
||||
})
|
||||
}
|
45
duckscript_sdk/src/sdk/std/process/watchdog/mod_test.rs
Normal file
45
duckscript_sdk/src/sdk/std/process/watchdog/mod_test.rs
Normal 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");
|
||||
}
|
42
test/std/process/watchdog_test.ds
Normal file
42
test/std/process/watchdog_test.ds
Normal 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
|
Loading…
Reference in a new issue