Skip to content

Commit e9ff883

Browse files
committed
Work in progress #270
1 parent bc77534 commit e9ff883

File tree

4 files changed

+250
-80
lines changed

4 files changed

+250
-80
lines changed

git-object/src/commit/ref_iter.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,17 @@ impl<'a> CommitRefIter<'a> {
6565
_ => None,
6666
})
6767
}
68+
69+
/// TODO:
70+
pub fn committer(&mut self) -> Option<git_actor::SignatureRef<'_>> {
71+
self.filter_map(Result::ok)
72+
.find(|t| matches!(t, Token::Committer { .. }))
73+
.map(|t| match t {
74+
Token::Committer { signature } => Some(signature),
75+
_ => None,
76+
})
77+
.flatten()
78+
}
6879
}
6980

7081
impl<'a> CommitRefIter<'a> {

git-traverse/src/commit.rs

Lines changed: 100 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,11 @@ pub struct Ancestors<Find, Predicate, StateMut> {
44
predicate: Predicate,
55
state: StateMut,
66
mode: Parents,
7+
sorting: Sorting,
78
}
89

910
/// Specify how to handle commit parents during traversal.
11+
#[derive(Copy, Clone)]
1012
pub enum Parents {
1113
/// Traverse all parents, useful for traversing the entire ancestry.
1214
All,
@@ -20,6 +22,22 @@ impl Default for Parents {
2022
}
2123
}
2224

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+
2341
///
2442
pub mod ancestors {
2543
use std::{
@@ -31,7 +49,7 @@ pub mod ancestors {
3149
use git_object::CommitRefIter;
3250
use quick_error::quick_error;
3351

34-
use crate::commit::{Ancestors, Parents};
52+
use crate::commit::{Ancestors, Parents, Sorting};
3553

3654
quick_error! {
3755
/// The error is part of the item returned by the [Ancestors] iterator.
@@ -71,6 +89,12 @@ pub mod ancestors {
7189
self.mode = mode;
7290
self
7391
}
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+
}
7498
}
7599

76100
impl<Find, StateMut> Ancestors<Find, fn(&oid) -> bool, StateMut>
@@ -138,6 +162,7 @@ pub mod ancestors {
138162
predicate,
139163
state,
140164
mode: Default::default(),
165+
sorting: Default::default(),
141166
}
142167
}
143168
}
@@ -151,6 +176,80 @@ pub mod ancestors {
151176
type Item = Result<ObjectId, Error>;
152177

153178
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>> {
154253
let state = self.state.borrow_mut();
155254
let res = state.next.pop_front();
156255
if let Some(oid) = res {

0 commit comments

Comments
 (0)