use std::path::PathBuf;
use std::process::Command;
use corpora_core::{OracleStatus, Rev, RevisionOracle};
pub struct GitOracle {
root: PathBuf,
}
impl GitOracle {
pub fn new(root: impl Into<PathBuf>) -> Self {
GitOracle { root: root.into() }
}
fn run(&self, args: &[&str]) -> Option<String> {
let out = Command::new("git")
.arg("-C")
.arg(&self.root)
.args(args)
.output()
.ok()?;
if !out.status.success() {
return None;
}
let s = String::from_utf8_lossy(&out.stdout).trim().to_string();
(!s.is_empty()).then_some(s)
}
fn git_present(&self) -> bool {
Command::new("git")
.arg("--version")
.output()
.map(|o| o.status.success())
.unwrap_or(false)
}
}
impl RevisionOracle for GitOracle {
fn status(&self) -> OracleStatus {
if !self.git_present() {
OracleStatus::Unavailable
} else if self.run(&["rev-parse", "--git-dir"]).is_none() {
OracleStatus::NoRepo
} else {
OracleStatus::Ready
}
}
fn resolve(&self, r: &Rev) -> Option<Rev> {
let spec = format!("{}^{{commit}}", r.0);
self.run(&["rev-parse", "--verify", "--quiet", "--end-of-options", &spec])
.map(Rev)
}
}