tidploy 0.16.0

Simple deployment tool for deploying small applications and loading secrets.
Documentation
use std::{
    collections::HashMap,
    io::{BufRead, BufReader},
    process::{Command as Cmd, Stdio},
};

use camino::Utf8Path;

use crate::errors::{ProcessError, ProcessErrorKind};

pub(crate) fn process_out(bytes: Vec<u8>, err_msg: String) -> Result<String, ProcessError> {
    Ok(String::from_utf8(bytes)
        .map_err(|e| ProcessError {
            msg: err_msg,
            source: ProcessErrorKind::Decode(e),
        })?
        .trim_end()
        .to_owned())
}

/// Convenience function to create a process error.
fn err_ctx<P: AsRef<Utf8Path>>(e: impl Into<ProcessErrorKind>, info: &str, p: P) -> ProcessError {
    let msg = format!(
        "IO error {} (running entrypoint at path: {:?})",
        info,
        p.as_ref()
    );
    ProcessError {
        msg,
        source: e.into(),
    }
}

pub(crate) fn run_entrypoint<P: AsRef<Utf8Path>>(
    entrypoint_dir: P,
    entrypoint: &str,
    envs: HashMap<String, String>,
) -> Result<(), ProcessError> {
    println!("Running {}!", &entrypoint);
    let entrypoint_dir = entrypoint_dir.as_ref();
    let program_path = entrypoint_dir.join(entrypoint);
    let mut entrypoint_output = Cmd::new(&program_path)
        .current_dir(entrypoint_dir)
        .envs(&envs)
        .stdout(Stdio::piped())
        .spawn()
        .map_err(|e| err_ctx(e, "spawning process", &program_path))?;

    let entrypoint_stdout = entrypoint_output
        .stdout
        .take()
        .ok_or_else(|| err_ctx(ProcessErrorKind::NoOutput, "", &program_path))?;

    let reader = BufReader::new(entrypoint_stdout);

    reader
        .lines()
        .map_while(Result::ok)
        .for_each(|line| println!("{}", line));

    let output_stderr = entrypoint_output
        .wait_with_output()
        .map_err(|e| err_ctx(e, "reading output err", &program_path))?
        .stderr;
    if !output_stderr.is_empty() {
        println!(
            "Entrypoint {:?} failed with error: {}",
            program_path.as_path(),
            process_out(output_stderr, "Failed to decode entrypoint".to_owned())?
        )
    }
    Ok(())
}