arpx 0.5.0

Small-scale process orchestration
Documentation
use anyhow::{Context, Result};
use arpx::BinCommand;
use std::{
    collections::HashMap,
    env::temp_dir,
    fs::{write, File},
    io::{BufRead, BufReader},
    process::{Command, Stdio},
    time::{SystemTime, UNIX_EPOCH},
};

pub struct TC {
    datetime: String,
    profile_path: String,
    pub envs: HashMap<String, String>,
    pub name: String,
    pub opts: String,
    pub profile: String,
}

impl TC {
    pub fn new(name: &str) -> Self {
        Self {
            datetime: Self::datetime(),
            envs: HashMap::new(),
            name: name.to_owned(),
            opts: String::new(),
            profile: String::new(),
            profile_path: String::new(),
        }
    }

    #[allow(dead_code)]
    pub fn env(mut self, key: &str, value: &str) -> Self {
        self.envs.insert(key.to_string(), value.to_string());

        self
    }

    pub fn profile(mut self, input: &str) -> Self {
        self.profile.push_str(input);

        let mut dir = temp_dir();
        dir.push(format!("{}_{}.yaml", self.name, self.datetime));
        self.profile_path = dir.as_path().display().to_string();

        File::create(dir)
            .context("Test profile creation failed")
            .unwrap();
        write(&self.profile_path, &self.profile).unwrap();

        self
    }

    pub fn opts(mut self, input: &str) -> Self {
        self.opts.push_str(input);

        self
    }

    pub fn run(self) -> Result<(Vec<String>, Vec<String>)> {
        let BinCommand { bin, mut args } = BinCommand::system_default();

        let test_command = format!(
            "{} -f {} {}",
            env!("CARGO_BIN_EXE_arpx"),
            self.profile_path,
            self.opts
        );
        args.push(test_command);

        let output = Command::new(bin)
            .args(args)
            .envs(self.envs)
            .current_dir(String::from(env!("CARGO_MANIFEST_DIR")))
            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .spawn()
            .context("Failed to spawn test command")?
            .wait_with_output()
            .context("Failed to wait test command")?;

        let out = BufReader::new(&*output.stdout)
            .lines()
            .map(|l| l.expect("!parse"))
            .collect();
        let err = BufReader::new(&*output.stderr)
            .lines()
            .map(|l| l.expect("!parse"))
            .collect();

        Ok((out, err))
    }

    fn datetime() -> String {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .expect("Time went backwards")
            .as_millis()
            .to_string()
    }
}