1 |
/* |
2 |
** Copyright 2012 Kamil Rytarowski < kamil AT mageia DOT org > |
3 |
** |
4 |
** This Source Code Form is subject to the terms of the Mozilla Public |
5 |
** License, v. 2.0. If a copy of the MPL was not distributed with this |
6 |
** file, You can obtain one at http://mozilla.org/MPL/2.0/. |
7 |
*/ |
8 |
|
9 |
#include <chrono> |
10 |
#include <cstdlib> |
11 |
#include <ctime> |
12 |
#include <iomanip> |
13 |
#include <iostream> |
14 |
#include <locale> |
15 |
#include <map> |
16 |
#include <set> |
17 |
#include <sstream> |
18 |
#include <string> |
19 |
#include <tuple> |
20 |
#include <vector> |
21 |
|
22 |
#include <boost/date_time/posix_time/posix_time.hpp> |
23 |
|
24 |
#include "pugixml.hpp" |
25 |
|
26 |
typedef std::tuple<unsigned long /* revision */, |
27 |
std::string /* author */, |
28 |
boost::posix_time::ptime /* date */> tuple; |
29 |
|
30 |
int main(int argc, char **argv) |
31 |
{ |
32 |
/* |
33 |
** Read text stream from stdin |
34 |
*/ |
35 |
|
36 |
std::cin >> std::noskipws; /* Don't skip whitespaces */ |
37 |
|
38 |
/* |
39 |
** Use iterators to slurp data from the standard input |
40 |
*/ |
41 |
|
42 |
std::istream_iterator<char> it(std::cin); |
43 |
std::istream_iterator<char> end; |
44 |
const std::string input(it, end); |
45 |
|
46 |
pugi::xml_document doc; |
47 |
pugi::xml_parse_result result = doc.load_buffer(input.c_str(), input.size()); |
48 |
|
49 |
#ifndef NDEBUG |
50 |
std::cerr << "Load result: " << result.description() << "\n"; |
51 |
#endif |
52 |
|
53 |
/* |
54 |
** <?xml version="1.0" encoding="UTF-8"?> |
55 |
** <log> |
56 |
** <logentry |
57 |
** revision="1234"> |
58 |
** <author>author</author> |
59 |
** <date>2012-01-21T10:00:00.000000Z</date> |
60 |
** </logentry> |
61 |
** </log> |
62 |
*/ |
63 |
pugi::xml_node log = doc.child("log"); |
64 |
|
65 |
std::vector<tuple> table; |
66 |
|
67 |
for (pugi::xml_node logentry: log.children()) |
68 |
{ |
69 |
unsigned long revision = std::stoul(logentry.attribute("revision").value()); |
70 |
std::string author = logentry.child("author").text().get(); |
71 |
|
72 |
#ifndef NDEBUG |
73 |
std::cerr << revision << "\t" << author << "\t"; |
74 |
#endif |
75 |
|
76 |
std::string datetime = logentry.child("date").text().get(); |
77 |
boost::posix_time::time_input_facet * facet = |
78 |
new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%sZ"); /* 'Z' stands for UTC */ |
79 |
|
80 |
std::stringstream ss; |
81 |
ss.imbue(std::locale(std::locale(), facet)); |
82 |
ss << datetime; |
83 |
boost::posix_time::ptime date; |
84 |
ss >> date; |
85 |
|
86 |
#ifndef NDEBUG |
87 |
std::cerr << datetime << "\t" << date << "\n"; |
88 |
#endif |
89 |
|
90 |
table.push_back(std::make_tuple(revision, author, date)); |
91 |
} |
92 |
|
93 |
/* |
94 |
** Statistics: |
95 |
** |
96 |
** 1. Overall number of the commiters |
97 |
** 2. Number of commits per a commiter |
98 |
** 3. |
99 |
*/ |
100 |
|
101 |
/* |
102 |
** 1. Overall number of the commiters |
103 |
*/ |
104 |
|
105 |
unsigned int overall_commiters = 0; |
106 |
{ |
107 |
std::set<std::string> tmp_set; |
108 |
overall_commiters = |
109 |
(unsigned int) count_if(table.begin(), table.end(), [&tmp_set](tuple & t) |
110 |
{ |
111 |
std::string author = std::get<1>(t); |
112 |
|
113 |
if (tmp_set.empty()) |
114 |
{ |
115 |
tmp_set.insert(author); |
116 |
return true; |
117 |
} |
118 |
else |
119 |
{ |
120 |
if (tmp_set.find(author) == tmp_set.end()) |
121 |
{ |
122 |
tmp_set.insert(author); |
123 |
return true; |
124 |
} |
125 |
else |
126 |
return false; |
127 |
} |
128 |
} |
129 |
); |
130 |
} |
131 |
|
132 |
#ifndef NDEBUG |
133 |
std::cerr << "Overall commiters: " << overall_commiters << "\n"; |
134 |
#endif |
135 |
|
136 |
/* |
137 |
** 2. Number of commits per a commiter |
138 |
*/ |
139 |
|
140 |
std::map<std::string, unsigned int> commits_per_a_commiter; |
141 |
{ |
142 |
for(auto t : table) |
143 |
{ |
144 |
std::string author = std::get<1>(t); |
145 |
if (commits_per_a_commiter.empty()) |
146 |
commits_per_a_commiter.insert(std::pair<std::string, unsigned int>(author, 1)); |
147 |
else |
148 |
{ |
149 |
auto a = commits_per_a_commiter.find(author); |
150 |
if (a == commits_per_a_commiter.end()) |
151 |
commits_per_a_commiter.insert(std::pair<std::string, unsigned int>(author, 1)); |
152 |
else |
153 |
commits_per_a_commiter.at(author) = (commits_per_a_commiter.at(author) + 1); |
154 |
} |
155 |
} |
156 |
} |
157 |
|
158 |
#ifndef NDEBUG |
159 |
std::cerr << "Commits per a commiter:\n"; |
160 |
for(auto c : commits_per_a_commiter) |
161 |
{ |
162 |
std::cerr << "\t" << (c.first) << "\t" << (c.second) << "\n"; |
163 |
} |
164 |
#endif |
165 |
|
166 |
return EXIT_SUCCESS; |
167 |
} |