use crate::log;
use camino::Utf8Path;
use duct::Expression;
use std::ffi::OsString;
use std::fmt::Write;
use std::io;
use std::process::Output;
use tracing::Level;
pub fn cmd<T, U>(program: T, args: U) -> Expression
where
T: duct::IntoExecutablePath + Clone,
U: IntoIterator + Clone,
<U as IntoIterator>::Item: Into<OsString>,
{
cmd_log(Level::INFO, program, args)
}
pub fn cmd_log<T, U>(l: Level, program: T, args: U) -> Expression
where
T: duct::IntoExecutablePath + Clone,
U: IntoIterator + Clone,
U::Item: Into<OsString>,
{
let mut formatted_cmd = format!(
"Running command: {program}",
program = shell_escape::escape(program.clone().to_executable().to_string_lossy())
);
for arg in args.clone() {
write!(
formatted_cmd,
" {arg}",
arg = shell_escape::escape(arg.into().to_string_lossy())
)
.expect("Writing to a string should never fail.");
}
log!(l, "{formatted_cmd}");
duct::cmd(program, args)
}
#[macro_export]
macro_rules! cmd {
( $program:expr $(, $arg:expr )* $(,)? ) => {
{
use std::ffi::OsString;
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
$crate::exec::cmd_log(tracing::Level::INFO, $program, args)
}
};
}
#[macro_export]
macro_rules! cmd_debug {
( $program:expr $(, $arg:expr )* $(,)? ) => {
{
use std::ffi::OsString;
let args: &[OsString] = &[$( Into::<OsString>::into($arg) ),*];
$crate::exec::cmd_log(tracing::Level::DEBUG, $program, args)
}
};
}
#[macro_export]
macro_rules! cmd_if_wet {
( $dry_run:expr, $program:expr $(, $arg:expr )* $(,)? ) => {
{
use std::ffi::OsString;
let mut actual_program = $program;
let args: Vec<OsString> = if $dry_run {
actual_program = "true";
vec![OsString::from("[Dry Run]"), Into::<OsString>::into($program), $( Into::<OsString>::into($arg) ),*]
} else {
vec![$( Into::<OsString>::into($arg) ),*]
};
$crate::exec::cmd_log(tracing::Level::INFO, actual_program, &args)
}
};
}
#[macro_export]
macro_rules! cmd_debug_if_wet {
( $dry_run:expr, $program:expr $(, $arg:expr )* $(,)? ) => {
{
use std::ffi::OsString;
let mut actual_program = $program;
let args: Vec<OsString> = if $dry_run {
actual_program = "true";
vec![OsString::from("[Dry Run]"), Into::<OsString>::into($program), $( Into::<OsString>::into($arg) ),*]
} else {
vec![$( Into::<OsString>::into($arg) ),*]
};
$crate::exec::cmd_log(tracing::Level::DEBUG, actual_program, &args)
}
};
}
pub trait UpDuct {
fn run_with(&self, stdout_fn: fn(&Expression) -> Expression) -> io::Result<Output>;
fn run_with_path(&self, path: &Utf8Path) -> io::Result<Output>;
fn run_with_inherit(&self) -> io::Result<Output>;
}
impl UpDuct for Expression {
fn run_with(&self, stdout_fn: fn(&Expression) -> Expression) -> io::Result<Output> {
#[allow(clippy::disallowed_methods)]
stdout_fn(self).run()
}
fn run_with_path(&self, path: &Utf8Path) -> io::Result<Output> {
#[allow(clippy::disallowed_methods)]
self.stdout_path(path).run()
}
fn run_with_inherit(&self) -> io::Result<Output> {
#[allow(clippy::disallowed_methods)]
self.run()
}
}