use std::process::Output;
use tokio::process::Command;
use crate::errors::GitCallError;
pub async fn run(command: &'static str, git: &mut Command) -> Result<Output, GitCallError> {
let output = git
.output()
.await
.map_err(|source| GitCallError::NotStarted { command, source })?;
if output.status.success() {
return Ok(output);
}
Err(GitCallError::Refused {
command,
status: output.status,
stderr: String::from_utf8_lossy(&output.stderr).trim().to_owned(),
})
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn a_git_that_cannot_start_is_told_apart_from_one_that_refused() {
let outcome = run("log", &mut Command::new("git-that-is-not-installed")).await;
assert!(matches!(
outcome,
Err(GitCallError::NotStarted { command: "log", source }) if source.kind() == std::io::ErrorKind::NotFound
));
}
#[tokio::test]
async fn a_git_that_exits_with_failure_is_refused() {
let mut failing = Command::new("sh");
failing.args(["-c", "echo nope >&2; exit 3"]);
let outcome = run("config", &mut failing).await;
assert!(matches!(
outcome,
Err(GitCallError::Refused { command: "config", status, stderr })
if status.code() == Some(3) && stderr == "nope"
));
}
}