From 6006e7aebdc4bb5a14442c0f1508e4bf242e84b6 Mon Sep 17 00:00:00 2001 From: Stephan Dilly Date: Fri, 4 Jun 2021 09:55:19 +0200 Subject: [PATCH] use new custom logwalker --- asyncgit/src/revlog.rs | 2 +- asyncgit/src/sync/commit.rs | 2 +- asyncgit/src/sync/logwalker.rs | 139 ++++++++++++++------------------- asyncgit/src/sync/mod.rs | 5 +- 4 files changed, 63 insertions(+), 85 deletions(-) diff --git a/asyncgit/src/revlog.rs b/asyncgit/src/revlog.rs index 52e93e34..8af0fd3e 100644 --- a/asyncgit/src/revlog.rs +++ b/asyncgit/src/revlog.rs @@ -151,7 +151,7 @@ impl AsyncLog { ) -> Result<()> { let mut entries = Vec::with_capacity(LIMIT_COUNT); let r = repo(CWD)?; - let mut walker = LogWalker::new(&r, LIMIT_COUNT); + let mut walker = LogWalker::new(&r, LIMIT_COUNT)?; loop { entries.clear(); let res_is_err = walker.read(&mut entries).is_err(); diff --git a/asyncgit/src/sync/commit.rs b/asyncgit/src/sync/commit.rs index cedbe9ae..6b0c4fba 100644 --- a/asyncgit/src/sync/commit.rs +++ b/asyncgit/src/sync/commit.rs @@ -126,7 +126,7 @@ mod tests { fn count_commits(repo: &Repository, max: usize) -> usize { let mut items = Vec::new(); - let mut walk = LogWalker::new(&repo, max); + let mut walk = LogWalker::new(&repo, max).unwrap(); walk.read(&mut items).unwrap(); items.len() } diff --git a/asyncgit/src/sync/logwalker.rs b/asyncgit/src/sync/logwalker.rs index 4bd174bb..cc73e6de 100644 --- a/asyncgit/src/sync/logwalker.rs +++ b/asyncgit/src/sync/logwalker.rs @@ -1,51 +1,82 @@ -#![allow(clippy::missing_panics_doc)] - use super::CommitId; use crate::error::Result; -use git2::{Repository, Revwalk}; +use git2::{Commit, Oid, Repository}; +use std::{ + cmp::Ordering, + collections::{BinaryHeap, HashSet}, +}; + +struct TimeOrderedCommit<'a>(Commit<'a>); + +impl<'a> Eq for TimeOrderedCommit<'a> {} + +impl<'a> PartialEq for TimeOrderedCommit<'a> { + fn eq(&self, other: &Self) -> bool { + self.0.time().eq(&other.0.time()) + } +} + +impl<'a> PartialOrd for TimeOrderedCommit<'a> { + fn partial_cmp(&self, other: &Self) -> Option { + self.0.time().partial_cmp(&other.0.time()) + } +} + +impl<'a> Ord for TimeOrderedCommit<'a> { + fn cmp(&self, other: &Self) -> Ordering { + self.0.time().cmp(&other.0.time()) + } +} /// pub struct LogWalker<'a> { - repo: &'a Repository, - revwalk: Option>, + commits: BinaryHeap>, + visited: HashSet, limit: usize, } impl<'a> LogWalker<'a> { /// - pub const fn new(repo: &'a Repository, limit: usize) -> Self { - Self { - repo, - revwalk: None, + pub fn new(repo: &'a Repository, limit: usize) -> Result { + let c = repo.head()?.peel_to_commit()?; + + let mut commits = BinaryHeap::with_capacity(10); + commits.push(TimeOrderedCommit(c)); + + Ok(Self { + commits, limit, - } + visited: HashSet::with_capacity(1000), + }) } /// pub fn read(&mut self, out: &mut Vec) -> Result { let mut count = 0_usize; - if self.revwalk.is_none() { - let mut walk = self.repo.revwalk()?; + while let Some(c) = self.commits.pop() { + for p in c.0.parents() { + self.visit(p); + } - walk.push_head()?; + out.push(c.0.id().into()); - self.revwalk = Some(walk); - } - - if let Some(ref mut walk) = self.revwalk { - for id in walk.into_iter().flatten() { - out.push(id.into()); - count += 1; - - if count == self.limit { - break; - } + count += 1; + if count == self.limit { + break; } } Ok(count) } + + // + fn visit(&mut self, c: Commit<'a>) { + if !self.visited.contains(&c.id()) { + self.visited.insert(c.id()); + self.commits.push(TimeOrderedCommit(c)); + } + } } #[cfg(test)] @@ -73,7 +104,7 @@ mod tests { let oid2 = commit(repo_path, "commit2").unwrap(); let mut items = Vec::new(); - let mut walk = LogWalker::new(&repo, 1); + let mut walk = LogWalker::new(&repo, 1)?; walk.read(&mut items).unwrap(); assert_eq!(items.len(), 1); @@ -97,7 +128,7 @@ mod tests { let oid2 = commit(repo_path, "commit2").unwrap(); let mut items = Vec::new(); - let mut walk = LogWalker::new(&repo, 100); + let mut walk = LogWalker::new(&repo, 100)?; walk.read(&mut items).unwrap(); let info = get_commits_info(repo_path, &items, 50).unwrap(); @@ -113,60 +144,4 @@ mod tests { Ok(()) } - - // fn walk_all_commits(repo: &Repository) -> Vec { - // let mut items = Vec::new(); - // let mut walk = LogWalker::new(&repo).mode(Mode::AllRefs); - // walk.read(&mut items, 10).unwrap(); - // items - // } - - // #[test] - // fn test_multiple_branches() { - // let (td, repo) = repo_init_empty().unwrap(); - // let repo_path = td.path().to_string_lossy(); - - // let c1 = write_commit_file_at( - // &repo, - // "test.txt", - // "", - // "c1", - // Time::new(1, 0), - // ); - - // let items = walk_all_commits(&repo); - - // assert_eq!(items, vec![c1]); - - // let b1 = create_branch(&repo_path, "b1").unwrap(); - - // let c2 = write_commit_file_at( - // &repo, - // "test2.txt", - // "", - // "c2", - // Time::new(2, 0), - // ); - - // let items = walk_all_commits(&repo); - // assert_eq!(items, vec![c2, c1]); - - // let _b2 = create_branch(&repo_path, "b2").unwrap(); - - // let c3 = write_commit_file_at( - // &repo, - // "test3.txt", - // "", - // "c3", - // Time::new(3, 0), - // ); - - // let items = walk_all_commits(&repo); - // assert_eq!(items, vec![c2, c3, c1]); - - // checkout_branch(&repo_path, &b1).unwrap(); - - // let items = walk_all_commits(&repo); - // assert_eq!(items, vec![c2, c3, c1]); - // } } diff --git a/asyncgit/src/sync/mod.rs b/asyncgit/src/sync/mod.rs index d805940e..4cb4671f 100644 --- a/asyncgit/src/sync/mod.rs +++ b/asyncgit/src/sync/mod.rs @@ -274,7 +274,10 @@ mod tests { max_count: usize, ) -> Vec { let mut commit_ids = Vec::::new(); - LogWalker::new(r, max_count).read(&mut commit_ids).unwrap(); + LogWalker::new(r, max_count) + .unwrap() + .read(&mut commit_ids) + .unwrap(); commit_ids }