magicpak 1.4.0

Build minimal docker images without static linking
Documentation
use std::io::Result;
use std::process::{Child, Command, ExitStatus, Output};

pub trait CommandLogExt {
    fn spawn_with_log(&mut self) -> Result<Child>;

    fn output_with_log(&mut self) -> Result<Output>;

    fn status_with_log(&mut self) -> Result<ExitStatus> {
        Ok(self.output_with_log()?.status)
    }
}

pub trait ChildLogExt {
    fn wait_output_with_log(self) -> Result<Output>;
}

impl CommandLogExt for Command {
    fn spawn_with_log(&mut self) -> Result<Child> {
        tracing::debug!(command = ?self, "spawn");
        self.spawn()
    }

    fn output_with_log(&mut self) -> Result<Output> {
        let output = self.output()?;
        let command_line = format!("{:?}", self);
        log_output(&command_line, &output);
        Ok(output)
    }
}

impl ChildLogExt for Child {
    fn wait_output_with_log(self) -> Result<Output> {
        let output = self.wait_with_output()?;
        log_output("<spawned>", &output);
        Ok(output)
    }
}

pub fn log_output(command_line: &str, output: &Output) {
    let mut message = format!("command: {}\n  => {}", command_line, output.status);

    if !output.stdout.is_empty() {
        let stdout = format_lines(String::from_utf8_lossy(&output.stdout));
        message.push_str("\n  => stdout: ");
        message.push_str(&stdout);
    }
    if !output.stderr.is_empty() {
        let stderr = format_lines(String::from_utf8_lossy(&output.stderr));
        message.push_str("\n  => stderr: ");
        message.push_str(&stderr);
    }

    tracing::debug!("{}", message);
}

fn format_lines<S>(s: S) -> String
where
    S: AsRef<str>,
{
    let string = s.as_ref().trim();
    if string.lines().nth(1).is_some() {
        string
            .lines()
            .fold(String::new(), |acc, line| format!("{}\n  |  {}", acc, line))
    } else {
        string.to_owned()
    }
}