pub extern crate generic_array;
#[cfg(unix)]
use std::{env, ffi::OsString};
use std::{
ffi::OsStr,
io::{self, ErrorKind, Read, Write},
process::{Command, Output, Stdio},
};
pub use execute_command_macro::{command, command_args};
use execute_command_tokens::command_tokens;
use generic_array::{
typenum::{IsGreaterOrEqual, True, U1, U256},
ArrayLength, GenericArray,
};
pub trait Execute {
fn execute(&mut self) -> Result<Option<i32>, io::Error>;
fn execute_output(&mut self) -> Result<Output, io::Error>;
#[inline]
fn execute_check_exit_status_code(
&mut self,
expected_exit_status_code: i32,
) -> Result<(), io::Error> {
match self.execute()? {
Some(exit_status_code) if exit_status_code == expected_exit_status_code => Ok(()),
_ => Err(io::Error::other("unexpected exit status")),
}
}
fn execute_input<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
) -> Result<Option<i32>, io::Error>;
fn execute_input_output<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
) -> Result<Output, io::Error>;
#[inline]
fn execute_input_reader(&mut self, reader: &mut dyn Read) -> Result<Option<i32>, io::Error> {
self.execute_input_reader2::<U256>(reader)
}
fn execute_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
) -> Result<Option<i32>, io::Error>;
#[inline]
fn execute_input_reader_output(&mut self, reader: &mut dyn Read) -> Result<Output, io::Error> {
self.execute_input_reader_output2::<U256>(reader)
}
fn execute_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
) -> Result<Output, io::Error>;
fn execute_multiple(&mut self, others: &mut [&mut Command]) -> Result<Option<i32>, io::Error>;
fn execute_multiple_output(&mut self, others: &mut [&mut Command])
-> Result<Output, io::Error>;
fn execute_multiple_input<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
others: &mut [&mut Command],
) -> Result<Option<i32>, io::Error>;
fn execute_multiple_input_output<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
others: &mut [&mut Command],
) -> Result<Output, io::Error>;
#[inline]
fn execute_multiple_input_reader(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Option<i32>, io::Error> {
self.execute_multiple_input_reader2::<U256>(reader, others)
}
fn execute_multiple_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Option<i32>, io::Error>;
#[inline]
fn execute_multiple_input_reader_output(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Output, io::Error> {
self.execute_multiple_input_reader_output2::<U256>(reader, others)
}
fn execute_multiple_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Output, io::Error>;
}
impl Execute for Command {
#[inline]
fn execute(&mut self) -> Result<Option<i32>, io::Error> {
self.stdout(Stdio::null());
self.stderr(Stdio::null());
Ok(self.status()?.code())
}
#[inline]
fn execute_output(&mut self) -> Result<Output, io::Error> {
self.spawn()?.wait_with_output()
}
#[inline]
fn execute_input<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
) -> Result<Option<i32>, io::Error> {
self.stdin(Stdio::piped());
self.stdout(Stdio::null());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
Ok(child.wait()?.code())
}
#[inline]
fn execute_input_output<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
) -> Result<Output, io::Error> {
self.stdin(Stdio::piped());
let mut child = self.spawn()?;
child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
child.wait_with_output()
}
#[inline]
fn execute_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
) -> Result<Option<i32>, io::Error> {
self.stdin(Stdio::piped());
self.stdout(Stdio::null());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
{
let stdin = child.stdin.as_mut().unwrap();
let mut buffer: GenericArray<u8, N> = GenericArray::default();
loop {
match reader.read(&mut buffer) {
Ok(0) => break,
Ok(c) => stdin.write_all(&buffer[0..c])?,
Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
Err(err) => return Err(err),
}
}
}
Ok(child.wait()?.code())
}
#[inline]
fn execute_input_reader_output2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
) -> Result<Output, io::Error> {
self.stdin(Stdio::piped());
let mut child = self.spawn()?;
{
let stdin = child.stdin.as_mut().unwrap();
let mut buffer: GenericArray<u8, N> = GenericArray::default();
loop {
match reader.read(&mut buffer) {
Ok(0) => break,
Ok(c) => stdin.write_all(&buffer[0..c])?,
Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
Err(err) => return Err(err),
}
}
}
child.wait_with_output()
}
fn execute_multiple(&mut self, others: &mut [&mut Command]) -> Result<Option<i32>, io::Error> {
if others.is_empty() {
return self.execute();
}
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.stdout(Stdio::null());
last_other.stderr(Stdio::null());
Ok(last_other.status()?.code())
}
fn execute_multiple_output(
&mut self,
others: &mut [&mut Command],
) -> Result<Output, io::Error> {
if others.is_empty() {
return self.execute_output();
}
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.spawn()?.wait_with_output()
}
fn execute_multiple_input<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
others: &mut [&mut Command],
) -> Result<Option<i32>, io::Error> {
if others.is_empty() {
return self.execute_input(data);
}
self.stdin(Stdio::piped());
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.stdout(Stdio::null());
last_other.stderr(Stdio::null());
Ok(last_other.status()?.code())
}
fn execute_multiple_input_output<D: ?Sized + AsRef<[u8]>>(
&mut self,
data: &D,
others: &mut [&mut Command],
) -> Result<Output, io::Error> {
if others.is_empty() {
return self.execute_input_output(data);
}
self.stdin(Stdio::piped());
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
child.stdin.as_mut().unwrap().write_all(data.as_ref())?;
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.spawn()?.wait_with_output()
}
fn execute_multiple_input_reader2<N: ArrayLength + IsGreaterOrEqual<U1, Output = True>>(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Option<i32>, io::Error> {
if others.is_empty() {
return self.execute_input_reader2::<N>(reader);
}
self.stdin(Stdio::piped());
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
{
let stdin = child.stdin.as_mut().unwrap();
let mut buffer: GenericArray<u8, N> = GenericArray::default();
loop {
match reader.read(&mut buffer) {
Ok(0) => break,
Ok(c) => stdin.write_all(&buffer[0..c])?,
Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
Err(err) => return Err(err),
}
}
}
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.stdout(Stdio::null());
last_other.stderr(Stdio::null());
Ok(last_other.status()?.code())
}
fn execute_multiple_input_reader_output2<
N: ArrayLength + IsGreaterOrEqual<U1, Output = True>,
>(
&mut self,
reader: &mut dyn Read,
others: &mut [&mut Command],
) -> Result<Output, io::Error> {
if others.is_empty() {
return self.execute_input_reader_output2::<N>(reader);
}
self.stdin(Stdio::piped());
self.stdout(Stdio::piped());
self.stderr(Stdio::null());
let mut child = self.spawn()?;
{
let stdin = child.stdin.as_mut().unwrap();
let mut buffer: GenericArray<u8, N> = GenericArray::default();
loop {
match reader.read(&mut buffer) {
Ok(0) => break,
Ok(c) => stdin.write_all(&buffer[0..c])?,
Err(ref err) if err.kind() == ErrorKind::Interrupted => (),
Err(err) => return Err(err),
}
}
}
let others_length_dec = others.len() - 1;
for other in others.iter_mut().take(others_length_dec) {
other.stdin(child.stdout.unwrap());
other.stdout(Stdio::piped());
other.stderr(Stdio::null());
child = other.spawn()?;
}
let last_other = &mut others[others_length_dec];
last_other.stdin(child.stdout.unwrap());
last_other.spawn()?.wait_with_output()
}
}
#[cfg(unix)]
#[inline]
pub fn shell<S: AsRef<OsStr>>(cmd: S) -> Command {
use std::sync::LazyLock;
static SHELL: LazyLock<OsString> = LazyLock::new(|| {
env::var_os("SHELL").unwrap_or_else(|| OsString::from(String::from("sh")))
});
let mut command = Command::new(&*SHELL);
command.arg("-c");
command.arg(cmd);
command
}
#[cfg(windows)]
#[inline]
pub fn shell<S: AsRef<OsStr>>(cmd: S) -> Command {
let mut command = Command::new("cmd.exe");
command.arg("/c");
command.arg(cmd);
command
}
#[inline]
pub fn command<S: AsRef<str>>(cmd: S) -> Command {
let tokens = command_tokens(cmd);
if tokens.is_empty() {
Command::new("")
} else {
let mut command = Command::new(&tokens[0]);
command.args(&tokens[1..]);
command
}
}