diff --git a/src/git/walker.rs b/src/git/walker.rs new file mode 100644 index 0000000..c0f8c51 --- /dev/null +++ b/src/git/walker.rs @@ -0,0 +1,67 @@ +use crate::git::Commit; +use anyhow::Result; +use git2::{Sort, Sortable}; + +pub struct CommitWalker<'a> { + repo: &'a git2::Repository, + revwalk: git2::Revwalk<'a>, +} + +impl<'a> CommitWalker<'a> { + pub fn new(repo: &'a git2::Repository) -> Result { + let mut revwalk = repo.revwalk()?; + revwalk.set_sorting(Sort::TIME)?; + revwalk.push_head()?; + Ok(Self { repo, revwalk }) + } + + pub fn with_sorting(repo: &'a git2::Repository, sorting: Sort) -> Result { + let mut revwalk = repo.revwalk()?; + revwalk.set_sorting(sorting)?; + revwalk.push_head()?; + Ok(Self { repo, revwalk }) + } + + pub fn hide(&mut self, oid: git2::Oid) -> Result<()> { + self.revwalk.hide(oid)?; + Ok(()) + } + + pub fn push(&mut self, oid: git2::Oid) -> Result<()> { + self.revwalk.push(oid)?; + Ok(()) + } + + pub fn push_head(&mut self) -> Result<()> { + self.revwalk.push_head()?; + Ok(()) + } + + pub fn simplify_first_parent(&mut self) { + self.revwalk.simplify_first_parent(); + } + + pub fn count(&self) -> usize { + let mut count = 0; + for _ in self.clone() { + count += 1; + } + count + } +} + +impl<'a> Iterator for CommitWalker<'a> { + type Item = Result>; + + fn next(&mut self) -> Option { + self.revwalk + .next() + .map(|oid| match oid { + Ok(oid) => match self.repo.find_commit(oid) { + Ok(commit) => Ok(Commit::new(commit)), + Err(e) => Err(anyhow::anyhow!("Failed to find commit {}: {}", oid, e)), + }, + Err(e) => Err(anyhow::anyhow!("Revwalk error: {}", e)), + }) + } +}