@@ -9,13 +9,28 @@ use git2::{
9
9
StatusShow ,
10
10
} ;
11
11
use regex:: Regex ;
12
+ use std:: collections:: HashMap ;
12
13
use std:: path:: Path ;
13
14
14
15
pub struct Repo < ' a > {
15
16
repo : & ' a Repository ,
16
17
logs : Vec < Commit < ' a > > ,
17
18
}
18
19
20
+ #[ derive( Hash , PartialEq , Eq ) ]
21
+ pub struct Sig {
22
+ name : String ,
23
+ email : String ,
24
+ }
25
+
26
+ impl From < Signature < ' _ > > for Sig {
27
+ fn from ( sig : Signature ) -> Self {
28
+ let name = String :: from_utf8_lossy ( sig. name_bytes ( ) ) . into_owned ( ) ;
29
+ let email = String :: from_utf8_lossy ( sig. email_bytes ( ) ) . into_owned ( ) ;
30
+ Self { name, email }
31
+ }
32
+ }
33
+
19
34
impl < ' a > Repo < ' a > {
20
35
pub fn new (
21
36
repo : & ' a Repository ,
@@ -70,42 +85,46 @@ impl<'a> Repo<'a> {
70
85
71
86
pub fn get_authors (
72
87
& self ,
73
- n : usize ,
88
+ number_of_author : usize ,
74
89
show_email : bool ,
75
- ) -> Vec < ( String , Option < String > , usize , usize ) > {
76
- let mut authors = std:: collections:: HashMap :: new ( ) ;
77
- let mut author_name_by_email = std:: collections:: HashMap :: new ( ) ;
90
+ ) -> Result < Vec < ( String , Option < String > , usize , usize ) > > {
91
+ let mut author_to_number_of_commits: HashMap < Sig , usize > = HashMap :: new ( ) ;
78
92
let mut total_nbr_of_commits = 0 ;
93
+ let mailmap = self . repo . mailmap ( ) ?;
79
94
for commit in & self . logs {
80
- let author = commit. author ( ) ;
81
- let author_name = String :: from_utf8_lossy ( author . name_bytes ( ) ) . into_owned ( ) ;
82
- let author_email = String :: from_utf8_lossy ( author . email_bytes ( ) ) . into_owned ( ) ;
83
-
84
- let author_nbr_of_commits = authors . entry ( author_email . to_string ( ) ) . or_insert ( 0 ) ;
85
- author_name_by_email . entry ( author_email . to_string ( ) ) . or_insert ( author_name ) ;
95
+ let author = match commit. author_with_mailmap ( & mailmap ) {
96
+ Ok ( val ) => val ,
97
+ Err ( _ ) => commit . author ( ) ,
98
+ } ;
99
+ let author_nbr_of_commits =
100
+ author_to_number_of_commits . entry ( Sig :: from ( author ) ) . or_insert ( 0 ) ;
86
101
* author_nbr_of_commits += 1 ;
87
102
total_nbr_of_commits += 1 ;
88
103
}
89
104
90
- let mut authors: Vec < ( String , usize ) > = authors. into_iter ( ) . collect ( ) ;
91
- authors. sort_by ( |( _, a_count) , ( _, b_count) | b_count. cmp ( a_count) ) ;
92
-
93
- authors. truncate ( n) ;
94
-
95
- let authors: Vec < ( String , Option < String > , usize , usize ) > = authors
96
- . into_iter ( )
97
- . map ( |( author_email, author_nbr_of_commits) | {
98
- (
99
- author_name_by_email. get ( & author_email) . unwrap ( ) . trim_matches ( '\'' ) . to_string ( ) ,
100
- show_email. then ( || author_email) ,
101
- author_nbr_of_commits,
102
- ( author_nbr_of_commits as f32 * 100. / total_nbr_of_commits as f32 ) . round ( )
103
- as usize ,
104
- )
105
- } )
106
- . collect ( ) ;
107
-
108
- authors
105
+ let mut authors_sorted_by_number_of_commits: Vec < ( Sig , usize ) > =
106
+ author_to_number_of_commits. into_iter ( ) . collect ( ) ;
107
+
108
+ authors_sorted_by_number_of_commits
109
+ . sort_by ( |( _, a_count) , ( _, b_count) | b_count. cmp ( a_count) ) ;
110
+
111
+ authors_sorted_by_number_of_commits. truncate ( number_of_author) ;
112
+
113
+ let result: Vec < ( String , Option < String > , usize , usize ) > =
114
+ authors_sorted_by_number_of_commits
115
+ . into_iter ( )
116
+ . map ( |( author, author_nbr_of_commits) | {
117
+ (
118
+ author. name . clone ( ) ,
119
+ show_email. then ( || author. email ) ,
120
+ author_nbr_of_commits,
121
+ ( author_nbr_of_commits as f32 * 100. / total_nbr_of_commits as f32 ) . round ( )
122
+ as usize ,
123
+ )
124
+ } )
125
+ . collect ( ) ;
126
+
127
+ Ok ( result)
109
128
}
110
129
111
130
pub fn get_date_of_last_commit ( & self , iso_time : bool ) -> String {
0 commit comments