@@ -28,11 +28,16 @@ impl<'a> Ord for TimeOrderedCommit<'a> {
28
28
}
29
29
}
30
30
31
+ type LogWalkerFilter =
32
+ Box < dyn Fn ( & Repository , & CommitId ) -> Result < bool > > ;
33
+
31
34
///
32
35
pub struct LogWalker < ' a > {
33
36
commits : BinaryHeap < TimeOrderedCommit < ' a > > ,
34
37
visited : HashSet < Oid > ,
35
38
limit : usize ,
39
+ repo : & ' a Repository ,
40
+ filter : Option < LogWalkerFilter > ,
36
41
}
37
42
38
43
impl < ' a > LogWalker < ' a > {
@@ -47,9 +52,19 @@ impl<'a> LogWalker<'a> {
47
52
commits,
48
53
limit,
49
54
visited : HashSet :: with_capacity ( 1000 ) ,
55
+ repo,
56
+ filter : None ,
50
57
} )
51
58
}
52
59
60
+ ///
61
+ pub fn filter ( self , filter : LogWalkerFilter ) -> Self {
62
+ Self {
63
+ filter : Some ( filter) ,
64
+ ..self
65
+ }
66
+ }
67
+
53
68
///
54
69
pub fn read ( & mut self , out : & mut Vec < CommitId > ) -> Result < usize > {
55
70
let mut count = 0_usize ;
@@ -59,7 +74,17 @@ impl<'a> LogWalker<'a> {
59
74
self . visit ( p) ;
60
75
}
61
76
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
+ }
63
88
64
89
count += 1 ;
65
90
if count == self . limit {
@@ -82,9 +107,10 @@ impl<'a> LogWalker<'a> {
82
107
#[ cfg( test) ]
83
108
mod tests {
84
109
use super :: * ;
110
+ use crate :: error:: Result ;
85
111
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,
88
114
} ;
89
115
use pretty_assertions:: assert_eq;
90
116
use std:: { fs:: File , io:: Write , path:: Path } ;
@@ -144,4 +170,79 @@ mod tests {
144
170
145
171
Ok ( ( ) )
146
172
}
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
+ }
147
248
}
0 commit comments