use std::env;
use std::process::Command;
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("io error")]
Io(#[from] std::io::Error),
#[error("key is empty")]
EmptyKey,
#[error("command error")]
CommandError,
}
pub fn parse_input<T: AsRef<str>>(args: &[T]) -> (Vec<(&str, &str)>, usize) {
let mut idx = 0;
let mut v = vec![];
for i in args {
if let Some(pair) = i.as_ref().split_once('=') {
v.push(pair);
idx += 1;
} else {
break;
}
}
(v, idx)
}
pub fn run(cmd: &str, cmd_args: &[String], envs: &Vec<(&str, &str)>) -> Result<(), Error> {
let mut cmd = Command::new(cmd);
for (key, value) in envs {
if key.is_empty() {
return Err(Error::EmptyKey);
}
cmd.env(key, value);
}
cmd.stdin(std::process::Stdio::inherit())
.stdout(std::process::Stdio::inherit())
.stderr(std::process::Stdio::inherit());
cmd.args(cmd_args);
cmd.output()?;
Ok(())
}
pub fn cross_env() -> Result<(), Error> {
let args: Vec<String> = env::args().skip(1).collect();
let (envs, idx) = parse_input(&args);
let cmd = &args[idx];
let cmd_args = &args[idx + 1..];
run(cmd, cmd_args, &envs)
}
#[cfg(test)]
mod test {
use crate::parse_input;
#[test]
fn test_parse_input() {
for (args, expect_envs, expect_idx) in [
(vec!["a=1"], vec![("a", "1")], 1),
(vec!["a=1", "b=2"], vec![("a", "1"), ("b", "2")], 2),
] {
let (envs, idx) = parse_input(&args);
assert_eq!(envs, expect_envs);
assert_eq!(idx, expect_idx);
}
}
}