cargo-auto 2026.306.1319

Automation tasks coded in Rust language for the workflow of Rust projects
Documentation
// utils_mod.rs

//! Functions for various utilities.

/// Print debugging to the standard error only in debug build.
///
/// It is easy to find where is used, because of the special name. \
/// The tracing debug is not for the same purpose.
#[macro_export]
macro_rules! print_debugging {
    ($($arg:tt)*) => ( eprintln!($($arg)*));
}

/// Macro to get source code position to log errors before propagation.
///
/// example:  read_to_string("x").log(pos!())?;
#[macro_export]
macro_rules! pos {
    // `()` indicates that the macro takes no argument.
    () => {
        // The macro will expand into the contents of this block.
        &format!("{}:{}:{}:", file!(), line!(), column!())
    };
}

/// Trait to log the error from Result before propagation with ?.
pub trait ResultLogError<T, E>: Sized {
    fn log(self, file_line_column: &str) -> Self;
    fn log_msg(self, file_line_column: &str, msg: &str) -> Self;
}

/// Implements ResultLogError for anyhow::Result.
impl<T, E: std::fmt::Debug> ResultLogError<T, E> for core::result::Result<T, E> {
    fn log(self, file_line_column: &str) -> Self {
        // Returns the original result.
        self.inspect_err(|err| tracing::debug!("automation_tasks_rs/{file_line_column} {err:?}"))
    }
    fn log_msg(self, file_line_column: &str, msg: &str) -> Self {
        // Returns the original result.
        self.inspect_err(|err| tracing::debug!("automation_tasks_rs/{file_line_column} {msg} {err:?}"))
    }
}

/// Trait to log the None from Option before propagation as Error with ?.
pub trait OptionLogNone<T>: Sized {
    #[allow(dead_code)]
    fn log(self, file_line_column: &str) -> anyhow::Result<T>;
    fn log_msg(self, file_line_column: &str, msg: &str) -> anyhow::Result<T>;
}

/// Implements OptionLogNone for Option.
impl<T> OptionLogNone<T> for core::option::Option<T> {
    fn log(self, file_line_column: &str) -> anyhow::Result<T> {
        match self {
            Some(x) => Ok(x),
            None => {
                tracing::debug!("Option None: {file_line_column}");
                anyhow::bail!("Option None: {file_line_column}")
            }
        }
    }
    fn log_msg(self, file_line_column: &str, msg: &str) -> anyhow::Result<T> {
        match self {
            Some(x) => Ok(x),
            None => {
                tracing::debug!("Option None: {msg} {file_line_column}");
                anyhow::bail!("Option None: {msg} {file_line_column}")
            }
        }
    }
}

/// Run one shell command and return true if success.
pub fn run_shell_command_success(shell_command: &str) -> bool {
    if !shell_command.starts_with("echo ") && !shell_command.starts_with("printf ") {
        println!("    $ {}", shell_command);
    }
    match std::process::Command::new("sh").arg("-c").arg(shell_command).status() {
        Ok(status) => status.success(),
        Err(_err) => false,
    }
}