@@ -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///
3235pub 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
3843impl < ' 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) ]
83108mod 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