use std::process::Command;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum GitError {
#[error("failed to execute command: {0}")]
IoError(#[from] std::io::Error),
#[error("git command error: {0}")]
CommandError(String),
}
pub trait Git {
fn show_top_level(&self, name: &str) -> Result<(bool, String), GitError>;
fn git_common_dir(&self, name: &str) -> Result<(bool, String), GitError>;
fn clone(&self, url: &str, cmd_dir: &str, dir: &str) -> Result<String, GitError>;
}
#[derive(Copy, Clone)]
pub struct RealGit;
impl Git for RealGit {
fn show_top_level(&self, name: &str) -> Result<(bool, String), GitError> {
let output = Command::new("git")
.args(["-C", name, "rev-parse", "--show-toplevel"])
.output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
Ok((true, stdout))
} else {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
Ok((false, stderr))
}
}
fn git_common_dir(&self, name: &str) -> Result<(bool, String), GitError> {
let output = Command::new("git")
.args(["-C", name, "rev-parse", "--git-common-dir"])
.output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
Ok((true, stdout))
} else {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
Ok((false, stderr))
}
}
fn clone(&self, url: &str, cmd_dir: &str, dir: &str) -> Result<String, GitError> {
let output = Command::new("git")
.args(["clone", url, dir])
.current_dir(cmd_dir)
.output()?;
if output.status.success() {
let stdout = String::from_utf8_lossy(&output.stdout).trim().to_string();
Ok(stdout)
} else {
let stderr = String::from_utf8_lossy(&output.stderr).trim().to_string();
Err(GitError::CommandError(stderr))
}
}
}
pub struct MockGit;
impl Git for MockGit {
fn show_top_level(&self, _name: &str) -> Result<(bool, String), GitError> {
Ok((true, String::from("/mock/repo/top-level")))
}
fn git_common_dir(&self, _name: &str) -> Result<(bool, String), GitError> {
Ok((true, String::from("/mock/repo/common-dir")))
}
fn clone(&self, _url: &str, _cmd_dir: &str, _dir: &str) -> Result<String, GitError> {
Ok(String::from("Mock clone successful"))
}
}