use git2::Repository;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, fs, path::Path};
use walkdir::WalkDir;
#[derive(Debug, Serialize, Deserialize)]
struct PersistableRepo {
pub(crate) path: String,
pub(crate) remote_url: String,
pub(crate) head: String,
}
fn main() -> anyhow::Result<()> {
let dir = match std::env::args().nth(1) {
Some(d) => d,
None => {
println!("Usage:\n gitice
\n");
return Ok(());
}
};
let mut repos: HashMap = HashMap::new();
for entry in WalkDir::new(dir.clone()).into_iter().filter_map(|e| e.ok()) {
if entry.file_type().is_dir() {
let path = format!("{}/.git", entry.path().display());
let git_dir = Path::new(&path);
if git_dir.exists() {
let repo = Repository::open(git_dir)?;
if repo.is_empty()? {
continue;
}
let head = repo.head()?;
if let Some(head) = head.name() {
if let Ok(upstream) = repo.branch_upstream_name(head) {
if let Ok(remote) = repo.find_remote(
// This is a rather ugly hack, but not sure how else to get the required name
// doesn't seem to work with the full name such as `refs/remotes/origin/master`
upstream.as_str().unwrap().split('/').collect::>()[2],
) {
let path = entry
.path()
.to_string_lossy()
.strip_prefix(&dir)
.unwrap()
.to_string();
repos.insert(
path.clone(),
PersistableRepo {
path,
remote_url: remote.url().unwrap_or("None").to_owned(),
head: head.to_owned(),
},
);
}
}
};
}
};
}
fs::write("gitice.lock", toml::to_string(&repos)?).expect("could not write to lockfile!");
Ok(())
}