1*bf2c3715SXin Li #include <string>
2*bf2c3715SXin Li #include <sstream>
3*bf2c3715SXin Li #include <iostream>
4*bf2c3715SXin Li #include <fstream>
5*bf2c3715SXin Li #include <iomanip>
6*bf2c3715SXin Li #include <map>
7*bf2c3715SXin Li #include <list>
8*bf2c3715SXin Li
9*bf2c3715SXin Li using namespace std;
10*bf2c3715SXin Li
11*bf2c3715SXin Li // this function takes a line that may contain a name and/or email address,
12*bf2c3715SXin Li // and returns just the name, while fixing the "bad cases".
contributor_name(const std::string & line)13*bf2c3715SXin Li std::string contributor_name(const std::string& line)
14*bf2c3715SXin Li {
15*bf2c3715SXin Li string result;
16*bf2c3715SXin Li
17*bf2c3715SXin Li // let's first take care of the case of isolated email addresses, like
18*bf2c3715SXin Li // "[email protected]" entries
19*bf2c3715SXin Li if(line.find("[email protected]") != string::npos)
20*bf2c3715SXin Li {
21*bf2c3715SXin Li return "Mark Borgerding";
22*bf2c3715SXin Li }
23*bf2c3715SXin Li
24*bf2c3715SXin Li if(line.find("[email protected]") != string::npos)
25*bf2c3715SXin Li {
26*bf2c3715SXin Li return "Guillaume Saupin";
27*bf2c3715SXin Li }
28*bf2c3715SXin Li
29*bf2c3715SXin Li // from there on we assume that we have a entry of the form
30*bf2c3715SXin Li // either:
31*bf2c3715SXin Li // Bla bli Blurp
32*bf2c3715SXin Li // or:
33*bf2c3715SXin Li // Bla bli Blurp <[email protected]>
34*bf2c3715SXin Li
35*bf2c3715SXin Li size_t position_of_email_address = line.find_first_of('<');
36*bf2c3715SXin Li if(position_of_email_address != string::npos)
37*bf2c3715SXin Li {
38*bf2c3715SXin Li // there is an e-mail address in <...>.
39*bf2c3715SXin Li
40*bf2c3715SXin Li // Hauke once committed as "John Smith", fix that.
41*bf2c3715SXin Li if(line.find("hauke.heibel") != string::npos)
42*bf2c3715SXin Li result = "Hauke Heibel";
43*bf2c3715SXin Li else
44*bf2c3715SXin Li {
45*bf2c3715SXin Li // just remove the e-mail address
46*bf2c3715SXin Li result = line.substr(0, position_of_email_address);
47*bf2c3715SXin Li }
48*bf2c3715SXin Li }
49*bf2c3715SXin Li else
50*bf2c3715SXin Li {
51*bf2c3715SXin Li // there is no e-mail address in <...>.
52*bf2c3715SXin Li
53*bf2c3715SXin Li if(line.find("convert-repo") != string::npos)
54*bf2c3715SXin Li result = "";
55*bf2c3715SXin Li else
56*bf2c3715SXin Li result = line;
57*bf2c3715SXin Li }
58*bf2c3715SXin Li
59*bf2c3715SXin Li // remove trailing spaces
60*bf2c3715SXin Li size_t length = result.length();
61*bf2c3715SXin Li while(length >= 1 && result[length-1] == ' ') result.erase(--length);
62*bf2c3715SXin Li
63*bf2c3715SXin Li return result;
64*bf2c3715SXin Li }
65*bf2c3715SXin Li
66*bf2c3715SXin Li // parses hg churn output to generate a contributors map.
contributors_map_from_churn_output(const char * filename)67*bf2c3715SXin Li map<string,int> contributors_map_from_churn_output(const char *filename)
68*bf2c3715SXin Li {
69*bf2c3715SXin Li map<string,int> contributors_map;
70*bf2c3715SXin Li
71*bf2c3715SXin Li string line;
72*bf2c3715SXin Li ifstream churn_out;
73*bf2c3715SXin Li churn_out.open(filename, ios::in);
74*bf2c3715SXin Li while(!getline(churn_out,line).eof())
75*bf2c3715SXin Li {
76*bf2c3715SXin Li // remove the histograms "******" that hg churn may draw at the end of some lines
77*bf2c3715SXin Li size_t first_star = line.find_first_of('*');
78*bf2c3715SXin Li if(first_star != string::npos) line.erase(first_star);
79*bf2c3715SXin Li
80*bf2c3715SXin Li // remove trailing spaces
81*bf2c3715SXin Li size_t length = line.length();
82*bf2c3715SXin Li while(length >= 1 && line[length-1] == ' ') line.erase(--length);
83*bf2c3715SXin Li
84*bf2c3715SXin Li // now the last space indicates where the number starts
85*bf2c3715SXin Li size_t last_space = line.find_last_of(' ');
86*bf2c3715SXin Li
87*bf2c3715SXin Li // get the number (of changesets or of modified lines for each contributor)
88*bf2c3715SXin Li int number;
89*bf2c3715SXin Li istringstream(line.substr(last_space+1)) >> number;
90*bf2c3715SXin Li
91*bf2c3715SXin Li // get the name of the contributor
92*bf2c3715SXin Li line.erase(last_space);
93*bf2c3715SXin Li string name = contributor_name(line);
94*bf2c3715SXin Li
95*bf2c3715SXin Li map<string,int>::iterator it = contributors_map.find(name);
96*bf2c3715SXin Li // if new contributor, insert
97*bf2c3715SXin Li if(it == contributors_map.end())
98*bf2c3715SXin Li contributors_map.insert(pair<string,int>(name, number));
99*bf2c3715SXin Li // if duplicate, just add the number
100*bf2c3715SXin Li else
101*bf2c3715SXin Li it->second += number;
102*bf2c3715SXin Li }
103*bf2c3715SXin Li churn_out.close();
104*bf2c3715SXin Li
105*bf2c3715SXin Li return contributors_map;
106*bf2c3715SXin Li }
107*bf2c3715SXin Li
108*bf2c3715SXin Li // find the last name, i.e. the last word.
109*bf2c3715SXin Li // for "van den Schbling" types of last names, that's not a problem, that's actually what we want.
lastname(const string & name)110*bf2c3715SXin Li string lastname(const string& name)
111*bf2c3715SXin Li {
112*bf2c3715SXin Li size_t last_space = name.find_last_of(' ');
113*bf2c3715SXin Li if(last_space >= name.length()-1) return name;
114*bf2c3715SXin Li else return name.substr(last_space+1);
115*bf2c3715SXin Li }
116*bf2c3715SXin Li
117*bf2c3715SXin Li struct contributor
118*bf2c3715SXin Li {
119*bf2c3715SXin Li string name;
120*bf2c3715SXin Li int changedlines;
121*bf2c3715SXin Li int changesets;
122*bf2c3715SXin Li string url;
123*bf2c3715SXin Li string misc;
124*bf2c3715SXin Li
contributorcontributor125*bf2c3715SXin Li contributor() : changedlines(0), changesets(0) {}
126*bf2c3715SXin Li
operator <contributor127*bf2c3715SXin Li bool operator < (const contributor& other)
128*bf2c3715SXin Li {
129*bf2c3715SXin Li return lastname(name).compare(lastname(other.name)) < 0;
130*bf2c3715SXin Li }
131*bf2c3715SXin Li };
132*bf2c3715SXin Li
add_online_info_into_contributors_list(list<contributor> & contributors_list,const char * filename)133*bf2c3715SXin Li void add_online_info_into_contributors_list(list<contributor>& contributors_list, const char *filename)
134*bf2c3715SXin Li {
135*bf2c3715SXin Li string line;
136*bf2c3715SXin Li ifstream online_info;
137*bf2c3715SXin Li online_info.open(filename, ios::in);
138*bf2c3715SXin Li while(!getline(online_info,line).eof())
139*bf2c3715SXin Li {
140*bf2c3715SXin Li string hgname, realname, url, misc;
141*bf2c3715SXin Li
142*bf2c3715SXin Li size_t last_bar = line.find_last_of('|');
143*bf2c3715SXin Li if(last_bar == string::npos) continue;
144*bf2c3715SXin Li if(last_bar < line.length())
145*bf2c3715SXin Li misc = line.substr(last_bar+1);
146*bf2c3715SXin Li line.erase(last_bar);
147*bf2c3715SXin Li
148*bf2c3715SXin Li last_bar = line.find_last_of('|');
149*bf2c3715SXin Li if(last_bar == string::npos) continue;
150*bf2c3715SXin Li if(last_bar < line.length())
151*bf2c3715SXin Li url = line.substr(last_bar+1);
152*bf2c3715SXin Li line.erase(last_bar);
153*bf2c3715SXin Li
154*bf2c3715SXin Li last_bar = line.find_last_of('|');
155*bf2c3715SXin Li if(last_bar == string::npos) continue;
156*bf2c3715SXin Li if(last_bar < line.length())
157*bf2c3715SXin Li realname = line.substr(last_bar+1);
158*bf2c3715SXin Li line.erase(last_bar);
159*bf2c3715SXin Li
160*bf2c3715SXin Li hgname = line;
161*bf2c3715SXin Li
162*bf2c3715SXin Li // remove the example line
163*bf2c3715SXin Li if(hgname.find("MercurialName") != string::npos) continue;
164*bf2c3715SXin Li
165*bf2c3715SXin Li list<contributor>::iterator it;
166*bf2c3715SXin Li for(it=contributors_list.begin(); it != contributors_list.end() && it->name != hgname; ++it)
167*bf2c3715SXin Li {}
168*bf2c3715SXin Li
169*bf2c3715SXin Li if(it == contributors_list.end())
170*bf2c3715SXin Li {
171*bf2c3715SXin Li contributor c;
172*bf2c3715SXin Li c.name = realname;
173*bf2c3715SXin Li c.url = url;
174*bf2c3715SXin Li c.misc = misc;
175*bf2c3715SXin Li contributors_list.push_back(c);
176*bf2c3715SXin Li }
177*bf2c3715SXin Li else
178*bf2c3715SXin Li {
179*bf2c3715SXin Li it->name = realname;
180*bf2c3715SXin Li it->url = url;
181*bf2c3715SXin Li it->misc = misc;
182*bf2c3715SXin Li }
183*bf2c3715SXin Li }
184*bf2c3715SXin Li }
185*bf2c3715SXin Li
main()186*bf2c3715SXin Li int main()
187*bf2c3715SXin Li {
188*bf2c3715SXin Li // parse the hg churn output files
189*bf2c3715SXin Li map<string,int> contributors_map_for_changedlines = contributors_map_from_churn_output("churn-changedlines.out");
190*bf2c3715SXin Li //map<string,int> contributors_map_for_changesets = contributors_map_from_churn_output("churn-changesets.out");
191*bf2c3715SXin Li
192*bf2c3715SXin Li // merge into the contributors list
193*bf2c3715SXin Li list<contributor> contributors_list;
194*bf2c3715SXin Li map<string,int>::iterator it;
195*bf2c3715SXin Li for(it=contributors_map_for_changedlines.begin(); it != contributors_map_for_changedlines.end(); ++it)
196*bf2c3715SXin Li {
197*bf2c3715SXin Li contributor c;
198*bf2c3715SXin Li c.name = it->first;
199*bf2c3715SXin Li c.changedlines = it->second;
200*bf2c3715SXin Li c.changesets = 0; //contributors_map_for_changesets.find(it->first)->second;
201*bf2c3715SXin Li contributors_list.push_back(c);
202*bf2c3715SXin Li }
203*bf2c3715SXin Li
204*bf2c3715SXin Li add_online_info_into_contributors_list(contributors_list, "online-info.out");
205*bf2c3715SXin Li
206*bf2c3715SXin Li contributors_list.sort();
207*bf2c3715SXin Li
208*bf2c3715SXin Li cout << "{| cellpadding=\"5\"\n";
209*bf2c3715SXin Li cout << "!\n";
210*bf2c3715SXin Li cout << "! Lines changed\n";
211*bf2c3715SXin Li cout << "!\n";
212*bf2c3715SXin Li
213*bf2c3715SXin Li list<contributor>::iterator itc;
214*bf2c3715SXin Li int i = 0;
215*bf2c3715SXin Li for(itc=contributors_list.begin(); itc != contributors_list.end(); ++itc)
216*bf2c3715SXin Li {
217*bf2c3715SXin Li if(itc->name.length() == 0) continue;
218*bf2c3715SXin Li if(i%2) cout << "|-\n";
219*bf2c3715SXin Li else cout << "|- style=\"background:#FFFFD0\"\n";
220*bf2c3715SXin Li if(itc->url.length())
221*bf2c3715SXin Li cout << "| [" << itc->url << " " << itc->name << "]\n";
222*bf2c3715SXin Li else
223*bf2c3715SXin Li cout << "| " << itc->name << "\n";
224*bf2c3715SXin Li if(itc->changedlines)
225*bf2c3715SXin Li cout << "| " << itc->changedlines << "\n";
226*bf2c3715SXin Li else
227*bf2c3715SXin Li cout << "| (no information)\n";
228*bf2c3715SXin Li cout << "| " << itc->misc << "\n";
229*bf2c3715SXin Li i++;
230*bf2c3715SXin Li }
231*bf2c3715SXin Li cout << "|}" << endl;
232*bf2c3715SXin Li }
233