use std::collections::HashMap;
use std::path::{Path, PathBuf};
use std::process::Command;
use anyhow::{Result, Context};
pub mod validation;
pub mod status;
pub mod sync;
#[derive(Debug, Clone)]
pub struct SubrepoInstance {
pub parent_repo: String,
#[allow(dead_code)]
pub parent_path: PathBuf,
pub subrepo_name: String,
pub subrepo_path: PathBuf,
#[allow(dead_code)]
pub relative_path: String,
pub commit_hash: String,
pub short_hash: String,
pub remote_url: Option<String>,
pub has_uncommitted: bool,
pub commit_timestamp: i64, }
#[derive(Debug)]
pub struct ValidationReport {
pub total_nested: usize,
pub by_remote: HashMap<String, Vec<SubrepoInstance>>,
pub no_remote: Vec<SubrepoInstance>,
}
impl ValidationReport {
pub fn shared_subrepos_count(&self) -> usize {
self.by_remote.iter()
.filter(|(_, instances)| instances.len() > 1)
.count()
}
pub fn unique_remotes(&self) -> usize {
self.by_remote.len()
}
}
fn get_current_commit(path: &Path) -> Result<String> {
let output = Command::new("git")
.args(["-C", path.to_str().unwrap(), "rev-parse", "HEAD"])
.output()
.context("Failed to run git rev-parse")?;
if !output.status.success() {
anyhow::bail!("git rev-parse failed");
}
Ok(String::from_utf8(output.stdout)?.trim().to_string())
}
fn get_remote_url(path: &Path) -> Result<String> {
let output = Command::new("git")
.args(["-C", path.to_str().unwrap(), "remote", "get-url", "origin"])
.output()
.context("Failed to run git remote")?;
if !output.status.success() {
anyhow::bail!("No remote 'origin' found");
}
let url = String::from_utf8(output.stdout)?.trim().to_string();
Ok(normalize_remote_url(&url))
}
fn normalize_remote_url(url: &str) -> String {
url.trim_end_matches(".git")
.trim_end_matches('/')
.replace("git@github.com:", "https://github.com/")
.to_lowercase()
}
fn has_uncommitted_changes(path: &Path) -> bool {
let output = Command::new("git")
.args(["-C", path.to_str().unwrap(), "diff-index", "--quiet", "HEAD", "--"])
.output();
match output {
Ok(out) => !out.status.success(),
Err(_) => false,
}
}
pub(crate) fn get_commit_timestamp(path: &Path, commit_hash: &str) -> i64 {
let output = Command::new("git")
.args([
"-C",
path.to_str().unwrap(),
"show",
"-s",
"--format=%ct",
commit_hash,
])
.output();
match output {
Ok(out) if out.status.success() => {
String::from_utf8_lossy(&out.stdout)
.trim()
.parse()
.unwrap_or(0)
}
_ => 0,
}
}