Added ability to strip a command argument if it fails.

This commit is contained in:
Filipe Rodrigues 2023-08-23 15:28:54 +01:00
parent 6f5329628a
commit 4662d73997
5 changed files with 72 additions and 34 deletions

View File

@ -384,4 +384,22 @@ pub enum CommandArg<'a> {
/// Command
#[serde(borrow)]
Command(Command<'a>),
/// Command full
CommandFull {
/// Strip the command if failed
strip_on_fail: bool,
/// Command
#[serde(borrow)]
cmd: Command<'a>,
},
/// Strip on fail
StripOnFail {
/// Command
#[serde(rename = "strip_on_fail")]
#[serde(borrow)]
cmd: Command<'a>,
},
}

View File

@ -649,38 +649,38 @@ impl<'s> Builder<'s> {
cmd: &Command<CowStr<'s>>,
capture_stdout: bool,
) -> Result<String, AppError> {
let (program, args) = cmd.args.split_first().ok_or_else(|| AppError::RuleExecEmpty {
// Process all arguments
// Note: When recursing, always capture stdout
let args = cmd
.args
.iter()
.map(async move |arg| match arg {
CommandArg::Expr(arg) => Ok(Some(Cow::Borrowed(&**arg))),
CommandArg::Command { strip_on_fail, cmd } => {
let res = self.exec_cmd(rule_name, cmd, true).await;
match (res, strip_on_fail) {
(Ok(arg), _) => Ok(Some(Cow::Owned(arg))),
(Err(err), true) => {
tracing::debug!(?arg, ?err, "Stripping argument from failure");
Ok(None)
},
(Err(err), false) => Err(err),
}
},
})
.collect::<FuturesUnordered<_>>()
.try_collect::<Vec<_>>()
.await?
.into_iter()
.flatten()
.collect::<Vec<_>>();
let (program, args) = args.split_first().ok_or_else(|| AppError::RuleExecEmpty {
rule_name: rule_name.to_owned(),
})?;
// Recurse on the arguments, if any is a command
// Note: When recursing, always capture stdout
let (program, args) = tokio::try_join!(
async move {
let program = match program {
CommandArg::Expr(program) => Cow::Borrowed(&**program),
CommandArg::Command(cmd) => self.exec_cmd(rule_name, cmd, true).await?.into(),
};
Ok(program)
},
async move {
args.iter()
.map(async move |arg| {
let arg = match arg {
CommandArg::Expr(arg) => Cow::Borrowed(&**arg),
CommandArg::Command(cmd) => self.exec_cmd(rule_name, cmd, true).await?.into(),
};
Ok(arg)
})
.collect::<FuturesUnordered<_>>()
.try_collect::<Vec<_>>()
.await
}
)?;
// Create the command
let mut os_cmd = process::Command::new(&*program);
let mut os_cmd = process::Command::new(&**program);
os_cmd.args(args.iter().map(|arg| &**arg));
// Set the working directory, if we have any

View File

@ -402,7 +402,7 @@ impl AppError {
.iter()
.map(|arg| match arg {
crate::rules::CommandArg::Expr(expr) => format!("\"{expr}\""),
crate::rules::CommandArg::Command(cmd) => Self::cmd_to_string(cmd),
crate::rules::CommandArg::Command { cmd, .. } => Self::cmd_to_string(cmd),
})
.join(" ");
format!("[{inner}]")

View File

@ -242,9 +242,12 @@ impl<'s> Expander<'s> {
.args
.iter()
.map(|arg| {
let arg = match arg {
CommandArg::Expr(expr) => CommandArg::Expr(self.expand_expr_string(expr, visitor)?),
CommandArg::Command(cmd) => CommandArg::Command(self.expand_cmd(cmd, visitor)?),
let arg = match *arg {
CommandArg::Expr(ref expr) => CommandArg::Expr(self.expand_expr_string(expr, visitor)?),
CommandArg::Command { strip_on_fail, ref cmd } => CommandArg::Command {
strip_on_fail,
cmd: self.expand_cmd(cmd, visitor)?,
},
};
Ok(arg)
})

View File

@ -99,7 +99,13 @@ pub enum CommandArg<T> {
Expr(T),
/// Command
Command(Command<T>),
Command {
/// Strip the command if failed
strip_on_fail: bool,
/// Command
cmd: Command<T>,
},
}
impl<'s> CommandArg<Expr<'s>> {
@ -107,7 +113,18 @@ impl<'s> CommandArg<Expr<'s>> {
pub fn new(arg: ast::CommandArg<'s>) -> Self {
match arg {
ast::CommandArg::Expr(expr) => Self::Expr(Expr::new(expr)),
ast::CommandArg::Command(cmd) => Self::Command(Command::new(cmd)),
ast::CommandArg::Command(cmd) => Self::Command {
strip_on_fail: false,
cmd: Command::new(cmd),
},
ast::CommandArg::CommandFull { strip_on_fail, cmd } => Self::Command {
strip_on_fail,
cmd: Command::new(cmd),
},
ast::CommandArg::StripOnFail { cmd } => Self::Command {
strip_on_fail: true,
cmd: Command::new(cmd),
},
}
}
}