11 // this function takes a line that may contain a name and/or email address,
12 // and returns just the name, while fixing the "bad cases".
13 std::string
contributor_name(const std::string
& line
)
17 // let's first take care of the case of isolated email addresses, like
18 // "user@localhost.localdomain" entries
19 if(line
.find("markb@localhost.localdomain") != string::npos
)
21 return "Mark Borgerding";
24 if(line
.find("kayhman@contact.intra.cea.fr") != string::npos
)
26 return "Guillaume Saupin";
29 // from there on we assume that we have a entry of the form
33 // Bla bli Blurp <bblurp@email.com>
35 size_t position_of_email_address
= line
.find_first_of('<');
36 if(position_of_email_address
!= string::npos
)
38 // there is an e-mail address in <...>.
40 // Hauke once committed as "John Smith", fix that.
41 if(line
.find("hauke.heibel") != string::npos
)
42 result
= "Hauke Heibel";
45 // just remove the e-mail address
46 result
= line
.substr(0, position_of_email_address
);
51 // there is no e-mail address in <...>.
53 if(line
.find("convert-repo") != string::npos
)
59 // remove trailing spaces
60 size_t length
= result
.length();
61 while(length
>= 1 && result
[length
-1] == ' ') result
.erase(--length
);
66 // parses hg churn output to generate a contributors map.
67 map
<string
,int> contributors_map_from_churn_output(const char *filename
)
69 map
<string
,int> contributors_map
;
73 churn_out
.open(filename
, ios::in
);
74 while(!getline(churn_out
,line
).eof())
76 // remove the histograms "******" that hg churn may draw at the end of some lines
77 size_t first_star
= line
.find_first_of('*');
78 if(first_star
!= string::npos
) line
.erase(first_star
);
80 // remove trailing spaces
81 size_t length
= line
.length();
82 while(length
>= 1 && line
[length
-1] == ' ') line
.erase(--length
);
84 // now the last space indicates where the number starts
85 size_t last_space
= line
.find_last_of(' ');
87 // get the number (of changesets or of modified lines for each contributor)
89 istringstream(line
.substr(last_space
+1)) >> number
;
91 // get the name of the contributor
92 line
.erase(last_space
);
93 string name
= contributor_name(line
);
95 map
<string
,int>::iterator it
= contributors_map
.find(name
);
96 // if new contributor, insert
97 if(it
== contributors_map
.end())
98 contributors_map
.insert(pair
<string
,int>(name
, number
));
99 // if duplicate, just add the number
101 it
->second
+= number
;
105 return contributors_map
;
108 // find the last name, i.e. the last word.
109 // for "van den Schbling" types of last names, that's not a problem, that's actually what we want.
110 string
lastname(const string
& name
)
112 size_t last_space
= name
.find_last_of(' ');
113 if(last_space
>= name
.length()-1) return name
;
114 else return name
.substr(last_space
+1);
125 contributor() : changedlines(0), changesets(0) {}
127 bool operator < (const contributor
& other
)
129 return lastname(name
).compare(lastname(other
.name
)) < 0;
133 void add_online_info_into_contributors_list(list
<contributor
>& contributors_list
, const char *filename
)
136 ifstream online_info
;
137 online_info
.open(filename
, ios::in
);
138 while(!getline(online_info
,line
).eof())
140 string hgname
, realname
, url
, misc
;
142 size_t last_bar
= line
.find_last_of('|');
143 if(last_bar
== string::npos
) continue;
144 if(last_bar
< line
.length())
145 misc
= line
.substr(last_bar
+1);
146 line
.erase(last_bar
);
148 last_bar
= line
.find_last_of('|');
149 if(last_bar
== string::npos
) continue;
150 if(last_bar
< line
.length())
151 url
= line
.substr(last_bar
+1);
152 line
.erase(last_bar
);
154 last_bar
= line
.find_last_of('|');
155 if(last_bar
== string::npos
) continue;
156 if(last_bar
< line
.length())
157 realname
= line
.substr(last_bar
+1);
158 line
.erase(last_bar
);
162 // remove the example line
163 if(hgname
.find("MercurialName") != string::npos
) continue;
165 list
<contributor
>::iterator it
;
166 for(it
=contributors_list
.begin(); it
!= contributors_list
.end() && it
->name
!= hgname
; ++it
)
169 if(it
== contributors_list
.end())
175 contributors_list
.push_back(c
);
188 // parse the hg churn output files
189 map
<string
,int> contributors_map_for_changedlines
= contributors_map_from_churn_output("churn-changedlines.out");
190 //map<string,int> contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out");
192 // merge into the contributors list
193 list
<contributor
> contributors_list
;
194 map
<string
,int>::iterator it
;
195 for(it
=contributors_map_for_changedlines
.begin(); it
!= contributors_map_for_changedlines
.end(); ++it
)
199 c
.changedlines
= it
->second
;
200 c
.changesets
= 0; //contributors_map_for_changesets.find(it->first)->second;
201 contributors_list
.push_back(c
);
204 add_online_info_into_contributors_list(contributors_list
, "online-info.out");
206 contributors_list
.sort();
208 cout
<< "{| cellpadding=\"5\"\n";
210 cout
<< "! Lines changed\n";
213 list
<contributor
>::iterator itc
;
215 for(itc
=contributors_list
.begin(); itc
!= contributors_list
.end(); ++itc
)
217 if(itc
->name
.length() == 0) continue;
218 if(i
%2) cout
<< "|-\n";
219 else cout
<< "|- style=\"background:#FFFFD0\"\n";
220 if(itc
->url
.length())
221 cout
<< "| [" << itc
->url
<< " " << itc
->name
<< "]\n";
223 cout
<< "| " << itc
->name
<< "\n";
224 if(itc
->changedlines
)
225 cout
<< "| " << itc
->changedlines
<< "\n";
227 cout
<< "| (no information)\n";
228 cout
<< "| " << itc
->misc
<< "\n";
231 cout
<< "|}" << endl
;