1- #![ allow( clippy:: missing_panics_doc) ]
2-
31use super :: CommitId ;
42use crate :: error:: Result ;
5- use git2:: { Repository , Revwalk } ;
3+ use git2:: { Commit , Oid , Repository } ;
4+ use std:: {
5+ cmp:: Ordering ,
6+ collections:: { BinaryHeap , HashSet } ,
7+ } ;
8+
9+ struct TimeOrderedCommit < ' a > ( Commit < ' a > ) ;
10+
11+ impl < ' a > Eq for TimeOrderedCommit < ' a > { }
12+
13+ impl < ' a > PartialEq for TimeOrderedCommit < ' a > {
14+ fn eq ( & self , other : & Self ) -> bool {
15+ self . 0 . time ( ) . eq ( & other. 0 . time ( ) )
16+ }
17+ }
18+
19+ impl < ' a > PartialOrd for TimeOrderedCommit < ' a > {
20+ fn partial_cmp ( & self , other : & Self ) -> Option < Ordering > {
21+ self . 0 . time ( ) . partial_cmp ( & other. 0 . time ( ) )
22+ }
23+ }
24+
25+ impl < ' a > Ord for TimeOrderedCommit < ' a > {
26+ fn cmp ( & self , other : & Self ) -> Ordering {
27+ self . 0 . time ( ) . cmp ( & other. 0 . time ( ) )
28+ }
29+ }
630
731///
832pub struct LogWalker < ' a > {
9- repo : & ' a Repository ,
10- revwalk : Option < Revwalk < ' a > > ,
33+ commits : BinaryHeap < TimeOrderedCommit < ' a > > ,
34+ visited : HashSet < Oid > ,
1135 limit : usize ,
1236}
1337
1438impl < ' a > LogWalker < ' a > {
1539 ///
16- pub const fn new ( repo : & ' a Repository , limit : usize ) -> Self {
17- Self {
18- repo,
19- revwalk : None ,
40+ pub fn new ( repo : & ' a Repository , limit : usize ) -> Result < Self > {
41+ let c = repo. head ( ) ?. peel_to_commit ( ) ?;
42+
43+ let mut commits = BinaryHeap :: with_capacity ( 10 ) ;
44+ commits. push ( TimeOrderedCommit ( c) ) ;
45+
46+ Ok ( Self {
47+ commits,
2048 limit,
21- }
49+ visited : HashSet :: with_capacity ( 1000 ) ,
50+ } )
2251 }
2352
2453 ///
2554 pub fn read ( & mut self , out : & mut Vec < CommitId > ) -> Result < usize > {
2655 let mut count = 0_usize ;
2756
28- if self . revwalk . is_none ( ) {
29- let mut walk = self . repo . revwalk ( ) ?;
30-
31- walk. push_head ( ) ?;
32-
33- self . revwalk = Some ( walk) ;
34- }
57+ while let Some ( c) = self . commits . pop ( ) {
58+ for p in c. 0 . parents ( ) {
59+ self . visit ( p) ;
60+ }
3561
36- if let Some ( ref mut walk) = self . revwalk {
37- for id in walk. into_iter ( ) . flatten ( ) {
38- out. push ( id. into ( ) ) ;
39- count += 1 ;
62+ out. push ( c. 0 . id ( ) . into ( ) ) ;
4063
41- if count == self . limit {
42- break ;
43- }
64+ count += 1 ;
65+ if count == self . limit {
66+ break ;
4467 }
4568 }
4669
4770 Ok ( count)
4871 }
72+
73+ //
74+ fn visit ( & mut self , c : Commit < ' a > ) {
75+ if !self . visited . contains ( & c. id ( ) ) {
76+ self . visited . insert ( c. id ( ) ) ;
77+ self . commits . push ( TimeOrderedCommit ( c) ) ;
78+ }
79+ }
4980}
5081
5182#[ cfg( test) ]
@@ -73,7 +104,7 @@ mod tests {
73104 let oid2 = commit ( repo_path, "commit2" ) . unwrap ( ) ;
74105
75106 let mut items = Vec :: new ( ) ;
76- let mut walk = LogWalker :: new ( & repo, 1 ) ;
107+ let mut walk = LogWalker :: new ( & repo, 1 ) ? ;
77108 walk. read ( & mut items) . unwrap ( ) ;
78109
79110 assert_eq ! ( items. len( ) , 1 ) ;
@@ -97,7 +128,7 @@ mod tests {
97128 let oid2 = commit ( repo_path, "commit2" ) . unwrap ( ) ;
98129
99130 let mut items = Vec :: new ( ) ;
100- let mut walk = LogWalker :: new ( & repo, 100 ) ;
131+ let mut walk = LogWalker :: new ( & repo, 100 ) ? ;
101132 walk. read ( & mut items) . unwrap ( ) ;
102133
103134 let info = get_commits_info ( repo_path, & items, 50 ) . unwrap ( ) ;
@@ -113,60 +144,4 @@ mod tests {
113144
114145 Ok ( ( ) )
115146 }
116-
117- // fn walk_all_commits(repo: &Repository) -> Vec<CommitId> {
118- // let mut items = Vec::new();
119- // let mut walk = LogWalker::new(&repo).mode(Mode::AllRefs);
120- // walk.read(&mut items, 10).unwrap();
121- // items
122- // }
123-
124- // #[test]
125- // fn test_multiple_branches() {
126- // let (td, repo) = repo_init_empty().unwrap();
127- // let repo_path = td.path().to_string_lossy();
128-
129- // let c1 = write_commit_file_at(
130- // &repo,
131- // "test.txt",
132- // "",
133- // "c1",
134- // Time::new(1, 0),
135- // );
136-
137- // let items = walk_all_commits(&repo);
138-
139- // assert_eq!(items, vec![c1]);
140-
141- // let b1 = create_branch(&repo_path, "b1").unwrap();
142-
143- // let c2 = write_commit_file_at(
144- // &repo,
145- // "test2.txt",
146- // "",
147- // "c2",
148- // Time::new(2, 0),
149- // );
150-
151- // let items = walk_all_commits(&repo);
152- // assert_eq!(items, vec![c2, c1]);
153-
154- // let _b2 = create_branch(&repo_path, "b2").unwrap();
155-
156- // let c3 = write_commit_file_at(
157- // &repo,
158- // "test3.txt",
159- // "",
160- // "c3",
161- // Time::new(3, 0),
162- // );
163-
164- // let items = walk_all_commits(&repo);
165- // assert_eq!(items, vec![c2, c3, c1]);
166-
167- // checkout_branch(&repo_path, &b1).unwrap();
168-
169- // let items = walk_all_commits(&repo);
170- // assert_eq!(items, vec![c2, c3, c1]);
171- // }
172147}
0 commit comments