source: trunk/lib/first_page.cc @ 796

Last change on this file since 796 was 759, checked in by Peter Johansson, 13 years ago

Change container in SVNlog to be std::set<Commitment>, in order to
avoid copying in SVNlog::operator+=. Previously we had vector, but the
index had no meaning, in other words, the random access was not used.

refs #74

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.1 KB
Line 
1// $Id: first_page.cc 759 2009-01-29 11:51:35Z peter $
2
3/*
4  Copyright (C) 2006 Peter Johansson
5  Copyright (C) 2007 Jari Häkkinen, Peter Johansson
6  Copyright (C) 2009 Peter Johansson
7
8  This file is part of svndigest, http://dev.thep.lu.se/svndigest
9
10  svndigest is free software; you can redistribute it and/or modify it
11  under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 3 of the License, or
13  (at your option) any later version.
14
15  svndigest is distributed in the hope that it will be useful, but
16  WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  General Public License for more details.
19
20  You should have received a copy of the GNU General Public License
21  along with svndigest. If not, see <http://www.gnu.org/licenses/>.
22*/
23
24#include "first_page.h"
25
26#include "Commitment.h"
27#include "Configuration.h"
28#include "Date.h"
29#include "HtmlStream.h"
30#include "html_utility.h"
31#include "Stats.h"
32#include "SVNlog.h"
33#include "Trac.h"
34#include "utility.h"
35#include <config.h> // this header file is created by configure
36
37#include <algorithm>
38#include <cassert>
39#include <fstream>
40#include <iostream>
41#include <sstream>
42#include <stdexcept>
43#include <string>
44#include <sys/param.h>
45#include <unistd.h>
46#include <vector>
47
48namespace theplu{
49namespace svndigest{
50
51  void print_main_page(const std::string& dir, const SVNlog& log,
52                       const StatsCollection& stats, std::string url)
53  {
54    std::string filename="index.html";
55    std::ofstream os(filename.c_str());
56    print_header(os, dir, 0, "all", "main", "index.html", "none");
57
58    using namespace std;
59    set<string> authors;
60    std::transform(log.commits().begin(), log.commits().end(),
61                   std::inserter(authors, authors.begin()), 
62                   std::mem_fun_ref(&Commitment::author));
63    // erase invalid authors
64    authors.erase("");
65    authors.erase("no author");
66
67    vector<Commitment> latest_commit;
68    latest_commit.reserve(authors.size());
69    for (set<string>::const_iterator i(authors.begin()); i!=authors.end(); ++i)
70      latest_commit.push_back(log.latest_commit(*i));
71
72    print_summary_plot(os, stats["classic"]);
73    print_general_information(os, log, authors.size(), url);
74    sort(latest_commit.begin(), latest_commit.end(), GreaterRevision());
75    print_authors(os, latest_commit, stats["classic"]);
76    print_recent_logs(os, log, stats);
77    os << "<hr width=100% />";
78    print_footer(os);
79    os.close();
80  }
81
82  void print_general_information(std::ostream& os, const SVNlog& log, 
83                                 size_t nof_authors, std::string url)
84  { 
85    assert(log.commits().size());
86    Date begin(log.commits().begin()->date());   
87    Date end(log.latest_commit().date());
88    std::string timefmt("%a %b %e %H:%M:%S %Y");
89
90    os << "<div class=\"main\">" 
91       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
92       << "General Information"
93       << "</th></tr></thead>\n"
94       << "<tbody>\n"
95       << "<tr><td>URL:</td><td>" 
96       << url << "</td></tr>\n"
97       << "<tr><td>First Revision Date:</td><td>" 
98       << begin(timefmt) << "</td></tr>\n"
99       << "<tr><td>Latest Revision Date:</td><td>" 
100       << end(timefmt) << "</td></tr>\n"
101       << "<tr><td>Age:</td><td>"; 
102    os << end.difftime(begin);
103    os << "</td></tr>\n"
104       << "<tr><td>Smallest Revision:</td><td>" 
105       << log.commits().begin()->revision() 
106       << "</td></tr>\n"
107       << "<tr><td>Largest Revision:</td><td>" << log.latest_commit().revision() 
108       << "</td></tr>\n"
109       << "<tr><td>Revision Count:</td><td>" << log.commits().size() 
110       << "</td></tr>\n"
111       << "<tr><td>Number of Authors:</td><td>" << nof_authors
112       << "</td></tr>\n"
113       << "</tbody>\n"
114       << "</table></div>\n";
115  }
116
117
118  void print_authors(std::ostream& os, 
119                     const std::vector<Commitment>& lc,
120                     const Stats& stats)
121  {
122    HtmlStream hs(os);
123    os << "<div class=\"main\">"
124       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
125       << "Authors"
126       << "</th></tr></thead>\n";
127
128    os << "<tr><td>Author</td>" 
129       << "<td>Number of Lines</td>"
130       << "<td>Code Lines</td>"
131       << "<td>Comment Lines</td>"
132       << "<td>Latest Commitment</td>"
133       <<"</tr>";
134
135    std::string timefmt("%Y-%m-%d  %H:%M");
136    using namespace std;
137    for (vector<Commitment>::const_iterator i=lc.begin(); i!=lc.end(); ++i) {
138      os << "<tr><td>"; 
139      if (!stats.lines(i->author()))
140        os << i->author();
141      else
142        os << anchor(std::string("classic/"+i->author()+"/total/index.html"),
143                     i->author());
144      os << "</td><td>" << stats.lines(i->author()) << " (" 
145         << 100*stats.lines(i->author())/(stats.lines()?stats.lines():1)
146         << "%)</td><td>" << stats.code(i->author()) << " (" 
147         << 100*stats.code(i->author())/(stats.code()?stats.code():1)
148         << "%)</td><td>" << stats.comments(i->author()) << " (" 
149         << 100*stats.comments(i->author())/(stats.comments()?stats.comments():1)
150         << "%)</td><td>";
151      hs << Date(i->date())(timefmt);
152      os << "</td>" <<"</tr>";
153    }
154    os << "<tr><td>Total</td>";
155    os << "<td>" << stats.lines() << "</td>"
156       << "<td>" << stats.code() << "</td>"
157       << "<td>" << stats.comments() << "</td>"
158       <<"</tr>";
159
160    os << "</table></div>\n";
161  }
162
163
164  void print_recent_logs(std::ostream& os, const SVNlog& log,
165                         const StatsCollection& stats)
166  {
167    os << "<div class=\"main\">\n"
168       << "<table class=\"main\"><thead><tr><th colspan=\"2\">" 
169       << "Recent Log"
170       << "</th></tr></thead>\n";
171
172    os << "<tr><td>Author</td><td>Date</td><td>Rev</td><td>Added</td>"
173       << "<td>Removed</td><td>Message</td></tr>\n";
174    HtmlStream hs(os);
175    std::string timefmt("%Y-%m-%d  %H:%M");
176    const size_t maxlength = 80;
177    const Configuration& conf = Configuration::instance();
178    typedef SVNlog::container::const_reverse_iterator iter;
179    size_t count = 0;
180    for (iter i=log.commits().rbegin(); 
181         i != log.commits().rend() && count<10; ++i) {
182      os << "<tr><td>" 
183         << anchor(std::string("classic/")+i->author()+"/total/index.html",
184                   i->author()) 
185         << "</td>";
186      Date date(i->date());
187      os << "<td>";
188      hs << date(timefmt); 
189      os << "</td>";
190      os << "<td>"; 
191      os << trac_revision(i->revision());
192      os << "</td>";
193      os << "<td>";
194      int added = stats["add"](LineTypeParser::total, "all", i->revision()) -
195        stats["add"](LineTypeParser::total, "all", i->revision() - 1); 
196      os << added;
197      os << "</td>";
198      os << "<td>";
199      os << added-(stats["blame"](LineTypeParser::total, "all", i->revision()) -
200                   stats["blame"](LineTypeParser::total,"all",i->revision()-1)); 
201      os << "</td>";
202      os << "<td>";
203      std::string mess = i->message();
204      // replace newlines with space
205      std::replace(mess.begin(), mess.end(), '\n', ' ');
206      mess = htrim(mess);
207
208      if (conf.trac_root().empty()) {
209        // truncate message if too long
210        if (mess.size()>maxlength)
211          mess = mess.substr(0,maxlength-3) + "...";
212        hs << mess;
213      }
214      else {// make anchors to trac
215        Trac trac(hs);
216        trac.print(mess, maxlength);
217      }
218
219      os << "</td></tr>\n";
220      ++count;
221    }
222    os << "</table></div>\n";
223  }
224
225
226  void print_summary_plot(std::ostream& os, const Stats& stats)
227  {
228    std::string name("summary_plot.png");
229    stats.plot_summary(name);
230    os << "<div class=\"main\">\n";
231    os << "<img src='" << name << "' alt='[plot]'/>"; 
232    os << "</div>";
233  }
234
235}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.