@@ -4,9 +4,11 @@ pub struct Ancestors<Find, Predicate, StateMut> {
4
4
predicate : Predicate ,
5
5
state : StateMut ,
6
6
mode : Parents ,
7
+ sorting : Sorting ,
7
8
}
8
9
9
10
/// Specify how to handle commit parents during traversal.
11
+ #[ derive( Copy , Clone ) ]
10
12
pub enum Parents {
11
13
/// Traverse all parents, useful for traversing the entire ancestry.
12
14
All ,
@@ -20,6 +22,22 @@ impl Default for Parents {
20
22
}
21
23
}
22
24
25
+ /// Specify how to sort commits during traversal.
26
+ #[ derive( Copy , Clone ) ]
27
+ pub enum Sorting {
28
+ /// Default order, sort commit looking up the first reachable parent
29
+ GraphOrder ,
30
+ /// Order commit looking up the most recent parent, since only parents are looked up
31
+ /// this ordering is partial
32
+ ByCommitterDate ,
33
+ }
34
+
35
+ impl Default for Sorting {
36
+ fn default ( ) -> Self {
37
+ Sorting :: GraphOrder
38
+ }
39
+ }
40
+
23
41
///
24
42
pub mod ancestors {
25
43
use std:: {
@@ -31,7 +49,7 @@ pub mod ancestors {
31
49
use git_object:: CommitRefIter ;
32
50
use quick_error:: quick_error;
33
51
34
- use crate :: commit:: { Ancestors , Parents } ;
52
+ use crate :: commit:: { Ancestors , Parents , Sorting } ;
35
53
36
54
quick_error ! {
37
55
/// The error is part of the item returned by the [Ancestors] iterator.
@@ -55,6 +73,7 @@ pub mod ancestors {
55
73
next : VecDeque < ObjectId > ,
56
74
buf : Vec < u8 > ,
57
75
seen : BTreeSet < ObjectId > ,
76
+ parents_with_date : Vec < ( ObjectId , u32 ) > ,
58
77
}
59
78
60
79
impl State {
@@ -71,6 +90,12 @@ pub mod ancestors {
71
90
self . mode = mode;
72
91
self
73
92
}
93
+
94
+ /// Set the sorting method, either topological or by author date
95
+ pub fn sorting ( mut self , sorting : Sorting ) -> Self {
96
+ self . sorting = sorting;
97
+ self
98
+ }
74
99
}
75
100
76
101
impl < Find , StateMut > Ancestors < Find , fn ( & oid ) -> bool , StateMut >
@@ -138,6 +163,7 @@ pub mod ancestors {
138
163
predicate,
139
164
state,
140
165
mode : Default :: default ( ) ,
166
+ sorting : Default :: default ( ) ,
141
167
}
142
168
}
143
169
}
@@ -151,6 +177,82 @@ pub mod ancestors {
151
177
type Item = Result < ObjectId , Error > ;
152
178
153
179
fn next ( & mut self ) -> Option < Self :: Item > {
180
+ match self . sorting {
181
+ Sorting :: GraphOrder => self . graph_sort_next ( ) ,
182
+ Sorting :: ByCommitterDate => self . next_by_commit_date ( ) ,
183
+ }
184
+ }
185
+ }
186
+
187
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
188
+ where
189
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
190
+ Predicate : FnMut ( & oid ) -> bool ,
191
+ StateMut : BorrowMut < State > ,
192
+ {
193
+ fn next_by_commit_date ( & mut self ) -> Option < Result < ObjectId , Error > > {
194
+ let state = self . state . borrow_mut ( ) ;
195
+ state. parents_with_date . clear ( ) ;
196
+ let res = state. next . pop_front ( ) ;
197
+
198
+ if let Some ( oid) = res {
199
+ match ( self . find ) ( & oid, & mut state. buf ) {
200
+ Some ( mut commit_iter) => {
201
+ if let Some ( Err ( decode_tree_err) ) = commit_iter. next ( ) {
202
+ return Some ( Err ( decode_tree_err. into ( ) ) ) ;
203
+ }
204
+
205
+ for token in commit_iter {
206
+ match token {
207
+ Ok ( git_object:: commit:: ref_iter:: Token :: Parent { id } ) => {
208
+ let mut vec = vec ! [ ] ;
209
+ let parent = ( self . find ) ( id. as_ref ( ) , & mut vec) ;
210
+
211
+ // Get the parent committer date
212
+ let parent_committer_date = parent
213
+ . map ( |parent| parent. into_iter ( ) . committer ( ) . map ( |committer| committer. time ) )
214
+ . flatten ( ) ;
215
+
216
+ if let Some ( parent_committer_date) = parent_committer_date {
217
+ state. parents_with_date . push ( ( id, parent_committer_date. time ) ) ;
218
+ }
219
+
220
+ if matches ! ( self . mode, Parents :: First ) {
221
+ break ;
222
+ }
223
+ }
224
+ Ok ( _unused_token) => break ,
225
+ Err ( err) => return Some ( Err ( err. into ( ) ) ) ,
226
+ }
227
+ }
228
+ }
229
+ None => return Some ( Err ( Error :: NotFound { oid } ) ) ,
230
+ }
231
+ }
232
+
233
+ state
234
+ . parents_with_date
235
+ . sort_by ( |( _, time) , ( _, other_time) | other_time. cmp ( & time) ) ;
236
+ for parent in & state. parents_with_date {
237
+ let id = parent. 0 ;
238
+ let was_inserted = state. seen . insert ( id) ;
239
+
240
+ if was_inserted && ( self . predicate ) ( & id) {
241
+ state. next . push_back ( id) ;
242
+ }
243
+ }
244
+
245
+ res. map ( Ok )
246
+ }
247
+ }
248
+
249
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
250
+ where
251
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
252
+ Predicate : FnMut ( & oid ) -> bool ,
253
+ StateMut : BorrowMut < State > ,
254
+ {
255
+ fn graph_sort_next ( & mut self ) -> Option < Result < ObjectId , Error > > {
154
256
let state = self . state . borrow_mut ( ) ;
155
257
let res = state. next . pop_front ( ) ;
156
258
if let Some ( oid) = res {
0 commit comments