@@ -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
+ /// TODO: The default sorting mode
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.
@@ -71,6 +89,12 @@ pub mod ancestors {
71
89
self . mode = mode;
72
90
self
73
91
}
92
+
93
+ /// Set the sorting method, either topological or by author date
94
+ pub fn sorting ( mut self , sorting : Sorting ) -> Self {
95
+ self . sorting = sorting;
96
+ self
97
+ }
74
98
}
75
99
76
100
impl < Find , StateMut > Ancestors < Find , fn ( & oid ) -> bool , StateMut >
@@ -138,6 +162,7 @@ pub mod ancestors {
138
162
predicate,
139
163
state,
140
164
mode : Default :: default ( ) ,
165
+ sorting : Default :: default ( ) ,
141
166
}
142
167
}
143
168
}
@@ -151,6 +176,80 @@ pub mod ancestors {
151
176
type Item = Result < ObjectId , Error > ;
152
177
153
178
fn next ( & mut self ) -> Option < Self :: Item > {
179
+ match self . sorting {
180
+ Sorting :: GraphOrder => self . graph_sort_next ( ) ,
181
+ Sorting :: ByCommitterDate => self . next_by_commit_date ( ) ,
182
+ }
183
+ }
184
+ }
185
+
186
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
187
+ where
188
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
189
+ Predicate : FnMut ( & oid ) -> bool ,
190
+ StateMut : BorrowMut < State > ,
191
+ {
192
+ fn next_by_commit_date ( & mut self ) -> Option < Result < ObjectId , Error > > {
193
+ let state = self . state . borrow_mut ( ) ;
194
+ let res = state. next . pop_front ( ) ;
195
+ let mut parents_with_date = vec ! [ ] ;
196
+
197
+ if let Some ( oid) = res {
198
+ match ( self . find ) ( & oid, & mut state. buf ) {
199
+ Some ( mut commit_iter) => {
200
+ if let Some ( Err ( decode_tree_err) ) = commit_iter. next ( ) {
201
+ return Some ( Err ( decode_tree_err. into ( ) ) ) ;
202
+ }
203
+
204
+ for token in commit_iter {
205
+ match token {
206
+ Ok ( git_object:: commit:: ref_iter:: Token :: Parent { id } ) => {
207
+ let mut vec = vec ! [ ] ;
208
+ let parent = ( self . find ) ( id. as_ref ( ) , & mut vec) ;
209
+
210
+ // Get the parent committer date
211
+ let parent_committer_date = parent
212
+ . map ( |parent| parent. into_iter ( ) . committer ( ) . map ( |committer| committer. time ) )
213
+ . flatten ( ) ;
214
+
215
+ if let Some ( parent_committer_date) = parent_committer_date {
216
+ parents_with_date. push ( ( id, parent_committer_date. time ) ) ;
217
+ }
218
+
219
+ if matches ! ( self . mode, Parents :: First ) {
220
+ break ;
221
+ }
222
+ }
223
+ Ok ( _unused_token) => break ,
224
+ Err ( err) => return Some ( Err ( err. into ( ) ) ) ,
225
+ }
226
+ }
227
+ }
228
+ None => return Some ( Err ( Error :: NotFound { oid } ) ) ,
229
+ }
230
+ }
231
+
232
+ parents_with_date. sort_by ( |( _, time) , ( _, other_time) | other_time. cmp ( & time) ) ;
233
+ for parent in parents_with_date {
234
+ let id = parent. 0 ;
235
+ let was_inserted = state. seen . insert ( id) ;
236
+
237
+ if was_inserted && ( self . predicate ) ( & id) {
238
+ state. next . push_back ( id) ;
239
+ }
240
+ }
241
+
242
+ res. map ( Ok )
243
+ }
244
+ }
245
+
246
+ impl < Find , Predicate , StateMut > Ancestors < Find , Predicate , StateMut >
247
+ where
248
+ Find : for < ' a > FnMut ( & oid , & ' a mut Vec < u8 > ) -> Option < CommitRefIter < ' a > > ,
249
+ Predicate : FnMut ( & oid ) -> bool ,
250
+ StateMut : BorrowMut < State > ,
251
+ {
252
+ fn graph_sort_next ( & mut self ) -> Option < Result < ObjectId , Error > > {
154
253
let state = self . state . borrow_mut ( ) ;
155
254
let res = state. next . pop_front ( ) ;
156
255
if let Some ( oid) = res {
0 commit comments