use std::{
ffi::{
OsStr,
OsString,
},
path::{
Path,
PathBuf,
},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Command {
program: OsString,
args: Vec<OsString>,
working_directory: Option<PathBuf>,
envs: Vec<(OsString, OsString)>,
}
impl Command {
#[inline]
pub fn new(program: &str) -> Self {
Self {
program: OsString::from(program),
args: Vec::new(),
working_directory: None,
envs: Vec::new(),
}
}
#[cfg(not(windows))]
#[inline]
pub fn shell(command_line: &str) -> Self {
Self::new("sh").arg("-c").arg(command_line)
}
#[cfg(windows)]
#[inline]
pub fn shell(command_line: &str) -> Self {
Self::new("cmd").arg("/C").arg(command_line)
}
#[inline]
pub fn arg(mut self, arg: &str) -> Self {
self.args.push(OsString::from(arg));
self
}
#[inline]
pub fn args(mut self, args: &[&str]) -> Self {
self.args.extend(args.iter().map(OsString::from));
self
}
#[inline]
pub fn working_directory<P>(mut self, working_directory: P) -> Self
where
P: Into<PathBuf>,
{
self.working_directory = Some(working_directory.into());
self
}
#[inline]
pub fn env(mut self, key: &str, value: &str) -> Self {
self.envs.push((OsString::from(key), OsString::from(value)));
self
}
#[inline]
pub fn program(&self) -> &OsStr {
&self.program
}
#[inline]
pub fn arguments(&self) -> &[OsString] {
&self.args
}
#[inline]
pub fn working_directory_override(&self) -> Option<&Path> {
self.working_directory.as_deref()
}
#[inline]
pub fn environment(&self) -> &[(OsString, OsString)] {
&self.envs
}
pub(crate) fn display_command(&self) -> String {
let mut text = self.program.to_string_lossy().into_owned();
for arg in &self.args {
text.push(' ');
text.push_str(&arg.to_string_lossy());
}
text
}
}