Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,26 @@ Or until a certain date/time with `--until-time`:
Fri May 25 20:49:59 UTC 2018
$

It is possible to start commands regardles of whether a previous run had already ended by providing `--detach` option:

$ loop --every 2s --detach -- date;sleep 5;
Wed Oct 7 10:55:45 CEST 2020
Wed Oct 7 10:55:47 CEST 2020
Wed Oct 7 10:55:49 CEST 2020
Wed Oct 7 10:55:51 CEST 2020
Wed Oct 7 10:55:53 CEST 2020
Wed Oct 7 10:55:55 CEST 2020

Without the `--detach` option it would print:

$ loop --every 2s -- date;sleep 5;
Wed Oct 7 10:56:09 CEST 2020
Wed Oct 7 10:56:14 CEST 2020
Wed Oct 7 10:56:19 CEST 2020
Wed Oct 7 10:56:24 CEST 2020
Wed Oct 7 10:56:29 CEST 2020
Wed Oct 7 10:56:34 CEST 2020

### Until Conditions

`loop` can iterate until output contains a string with `--until-contains`:
Expand Down
89 changes: 89 additions & 0 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use subprocess::{Exec, ExitStatus, CaptureData};
use crate::ErrorCode;
use crate::Opt;

pub struct Response{
pub options: Opt,
pub result: CaptureData,
pub last_result: Option<CaptureData>,
}

impl Response{
pub fn should_stop(&self) -> bool {
let result_checks = [
stop_if_fail,
stop_if_success,
stop_if_contains,
stop_if_match,
stop_if_error
];

result_checks.iter().any(|&fun| fun(&self.result, &self.options))
|| should_stop_on_comparison(&self.options, &self.last_result.as_ref(), &self.result)
}
}

fn stop_if_contains(result: &CaptureData, options: &Opt) -> bool{
// --until-contains
let result_str = result.stdout_str();
if let Some(string) = &options.until_contains {
result_str.contains(string)
} else {
false
}
}
fn stop_if_match(result: &CaptureData, options: &Opt) -> bool{
// --until-match
let result_str = result.stdout_str();
if let Some(regex) = &options.until_match {
regex.captures(&result_str).is_some()
} else {
false
}
}
fn stop_if_error(result: &CaptureData, options: &Opt) -> bool{
if let Some(error_code) = &options.until_error {
match error_code {
ErrorCode::Any => !result.exit_status.success(),
ErrorCode::Code(code) => result.exit_status == ExitStatus::Exited(*code)
}
} else {
false
}
}

fn stop_if_success(result: &CaptureData, options: &Opt) -> bool{
options.until_success && result.exit_status.success()
}
fn stop_if_fail(result: &CaptureData, options: &Opt) -> bool{
options.until_fail && !(result.exit_status.success())
}

fn is_equivalent(previous: &Option<&CaptureData>, current: &CaptureData) -> bool{
if let Some(prev) = previous{
prev.stdout == current.stdout
} else {
false
}
}

fn is_differrent(previous: &Option<&CaptureData>, current: &CaptureData) -> bool{
if let Some(prev) = previous{
prev.stdout != current.stdout
} else {
false
}
}

pub fn should_stop_on_comparison(options: &Opt, previous: &Option<&CaptureData>, current: &CaptureData) -> bool {

(options.until_same && is_equivalent(&previous.clone(), &current.clone()))
|| (options.until_changes && is_differrent(&previous.clone(), &current.clone()))
}

pub fn execute(opt: Opt) -> (Opt, CaptureData) {
let result = Exec::shell(opt.input.join(""))
.capture().unwrap();
(opt, result)
}

Loading