use std::ffi::OsStr;
use std::process::Stdio;
use tokio::process::Command;
use crate::error::{ScriptError, ScriptResult};
use crate::output::Output;
#[derive(Debug)]
pub struct CommandBuilder {
cmd: Command,
}
impl CommandBuilder {
pub fn new<S: AsRef<OsStr>>(program: S) -> Self {
Self {
cmd: Command::new(program),
}
}
pub fn arg<S: AsRef<OsStr>>(mut self, arg: S) -> Self {
let _ = self.cmd.arg(arg);
self
}
pub fn args<I, S>(mut self, args: I) -> Self
where
I: IntoIterator<Item = S>,
S: AsRef<OsStr>,
{
let _ = self.cmd.args(args);
self
}
pub fn env<K, V>(mut self, key: K, value: V) -> Self
where
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
let _ = self.cmd.env(key, value);
self
}
pub fn envs<I, K, V>(mut self, vars: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: AsRef<OsStr>,
V: AsRef<OsStr>,
{
let _ = self.cmd.envs(vars);
self
}
pub fn env_clear(mut self) -> Self {
let _ = self.cmd.env_clear();
self
}
pub fn env_remove<K>(mut self, key: K) -> Self
where
K: AsRef<OsStr>,
{
let _ = self.cmd.env_remove(key);
self
}
pub fn current_dir<D>(mut self, dir: D) -> Self
where
D: AsRef<std::path::Path>,
{
let _ = self.cmd.current_dir(dir);
self
}
pub fn stdin<T: Into<Stdio>>(mut self, stdin: T) -> Self {
let _ = self.cmd.stdin(stdin);
self
}
pub fn stdout<T: Into<Stdio>>(mut self, stdout: T) -> Self {
let _ = self.cmd.stdout(stdout);
self
}
pub fn stderr<T: Into<Stdio>>(mut self, stderr: T) -> Self {
let _ = self.cmd.stderr(stderr);
self
}
pub fn capture_output(mut self) -> Self {
let _ = self.cmd.stdout(Stdio::piped());
let _ = self.cmd.stderr(Stdio::piped());
self
}
pub fn inherit_stdin(mut self) -> Self {
let _ = self.cmd.stdin(Stdio::inherit());
self
}
pub fn inherit_stdout(mut self) -> Self {
let _ = self.cmd.stdout(Stdio::inherit());
self
}
pub fn inherit_stderr(mut self) -> Self {
let _ = self.cmd.stderr(Stdio::inherit());
self
}
pub fn null_stdin(mut self) -> Self {
let _ = self.cmd.stdin(Stdio::null());
self
}
pub fn null_stdout(mut self) -> Self {
let _ = self.cmd.stdout(Stdio::null());
self
}
pub fn null_stderr(mut self) -> Self {
let _ = self.cmd.stderr(Stdio::null());
self
}
pub fn kill_on_drop(mut self, kill: bool) -> Self {
let _ = self.cmd.kill_on_drop(kill);
self
}
pub async fn spawn(&mut self) -> std::io::Result<tokio::process::Child> {
self.cmd.spawn()
}
pub async fn output(&mut self) -> std::io::Result<Output> {
let output = self.cmd.output().await?;
Ok(Output::new(output.stdout, output.stderr, output.status))
}
pub async fn execute(&mut self) -> ScriptResult<Output> {
self.output().await.map_err(ScriptError::IoError)
}
pub async fn execute_with_timeout(
mut self,
timeout: std::time::Duration,
) -> ScriptResult<Output> {
use tokio::time;
match time::timeout(timeout, self.cmd.output()).await {
Ok(Ok(output)) => Ok(Output::new(output.stdout, output.stderr, output.status)),
Ok(Err(e)) => Err(ScriptError::IoError(e)),
Err(_) => Err(ScriptError::Timeout(timeout)),
}
}
pub async fn status(&mut self) -> std::io::Result<std::process::ExitStatus> {
self.cmd.status().await
}
}