use std::process::Command;
pub trait IsFailure {
fn failed(&self) -> bool;
fn code(&self) -> i32;
fn stdout(&self) -> Option<String>;
fn stderr(&self) -> Option<String>;
}
impl IsFailure for Result<Success, Failure> {
fn failed(&self) -> bool {
self.is_err()
}
fn code(&self) -> i32 {
match self {
Ok(success) => success.code,
Err(failure) => failure.code,
}
}
fn stdout(&self) -> Option<String> {
match self {
Ok(success) => success.stdout.clone(),
Err(failure) => failure.stdout.clone(),
}
}
fn stderr(&self) -> Option<String> {
match self {
Ok(_) => None,
Err(failure) => failure.stderr.clone(),
}
}
}
pub struct Success {
pub stdout: Option<String>,
pub code: i32,
}
pub struct Failure {
pub stderr: Option<String>,
pub stdout: Option<String>,
pub code: i32,
}
pub struct Git {
command: Vec<String>,
}
impl Git {
pub fn new<T>(items: T) -> Git
where
T: IntoIterator,
T::Item: ToString,
{
Git {
command: items.into_iter().map(|x| x.to_string()).collect(),
}
}
pub fn stream(&self) -> Result<Success, Failure> {
let mut out = Command::new("git");
for argument in self.command.clone() {
out.arg(argument);
}
let output = out.status().expect("Failed to execute `git`");
if output.success() {
Ok(Success {
stdout: None,
code: output.code().unwrap_or(0)
})
} else {
Err(Failure{
stderr: None,
stdout: None,
code: output.code().unwrap_or(1)
})
}
}
pub fn run(&self) -> Result<Success, Failure> {
let mut out = Command::new("git");
for argument in self.command.clone() {
out.arg(argument);
}
let output = out.output().expect("Failed to execute `git`");
if output.status.success() {
Ok(Success {
stdout: Some(String::from_utf8(output.stdout).unwrap_or("".to_string())),
code: output.status.code().unwrap_or(0)
})
} else {
Err(Failure {
stderr: Some(String::from_utf8(output.stderr).unwrap_or("".to_string())),
stdout: Some(String::from_utf8(output.stdout).unwrap_or("".to_string())),
code: output.status.code().unwrap_or(1)
})
}
}
}
pub trait Run {
fn run(self) -> Result<Success, Failure>;
fn stream(self) -> Result<Success, Failure>;
}
impl<T> Run for T
where
T: IntoIterator,
T::Item: ToString,
{
fn run(self) -> Result<Success, Failure> {
Git::new(self.into_iter().map(|x| x.to_string())).run()
}
fn stream(self) -> Result<Success, Failure> {
Git::new(self.into_iter().map(|x| x.to_string())).stream()
}
}