Skip to content

Commit f132722

Browse files
cruesslerStephan Dilly
authored andcommitted
Add filter to LogWalker
This is the first step towards adding a file history view. The filter itself is not related to files specifically, though. It could also be used for different purposes.
1 parent 947c4a1 commit f132722

File tree

1 file changed

+104
-3
lines changed

1 file changed

+104
-3
lines changed

asyncgit/src/sync/logwalker.rs

Lines changed: 104 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@ impl<'a> Ord for TimeOrderedCommit<'a> {
2828
}
2929
}
3030

31+
type LogWalkerFilter =
32+
Box<dyn Fn(&Repository, &CommitId) -> Result<bool>>;
33+
3134
///
3235
pub struct LogWalker<'a> {
3336
commits: BinaryHeap<TimeOrderedCommit<'a>>,
3437
visited: HashSet<Oid>,
3538
limit: usize,
39+
repo: &'a Repository,
40+
filter: Option<LogWalkerFilter>,
3641
}
3742

3843
impl<'a> LogWalker<'a> {
@@ -47,9 +52,19 @@ impl<'a> LogWalker<'a> {
4752
commits,
4853
limit,
4954
visited: HashSet::with_capacity(1000),
55+
repo,
56+
filter: None,
5057
})
5158
}
5259

60+
///
61+
pub fn filter(self, filter: LogWalkerFilter) -> Self {
62+
Self {
63+
filter: Some(filter),
64+
..self
65+
}
66+
}
67+
5368
///
5469
pub fn read(&mut self, out: &mut Vec<CommitId>) -> Result<usize> {
5570
let mut count = 0_usize;
@@ -59,7 +74,17 @@ impl<'a> LogWalker<'a> {
5974
self.visit(p);
6075
}
6176

62-
out.push(c.0.id().into());
77+
let id: CommitId = c.0.id().into();
78+
let commit_should_be_included =
79+
if let Some(ref filter) = self.filter {
80+
filter(self.repo, &id)?
81+
} else {
82+
true
83+
};
84+
85+
if commit_should_be_included {
86+
out.push(id);
87+
}
6388

6489
count += 1;
6590
if count == self.limit {
@@ -82,9 +107,10 @@ impl<'a> LogWalker<'a> {
82107
#[cfg(test)]
83108
mod tests {
84109
use super::*;
110+
use crate::error::Result;
85111
use crate::sync::{
86-
commit, get_commits_info, stage_add_file,
87-
tests::repo_init_empty,
112+
commit, commit_files::get_commit_diff, get_commits_info,
113+
stage_add_file, tests::repo_init_empty,
88114
};
89115
use pretty_assertions::assert_eq;
90116
use std::{fs::File, io::Write, path::Path};
@@ -144,4 +170,79 @@ mod tests {
144170

145171
Ok(())
146172
}
173+
174+
#[test]
175+
fn test_logwalker_with_filter() -> Result<()> {
176+
let file_path = Path::new("foo");
177+
let second_file_path = Path::new("baz");
178+
let (_td, repo) = repo_init_empty().unwrap();
179+
let root = repo.path().parent().unwrap();
180+
let repo_path = root.as_os_str().to_str().unwrap();
181+
182+
File::create(&root.join(file_path))?.write_all(b"a")?;
183+
stage_add_file(repo_path, file_path).unwrap();
184+
185+
let _first_commit_id = commit(repo_path, "commit1").unwrap();
186+
187+
File::create(&root.join(second_file_path))?
188+
.write_all(b"a")?;
189+
stage_add_file(repo_path, second_file_path).unwrap();
190+
191+
let second_commit_id = commit(repo_path, "commit2").unwrap();
192+
193+
File::create(&root.join(file_path))?.write_all(b"b")?;
194+
stage_add_file(repo_path, file_path).unwrap();
195+
196+
let _third_commit_id = commit(repo_path, "commit3").unwrap();
197+
198+
let diff_contains_baz = |repo: &Repository,
199+
commit_id: &CommitId|
200+
-> Result<bool> {
201+
let diff = get_commit_diff(
202+
&repo,
203+
*commit_id,
204+
Some("baz".into()),
205+
)?;
206+
207+
let contains_file = diff.deltas().len() > 0;
208+
209+
Ok(contains_file)
210+
};
211+
212+
let mut items = Vec::new();
213+
let mut walker = LogWalker::new(&repo, 100)?
214+
.filter(Box::new(diff_contains_baz));
215+
walker.read(&mut items).unwrap();
216+
217+
assert_eq!(items.len(), 1);
218+
assert_eq!(items[0], second_commit_id.into());
219+
220+
let mut items = Vec::new();
221+
walker.read(&mut items).unwrap();
222+
223+
assert_eq!(items.len(), 0);
224+
225+
let diff_contains_bar = |repo: &Repository,
226+
commit_id: &CommitId|
227+
-> Result<bool> {
228+
let diff = get_commit_diff(
229+
&repo,
230+
*commit_id,
231+
Some("bar".into()),
232+
)?;
233+
234+
let contains_file = diff.deltas().len() > 0;
235+
236+
Ok(contains_file)
237+
};
238+
239+
let mut items = Vec::new();
240+
let mut walker = LogWalker::new(&repo, 100)?
241+
.filter(Box::new(diff_contains_bar));
242+
walker.read(&mut items).unwrap();
243+
244+
assert_eq!(items.len(), 0);
245+
246+
Ok(())
247+
}
147248
}

0 commit comments

Comments
 (0)