Skip to main content

cargo_auto_main_lib/
utils_mod.rs

1// utils_mod.rs
2
3//! Functions for various utilities.
4
5/// Print debugging to the standard error only in debug build.
6///
7/// It is easy to find where is used, because of the special name. \
8/// The tracing debug is not for the same purpose.
9#[macro_export]
10macro_rules! print_debugging {
11    ($($arg:tt)*) => ( eprintln!($($arg)*));
12}
13
14/// Macro to get source code position to log errors before propagation.
15///
16/// example:  read_to_string("x").log(pos!())?;
17#[macro_export]
18macro_rules! pos {
19    // `()` indicates that the macro takes no argument.
20    () => {
21        // The macro will expand into the contents of this block.
22        &format!("{}:{}:{}:", file!(), line!(), column!())
23    };
24}
25
26/// Trait to log the error from Result before propagation with ?.
27pub trait ResultLogError<T, E>: Sized {
28    fn log(self, file_line_column: &str) -> Self;
29    fn log_msg(self, file_line_column: &str, msg: &str) -> Self;
30}
31
32/// Implements ResultLogError for anyhow::Result.
33impl<T, E: std::fmt::Debug> ResultLogError<T, E> for core::result::Result<T, E> {
34    fn log(self, file_line_column: &str) -> Self {
35        // Returns the original result.
36        self.inspect_err(|err| tracing::debug!("automation_tasks_rs/{file_line_column} {err:?}"))
37    }
38    fn log_msg(self, file_line_column: &str, msg: &str) -> Self {
39        // Returns the original result.
40        self.inspect_err(|err| tracing::debug!("automation_tasks_rs/{file_line_column} {msg} {err:?}"))
41    }
42}
43
44/// Trait to log the None from Option before propagation as Error with ?.
45pub trait OptionLogNone<T>: Sized {
46    #[allow(dead_code)]
47    fn log(self, file_line_column: &str) -> anyhow::Result<T>;
48    fn log_msg(self, file_line_column: &str, msg: &str) -> anyhow::Result<T>;
49}
50
51/// Implements OptionLogNone for Option.
52impl<T> OptionLogNone<T> for core::option::Option<T> {
53    fn log(self, file_line_column: &str) -> anyhow::Result<T> {
54        match self {
55            Some(x) => Ok(x),
56            None => {
57                tracing::debug!("Option None: {file_line_column}");
58                anyhow::bail!("Option None: {file_line_column}")
59            }
60        }
61    }
62    fn log_msg(self, file_line_column: &str, msg: &str) -> anyhow::Result<T> {
63        match self {
64            Some(x) => Ok(x),
65            None => {
66                tracing::debug!("Option None: {msg} {file_line_column}");
67                anyhow::bail!("Option None: {msg} {file_line_column}")
68            }
69        }
70    }
71}
72
73/// Run one shell command and return true if success.
74pub fn run_shell_command_success(shell_command: &str) -> bool {
75    if !shell_command.starts_with("echo ") && !shell_command.starts_with("printf ") {
76        println!("    $ {}", shell_command);
77    }
78    match std::process::Command::new("sh").arg("-c").arg(shell_command).status() {
79        Ok(status) => status.success(),
80        Err(_err) => false,
81    }
82}