177 |
02 Sep 06 |
peter |
// $Id$ |
177 |
02 Sep 06 |
peter |
2 |
|
177 |
02 Sep 06 |
peter |
3 |
/* |
408 |
29 Jun 07 |
jari |
Copyright (C) 2006 Peter Johansson |
978 |
12 Dec 09 |
peter |
Copyright (C) 2007, 2008, 2009 Jari Häkkinen, Peter Johansson |
1635 |
30 Mar 23 |
peter |
Copyright (C) 2010, 2015 Peter Johansson |
177 |
02 Sep 06 |
peter |
7 |
|
687 |
04 Aug 08 |
peter |
This file is part of svndigest, http://dev.thep.lu.se/svndigest |
177 |
02 Sep 06 |
peter |
9 |
|
177 |
02 Sep 06 |
peter |
svndigest is free software; you can redistribute it and/or modify it |
177 |
02 Sep 06 |
peter |
under the terms of the GNU General Public License as published by |
693 |
11 Sep 08 |
jari |
the Free Software Foundation; either version 3 of the License, or |
177 |
02 Sep 06 |
peter |
(at your option) any later version. |
177 |
02 Sep 06 |
peter |
14 |
|
177 |
02 Sep 06 |
peter |
svndigest is distributed in the hope that it will be useful, but |
177 |
02 Sep 06 |
peter |
WITHOUT ANY WARRANTY; without even the implied warranty of |
177 |
02 Sep 06 |
peter |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
177 |
02 Sep 06 |
peter |
General Public License for more details. |
177 |
02 Sep 06 |
peter |
19 |
|
177 |
02 Sep 06 |
peter |
You should have received a copy of the GNU General Public License |
693 |
11 Sep 08 |
jari |
along with svndigest. If not, see <http://www.gnu.org/licenses/>. |
177 |
02 Sep 06 |
peter |
22 |
*/ |
177 |
02 Sep 06 |
peter |
23 |
|
1253 |
31 Oct 10 |
peter |
24 |
#include <config.h> // this header file is created by configure |
1253 |
31 Oct 10 |
peter |
25 |
|
285 |
06 May 07 |
peter |
26 |
#include "first_page.h" |
285 |
06 May 07 |
peter |
27 |
|
256 |
30 Apr 07 |
peter |
28 |
#include "Commitment.h" |
274 |
02 May 07 |
peter |
29 |
#include "Configuration.h" |
235 |
21 Apr 07 |
peter |
30 |
#include "Date.h" |
234 |
09 Apr 07 |
peter |
31 |
#include "HtmlStream.h" |
400 |
28 Jun 07 |
peter |
32 |
#include "html_utility.h" |
1254 |
31 Oct 10 |
peter |
33 |
#include "NodeCounter.h" |
223 |
09 Mar 07 |
peter |
34 |
#include "Stats.h" |
1237 |
23 Oct 10 |
peter |
35 |
#include "StatsCollection.h" |
1290 |
12 Nov 10 |
peter |
36 |
#include "StatsPlotter.h" |
234 |
09 Apr 07 |
peter |
37 |
#include "SVNlog.h" |
286 |
07 May 07 |
peter |
38 |
#include "Trac.h" |
177 |
02 Sep 06 |
peter |
39 |
#include "utility.h" |
177 |
02 Sep 06 |
peter |
40 |
|
234 |
09 Apr 07 |
peter |
41 |
#include <algorithm> |
263 |
30 Apr 07 |
jari |
42 |
#include <cassert> |
177 |
02 Sep 06 |
peter |
43 |
#include <fstream> |
200 |
09 Sep 06 |
peter |
44 |
#include <iostream> |
177 |
02 Sep 06 |
peter |
45 |
#include <sstream> |
177 |
02 Sep 06 |
peter |
46 |
#include <stdexcept> |
177 |
02 Sep 06 |
peter |
47 |
#include <string> |
177 |
02 Sep 06 |
peter |
48 |
#include <sys/param.h> |
177 |
02 Sep 06 |
peter |
49 |
#include <unistd.h> |
201 |
09 Sep 06 |
peter |
50 |
#include <vector> |
177 |
02 Sep 06 |
peter |
51 |
|
177 |
02 Sep 06 |
peter |
52 |
namespace theplu{ |
177 |
02 Sep 06 |
peter |
53 |
namespace svndigest{ |
177 |
02 Sep 06 |
peter |
54 |
|
234 |
09 Apr 07 |
peter |
55 |
void print_main_page(const std::string& dir, const SVNlog& log, |
1513 |
23 Sep 12 |
peter |
56 |
const StatsCollection& stats, std::string url, |
1254 |
31 Oct 10 |
peter |
57 |
const NodeCounter& node_counter) |
201 |
09 Sep 06 |
peter |
58 |
{ |
207 |
11 Sep 06 |
peter |
59 |
std::string filename="index.html"; |
201 |
09 Sep 06 |
peter |
60 |
std::ofstream os(filename.c_str()); |
546 |
04 Jan 08 |
peter |
61 |
print_header(os, dir, 0, "all", "main", "index.html", "none"); |
234 |
09 Apr 07 |
peter |
62 |
|
234 |
09 Apr 07 |
peter |
63 |
using namespace std; |
256 |
30 Apr 07 |
peter |
64 |
set<string> authors; |
642 |
31 May 08 |
peter |
65 |
std::transform(log.commits().begin(), log.commits().end(), |
1513 |
23 Sep 12 |
peter |
66 |
std::inserter(authors, authors.begin()), |
1652 |
14 Jun 23 |
peter |
67 |
std::mem_fn(&Commitment::author)); |
234 |
09 Apr 07 |
peter |
// erase invalid authors |
256 |
30 Apr 07 |
peter |
69 |
authors.erase(""); |
256 |
30 Apr 07 |
peter |
70 |
authors.erase("no author"); |
234 |
09 Apr 07 |
peter |
71 |
|
256 |
30 Apr 07 |
peter |
72 |
vector<Commitment> latest_commit; |
256 |
30 Apr 07 |
peter |
73 |
latest_commit.reserve(authors.size()); |
256 |
30 Apr 07 |
peter |
74 |
for (set<string>::const_iterator i(authors.begin()); i!=authors.end(); ++i) |
256 |
30 Apr 07 |
peter |
75 |
latest_commit.push_back(log.latest_commit(*i)); |
234 |
09 Apr 07 |
peter |
76 |
|
556 |
16 Jan 08 |
peter |
77 |
print_summary_plot(os, stats["classic"]); |
1254 |
31 Oct 10 |
peter |
78 |
print_general_information(os, log, authors.size(), url, node_counter); |
256 |
30 Apr 07 |
peter |
79 |
sort(latest_commit.begin(), latest_commit.end(), GreaterRevision()); |
556 |
16 Jan 08 |
peter |
80 |
print_authors(os, latest_commit, stats["classic"]); |
556 |
16 Jan 08 |
peter |
81 |
print_recent_logs(os, log, stats); |
234 |
09 Apr 07 |
peter |
82 |
os << "<hr width=100% />"; |
234 |
09 Apr 07 |
peter |
83 |
print_footer(os); |
234 |
09 Apr 07 |
peter |
84 |
os.close(); |
234 |
09 Apr 07 |
peter |
85 |
} |
234 |
09 Apr 07 |
peter |
86 |
|
1513 |
23 Sep 12 |
peter |
87 |
void print_general_information(std::ostream& os, const SVNlog& log, |
1254 |
31 Oct 10 |
peter |
88 |
size_t nof_authors, std::string url, |
1254 |
31 Oct 10 |
peter |
89 |
const NodeCounter& node_counter) |
1513 |
23 Sep 12 |
peter |
90 |
{ |
642 |
31 May 08 |
peter |
91 |
assert(log.commits().size()); |
1513 |
23 Sep 12 |
peter |
92 |
Date begin(log.commits().begin()->date()); |
759 |
29 Jan 09 |
peter |
93 |
Date end(log.latest_commit().date()); |
751 |
14 Jan 09 |
peter |
94 |
std::string timefmt("%a %b %e %H:%M:%S %Y"); |
223 |
09 Mar 07 |
peter |
95 |
|
1513 |
23 Sep 12 |
peter |
96 |
os << "<div class=\"main\">" |
1513 |
23 Sep 12 |
peter |
97 |
<< "<table class=\"main\"><thead><tr><th colspan=\"2\">" |
223 |
09 Mar 07 |
peter |
98 |
<< "General Information" |
234 |
09 Apr 07 |
peter |
99 |
<< "</th></tr></thead>\n" |
378 |
20 Jun 07 |
jari |
100 |
<< "<tbody>\n" |
1513 |
23 Sep 12 |
peter |
101 |
<< "<tr><td>URL:</td><td>"; |
893 |
26 Nov 09 |
peter |
102 |
if (url.size()>=4 && url.substr(0,4)=="http") |
893 |
26 Nov 09 |
peter |
103 |
os << anchor(url, url); |
893 |
26 Nov 09 |
peter |
104 |
else |
893 |
26 Nov 09 |
peter |
105 |
os << url; |
893 |
26 Nov 09 |
peter |
106 |
os << "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
107 |
<< "<tr><td>First Revision Date:</td><td>" |
235 |
21 Apr 07 |
peter |
108 |
<< begin(timefmt) << "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
109 |
<< "<tr><td>Latest Revision Date:</td><td>" |
235 |
21 Apr 07 |
peter |
110 |
<< end(timefmt) << "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
111 |
<< "<tr><td>Age:</td><td>"; |
363 |
10 Jun 07 |
peter |
112 |
os << end.difftime(begin); |
223 |
09 Mar 07 |
peter |
113 |
os << "</td></tr>\n" |
1571 |
05 Feb 15 |
peter |
114 |
<< "<tr><td>First Revision:</td><td>" |
1513 |
23 Sep 12 |
peter |
115 |
<< log.commits().begin()->revision() |
363 |
10 Jun 07 |
peter |
116 |
<< "</td></tr>\n" |
1571 |
05 Feb 15 |
peter |
117 |
<< "<tr><td>Latest Revision:</td><td>" << log.latest_commit().revision() |
363 |
10 Jun 07 |
peter |
118 |
<< "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
119 |
<< "<tr><td>Revision Count:</td><td>" << log.commits().size() |
363 |
10 Jun 07 |
peter |
120 |
<< "</td></tr>\n" |
234 |
09 Apr 07 |
peter |
121 |
<< "<tr><td>Number of Authors:</td><td>" << nof_authors |
223 |
09 Mar 07 |
peter |
122 |
<< "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
123 |
<< "<tr><td>Number of Directories:</td><td>" |
1254 |
31 Oct 10 |
peter |
124 |
<< node_counter.directories() |
1254 |
31 Oct 10 |
peter |
125 |
<< "</td></tr>\n" |
1513 |
23 Sep 12 |
peter |
126 |
<< "<tr><td>Number of Files:</td><td>" |
1254 |
31 Oct 10 |
peter |
127 |
<< node_counter.files() |
1254 |
31 Oct 10 |
peter |
128 |
<< "</td></tr>\n" |
378 |
20 Jun 07 |
jari |
129 |
<< "</tbody>\n" |
201 |
09 Sep 06 |
peter |
130 |
<< "</table></div>\n"; |
201 |
09 Sep 06 |
peter |
131 |
} |
201 |
09 Sep 06 |
peter |
132 |
|
201 |
09 Sep 06 |
peter |
133 |
|
1513 |
23 Sep 12 |
peter |
134 |
void print_authors(std::ostream& os, |
256 |
30 Apr 07 |
peter |
135 |
const std::vector<Commitment>& lc, |
256 |
30 Apr 07 |
peter |
136 |
const Stats& stats) |
234 |
09 Apr 07 |
peter |
137 |
{ |
751 |
14 Jan 09 |
peter |
138 |
HtmlStream hs(os); |
234 |
09 Apr 07 |
peter |
139 |
os << "<div class=\"main\">" |
1513 |
23 Sep 12 |
peter |
140 |
<< "<table class=\"main\"><thead><tr><th colspan=\"2\">" |
234 |
09 Apr 07 |
peter |
141 |
<< "Authors" |
234 |
09 Apr 07 |
peter |
142 |
<< "</th></tr></thead>\n"; |
234 |
09 Apr 07 |
peter |
143 |
|
1513 |
23 Sep 12 |
peter |
144 |
os << "<tr><td>Author</td>" |
234 |
09 Apr 07 |
peter |
145 |
<< "<td>Number of Lines</td>" |
234 |
09 Apr 07 |
peter |
146 |
<< "<td>Code Lines</td>" |
234 |
09 Apr 07 |
peter |
147 |
<< "<td>Comment Lines</td>" |
234 |
09 Apr 07 |
peter |
148 |
<< "<td>Latest Commitment</td>" |
234 |
09 Apr 07 |
peter |
149 |
<<"</tr>"; |
234 |
09 Apr 07 |
peter |
150 |
|
751 |
14 Jan 09 |
peter |
151 |
std::string timefmt("%Y-%m-%d %H:%M"); |
234 |
09 Apr 07 |
peter |
152 |
using namespace std; |
256 |
30 Apr 07 |
peter |
153 |
for (vector<Commitment>::const_iterator i=lc.begin(); i!=lc.end(); ++i) { |
1513 |
23 Sep 12 |
peter |
154 |
os << "<tr><td>"; |
311 |
17 May 07 |
peter |
155 |
if (!stats.lines(i->author())) |
310 |
12 May 07 |
peter |
156 |
os << i->author(); |
310 |
12 May 07 |
peter |
157 |
else |
497 |
14 Oct 07 |
peter |
158 |
os << anchor(std::string("classic/"+i->author()+"/total/index.html"), |
497 |
14 Oct 07 |
peter |
159 |
i->author()); |
1513 |
23 Sep 12 |
peter |
160 |
os << "</td><td>" << stats.lines(i->author()) << " (" |
492 |
14 Oct 07 |
peter |
161 |
<< 100*stats.lines(i->author())/(stats.lines()?stats.lines():1) |
1513 |
23 Sep 12 |
peter |
162 |
<< "%)</td><td>" << stats.code(i->author()) << " (" |
492 |
14 Oct 07 |
peter |
163 |
<< 100*stats.code(i->author())/(stats.code()?stats.code():1) |
1513 |
23 Sep 12 |
peter |
164 |
<< "%)</td><td>" << stats.comments(i->author()) << " (" |
492 |
14 Oct 07 |
peter |
165 |
<< 100*stats.comments(i->author())/(stats.comments()?stats.comments():1) |
751 |
14 Jan 09 |
peter |
166 |
<< "%)</td><td>"; |
1095 |
13 Jun 10 |
peter |
167 |
std::string date = Date(i->date())(timefmt); |
1095 |
13 Jun 10 |
peter |
168 |
const Configuration& conf = Configuration::instance(); |
1095 |
13 Jun 10 |
peter |
169 |
if (conf.trac_root().empty()) |
1095 |
13 Jun 10 |
peter |
170 |
hs << date; |
1095 |
13 Jun 10 |
peter |
171 |
else { |
1095 |
13 Jun 10 |
peter |
172 |
std::stringstream url; |
1095 |
13 Jun 10 |
peter |
173 |
url << conf.trac_root() << "changeset/" << i->revision(); |
1095 |
13 Jun 10 |
peter |
174 |
os << anchor(url.str(), date); |
1095 |
13 Jun 10 |
peter |
175 |
} |
751 |
14 Jan 09 |
peter |
176 |
os << "</td>" <<"</tr>"; |
234 |
09 Apr 07 |
peter |
177 |
} |
362 |
10 Jun 07 |
peter |
178 |
os << "<tr><td>Total</td>"; |
362 |
10 Jun 07 |
peter |
179 |
os << "<td>" << stats.lines() << "</td>" |
362 |
10 Jun 07 |
peter |
180 |
<< "<td>" << stats.code() << "</td>" |
362 |
10 Jun 07 |
peter |
181 |
<< "<td>" << stats.comments() << "</td>" |
362 |
10 Jun 07 |
peter |
182 |
<<"</tr>"; |
234 |
09 Apr 07 |
peter |
183 |
|
234 |
09 Apr 07 |
peter |
184 |
os << "</table></div>\n"; |
234 |
09 Apr 07 |
peter |
185 |
} |
234 |
09 Apr 07 |
peter |
186 |
|
234 |
09 Apr 07 |
peter |
187 |
|
556 |
16 Jan 08 |
peter |
188 |
void print_recent_logs(std::ostream& os, const SVNlog& log, |
556 |
16 Jan 08 |
peter |
189 |
const StatsCollection& stats) |
234 |
09 Apr 07 |
peter |
190 |
{ |
234 |
09 Apr 07 |
peter |
191 |
os << "<div class=\"main\">\n" |
1513 |
23 Sep 12 |
peter |
192 |
<< "<table class=\"main\"><thead><tr><th colspan=\"2\">" |
234 |
09 Apr 07 |
peter |
193 |
<< "Recent Log" |
234 |
09 Apr 07 |
peter |
194 |
<< "</th></tr></thead>\n"; |
234 |
09 Apr 07 |
peter |
195 |
|
556 |
16 Jan 08 |
peter |
196 |
os << "<tr><td>Author</td><td>Date</td><td>Rev</td><td>Added</td>" |
556 |
16 Jan 08 |
peter |
197 |
<< "<td>Removed</td><td>Message</td></tr>\n"; |
234 |
09 Apr 07 |
peter |
198 |
HtmlStream hs(os); |
751 |
14 Jan 09 |
peter |
199 |
std::string timefmt("%Y-%m-%d %H:%M"); |
235 |
21 Apr 07 |
peter |
200 |
const size_t maxlength = 80; |
289 |
08 May 07 |
peter |
201 |
const Configuration& conf = Configuration::instance(); |
759 |
29 Jan 09 |
peter |
202 |
typedef SVNlog::container::const_reverse_iterator iter; |
759 |
29 Jan 09 |
peter |
203 |
size_t count = 0; |
1513 |
23 Sep 12 |
peter |
204 |
for (iter i=log.commits().rbegin(); |
759 |
29 Jan 09 |
peter |
205 |
i != log.commits().rend() && count<10; ++i) { |
1513 |
23 Sep 12 |
peter |
206 |
os << "<tr><td>" |
642 |
31 May 08 |
peter |
207 |
<< anchor(std::string("classic/")+i->author()+"/total/index.html", |
1513 |
23 Sep 12 |
peter |
208 |
i->author()) |
497 |
14 Oct 07 |
peter |
209 |
<< "</td>"; |
642 |
31 May 08 |
peter |
210 |
Date date(i->date()); |
751 |
14 Jan 09 |
peter |
211 |
os << "<td>"; |
1513 |
23 Sep 12 |
peter |
212 |
hs << date(timefmt); |
751 |
14 Jan 09 |
peter |
213 |
os << "</td>"; |
1513 |
23 Sep 12 |
peter |
214 |
os << "<td>"; |
642 |
31 May 08 |
peter |
215 |
os << trac_revision(i->revision()); |
274 |
02 May 07 |
peter |
216 |
os << "</td>"; |
234 |
09 Apr 07 |
peter |
217 |
os << "<td>"; |
642 |
31 May 08 |
peter |
218 |
int added = stats["add"](LineTypeParser::total, "all", i->revision()) - |
1513 |
23 Sep 12 |
peter |
219 |
stats["add"](LineTypeParser::total, "all", i->revision() - 1); |
556 |
16 Jan 08 |
peter |
220 |
os << added; |
556 |
16 Jan 08 |
peter |
221 |
os << "</td>"; |
556 |
16 Jan 08 |
peter |
222 |
os << "<td>"; |
642 |
31 May 08 |
peter |
223 |
os << added-(stats["blame"](LineTypeParser::total, "all", i->revision()) - |
1513 |
23 Sep 12 |
peter |
224 |
stats["blame"](LineTypeParser::total,"all",i->revision()-1)); |
556 |
16 Jan 08 |
peter |
225 |
os << "</td>"; |
556 |
16 Jan 08 |
peter |
226 |
os << "<td>"; |
642 |
31 May 08 |
peter |
227 |
std::string mess = i->message(); |
235 |
21 Apr 07 |
peter |
// replace newlines with space |
235 |
21 Apr 07 |
peter |
229 |
std::replace(mess.begin(), mess.end(), '\n', ' '); |
235 |
21 Apr 07 |
peter |
230 |
mess = htrim(mess); |
274 |
02 May 07 |
peter |
231 |
|
317 |
17 May 07 |
peter |
232 |
if (conf.trac_root().empty()) { |
317 |
17 May 07 |
peter |
// truncate message if too long |
317 |
17 May 07 |
peter |
234 |
if (mess.size()>maxlength) |
317 |
17 May 07 |
peter |
235 |
mess = mess.substr(0,maxlength-3) + "..."; |
274 |
02 May 07 |
peter |
236 |
hs << mess; |
317 |
17 May 07 |
peter |
237 |
} |
286 |
07 May 07 |
peter |
238 |
else {// make anchors to trac |
286 |
07 May 07 |
peter |
239 |
Trac trac(hs); |
317 |
17 May 07 |
peter |
240 |
trac.print(mess, maxlength); |
274 |
02 May 07 |
peter |
241 |
} |
274 |
02 May 07 |
peter |
242 |
|
400 |
28 Jun 07 |
peter |
243 |
os << "</td></tr>\n"; |
759 |
29 Jan 09 |
peter |
244 |
++count; |
234 |
09 Apr 07 |
peter |
245 |
} |
234 |
09 Apr 07 |
peter |
246 |
os << "</table></div>\n"; |
234 |
09 Apr 07 |
peter |
247 |
} |
234 |
09 Apr 07 |
peter |
248 |
|
274 |
02 May 07 |
peter |
249 |
|
345 |
19 May 07 |
peter |
250 |
void print_summary_plot(std::ostream& os, const Stats& stats) |
345 |
19 May 07 |
peter |
251 |
{ |
1007 |
03 Jan 10 |
peter |
252 |
std::string name("summary_plot"); |
1290 |
12 Nov 10 |
peter |
253 |
StatsPlotter(stats).plot_summary(name); |
345 |
19 May 07 |
peter |
254 |
os << "<div class=\"main\">\n"; |
1024 |
10 Jan 10 |
peter |
255 |
os << image(name); |
345 |
19 May 07 |
peter |
256 |
os << "</div>"; |
860 |
19 Nov 09 |
jari |
257 |
|
860 |
19 Nov 09 |
jari |
258 |
|
345 |
19 May 07 |
peter |
259 |
} |
345 |
19 May 07 |
peter |
260 |
|
177 |
02 Sep 06 |
peter |
261 |
}} // end of namespace svndigest and namespace theplu |