Viewing:
use anyhow::Result;
use git2::{BranchType, Oid, Repository, Tree};
use std::collections::HashMap;
const USAGE: &str = r#"
whizpopper <path to original repo> <path to bfg'ed repo> <comma separated list of branches to check>
"#;
// If no other is supplied, then build up hashmap
// If other is supplied, then additionally print diffs where they arise
fn get_or_diff_file_hashes(
tree: &Tree,
other: Option<&HashMap<String, Oid>>,
) -> (HashMap<String, Oid>, i32) {
let mut file_hashes: HashMap<String, Oid> = HashMap::new();
let mut return_code = 0;
tree.walk(git2::TreeWalkMode::PreOrder, |parent_directory, entry| {
if entry.kind().is_none() {
return git2::TreeWalkResult::Skip;
}
let kind = entry.kind().unwrap();
if kind != git2::ObjectType::Tree && kind != git2::ObjectType::Blob {
return git2::TreeWalkResult::Skip;
};
let entry_name = entry.name().unwrap_or("Name not understood");
let is_dir = kind == git2::ObjectType::Tree;
let file_path = format!(
"{}{}{}",
parent_directory,
entry_name,
if is_dir { "/" } else { "" }
);
let oid = entry.id();
if let Some(other_hashes) = other {
if !other_hashes.contains_key(&file_path) {
return_code = 1;
println!("{} is in new but not original", file_path);
} else {
let original_oid = other_hashes.get(&file_path);
if original_oid != Some(&oid) {
return_code = 1;
println!(
"{}: new id is {:?}, old id is {:?}",
file_path, oid, original_oid
);
}
}
};
file_hashes.insert(file_path, oid);
git2::TreeWalkResult::Ok
})
.unwrap();
(file_hashes, return_code)
}
fn main() -> Result<()> {
let mut args = std::env::args().skip(1);
if args.len() != 3 {
eprintln!("{}", USAGE);
std::process::exit(1);
}
let path_to_original = args.next().expect(USAGE);
let path_to_bfged = args.next().expect(USAGE);
let branches_str = args.next().expect(USAGE);
let branches = branches_str.split(",");
let original_repo = Repository::open(path_to_original)?;
let bfged_repo = Repository::open(path_to_bfged)?;
let mut exit_code = 0;
for branch in branches {
println!("checking branch {}", branch);
let original_tree = original_repo
.find_branch(branch, BranchType::Local)?
.get()
.peel_to_tree()?;
let (original_hashes, _) = get_or_diff_file_hashes(&original_tree, None);
let bfged_tree = bfged_repo
.find_branch(branch, BranchType::Local)?
.get()
.peel_to_tree()?;
let (bfged_hashes, branch_exit_code) =
get_or_diff_file_hashes(&bfged_tree, Some(&original_hashes));
if branch_exit_code != 0 {
exit_code = branch_exit_code
}
for (path, _) in &original_hashes {
if !bfged_hashes.contains_key(path) {
exit_code = 1;
println!("original has {} but new does not", path);
}
}
}
if exit_code != 0 {
println!("some content was unexpectedly different");
std::process::exit(exit_code);
}
Ok(())
}