source: trunk/lib/html_utility.cc @ 257

Last change on this file since 257 was 257, checked in by Peter Johansson, 16 years ago

'Number of Revisions' on main page is changed. Instead of dispaly revision of last commit, we now display number of ChangeSets? (in the branch being parsed). For time being we do count rev 0

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 14.1 KB
Line 
1// $Id: html_utility.cc 257 2007-04-30 11:23:47Z peter $
2
3/*
4  Copyright (C) 2006, 2007 Peter Johansson
5
6  This file is part of svndigest, http://lev.thep.lu.se/trac/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
21  02111-1307, USA.
22*/
23
24#include "html_utility.h"
25
26#include "Commitment.h"
27#include "Date.h"
28#include "HtmlStream.h"
29#include "Stats.h"
30#include "SVNlog.h"
31#include "utility.h"
32#include <config.h> // this header file is created by configure
33
34#include <algorithm>
35#include <fstream>
36#include <iostream>
37#include <sstream>
38#include <stdexcept>
39#include <string>
40#include <sys/param.h>
41#include <unistd.h>
42#include <vector>
43
44namespace theplu{
45namespace svndigest{
46
47  std::string anchor(const std::string& href, 
48                     const std::string& name, u_int level, 
49                     const std::string& title)
50  {
51    std::stringstream ss;
52    HtmlStream hs(ss);
53    ss << "<a title=\"";
54    hs << title; 
55    ss << "\" href=\"";
56    for (size_t i=0; i<level; ++i)
57      ss << "../";
58    hs << href; 
59    ss << "\">"; 
60    hs << name; 
61    ss << "</a>";
62    return ss.str();
63  }
64
65 
66  void print_css(const std::string& str)
67  {
68    std::ofstream s(str.c_str());
69    s << "<-- svndigest.css generated by " << PACKAGE_STRING << "\n"
70
71      << "Copyright (C) 2006, 2007 Peter Johansson\n\n"
72      << "This file is part of svndigest, " 
73      << "http://lev.thep.lu.se/trac/svndigest\n\n"
74
75      << "svndigest is free software; you can redistribute it and/or " 
76      << "modify it\n"
77      << "under the terms of the GNU General Public License as published by\n"
78      << "the Free Software Foundation; either version 2 of the License, or\n"
79      << "(at your option) any later version.\n\n"
80
81      << "svndigest is distributed in the hope that it will be useful, but\n"
82      << "WITHOUT ANY WARRANTY; without even the implied warranty of\n"
83      << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n"
84      << "General Public License for more details.\n\n"
85
86      << "You should have received a copy of the GNU General Public License\n"
87      << "along with this program; if not, write to the Free Software\n"
88      << "Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA\n"
89      << "02111-1307, USA.\n\n"
90
91      << "This file was initially inspired by the cascading style sheet\n"
92      << "within the Trac open source project (http://trac.edgewall.org/)\n"
93      << "Copyright (C) 2003-2006 Edgewall Software\n"
94      << "All rights reserved.\n\n"
95
96      << "Redistribution and use in source and binary forms, with or without\n"
97      << "modification, are permitted provided that the following conditions\n"
98      << "are met:\n\n"
99     
100      << "1. Redistributions of source code must retain the above copyright\n"
101      << "   notice, this list of conditions and the following disclaimer.\n"
102      << "2. Redistributions in binary form must reproduce the above " 
103      << "copyright\n"
104      << "   notice, this list of conditions and the following disclaimer in\n"
105      << "   the documentation and/or other materials provided with the\n"
106      << "   distribution.\n"
107      << "3. The name of the author may not be used to endorse or promote\n"
108      << "   products derived from this software without specific prior\n"
109      << "   written permission.\n\n"
110     
111      << "THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS\n"
112      << "OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n"
113      << "WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n"
114      << "ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\n"
115      << "DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n"
116      << "DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\n"
117      << "GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n"
118      << "INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\n"
119      << "WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\n"
120      << "NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\n"
121      << "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.-->\n";
122
123
124    s << "body {\n";
125    s << " background: #fff; \n";
126    s << " color: #000; \n";
127    s << " margin: 0px; \n";
128    s << " padding: 0; \n";
129    s << "} \n";
130    s << "\n";
131    s << "#menu {\n";
132    s << " background: #eee;\n";
133    s << " width: 100%;\n";
134    s << " margin: 0px;\n";
135    s << " padding: 0px;\n";
136    s << "}\n\n";
137    s << "#menu ul\n";
138    s << "{ \n";
139    s << "padding: 0px;\n";
140    s << "margin: 0px;list-style-type: none; text-align: center;"
141      << "border-bottom: 1px solid black;}\n";
142    s << "#menu ul li { display: inline; border-right: 1px solid black;}\n";
143    s << "#menu ul li a {text-decoration: none; padding-right: 1em;" 
144      << "padding-left: 1em; margin: 0px;}\n";
145    s << "#menu ul li a:hover{ color: #000; background: #ddd;}\n";
146    s << "#menu ul li.highlight a {color: #fff; background: #777; }";
147    s << "\n";
148    s << "#main {\n";
149    s << " margin: 10px; \n";
150    s << "}\n";
151    s << "\n";
152    s << "body, th, td {\n";
153    s << " font: normal 13px verdana,arial,'Bitstream Vera Sans',"
154      << "helvetica,sans-serif;\n";
155    s << "}\n";
156    s << ":link, :visited {\n";
157    s << " text-decoration: none;\n";
158    s << " color: #b00;\n";
159    s << "}\n";
160    s << "\n";
161    s << "div.main {\n";
162    s << "margin-top: 50px;\n";         
163    s << "margin-left: 50px;\n";
164    s << " \n";
165    s << "}\n";
166    s << "table.main {\n"; 
167    s << " text-align: left;\n";
168    s << " padding: 0 1em .1em 0;\n";
169    s << "}\n";
170    s << "table.main th {\n";
171    s << " text-align: left;\n";
172    s << " padding: 0 1em 0.5em 0;\n";
173    s << " font-size: 150%;\n";
174    s << " font-wheight: bold;\n";
175    s << "}\n";
176    s << "table.main td {\n";
177    s << " padding: 0 1em .1em 0;\n";
178    s << "}\n";
179
180
181
182
183    s << "table.listings {\n";
184    s << " clear: both;\n";
185    s << " border-bottom: 1px solid #d7d7d7;\n";
186    s << " border-collapse: collapse;\n";
187    s << " border-spacing: 0;\n";
188    s << " margin-top: 1em;\n";
189    s << " width: 100%;\n";
190    s << "}\n";
191    s << "\n";
192    s << "table.listings th {\n";
193    s << " text-align: left;\n";
194    s << " padding: 0 1em .1em 0;\n";
195    s << " font-size: 12px\n";
196    s << "}\n";
197    s << "table.listings thead { background: #f7f7f0 }\n";
198    s << "table.listings thead th {\n";
199    s << " border: 1px solid #d7d7d7;\n";
200    s << " border-bottom-color: #999;\n";
201    s << " font-size: 11px;\n";
202    s << " font-wheight: bold;\n";
203    s << " padding: 2px .5em;\n";
204    s << " vertical-align: bottom;\n";
205    s << "}\n";
206    s << "\n";
207    s << "table.listings tbody td a:hover, table.listing tbody th a:hover {\n";
208    s << " background-color: transparent;\n";
209    s << "}\n";
210    s << "\n";
211    s << "table.listings tbody td, table.listing tbody th {\n";
212    s << " border: 1px dotted #ddd;\n";
213    s << " padding: .33em .5em;\n";
214    s << " vertical-align: top;\n";
215    s << "}\n";
216    s << "\n";
217    s << "table.listings tbody td a:hover, table.listing tbody th a:hover {\n";
218    s << " background-color: transparent;\n";
219    s << "}\n";
220    s << "table.listings tbody tr { border-top: 1px solid #ddd }\n";
221    s << "table.listings tbody tr.light { background-color: #fcfcfc }\n";
222    s << "table.listings tbody tr.dark { background-color: #f7f7f7 }\n";
223    s << "table.listings tbody tr:hover { background: #eed }\n";
224    s << "table.listings tbody td { text-align: left }\n";
225    s << "table.listings tbody td.directory a { font-weight: bold }\n";
226    s << "\n";
227    s << ".sep { color: #666}\n";
228    s << "\n";
229    s << "\n";
230    s.close();
231  }
232
233
234  void print_main_page(const std::string& dir, const SVNlog& log,
235                       const Stats& stats)
236  {
237    std::string filename="index.html";
238    std::ofstream os(filename.c_str());
239    print_header(os, dir, 0, "all", "main", "index.html");
240
241    using namespace std;
242    set<string> authors;
243    authors.insert(log.author().begin(), log.author().end());
244    // erase invalid authors
245    authors.erase("");
246    authors.erase("no author");
247
248    vector<Commitment> latest_commit;
249    latest_commit.reserve(authors.size());
250    for (set<string>::const_iterator i(authors.begin()); i!=authors.end(); ++i)
251      latest_commit.push_back(log.latest_commit(*i));
252
253    print_general_information(os, log, authors.size());
254    sort(latest_commit.begin(), latest_commit.end(), GreaterRevision());
255    print_authors(os, latest_commit, stats);
256    print_recent_logs(os, log);
257    os << "<hr width=100% />";
258    print_footer(os);
259    os.close();
260
261  }
262
263  void print_general_information(std::ostream& os, const SVNlog& log, 
264                                 size_t nof_authors)
265  { 
266    Date begin(log.date()[0]);
267    if (log.date().size()>1)
268      begin = std::min(begin, Date(log.date()[1]));
269    Date end(log.date().back());
270    Date now;
271    std::string timefmt("%a, %e %b %Y");
272
273    os << "<div class=\"main\">" 
274       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
275       << "General Information"
276       << "</th></tr></thead>\n"
277       << "<tr><td>First Revision:</td><td>" 
278       << begin(timefmt) << "</td></tr>\n"
279       << "<tr><td>Latest Revision:</td><td>" 
280       << end(timefmt) << "</td></tr>\n"
281       << "<tr><td>Report Generated:</td><td>" 
282       << now(timefmt) << "</td></tr>\n"
283       << "<tr><td>Repository Age:</td><td>"; 
284    os << now.difftime(begin);
285    os << "</td></tr>\n"
286       << "<tr><td>Number of Authors:</td><td>" << nof_authors
287       << "</td></tr>\n"
288       << "<tr><td>Revisions:</td><td>" << log.revision().size() 
289       << "</td></tr>\n"
290       << "</table></div>\n";
291  }
292
293
294  void print_footer(std::ostream& os)
295  {
296    Date date;
297    os << "<p align=center><font size=-2>\nGenerated on "
298       << date("%a %b %d %H:%M:%S %Y") << " (UTC) by "
299       << anchor("http://lev.thep.lu.se/trac/svndigest/", 
300                 PACKAGE_STRING, 0, "")
301       << "</font>\n</p>\n</div>\n</body>\n</html>\n";
302  }
303
304
305  void print_header(std::ostream& os, std::string title, u_int level,
306                    std::string user, std::string item, std::string path)
307  {
308    os << "<!DOCTYPE html\n"
309       << "PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n"
310       << "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n"
311       << "<html xmlns=\"http://www.w3.org/1999/xhtml\""
312       << " xml:lang=\"en\" lang=\"en\"><head>\n"
313       << "<head>\n"
314       << "<title> " << title << " - svndigest</title>\n"
315       << "</head>\n"
316       << "<link rel=\"stylesheet\" "
317       << "href=\"";
318    for (u_int i=0; i<level; ++i)
319      os << "../";
320    os << "svndigest.css\" type=\"text/css\" />\n"
321       << "<body>\n"
322       << "<div id=\"menu\">"
323       << "<ul><li></li>";
324    if (item=="main")
325      os << "<li class=\"highlight\">";
326    else
327      os << "<li>";
328    os << anchor("index.html", "Main", level, "Main page");
329    os << "</li>";
330
331    if (item=="total")
332      os << "<li class=\"highlight\">";
333    else
334      os << "<li>";
335    os << anchor(user+"/total/"+path, "Total", level, 
336           "View statistics of all lines");
337    os << "</li>";
338
339    if (item=="code")
340      os << "<li class=\"highlight\">";
341    else
342      os << "<li>";
343    os << anchor(user+"/code/"+path, "Code", level, 
344                 "View statistics of code lines");
345    os << "</li>";
346
347    if (item=="comments")
348      os << "<li class=\"highlight\">";
349    else
350      os << "<li>";
351    os << anchor(user+"/comments/"+path, "Comment", level, 
352                 "View statistics of comment lines");
353    os << "</li>";
354
355
356    if (item=="empty")
357      os << "<li class=\"highlight\">";
358    else
359      os << "<li>";
360    os << anchor(user+"/empty/"+path, "Other", level, 
361                 "View statistics of empty lines");
362    os << "</li>"
363       << "</ul></div>"
364       << "<div id=\"main\">\n";
365  }
366
367
368  void print_authors(std::ostream& os, 
369                     const std::vector<Commitment>& lc,
370                     const Stats& stats)
371  {
372    os << "<div class=\"main\">"
373       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
374       << "Authors"
375       << "</th></tr></thead>\n";
376
377    os << "<tr><td>Author</td>" 
378       << "<td>Number of Lines</td>"
379       << "<td>Code Lines</td>"
380       << "<td>Comment Lines</td>"
381       << "<td>Latest Commitment</td>"
382       <<"</tr>";
383
384    std::string timefmt("%b %d %H:%M:%S %Y");
385    using namespace std;
386    for (vector<Commitment>::const_iterator i=lc.begin(); i!=lc.end(); ++i) {
387      os << "<tr><td>" 
388         << anchor(string(i->author()+"/total/index.html"),i->author())
389         << "</td><td>" << stats.lines(i->author()) << " (" 
390         << 100*stats.lines(i->author())/stats.lines() << "%)</td>"
391         << "<td>" << stats.code(i->author()) << " (" 
392         << 100*stats.code(i->author())/stats.code() << "%)</td>"
393         << "<td>" << stats.comments(i->author()) << " (" 
394         << 100*stats.comments(i->author())/stats.comments() << "%)</td>"
395         << "<td>" << i->date()(timefmt) << "</td>"
396         <<"</tr>";
397    }
398
399    os << "</table></div>\n";
400   
401  }
402
403
404  void print_recent_logs(std::ostream& os, const SVNlog& log)
405  {
406    os << "<div class=\"main\">\n"
407       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
408       << "Recent Log"
409       << "</th></tr></thead>\n";
410
411    std::vector<std::string>::const_reverse_iterator a=log.author().rbegin();
412    std::vector<std::string>::const_reverse_iterator d=log.date().rbegin();
413    std::vector<std::string>::const_reverse_iterator m=log.message().rbegin();
414    std::vector<size_t>::const_reverse_iterator r=log.revision().rbegin();
415    assert(log.author().size()==log.date().size());
416    assert(log.author().size()==log.message().size());
417    assert(log.author().size()==log.revision().size());
418    os << "<tr><td>Author</td><td>Date</td><td>Rev</td><td>Message</td></tr>\n";
419    HtmlStream hs(os);
420    std::string timefmt("%b %d %H:%M:%S %Y");
421    const size_t maxlength = 80;
422    for (size_t i=0; i<10 && a!=log.author().rend(); ++i) {
423      os << "<tr><td>" << anchor(*a+"/total/index.html",*a) << "</td>";
424      Date date(*d);
425      os << "<td>" << date(timefmt) << "</td>";
426      os << "<td>" << *r << "</td>";
427      os << "<td>";
428      std::string mess = *m;
429      // replace newlines with space
430      std::replace(mess.begin(), mess.end(), '\n', ' ');
431      mess = htrim(mess);
432      // trunctate message if too long
433      if (mess.size()>maxlength)
434        mess = mess.substr(0,maxlength-3) + "...";
435      hs << mess;
436      os << "</td></tr>";
437      ++a;
438      ++d;
439      ++m;
440      ++r;
441    }
442    os << "</table></div>\n";
443  }
444
445}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.