use std::time::Duration;
use anyhow::Context;
use async_std::{
process::{Command, Stdio},
task::sleep,
};
use clap::AppSettings::TrailingVarArg;
use log::debug;
use structopt::StructOpt;
#[derive(Debug, StructOpt)]
#[structopt(setting = TrailingVarArg, about)]
struct Opt {
#[structopt(short, long)]
verbose: bool,
#[structopt(short, long, parse(try_from_str = parse_duration::parse))]
wait: Option<Duration>,
#[structopt(min_values = 1, required = true)]
cmd: Vec<String>,
}
#[async_std::main]
async fn main() -> anyhow::Result<()> {
pretty_env_logger::try_init()?;
let opt = Opt::from_args_safe()?;
debug!("opt = {:?}", opt);
loop {
let mut cmd = Command::new(&opt.cmd[0]);
let cmd = cmd
.args(&opt.cmd[1..])
.stdin(Stdio::null())
.stdout(verbose_to_stdio(opt.verbose))
.stderr(verbose_to_stdio(opt.verbose));
debug!("cmd = {:?}", cmd);
let status = cmd.status().await.context("Couldn't run command")?;
debug!("status = {:?}", status);
if status.success() {
break;
}
if let Some(dur) = opt.wait {
debug!("sleep for {:?}", dur);
sleep(dur).await;
}
}
Ok(())
}
fn verbose_to_stdio(verbose: bool) -> Stdio {
match verbose {
false => Stdio::null(),
true => Stdio::inherit(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse() {
let opt = Opt::from_iter(&["wait-until", "ping", "-c", "1", "example.com"]);
assert_eq!(opt.cmd, ["ping", "-c", "1", "example.com"]);
}
}