rustible/src/utils/cmd.rs

151 lines
3.5 KiB
Rust
Raw Normal View History

2023-04-19 21:49:30 +02:00
use duct::cmd as duct_cmd;
use std::collections::HashMap;
2023-04-19 21:49:30 +02:00
use std::path::PathBuf;
2023-10-05 17:58:41 +02:00
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
2023-04-19 21:49:30 +02:00
pub struct Cmd {
2023-10-05 17:58:41 +02:00
program: String,
#[serde(default)]
args: Vec<String>,
#[serde(default)]
stdin: Option<String>,
#[serde(default)]
chdir: Option<PathBuf>,
#[serde(default)]
env: HashMap<String, String>,
2023-04-19 21:49:30 +02:00
}
impl Cmd {
pub fn new<T: AsRef<str>>(program: T) -> Cmd {
Cmd {
program: program.as_ref().to_string(),
args: Vec::new(),
stdin: None,
chdir: None,
env: HashMap::new(),
2023-04-19 21:49:30 +02:00
}
}
pub fn arg<T: AsRef<str>>(self, arg: T) -> Cmd {
let Self { program, mut args, stdin, chdir, env, .. } = self;
2023-04-19 21:49:30 +02:00
args.push(arg.as_ref().to_string());
Cmd {
program,
args,
stdin,
chdir,
env,
2023-04-19 21:49:30 +02:00
}
}
pub fn args<T: AsRef<str>>(self, new_args: & [ T ]) -> Cmd {
let Self { program, mut args, stdin, chdir, env, .. } = self;
2023-04-19 21:49:30 +02:00
for arg in new_args {
args.push(arg.as_ref().to_string());
}
Cmd {
program,
args,
stdin,
chdir,
env,
}
}
2023-04-19 21:49:30 +02:00
pub fn stdin<T: AsRef<str>>(self, input: T) -> Cmd {
let Self { program, args, mut stdin, chdir, env, .. } = self;
2023-04-19 21:49:30 +02:00
stdin = if let Some(mut s) = stdin {
s.push_str(input.as_ref());
Some(s)
} else {
Some(input.as_ref().to_string())
};
Cmd {
program,
args,
stdin,
chdir,
env,
2023-04-19 21:49:30 +02:00
}
}
pub fn chdir<T: AsRef<str>>(self, dir: T) -> Cmd {
let Self { program, args, stdin, env, .. } = self;
2023-04-19 21:49:30 +02:00
Cmd {
program,
args,
stdin,
chdir: Some(PathBuf::from(dir.as_ref())),
env,
}
}
pub fn env<K: AsRef<str>, V: AsRef<str>>(self, key: K, value: V) -> Cmd {
let Self { program, args, stdin, chdir, mut env, .. } = self;
env.insert(key.as_ref().to_string(), value.as_ref().to_string());
Cmd {
program,
args,
stdin,
chdir,
env,
2023-04-19 21:49:30 +02:00
}
}
pub fn run(self) -> Result<CmdOutput, std::io::Error> {
let Self { program, args, stdin, chdir, env, .. } = self;
2023-04-19 21:49:30 +02:00
let mut cmd = duct_cmd(&program, &args);
if ! env.is_empty() {
for (key, value) in env {
cmd = cmd.env(key, value);
}
}
2023-04-19 21:49:30 +02:00
if let Some(stdin) = &stdin {
cmd = cmd.stdin_bytes(stdin.as_bytes());
}
if let Some(chdir) = &chdir {
cmd = cmd.dir(chdir);
}
let res = cmd.unchecked()
.stdout_capture()
.stderr_capture()
.run()?;
Ok(CmdOutput {
program,
args,
success: res.status.success(),
stdin,
dir: chdir,
stdout: String::from_utf8(res.stdout).unwrap(),
stderr: String::from_utf8(res.stderr).unwrap(),
})
}
}
#[derive(Clone, Debug, Serialize)]
pub struct CmdOutput {
pub program: String,
pub args: Vec<String>,
pub success: bool,
pub stdin: Option<String>,
pub dir: Option<PathBuf>,
pub stdout: String,
pub stderr: String,
}