use crate::{Branch, Error, NameWithId};
use std::path::Path;
pub struct Repo {
repo: git2::Repository,
}
impl Repo {
pub fn open(path: impl AsRef<Path>) -> Result<Repo, Error> {
let repo = git2::Repository::open(path)?;
Ok(Repo { repo })
}
pub fn browse_branch<'a>(&'a self, branch: &str) -> Result<Branch<'a>, Error> {
Branch::new(&self.repo, branch)
}
pub fn current_branch(&self) -> Result<Option<Branch>, Error> {
let head = self.repo.head()?;
Ok(if let Some(target) = head.symbolic_target() {
Some(self.browse_branch(target)?)
} else {
Some(Branch::new_by_reference(&self.repo, head)?)
})
}
pub fn list_branches_with_newest_commit_id(&self) -> Result<Vec<NameWithId>, Error> {
let branches = self.repo.branches(Some(git2::BranchType::Local))?;
let mut result = Vec::new();
for branch in branches {
let branch = branch?.0;
if let (Some(name), Some(oid)) = (branch.name()?, branch.get().target()) {
result.push(NameWithId {
commit_id: oid.to_string(),
name: name.to_owned(),
});
}
}
Ok(result)
}
pub fn list_branches(&self) -> Result<Vec<String>, Error> {
Ok(self
.list_branches_with_newest_commit_id()?
.into_iter()
.map(|n| n.name)
.collect())
}
pub fn list_tags_with_commit_id(&self) -> Result<Vec<NameWithId>, Error> {
let mut result = Vec::new();
self.repo.tag_foreach(|oid, bytes| {
if let Ok(mut name) = std::str::from_utf8(bytes) {
if let Some(index) = name.rfind('/') {
name = &name[index + 1..];
}
result.push(NameWithId {
commit_id: oid.to_string(),
name: name.to_owned(),
});
}
true
})?;
Ok(result)
}
pub fn list_tags(&self) -> Result<Vec<String>, Error> {
Ok(self
.list_tags_with_commit_id()?
.into_iter()
.map(|n| n.name)
.collect())
}
}