use anyhow::{bail, Result};
use git2::Repository;
use std::path::Path;
pub struct RevParseOptions<'a> {
pub abbrev_ref: bool,
pub show_toplevel: bool,
pub git_dir: bool,
pub is_inside_work_tree: bool,
pub short: bool,
pub verify: bool,
pub args: &'a [String],
}
pub fn execute(path: &Path, opts: &RevParseOptions) -> Result<()> {
let repo = Repository::discover(path)?;
if opts.show_toplevel {
let workdir = repo
.workdir()
.ok_or_else(|| anyhow::anyhow!("not a working tree"))?;
println!("{}", workdir.canonicalize()?.display());
return Ok(());
}
if opts.git_dir {
println!("{}", repo.path().display());
return Ok(());
}
if opts.is_inside_work_tree {
println!("{}", repo.workdir().is_some());
return Ok(());
}
if opts.verify {
if opts.args.len() != 1 {
bail!("--verify requires exactly one argument");
}
let obj = repo.revparse_single(&opts.args[0])?;
println!("{}", obj.id());
return Ok(());
}
if opts.args.is_empty() && opts.abbrev_ref {
print_abbrev_ref(&repo, "HEAD")?;
return Ok(());
}
for arg in opts.args {
if opts.abbrev_ref {
print_abbrev_ref(&repo, arg)?;
} else if opts.short {
let obj = repo.revparse_single(arg)?;
let id = obj.id();
println!("{}", &id.to_string()[..7.min(id.to_string().len())]);
} else {
let obj = repo.revparse_single(arg)?;
println!("{}", obj.id());
}
}
Ok(())
}
fn print_abbrev_ref(repo: &Repository, refspec: &str) -> Result<()> {
if refspec == "HEAD" {
if let Ok(head) = repo.head() {
if let Some(name) = head.shorthand() {
println!("{}", name);
return Ok(());
}
}
println!("HEAD");
return Ok(());
}
if let Ok(reference) = repo.find_reference(&format!("refs/heads/{}", refspec)) {
if let Some(name) = reference.shorthand() {
println!("{}", name);
return Ok(());
}
}
if let Ok(reference) = repo.find_reference(refspec) {
if let Some(name) = reference.shorthand() {
println!("{}", name);
return Ok(());
}
}
println!("{}", refspec);
Ok(())
}