macro_rules! cmd {
(@arg $ident:ident) => { stringify!($ident) };
(@arg $literal:literal) => { $literal };
(@arg ($expr:expr)) => { $expr };
(@stdout $cmd:ident -> String) => { std::process::Stdio::piped() };
(@stdout $cmd:ident $(-> $ty:ident)?) => { std::io::stderr() };
(@success $out:ident -> bool) => { true };
(@success $out:ident $(-> $ty:ident)?) => { $out.status.success() };
(@out $out:ident -> bool) => { $out.status.success() };
(@out $out:ident -> String) => {{
let mut out = $out.stdout;
if out.last() == Some(&b'\n') {
out.pop();
}
String::from_utf8(out)?
}};
(@out $out:ident) => { () };
([$cmd0:tt $($cmd_args:tt)*] $([$($args:tt)*])? $(-> $ret:tt)? $(in $path:expr)?) => {{
let cmd0 = $crate::cmd::cmd!(@arg $cmd0);
let cmd_args: [&str;_] = [$($crate::cmd::cmd!(@arg $cmd_args)),*];
let mut cmd = std::process::Command::new(cmd0);
cmd.args(&cmd_args)
$($(.arg($crate::cmd::cmd!(@arg $args)))?)?;
$(
if let Some(path) = $path {
cmd.current_dir(path);
}
)?
cmd.stdout($crate::cmd::cmd!(@stdout cmd $(-> $ret)?));
let output = cmd.spawn()?.wait_with_output()?;
if !$crate::cmd::cmd!(@success output $(-> $ret)?) {
color_eyre::eyre::bail!(
"Failed to run `{} {}`, returned status code {}",
cmd0,
cmd_args.join(" "),
output.status,
);
}
<color_eyre::Result<_>>::Ok($crate::cmd::cmd!(@out output $(-> $ret)?))
}};
}
pub(crate) use cmd;