use super::*;
use std::process::Command;
fn git_repo_toplevel(start_dir: &Path) -> Option<PathBuf> {
let output = Command::new("git")
.arg("-C")
.arg(start_dir)
.args(["rev-parse", "--show-toplevel"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
let stdout = String::from_utf8(output.stdout).ok()?;
let trimmed = stdout.trim();
(!trimmed.is_empty()).then(|| PathBuf::from(trimmed))
}
fn git_behind_count(repo_toplevel: &Path) -> Option<u32> {
let output = Command::new("git")
.arg("-C")
.arg(repo_toplevel)
.args(["rev-list", "--count", "HEAD..@{upstream}"])
.output()
.ok()?;
if !output.status.success() {
return None;
}
String::from_utf8(output.stdout)
.ok()?
.trim()
.parse::<u32>()
.ok()
}
pub fn git_outdated_warnings(config: &Config) -> Vec<IncludeWarning> {
let mut cache: HashMap<PathBuf, Option<u32>> = HashMap::new();
let mut warned: HashSet<PathBuf> = HashSet::new();
let mut warnings = Vec::new();
for entry in &config.groups {
let ConfigEntry::Namespace(ns) = entry else {
continue;
};
if ns.source_path.starts_with("http://") || ns.source_path.starts_with("https://") {
continue;
}
let Some(parent) = Path::new(&ns.source_path).parent() else {
continue;
};
let Some(toplevel) = git_repo_toplevel(parent) else {
continue;
};
let behind = *cache
.entry(toplevel.clone())
.or_insert_with(|| git_behind_count(&toplevel));
if let Some(behind) = behind
&& behind > 0
&& warned.insert(toplevel.clone())
{
warnings.push(IncludeWarning::GitOutdated {
path: toplevel.display().to_string(),
behind,
});
}
}
warnings
}