use std::{
borrow::Borrow,
ffi::OsStr,
path::Path,
process::{Command, Stdio},
};
pub trait CommandExtra: Sized {
fn with_current_dir(self, dir: impl AsRef<Path>) -> Self;
fn with_env(self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Self;
fn without_env(self, key: impl AsRef<OsStr>) -> Self;
fn with_no_env(self) -> Self;
fn with_arg(self, arg: impl AsRef<OsStr>) -> Self;
fn with_stdin(self, stdio: Stdio) -> Self;
fn with_stdout(self, stdio: Stdio) -> Self;
fn with_stderr(self, stdio: Stdio) -> Self;
#[inline]
fn with_args<Args>(self, args: Args) -> Self
where
Args: IntoIterator,
Args::Item: AsRef<OsStr>,
{
args.into_iter().fold(self, Self::with_arg)
}
#[inline]
fn with_envs<Envs, Key, Value>(self, envs: Envs) -> Self
where
Envs: IntoIterator,
Envs::Item: Borrow<(Key, Value)>,
Key: AsRef<OsStr>,
Value: AsRef<OsStr>,
{
envs.into_iter().fold(self, |cmd, pair| {
let (key, value) = pair.borrow();
cmd.with_env(key, value)
})
}
#[inline]
fn without_envs<Keys>(self, keys: Keys) -> Self
where
Keys: IntoIterator,
Keys::Item: AsRef<OsStr>,
{
keys.into_iter().fold(self, Self::without_env)
}
}
macro_rules! impl_unit {
($(#[$attrs:meta])* $command:ty) => {
$(#[$attrs])*
impl CommandExtra for $command {
#[inline]
fn with_current_dir(mut self, dir: impl AsRef<Path>) -> Self {
self.current_dir(dir);
self
}
#[inline]
fn with_env(mut self, key: impl AsRef<OsStr>, value: impl AsRef<OsStr>) -> Self {
self.env(key, value);
self
}
#[inline]
fn without_env(mut self, key: impl AsRef<OsStr>) -> Self {
self.env_remove(key);
self
}
#[inline]
fn with_no_env(mut self) -> Self {
self.env_clear();
self
}
#[inline]
fn with_arg(mut self, arg: impl AsRef<OsStr>) -> Self {
self.arg(arg);
self
}
#[inline]
fn with_stdin(mut self, stdio: Stdio) -> Self {
self.stdin(stdio);
self
}
#[inline]
fn with_stdout(mut self, stdio: Stdio) -> Self {
self.stdout(stdio);
self
}
#[inline]
fn with_stderr(mut self, stdio: Stdio) -> Self {
self.stderr(stdio);
self
}
}
};
}
macro_rules! impl_set {
($(#[$attrs:meta])* $base:ty) => {
impl_unit!($(#[$attrs])* $base);
impl_unit!($(#[$attrs])* Box<$base>);
};
}
impl_set!(Command);
impl_set!(
#[cfg(feature = "async_process")]
async_process::Command
);
impl_set!(
#[cfg(feature = "tokio_process")]
tokio::process::Command
);