1
- #![ allow( clippy:: missing_panics_doc) ]
2
-
3
1
use super :: CommitId ;
4
2
use 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
+ }
6
30
7
31
///
8
32
pub struct LogWalker < ' a > {
9
- repo : & ' a Repository ,
10
- revwalk : Option < Revwalk < ' a > > ,
33
+ commits : BinaryHeap < TimeOrderedCommit < ' a > > ,
34
+ visited : HashSet < Oid > ,
11
35
limit : usize ,
12
36
}
13
37
14
38
impl < ' a > LogWalker < ' a > {
15
39
///
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,
20
48
limit,
21
- }
49
+ visited : HashSet :: with_capacity ( 1000 ) ,
50
+ } )
22
51
}
23
52
24
53
///
25
54
pub fn read ( & mut self , out : & mut Vec < CommitId > ) -> Result < usize > {
26
55
let mut count = 0_usize ;
27
56
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
+ }
35
61
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 ( ) ) ;
40
63
41
- if count == self . limit {
42
- break ;
43
- }
64
+ count += 1 ;
65
+ if count == self . limit {
66
+ break ;
44
67
}
45
68
}
46
69
47
70
Ok ( count)
48
71
}
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
+ }
49
80
}
50
81
51
82
#[ cfg( test) ]
@@ -73,7 +104,7 @@ mod tests {
73
104
let oid2 = commit ( repo_path, "commit2" ) . unwrap ( ) ;
74
105
75
106
let mut items = Vec :: new ( ) ;
76
- let mut walk = LogWalker :: new ( & repo, 1 ) ;
107
+ let mut walk = LogWalker :: new ( & repo, 1 ) ? ;
77
108
walk. read ( & mut items) . unwrap ( ) ;
78
109
79
110
assert_eq ! ( items. len( ) , 1 ) ;
@@ -97,7 +128,7 @@ mod tests {
97
128
let oid2 = commit ( repo_path, "commit2" ) . unwrap ( ) ;
98
129
99
130
let mut items = Vec :: new ( ) ;
100
- let mut walk = LogWalker :: new ( & repo, 100 ) ;
131
+ let mut walk = LogWalker :: new ( & repo, 100 ) ? ;
101
132
walk. read ( & mut items) . unwrap ( ) ;
102
133
103
134
let info = get_commits_info ( repo_path, & items, 50 ) . unwrap ( ) ;
@@ -113,60 +144,4 @@ mod tests {
113
144
114
145
Ok ( ( ) )
115
146
}
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
- // }
172
147
}
0 commit comments