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