Changeset 1290
- Timestamp:
- Nov 12, 2010, 5:01:35 AM (12 years ago)
- Location:
- trunk
- Files:
-
- 2 added
- 14 edited
- 6 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/bin/Makefile.am
r1267 r1290 31 31 EXTRA_DIST = svndigest-copy-cache.as 32 32 33 LDADD = $(top_builddir)/lib/libsvndigest .a \34 $(top_builddir)/yat/libyat.a $(SVN_LIBS) $(APR_LIBS) $(PLPLOT_LIBS)33 LDADD = $(top_builddir)/lib/libsvndigest_core.a \ 34 $(top_builddir)/yat/libyat.a $(SVN_LIBS) $(APR_LIBS) 35 35 AM_LDFLAGS = $(SVNDIGEST_LDFLAGS) 36 36 … … 38 38 AM_CXXFLAGS = $(SVNDIGEST_CXXFLAGS) 39 39 40 ##svndigest_LDADD = $(LDADD) $(PLPLOT_LIBS) 40 svndigest_LDADD = $(top_builddir)/lib/libsvndigest.a $(LDADD) $(PLPLOT_LIBS) 41 41 ##svndigest_LDFLAGS = $(AM_LDFLAGS) $(PLPLOT_LDFLAGS) 42 42 ##svndigest_CPPFLAGS = $(AM_CPPFLAGS) $(PLPLOT_CPPFLAGS) -
trunk/bin/svndigest.cc
r1280 r1290 130 130 131 131 if (option.report()) 132 print_main_page(tree.name(), tree.log(), tree.stats(), tree.url(),133 file_count);132 print_main_page(tree.name(), tree.log(), tree.stats(), 133 tree.svn_info().url(), file_count); 134 134 135 135 } -
trunk/lib/Directory.cc
r1289 r1290 146 146 147 147 148 std::string Directory::output_path(void) const149 {150 return output_dir()+"index.html";151 }152 153 154 void Directory::print_core(const bool verbose) const155 {156 }157 158 159 void Directory::print_core(const std::string& stats_type,160 const std::string& user,161 const std::string& line_type,162 const SVNlog& log) const163 {164 165 const Stats& stats = stats_[stats_type];166 std::string imagedir = stats_type+"/"+"images/"+line_type;167 std::string outdir = stats_type+"/"+user+"/" +line_type;168 if (local_path()!="") {169 imagedir += "/"+local_path();170 outdir += "/"+local_path();171 }172 mkdir_p(outdir);173 if (user=="all")174 mkdir_p(imagedir);175 std::string html_name = outdir+"/index.html";176 std::ofstream os(html_name.c_str());177 assert(os.good());178 if (local_path().empty())179 print_header(os, name(), level_+3, user, line_type, "index.html",180 stats_type);181 else182 print_header(os, name(), level_+3, user, line_type,183 local_path()+"/index.html", stats_type);184 path_anchor(os);185 186 std::stringstream ss;187 for (size_t i=0; i<level_; ++i)188 ss << "../";189 ss << "../../../";190 if (user=="all")191 ss << stats.plot(imagedir+"/index", line_type);192 else193 ss << imagedir << "/index";194 os << "<p class=\"plot\">\n";195 os << image(ss.str());196 os << "</p>\n";197 198 os << "<h3>File Summary";199 if (user!="all")200 os << " for " << user;201 os << "</h3>";202 os << "<table class=\"listings\">\n";203 os << "<thead>\n";204 os << "<tr>\n";205 os << "<th>Node</th>\n";206 os << "<th>Lines</th>\n";207 os << "<th>Code</th>\n";208 os << "<th>Comments</th>\n";209 os << "<th>Other</th>\n";210 os << "<th>Revision</th>\n";211 os << "<th>Author</th>\n";212 os << "</tr>\n</thead>\n";213 os << "<tbody>\n";214 215 std::string color("light");216 if (level_){217 os << "<tr class=\"light\">\n";218 os << "<td class=\"directory\" colspan=\"7\">";219 os << anchor("../index.html", "../");220 os << "</td>\n</tr>\n";221 color = "dark";222 }223 224 // print html links to daughter nodes225 for (NodeConstIterator d = daughters_.begin(); d!=daughters_.end(); ++d) {226 (*d)->html_tablerow(os,stats_type, color, user);227 if (color=="dark")228 color = "light";229 else230 color = "dark";231 }232 os << "<tr class=\"" << color << "\">\n";233 os << "<td>Total</td>\n";234 if (user=="all"){235 os << "<td>" << stats.lines() << "</td>\n";236 os << "<td>" << stats.code() << "</td>\n";237 os << "<td>" << stats.comments() << "</td>\n";238 os << "<td>" << stats.empty() << "</td>\n";239 }240 else {241 os << "<td>" << stats.lines(user);242 if (stats.lines(user))243 os << " (" << percent(stats.lines(user),stats.lines()) << "%)";244 os << "</td>\n";245 os << "<td>" << stats.code(user);246 if (stats.code(user))247 os << " (" << percent(stats.code(user),stats.code()) << "%)";248 os << "</td>\n";249 os << "<td>" << stats.comments(user);250 if (stats.comments(user))251 os << " (" << percent(stats.comments(user),stats.comments()) << "%)";252 os << "</td>\n";253 os << "<td>" << stats.empty(user);254 if (stats.empty(user))255 os << " (" << percent(stats.empty(user),stats.empty()) << "%)";256 os << "</td>\n";257 }258 os << "<td>" << trac_revision(last_changed_rev()) << "</td>\n";259 os << "<td>" << author() << "</td>\n";260 os << "</tr>\n";261 os << "</tbody>\n";262 os << "</table>\n";263 print_author_summary(os, stats, line_type, log);264 os << "\n";265 print_footer(os);266 os.close();267 }268 269 270 148 void Directory::traverse(NodeVisitor& visitor) 271 149 { -
trunk/lib/Directory.h
r1264 r1290 111 111 Directory(const Directory&); 112 112 113 void print_core(bool verbose=false) const;114 115 void print_core(const std::string& stats_type, const std::string& user,116 const std::string& line_type, const SVNlog&) const;117 118 119 113 typedef std::vector<Node*> NodeContainer; 120 114 typedef NodeContainer::iterator NodeIterator; 121 115 typedef NodeContainer::const_iterator NodeConstIterator; 122 116 NodeContainer daughters_; 117 118 friend class DirectoryPrinter; 123 119 }; 124 120 -
trunk/lib/DirectoryPrinter.cc
r1289 r1290 20 20 */ 21 21 22 #include "Directory .h"22 #include "DirectoryPrinter.h" 23 23 24 24 #include "Alias.h" 25 25 #include "Configuration.h" 26 #include "Directory.h" 26 27 #include "File.h" 27 28 #include "html_utility.h" 28 29 #include "Node.h" 29 30 #include "NodeVisitor.h" 31 #include "StatsPlotter.h" 30 32 #include "SVN.h" 31 33 #include "SVNlog.h" … … 51 53 52 54 53 Directory::Directory(const unsigned int level, const std::string& path, 54 const std::string& output, const std::string& project) 55 : Node(level,path,output,project) 55 DirectoryPrinter::DirectoryPrinter(const Directory& dir) 56 : NodePrinter(), directory_(dir) 56 57 { 57 output_dir_=local_path();58 if (!output_dir_.empty())59 output_dir_+='/';60 61 using namespace std;62 DIR* directory=opendir(path.c_str()); // C API from dirent.h63 if (!directory)64 throw NodeException("ERROR: opendir() failed; " + path +65 " is not a directory");66 list<string> entries;67 struct dirent* entry;68 errno=0; // Global variable used by C to track errors, from errno.h69 while ((entry=readdir(directory))) // C API from dirent.h70 entries.push_back(string(entry->d_name));71 if (errno)72 throw NodeException("ERROR: readdir() failed on " + path);73 closedir(directory);74 75 SVN* svn=SVN::instance();76 for (list<string>::iterator i=entries.begin(); i!=entries.end(); ++i)77 if ((*i)!=string(".") && (*i)!=string("..") && (*i)!=string(".svn")) {78 string fullpath(path_+'/'+(*i));79 switch (svn->version_controlled(fullpath)) {80 case SVN::uptodate:81 struct stat nodestat; // C api from sys/stat.h82 lstat(fullpath,&nodestat); // C api from sys/stat.h83 if (S_ISDIR(nodestat.st_mode)) // C api from sys/stat.h84 daughters_.push_back(new Directory(level_+1,fullpath,local_path()));85 else86 daughters_.push_back(new File(level_,fullpath,local_path()));87 break;88 case SVN::unresolved:89 throw NodeException(fullpath+" is not up to date");90 case SVN::unversioned: ; // do nothing91 }92 }93 std::sort(daughters_.begin(), daughters_.end(), NodePtrLess());94 58 } 95 59 96 60 97 Directory ::~Directory(void)61 DirectoryPrinter::~DirectoryPrinter(void) 98 62 { 99 for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)100 delete *i;101 63 } 102 64 103 65 104 void Directory::collect_stats(void)66 const Node& DirectoryPrinter::node(void) const 105 67 { 106 stats_.reset(); 107 for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i) 108 if (!(*i)->ignore()) { 109 stats_ += (*i)->stats(); 110 (*i)->stats().reset(); 111 } 68 return directory_; 112 69 } 113 70 114 71 115 bool Directory::dir(void) const 116 { 117 return true; 118 } 119 120 121 std::string Directory::href(void) const 122 { 123 return name() + "/index.html"; 124 } 125 126 127 svn_revnum_t Directory::last_changed_rev(void) const 128 { 129 svn_revnum_t res = svn_info().last_changed_rev(); 130 for (NodeConstIterator i=daughters_.begin(); i!=daughters_.end(); ++i) 131 res = std::max(res, (*i)->last_changed_rev()); 132 return res; 133 } 134 135 136 void Directory::log_core(SVNlog& log) const 137 { 138 for (NodeConstIterator i(daughters_.begin()); i != daughters_.end(); ++i) 139 log += (*i)->log(); 140 } 141 142 std::string Directory::node_type(void) const 143 { 144 return std::string("directory"); 145 } 146 147 148 std::string Directory::output_path(void) const 72 std::string DirectoryPrinter::output_path(void) const 149 73 { 150 74 return output_dir()+"index.html"; … … 152 76 153 77 154 void Directory ::print_core(const bool verbose) const78 void DirectoryPrinter::print_core(const bool verbose) const 155 79 { 156 80 } 157 81 158 82 159 void Directory ::print_core(const std::string& stats_type,83 void DirectoryPrinter::print_core(const std::string& stats_type, 160 84 const std::string& user, 161 85 const std::string& line_type, … … 163 87 { 164 88 165 const Stats& stats = stats_[stats_type];89 const Stats& stats = directory_.stats_[stats_type]; 166 90 std::string imagedir = stats_type+"/"+"images/"+line_type; 167 91 std::string outdir = stats_type+"/"+user+"/" +line_type; 168 if ( local_path()!="") {169 imagedir += "/"+ local_path();170 outdir += "/"+ local_path();92 if (node().local_path()!="") { 93 imagedir += "/"+node().local_path(); 94 outdir += "/"+node().local_path(); 171 95 } 172 96 mkdir_p(outdir); … … 176 100 std::ofstream os(html_name.c_str()); 177 101 assert(os.good()); 178 if ( local_path().empty())179 print_header(os, n ame(),level_+3, user, line_type, "index.html",102 if (node().local_path().empty()) 103 print_header(os, node().name(), directory_.level_+3, user, line_type, "index.html", 180 104 stats_type); 181 105 else 182 print_header(os, n ame(),level_+3, user, line_type,183 local_path()+"/index.html", stats_type);106 print_header(os, node().name(), directory_.level_+3, user, line_type, 107 node().local_path()+"/index.html", stats_type); 184 108 path_anchor(os); 185 109 186 110 std::stringstream ss; 187 for (size_t i=0; i< level_; ++i)111 for (size_t i=0; i<directory_.level_; ++i) 188 112 ss << "../"; 189 113 ss << "../../../"; 190 114 if (user=="all") 191 ss << stats.plot(imagedir+"/index", line_type);115 ss << StatsPlotter(stats).plot(imagedir+"/index", line_type); 192 116 else 193 117 ss << imagedir << "/index"; … … 214 138 215 139 std::string color("light"); 216 if ( level_){140 if (directory_.level_){ 217 141 os << "<tr class=\"light\">\n"; 218 142 os << "<td class=\"directory\" colspan=\"7\">"; … … 223 147 224 148 // print html links to daughter nodes 225 for (NodeConstIterator d = daughters_.begin(); d!=daughters_.end(); ++d) { 226 (*d)->html_tablerow(os,stats_type, color, user); 149 for (NodeConstIterator d = directory_.daughters_.begin(); 150 d!=directory_.daughters_.end(); ++d) { 151 152 (*d)->html_tablerow(os, stats_type, color, user); 227 153 if (color=="dark") 228 154 color = "light"; … … 256 182 os << "</td>\n"; 257 183 } 258 os << "<td>" << trac_revision( last_changed_rev()) << "</td>\n";259 os << "<td>" << author() << "</td>\n";184 os << "<td>" << trac_revision(node().last_changed_rev()) << "</td>\n"; 185 os << "<td>" << node().author() << "</td>\n"; 260 186 os << "</tr>\n"; 261 187 os << "</tbody>\n"; … … 268 194 269 195 270 void Directory::traverse(NodeVisitor& visitor)271 {272 if (visitor.enter(*this))273 for (NodeIterator first=daughters_.begin(), end=daughters_.end();274 first!=end; ++first)275 (*first)->traverse(visitor);276 visitor.leave(*this);277 }278 279 280 196 }} // end of namespace svndigest and namespace theplu -
trunk/lib/DirectoryPrinter.h
r1289 r1290 1 #ifndef _theplu_svndigest_directory_ 2 #define _theplu_svndigest_directory_ 1 #ifndef _theplu_svndigest_directory_printer_ 2 #define _theplu_svndigest_directory_printer_ 3 3 4 4 // $Id$ … … 24 24 */ 25 25 26 #include "Node .h"26 #include "NodePrinter.h" 27 27 28 28 #include <map> … … 33 33 namespace svndigest{ 34 34 35 class NodeVisitor; 35 class Directory; 36 class Node; 36 37 37 38 /// 38 39 /// Class taking care of directories. 39 40 /// 40 class Directory : public Node41 class DirectoryPrinter : public NodePrinter 41 42 { 42 43 public: 43 /// 44 /// @brief Constructor 45 /// 46 /// Recursively create a directory tree starting from \a path. All 47 /// entries except explicit directories are treated as File nodes, 48 /// i.e. symbolic links to directories are treated as File 49 /// nodes. This will ensure that the directory structure is a tree 50 /// and double counting of branches is avoided. 51 /// 52 /// @note Nodes named '.', '..', and '.svn' are ignored and not 53 /// traversed. 54 /// 55 Directory(const unsigned int level, const std::string& path, 56 const std::string& output="", const std::string& project=""); 57 58 /// 59 /// @brief Destructor 60 /// 61 ~Directory(void); 44 /** 45 \brief Constructor 46 */ 47 explicit DirectoryPrinter(const Directory&); 62 48 63 49 /** 64 Collect stats from daughter nodes and reset stats in daughter 65 nodes. 66 */ 67 void collect_stats(void); 68 69 /// 70 /// @return true 71 /// 72 bool dir(void) const; 73 74 /// 75 /// @return directory-name/index.html 76 /// 77 std::string href(void) const; 78 79 /** 80 \brief Get the revision number of the latest commit. 81 82 Does not only check this directory but also daughter nodes. 50 \brief Destructor 83 51 */ 84 svn_revnum_t last_changed_rev(void) const; 85 86 /** 87 @return The explicit string "directory", nothing else. 88 */ 89 std::string node_type(void) const; 52 ~DirectoryPrinter(void); 90 53 91 54 /** … … 94 57 std::string output_path(void) const; 95 58 96 /**97 Calls visitor.enter(*this). If enter returns true, daughter98 nodes are traverses. Finally visitor visitor.leave(*this) i called.99 */100 void traverse(NodeVisitor& visitor);101 102 59 private: 103 /**104 add union of logs from daughter nodes.105 */106 void log_core(SVNlog&) const;107 108 60 /// 109 61 /// @brief Copy Constructor, not implemented 110 62 /// 111 Directory(const Directory&); 63 DirectoryPrinter(const DirectoryPrinter&); 64 65 const Node& node(void) const; 112 66 113 67 void print_core(bool verbose=false) const; … … 117 71 118 72 73 74 75 const Directory& directory_; 119 76 typedef std::vector<Node*> NodeContainer; 120 77 typedef NodeContainer::iterator NodeIterator; 121 78 typedef NodeContainer::const_iterator NodeConstIterator; 122 NodeContainer daughters_;123 79 }; 124 80 -
trunk/lib/File.cc
r1288 r1290 27 27 #include "Configuration.h" 28 28 #include "Date.h" 29 #include "Graph.h"30 29 #include "html_utility.h" 31 30 #include "HtmlStream.h" … … 62 61 63 62 64 std::string File::blame_output_file_name(void) const65 {66 return "blame_output/" + local_path() + ".html";67 }68 69 70 63 std::string File::href(void) const 71 64 { … … 88 81 { 89 82 return std::string("file"); 90 }91 92 93 std::string File::output_path(void) const94 {95 return output_dir()+name()+".html";96 83 } 97 84 … … 126 113 127 114 128 void File::print_blame(std::ofstream& os) const129 {130 os << "<br /><h3>" << local_path() << "</h3>";131 os << "<div class=\"blame_legend\">\n";132 os << "<dl>\n";133 os << "<dt class=\"code\"></dt><dd>Code</dd>\n";134 os << "<dt class=\"comment\"></dt><dd>Comments</dd>\n";135 os << "<dt class=\"other\"></dt><dd>Other</dd>\n";136 os << "</dl>\n</div>\n";137 os << "<table class=\"blame\">\n";138 os << "<thead>\n";139 os << "<tr>\n";140 os << "<th class=\"rev\">Rev</th>\n";141 os << "<th class=\"date\">Date</th>\n";142 os << "<th class=\"author\">Author</th>\n";143 os << "<th class=\"line\">Line</th>\n";144 os << "<th></th>\n";145 os << "</tr>\n</thead>\n";146 os << "<tbody>\n";147 HtmlStream hs(os);148 SVNblame blame(path_);149 LineTypeParser parser(path_);150 while (blame.valid()) {151 parser.parse(blame.line());152 blame.next_line();153 }154 blame.reset();155 156 std::vector<LineTypeParser::line_type>::const_iterator157 line_type(parser.type().begin());158 int last=0;159 int first=0;160 bool using_dates=true;161 if (!Graph::date_xticks()) {162 using_dates=false;163 first = Graph::rev_min();164 last = Graph::rev_max();165 }166 else {167 first = Graph::xticks()[Graph::rev_min()];168 assert(Graph::rev_max()<Graph::xticks().size());169 last = Graph::xticks()[Graph::rev_max()];170 }171 assert(last>first);172 // color is calculated linearly on time, c = kt + m173 // brightest color (for oldest rev in log) is set to 192.174 double k = 192.0/(first-last);175 double m = -last*k;176 while (blame.valid()) {177 std::string color;178 Date date(blame.date());179 if (using_dates)180 color = hex(static_cast<int>(k*date.seconds()+m),2);181 else182 color = hex(static_cast<int>(k*blame.revision()+m),2);183 os << "<tr>\n<td class=\"rev\">";184 std::stringstream color_ss;185 color_ss << "#" << color << color << color;186 os << "<font color=\"" << color_ss.str() << "\">"187 << trac_revision(blame.revision(), color_ss.str())188 << "</font></td>\n<td class=\"date\"><font color=\"#" << color189 << color << color << "\">" ;190 hs << date("%d %b %y");191 os << "</font></td>\n<td class=\"author\">";192 const std::string& author_color =193 Colors::instance().color_str(blame.author());194 assert(!author_color.empty());195 os << "<font color=\"#" << author_color << "\">";196 hs << blame.author();197 os << "</td>\n<td class=\"";198 assert(line_type!=parser.type().end());199 if (*line_type==LineTypeParser::other)200 os << "line-other";201 else if (*line_type==LineTypeParser::comment ||202 *line_type==LineTypeParser::copyright)203 os << "line-comment";204 else if (*line_type==LineTypeParser::code)205 os << "line-code";206 else {207 std::string msg="File::print_blame(): unexpected line type found";208 throw std::runtime_error(msg);209 }210 os << "\">" << blame.line_no()+1211 << "</td>\n<td>";212 hs << blame.line();213 os << "</td>\n</tr>\n";214 blame.next_line();215 ++line_type;216 }217 os << "</tbody>\n";218 os << "</table>\n";219 }220 221 222 void File::print_core(const bool verbose) const223 {224 if (!Configuration::instance().output_blame_information())225 return;226 mkdir_p(directory_name(blame_output_file_name()));227 std::ofstream os(blame_output_file_name().c_str());228 assert(os.good());229 print_html_start(os, "svndigest", level_+1);230 print_blame(os);231 print_footer(os);232 os.close();233 }234 235 236 void File::print_core(const std::string& stats_type,237 const std::string& user, const std::string& line_type,238 const SVNlog& log) const239 {240 std::string lpath = local_path();241 if (lpath.empty())242 lpath = "index";243 std::string outpath = stats_type+"/"+user+"/"+line_type+"/"+lpath;244 std::string imagefile = stats_type+"/"+"images/"+line_type+"/"+lpath;245 std::string html_name(outpath + ".html");246 mkdir_p(directory_name(html_name));247 mkdir_p(directory_name(imagefile));248 std::ofstream os(html_name.c_str());249 assert(os);250 print_header(os, name(), level_+3, user, line_type, lpath+".html",251 stats_type);252 path_anchor(os);253 254 std::stringstream ss;255 for (size_t i=0; i<level_; ++i)256 ss << "../";257 ss << "../../../";258 if (user=="all")259 ss << stats_[stats_type].plot(imagefile,line_type);260 else261 ss << imagefile;262 os << "<p class=\"plot\">\n";263 os << image(ss.str());264 os << "</p>\n";265 266 print_author_summary(os, stats_[stats_type], line_type, log);267 os << "\n";268 if (Configuration::instance().output_blame_information())269 os << "<h3>"270 << anchor(blame_output_file_name(), "Blame Information", level_+3)271 << "</h3>\n";272 273 print_footer(os);274 os.close();275 }276 277 278 115 void File::traverse(NodeVisitor& visitor) 279 116 { -
trunk/lib/File.h
r1267 r1290 26 26 #include "Node.h" 27 27 28 #include <map>29 28 #include <string> 30 29 … … 60 59 std::string node_type(void) const; 61 60 62 /**63 @return output path for example 'lib/File.h.html' for this file64 */65 std::string output_path(void) const;66 67 61 /// 68 62 /// @brief Parsing out information from svn repository … … 78 72 79 73 private: 80 std::string blame_output_file_name(void) const;81 82 74 /** 83 75 do nothing … … 90 82 File(const File&); 91 83 92 ///93 /// @brief Parsing svn blame output94 ///95 /// @return true if parsing is succesful96 ///97 bool blame(void) const;98 99 /**100 @brief Print blame output101 */102 void print_blame(std::ofstream& os) const;103 104 void print_core(bool verbose=false) const;105 106 ///107 /// print page for specific user (or all) and specific line_style108 /// (or total).109 ///110 void print_core(const std::string& stats_type, const std::string& user,111 const std::string& line_type, const SVNlog&) const;112 113 84 }; 114 85 -
trunk/lib/FilePrinter.cc
r1289 r1290 20 20 along with svndigest. If not, see <http://www.gnu.org/licenses/>. 21 21 */ 22 23 #include "FilePrinter.h" 22 24 23 25 #include "File.h" … … 32 34 #include "NodeVisitor.h" 33 35 #include "Stats.h" 36 #include "StatsPlotter.h" 34 37 #include "SVNblame.h" 35 38 #include "SVNlog.h" … … 51 54 namespace svndigest{ 52 55 53 54 File::File(const unsigned int level, const std::string& path, 55 const std::string& output) 56 : Node(level,path,output) 57 { 58 output_dir_=output; 59 if (!output_dir_.empty()) 60 output_dir_+='/'; 61 } 62 63 64 std::string File::blame_output_file_name(void) const 65 { 66 return "blame_output/" + local_path() + ".html"; 67 } 68 69 70 std::string File::href(void) const 71 { 72 return name()+".html"; 73 } 74 75 76 svn_revnum_t File::last_changed_rev(void) const 77 { 78 return svn_info().last_changed_rev(); 79 } 80 81 82 void File::log_core(SVNlog&) const 83 { 84 } 85 86 87 std::string File::node_type(void) const 88 { 89 return std::string("file"); 90 } 91 92 93 std::string File::output_path(void) const 94 { 95 return output_dir()+name()+".html"; 96 } 97 98 99 const StatsCollection& File::parse(bool verbose, bool ignore) 100 { 101 if (verbose) 102 std::cout << "Parsing '" << path_ << "'" << std::endl; 103 stats_.reset(); 104 std::string cache_dir = directory_name(path()) + std::string(".svndigest/"); 105 std::string cache_file = cache_dir + name()+std::string(".svndigest-cache"); 106 if (!ignore && node_exist(cache_file)){ 107 std::ifstream is(cache_file.c_str()); 108 if (stats_.load_cache(is)) { 109 is.close(); 110 return stats_; 111 } 112 is.close(); 113 } 114 else 115 stats_.parse(path_); 116 if (!node_exist(cache_dir)) 117 mkdir(cache_dir); 118 std::string tmp_cache_file(cache_file+"~"); 119 std::ofstream os(tmp_cache_file.c_str()); 120 assert(os); 121 stats_.print(os); 122 os.close(); 123 rename(tmp_cache_file, cache_file); 124 return stats_; 125 } 126 127 128 void File::print_blame(std::ofstream& os) const 129 { 130 os << "<br /><h3>" << local_path() << "</h3>"; 56 FilePrinter::FilePrinter(const File& file) 57 : NodePrinter(), file_(file) 58 { 59 } 60 61 62 std::string FilePrinter::blame_output_file_name(void) const 63 { 64 return "blame_output/" + node().local_path() + ".html"; 65 } 66 67 68 const Node& FilePrinter::node(void) const 69 { 70 return file_; 71 } 72 73 74 std::string FilePrinter::output_path(void) const 75 { 76 return output_dir()+node().name()+".html"; 77 } 78 79 80 void FilePrinter::print_blame(std::ofstream& os) const 81 { 82 os << "<br /><h3>" << node().local_path() << "</h3>"; 131 83 os << "<div class=\"blame_legend\">\n"; 132 84 os << "<dl>\n"; … … 146 98 os << "<tbody>\n"; 147 99 HtmlStream hs(os); 148 SVNblame blame( path_);149 LineTypeParser parser( path_);100 SVNblame blame(node().path_); 101 LineTypeParser parser(node().path_); 150 102 while (blame.valid()) { 151 103 parser.parse(blame.line()); … … 205 157 os << "line-code"; 206 158 else { 207 std::string msg="File ::print_blame(): unexpected line type found";159 std::string msg="FilePrinter::print_blame(): unexpected line type found"; 208 160 throw std::runtime_error(msg); 209 161 } … … 220 172 221 173 222 void File ::print_core(const bool verbose) const174 void FilePrinter::print_core(const bool verbose) const 223 175 { 224 176 if (!Configuration::instance().output_blame_information()) … … 227 179 std::ofstream os(blame_output_file_name().c_str()); 228 180 assert(os.good()); 229 print_html_start(os, "svndigest", level_+1);181 print_html_start(os, "svndigest", file_.level_+1); 230 182 print_blame(os); 231 183 print_footer(os); … … 234 186 235 187 236 void File ::print_core(const std::string& stats_type,188 void FilePrinter::print_core(const std::string& stats_type, 237 189 const std::string& user, const std::string& line_type, 238 190 const SVNlog& log) const 239 191 { 240 std::string lpath = local_path();192 std::string lpath = node().local_path(); 241 193 if (lpath.empty()) 242 194 lpath = "index"; … … 248 200 std::ofstream os(html_name.c_str()); 249 201 assert(os); 250 print_header(os, n ame(),level_+3, user, line_type, lpath+".html",202 print_header(os, node().name(), file_.level_+3, user, line_type, lpath+".html", 251 203 stats_type); 252 204 path_anchor(os); 253 205 254 206 std::stringstream ss; 255 for (size_t i=0; i< level_; ++i)207 for (size_t i=0; i<file_.level_; ++i) 256 208 ss << "../"; 257 209 ss << "../../../"; 258 210 if (user=="all") 259 ss << stats_[stats_type].plot(imagefile,line_type);211 ss << StatsPlotter(file_.stats_[stats_type]).plot(imagefile,line_type); 260 212 else 261 213 ss << imagefile; … … 264 216 os << "</p>\n"; 265 217 266 print_author_summary(os, stats_[stats_type], line_type, log);218 print_author_summary(os, file_.stats_[stats_type], line_type, log); 267 219 os << "\n"; 268 220 if (Configuration::instance().output_blame_information()) 269 221 os << "<h3>" 270 << anchor(blame_output_file_name(), "Blame Information", level_+3)222 << anchor(blame_output_file_name(), "Blame Information", file_.level_+3) 271 223 << "</h3>\n"; 272 224 … … 276 228 277 229 278 void File::traverse(NodeVisitor& visitor)279 {280 visitor.visit(*this);281 }282 283 230 }} // end of namespace svndigest and namespace theplu -
trunk/lib/FilePrinter.h
r1289 r1290 1 #ifndef _theplu_svndigest_file_ 2 #define _theplu_svndigest_file_ 1 #ifndef _theplu_svndigest_file_printer_ 2 #define _theplu_svndigest_file_printer_ 3 3 4 4 // $Id$ … … 24 24 */ 25 25 26 #include "Node .h"26 #include "NodePrinter.h" 27 27 28 #include <map>29 28 #include <string> 30 29 … … 32 31 namespace svndigest{ 33 32 34 class NodeVisitor;33 class File; 35 34 36 class File : public Node35 class FilePrinter : public NodePrinter 37 36 { 38 37 public: … … 40 39 /// @brief Default Constructor 41 40 /// 42 File(const unsigned int level, const std::string& path, 43 const std::string& output=""); 41 explicit FilePrinter(const File& file); 44 42 45 43 /** 46 For example 'File.h.html' 47 48 @return href to this file 49 */ 50 std::string href(void) const; 51 52 /** 53 \brief Get the revision number of the latest commit. 54 */ 55 svn_revnum_t last_changed_rev(void) const; 56 57 /** 58 @return The explicit string "file", nothing else. 59 */ 60 std::string node_type(void) const; 61 62 /** 63 @return output path for example 'lib/File.h.html' for this file 44 @return output path for example 'lib/FilePrinter.h.html' for this file 64 45 */ 65 46 std::string output_path(void) const; 66 67 ///68 /// @brief Parsing out information from svn repository69 ///70 /// @return Stats object of the file71 ///72 const StatsCollection& parse(bool verbose, bool ignore);73 74 /**75 Let the visitor perform its mission via visitor(*this)76 */77 void traverse(NodeVisitor& visitor);78 47 79 48 private: … … 88 57 /// @brief Copy Constructor, not implemented 89 58 /// 90 File (const File&);59 FilePrinter(const FilePrinter&); 91 60 92 61 /// … … 111 80 const std::string& line_type, const SVNlog&) const; 112 81 82 const Node& node(void) const; 83 84 const File& file_; 85 113 86 }; 114 87 -
trunk/lib/Makefile.am
r1254 r1290 28 28 AM_CXXFLAGS = $(SVNDIGEST_CXXFLAGS) 29 29 30 noinst_LIBRARIES = libsvndigest.a 30 noinst_LIBRARIES = libsvndigest.a libsvndigest_core.a 31 31 32 32 noinst_HEADERS = AddStats.h Alias.h BlameStats.h ClassicStats.h \ 33 33 Colors.h Commitment.h Configuration.h CopyrightVisitor.h css.h \ 34 Date.h Directory.h File.h first_page.h Functor.h \ 34 Date.h Directory.h DirectoryPrinter.h File.h FilePrinter.h \ 35 first_page.h Functor.h \ 35 36 Graph.h \ 36 37 HtmlBuf.h HtmlStream.h html_utility.h LineTypeParser.h \ 37 main_utility.h Node.h NodeCounter.h Node Visitor.h \38 main_utility.h Node.h NodeCounter.h NodePrinter.h NodeVisitor.h \ 38 39 OptionVersion.h rmdirhier.h \ 39 40 Stats.h StatsCollection.h subversion_info.h \ … … 42 43 Trac.h utility.h Vector.h 43 44 44 libsvndigest_a_SOURCES = AddStats.cc Alias.cc BlameStats.cc \ 45 libsvndigest_a_SOURCES = 46 libsvndigest_a_SOURCES += DirectoryPrinter.cc 47 libsvndigest_a_SOURCES += FilePrinter.cc 48 libsvndigest_a_SOURCES += first_page.cc 49 libsvndigest_a_SOURCES += Graph.cc 50 libsvndigest_a_SOURCES += NodePrinter.cc 51 libsvndigest_a_SOURCES += StatsPlotter.cc 52 libsvndigest_a_SOURCES += SvndigestVisitor.cc 53 54 libsvndigest_core_a_SOURCES = AddStats.cc Alias.cc BlameStats.cc \ 45 55 ClassicStats.cc Colors.cc \ 46 56 Commitment.cc Configuration.cc CopyrightVisitor.cc \ 47 css.cc Date.cc Directory.cc File.cc first_page.cc\48 Functor.cc Graph.ccHtmlBuf.cc HtmlStream.cc \57 css.cc Date.cc Directory.cc File.cc \ 58 Functor.cc HtmlBuf.cc HtmlStream.cc \ 49 59 html_utility.cc LineTypeParser.cc main_utility.cc Node.cc \ 50 60 NodeCounter.cc OptionVersion.cc \ 51 61 rmdirhier.cc Stats.cc StatsCollection.cc subversion_info.cc SVN.cc \ 52 SVNblame.cc SVNdiff.cc S vndigestVisitor.cc SVNinfo.cc \62 SVNblame.cc SVNdiff.cc SVNinfo.cc \ 53 63 SVNlog.cc SVNproperty.cc TinyStats.cc \ 54 64 Trac.cc utility.cc Vector.cc -
trunk/lib/Node.cc
r1264 r1290 105 105 os << name() << " (<i>link</i>)"; 106 106 // there is no output for nodes when user has zero contribution 107 else if (user!="all" && !tiny_stats_(stats_type,user,LineTypeParser::total)) 107 else if (user!="all" 108 && !tiny_stats()(stats_type,user,LineTypeParser::total)) 108 109 os << name(); 109 else if (!Configuration::instance().output_file() && ! this->dir())110 else if (!Configuration::instance().output_file() && !dir()) 110 111 os << name(); 111 112 else … … 124 125 125 126 126 void Node::html_tabletd(std::ostream& os, const std::string& stats_type, 127 void Node::html_tabletd(std::ostream& os, 128 const std::string& stats_type, 127 129 const std::string& user, 128 130 LineTypeParser::line_type lt) const 129 131 { 130 os << "<td>" << tiny_stats _(stats_type, user, lt);131 if (user!="all" && tiny_stats _(stats_type, user, lt))132 os << " (" << percent(tiny_stats _(stats_type, user, lt),133 tiny_stats _(stats_type, "all", lt)) << "%)";132 os << "<td>" << tiny_stats()(stats_type, user, lt); 133 if (user!="all" && tiny_stats()(stats_type, user, lt)) 134 os << " (" << percent(tiny_stats()(stats_type, user, lt), 135 tiny_stats()(stats_type, "all", lt)) << "%)"; 134 136 os << "</td>\n"; 135 137 } … … 163 165 164 166 165 std::string Node::output_dir(void) const166 {167 return output_dir_;168 }169 170 171 void Node::path_anchor(std::ostream& os) const172 {173 os << "<h2 class=\"path\">\n";174 std::vector<std::string> words;175 words.reserve(level_+1);176 std::string word;177 words.push_back(Node::project_);178 std::stringstream ss(local_path());179 while(getline(ss,word,'/'))180 if (!word.empty()) // ignore double slash in path181 words.push_back(word);182 if (words.size()==1)183 os << anchor("index.html", Node::project_,0, "View " + Node::project_);184 else {185 for (size_t i=0; i<words.size()-1; ++i){186 os << anchor("index.html", words[i], level_-i, "View " + words[i]);187 os << "<span class=\"sep\">/</span>";188 }189 os << anchor(href(), words.back(), level_+2-words.size(),190 "View " + words.back());191 }192 os << "\n</h2>\n";193 }194 195 196 void Node::print(const bool verbose) const197 {198 if (ignore())199 return;200 if (!Configuration::instance().output_file() && !this->dir())201 return;202 if (verbose)203 std::cout << "Printing output for '" << path_ << "'" << std::endl;204 const SVNlog& log = this->log();205 typedef std::map<std::string, Stats*>::const_iterator iter;206 207 const iter end(stats_.stats().end());208 for (iter i=stats_.stats().begin();i!=end; ++i){209 print_core(i->first, "all", "total", log);210 print_core(i->first, "all", "code", log);211 print_core(i->first, "all", "comments", log);212 print_core(i->first, "all", "empty", log);213 for (std::set<std::string>::const_iterator j=i->second->authors().begin();214 j!=i->second->authors().end(); ++j) {215 print_core(i->first, *j, "total", log);216 print_core(i->first, *j, "code", log);217 print_core(i->first, *j, "comments", log);218 print_core(i->first, *j, "empty", log);219 }220 }221 print_core(verbose);222 }223 224 225 void Node::print_author_summary(std::ostream& os,226 const Stats& stats,227 const std::string& line_type,228 const SVNlog& log) const229 {230 HtmlStream hs(os);231 os << "<h3>Author Summary</h3>";232 os << "<table class=\"listings\">\n";233 os << "<thead>\n";234 os << "<tr>\n";235 os << "<th>Author</th>\n";236 os << "<th>Lines</th>\n";237 os << "<th>Code</th>\n";238 os << "<th>Comments</th>\n";239 os << "<th>Other</th>\n";240 os << "<th>Revision</th>\n";241 os << "<th>Date</th>\n";242 os << "</tr>\n</thead>\n";243 os << "<tbody>\n";244 245 std::string color("light");246 if (!dir()) {247 os << "<tr class=\"" << color << "\">\n";248 os << "<td class=\"directory\" colspan=\"7\">";249 os << anchor("index.html", "../");250 os << "</td>\n</tr>\n";251 }252 253 // print authors254 const std::string timefmt("%Y-%m-%d %H:%M");255 for (std::set<std::string>::const_iterator i=stats.authors().begin();256 i!=stats.authors().end(); ++i){257 if (color=="dark")258 color="light";259 else260 color="dark";261 os << "<tr class=\"" << color << "\"><td>";262 os << anchor(*i+"/"+line_type+"/"+output_path()263 ,*i, level_+2, "View statistics for "+*i);264 os << "</td><td>" << stats.lines(*i)265 << "</td><td>" << stats.code(*i)266 << "</td><td>" << stats.comments(*i)267 << "</td><td>" << stats.empty(*i);268 if (log.exist(*i)) {269 const Commitment& lc(log.latest_commit(*i));270 os << "</td>" << "<td>" << trac_revision(lc.revision())271 << "</td>" << "<td>";272 hs << Date(lc.date())(timefmt);273 }274 else {275 os << "</td>" << "<td>N/A"276 << "</td>" << "<td>N/A";277 }278 os << "</td></tr>\n";279 }280 281 os << "<tr class=\"" << color << "\">\n";282 os << "<td>";283 if (dir())284 if (local_path().empty())285 os << anchor("all/"+line_type+"/index.html"286 ,"Total", level_+2, "View statistics for all");287 else288 os << anchor("all/"+line_type+"/"+local_path()+"/index.html"289 ,"Total", level_+2, "View statistics for all");290 else291 os << anchor("all/"+line_type+"/"+local_path()+".html"292 ,"Total", level_+2, "View statistics for all");293 os << "</td>\n";294 os << "<td>" << stats.lines() << "</td>\n";295 os << "<td>" << stats.code() << "</td>\n";296 os << "<td>" << stats.comments() << "</td>\n";297 os << "<td>" << stats.empty() << "</td>\n";298 const Commitment& lc(log.latest_commit());299 os << "<td>" << trac_revision(lc.revision()) << "</td>\n";300 os << "<td>";301 hs << Date(lc.date())(timefmt);302 os << "</td>\n";303 os << "</tr>\n";304 os << "</tbody>\n";305 os << "</table>\n";306 }307 308 309 167 const StatsCollection& Node::stats(void) const 310 168 { … … 324 182 } 325 183 326 327 std::string Node::url(void) const328 {329 return svninfo_.url();330 }331 332 184 }} // end of namespace svndigest and namespace theplu -
trunk/lib/Node.h
r1280 r1290 92 92 virtual std::string href(void) const=0; 93 93 94 void html_tablerow(std::ostream&, const std::string&, 95 const std::string& css, 94 /** 95 */ 96 void html_tablerow(std::ostream& os, 97 const std::string& stats_type, 98 const std::string& css_class, 96 99 const std::string& user) const; 97 100 … … 127 130 const SVNlog& log(void) const; 128 131 132 /// 133 /// @return 134 /// 135 inline const std::string& local_path(void) const { return local_path_; } 136 137 /// 138 /// Function returning everything after the last '/' 139 /// 140 /// @return name of node (not full path) 141 /// 142 std::string name(void) const; 143 129 144 /** 130 145 @return The explicit string identifying the underlying derived … … 132 147 */ 133 148 virtual std::string node_type(void) const=0; 134 135 ///136 /// @return137 ///138 inline const std::string& local_path(void) const { return local_path_; }139 140 ///141 /// Function returning everything after the last '/'142 ///143 /// @return name of node (not full path)144 ///145 std::string name(void) const;146 147 /**148 Note that returned string always end with '/' with the149 exception when an empty string is returned.150 151 @return output dir for example 'lib/' for this file152 */153 std::string output_dir(void) const;154 155 /**156 @return output path for example 'lib/Node.h.html' for this file157 */158 virtual std::string output_path(void) const=0;159 149 160 150 /// … … 163 153 inline const std::string& path(void) const { return path_; } 164 154 165 ///166 /// Function printing HTML in current working directory167 ///168 void print(const bool verbose=false) const;169 170 void print_author_summary(std::ostream&,171 const Stats& stats,172 const std::string& line_type,173 const SVNlog&) const;174 175 155 /** 176 156 \return true if svncopyright::ignore property was set … … 194 174 const StatsCollection& stats(void) const; 195 175 176 /** 177 */ 196 178 StatsCollection& stats(void); 197 179 … … 203 185 204 186 /** 205 \see SVNinfo::url(void) 206 */ 207 std::string url(void) const; 208 187 */ 209 188 inline const SVNinfo& svn_info(void) const { return svninfo_; } 210 189 190 /** 191 */ 192 const TinyStats& tiny_stats(void) const { return tiny_stats_; } 193 211 194 protected: 212 ///213 /// print path in html format (with anchors) to @a os214 ///215 void path_anchor(std::ostream& os) const;216 217 195 unsigned int level_; 218 196 std::string output_dir_; … … 228 206 Node(const Node&); 229 207 230 void html_tabletd(std::ostream&, const std::string& stats_type, 208 /** 209 */ 210 void html_tabletd(std::ostream&, 211 const std::string& stats_type, 231 212 const std::string& user, 232 213 LineTypeParser::line_type lt) const; 233 214 234 215 virtual void log_core(SVNlog&) const=0; 235 236 virtual void print_core(bool verbose=false) const=0;237 238 ///239 /// print page for specific user (or all) and specific line_style240 /// (or total).241 ///242 virtual void print_core(const std::string& stats_type,243 const std::string& user,244 const std::string& line_type,245 const SVNlog&) const=0;246 216 247 217 bool binary_; … … 252 222 bool svncopyright_ignore_; 253 223 SVNinfo svninfo_; 224 225 friend class FilePrinter; 226 friend class DirectoryPrinter; 227 friend class NodePrinter; 254 228 }; 255 229 -
trunk/lib/NodePrinter.cc
r1289 r1290 21 21 */ 22 22 23 #include "Node .h"23 #include "NodePrinter.h" 24 24 25 25 #include "Configuration.h" … … 28 28 #include "html_utility.h" 29 29 #include "LineTypeParser.h" 30 #include "Node.h" 30 31 #include "SVNlog.h" 31 32 #include "SVNproperty.h" … … 45 46 namespace svndigest{ 46 47 47 std::string Node::project_=std::string(); 48 49 Node::Node(const unsigned int level, const std::string& path, 50 const std::string& local_path, const std::string& project) 51 : level_(level), path_(path), stats_(path), log_(NULL), 52 svninfo_(path) 53 { 54 SVNproperty property(path); 55 binary_=property.binary(); 56 svndigest_ignore_=property.svndigest_ignore(); 57 svncopyright_ignore_=property.svncopyright_ignore(); 58 if (Node::project_==std::string()) // no root directory in local path 59 Node::project_ = project; 60 else if (local_path.empty()) 61 local_path_ = file_name(path); 62 else 63 local_path_ = local_path + "/" + file_name(path); 64 65 struct stat nodestat; // C api from sys/stat.h 66 lstat(path,&nodestat); // C api from sys/stat.h 67 link_ = S_ISLNK(nodestat.st_mode); 68 } 69 70 71 Node::~Node(void) 72 { 73 if (log_) 74 delete log_; 75 } 76 77 78 std::string Node::author(void) const 79 { 80 if (ignore()) 81 return svninfo_.last_changed_author(); 82 assert(log().commits().size()); 83 return log().latest_commit().author(); 84 } 85 86 87 bool Node::dir(void) const 88 { 89 return false; 90 } 91 92 93 void Node::html_tablerow(std::ostream& os, 94 const std::string& stats_type, 95 const std::string& css_class, 96 const std::string& user) const 97 { 98 os << "<tr class=\"" << css_class << "\">\n" 99 << "<td class=\"" << node_type() << "\">"; 100 if (svndigest_ignore()) 101 os << name() << " (<i>svndigest:ignore</i>)"; 102 else if (binary()) 103 os << name() << " (<i>binary</i>)"; 104 else if (link_) 105 os << name() << " (<i>link</i>)"; 106 // there is no output for nodes when user has zero contribution 107 else if (user!="all" && !tiny_stats_(stats_type,user,LineTypeParser::total)) 108 os << name(); 109 else if (!Configuration::instance().output_file() && !this->dir()) 110 os << name(); 111 else 112 os << anchor(href(), name()); 113 os << "</td>\n"; 114 115 html_tabletd(os, stats_type, user, LineTypeParser::total); 116 html_tabletd(os, stats_type, user, LineTypeParser::code); 117 html_tabletd(os, stats_type, user, LineTypeParser::comment); 118 html_tabletd(os, stats_type, user, LineTypeParser::other); 119 120 os << "<td>" << trac_revision(last_changed_rev()) << "</td>\n" 121 << "<td>" << author() << "</td>\n" 122 << "</tr>\n"; 123 } 124 125 126 void Node::html_tabletd(std::ostream& os, const std::string& stats_type, 127 const std::string& user, 128 LineTypeParser::line_type lt) const 129 { 130 os << "<td>" << tiny_stats_(stats_type, user, lt); 131 if (user!="all" && tiny_stats_(stats_type, user, lt)) 132 os << " (" << percent(tiny_stats_(stats_type, user, lt), 133 tiny_stats_(stats_type, "all", lt)) << "%)"; 134 os << "</td>\n"; 135 } 136 137 138 void Node::init_tiny_stats(void) 139 { 140 tiny_stats_.init(stats_); 141 } 142 143 144 const SVNlog& Node::log(void) const 145 { 146 if (!log_) { 147 if (ignore()) 148 log_ = new SVNlog; 149 else { 150 log_ = new SVNlog(path()); 151 log_core(*log_); 152 } 153 } 154 return *log_; 155 } 156 157 158 std::string Node::name(void) const 159 { 160 std::string res = file_name(path_); 161 return res; 162 } 163 164 165 std::string Node::output_dir(void) const 166 { 167 return output_dir_; 168 } 169 170 171 void Node::path_anchor(std::ostream& os) const 48 NodePrinter::NodePrinter(void) 49 { 50 } 51 52 NodePrinter::~NodePrinter(void) 53 { 54 } 55 56 57 std::string NodePrinter::output_dir(void) const 58 { 59 return node().output_dir_; 60 } 61 62 63 void NodePrinter::path_anchor(std::ostream& os) const 172 64 { 173 65 os << "<h2 class=\"path\">\n"; 174 66 std::vector<std::string> words; 175 words.reserve( level_+1);67 words.reserve(node().level_+1); 176 68 std::string word; 177 69 words.push_back(Node::project_); 178 std::stringstream ss( local_path());70 std::stringstream ss(node().local_path()); 179 71 while(getline(ss,word,'/')) 180 72 if (!word.empty()) // ignore double slash in path … … 184 76 else { 185 77 for (size_t i=0; i<words.size()-1; ++i){ 186 os << anchor("index.html", words[i], level_-i, "View " + words[i]);78 os << anchor("index.html", words[i], node().level_-i, "View " + words[i]); 187 79 os << "<span class=\"sep\">/</span>"; 188 80 } 189 os << anchor( href(), words.back(),level_+2-words.size(),81 os << anchor(node().href(), words.back(), node().level_+2-words.size(), 190 82 "View " + words.back()); 191 83 } … … 194 86 195 87 196 void Node ::print(const bool verbose) const197 { 198 if ( ignore())88 void NodePrinter::print(const bool verbose) const 89 { 90 if (node().ignore()) 199 91 return; 200 if (!Configuration::instance().output_file() && ! this->dir())92 if (!Configuration::instance().output_file() && !node().dir()) 201 93 return; 202 94 if (verbose) 203 std::cout << "Printing output for '" << path_ << "'" << std::endl;204 const SVNlog& log = this->log();95 std::cout << "Printing output for '" << node().path_ << "'" << std::endl; 96 const SVNlog& log = node().log(); 205 97 typedef std::map<std::string, Stats*>::const_iterator iter; 206 98 207 const iter end( stats_.stats().end());208 for (iter i= stats_.stats().begin();i!=end; ++i){99 const iter end(node().stats_.stats().end()); 100 for (iter i=node().stats_.stats().begin();i!=end; ++i){ 209 101 print_core(i->first, "all", "total", log); 210 102 print_core(i->first, "all", "code", log); … … 223 115 224 116 225 void Node ::print_author_summary(std::ostream& os,117 void NodePrinter::print_author_summary(std::ostream& os, 226 118 const Stats& stats, 227 119 const std::string& line_type, … … 244 136 245 137 std::string color("light"); 246 if (! dir()) {138 if (!node().dir()) { 247 139 os << "<tr class=\"" << color << "\">\n"; 248 140 os << "<td class=\"directory\" colspan=\"7\">"; … … 261 153 os << "<tr class=\"" << color << "\"><td>"; 262 154 os << anchor(*i+"/"+line_type+"/"+output_path() 263 ,*i, level_+2, "View statistics for "+*i);155 ,*i, node().level_+2, "View statistics for "+*i); 264 156 os << "</td><td>" << stats.lines(*i) 265 157 << "</td><td>" << stats.code(*i) … … 281 173 os << "<tr class=\"" << color << "\">\n"; 282 174 os << "<td>"; 283 if ( dir())284 if ( local_path().empty())175 if (node().dir()) 176 if (node().local_path().empty()) 285 177 os << anchor("all/"+line_type+"/index.html" 286 ,"Total", level_+2, "View statistics for all");178 ,"Total", node().level_+2, "View statistics for all"); 287 179 else 288 os << anchor("all/"+line_type+"/"+ local_path()+"/index.html"289 ,"Total", level_+2, "View statistics for all");180 os << anchor("all/"+line_type+"/"+node().local_path()+"/index.html" 181 ,"Total", node().level_+2, "View statistics for all"); 290 182 else 291 os << anchor("all/"+line_type+"/"+ local_path()+".html"292 ,"Total", level_+2, "View statistics for all");183 os << anchor("all/"+line_type+"/"+node().local_path()+".html" 184 ,"Total", node().level_+2, "View statistics for all"); 293 185 os << "</td>\n"; 294 186 os << "<td>" << stats.lines() << "</td>\n"; … … 307 199 308 200 309 const StatsCollection& Node::stats(void) const310 {311 return stats_;312 }313 314 315 StatsCollection& Node::stats(void)316 {317 return stats_;318 }319 320 321 bool Node::svncopyright_ignore(void) const322 {323 return svncopyright_ignore_;324 }325 326 327 std::string Node::url(void) const328 {329 return svninfo_.url();330 }331 332 201 }} // end of namespace svndigest and namespace theplu -
trunk/lib/NodePrinter.h
r1289 r1290 1 #ifndef _theplu_svndigest_node_ 2 #define _theplu_svndigest_node_ 1 #ifndef _theplu_svndigest_node_printer_ 2 #define _theplu_svndigest_node_printer_ 3 3 4 4 // $Id$ … … 41 41 namespace svndigest{ 42 42 43 class Alias; 44 class NodeVisitor; 45 46 /// 47 /// If something goes wrong in the use of the Node or its derived 48 /// classes, a NodeException is thrown. 49 /// 50 struct NodeException : public std::runtime_error 51 { inline NodeException(const std::string& msg) : runtime_error(msg) {} }; 43 class Node; 52 44 53 45 /// 54 /// Abstract Base Class for files.46 /// Base class for FilePrinter and DirectoryPrinter 55 47 /// 56 class Node 48 class NodePrinter 57 49 { 58 50 public: … … 61 53 /// @brief Constructor 62 54 /// 63 Node(const unsigned int, const std::string&, const std::string&, 64 const std::string& = ""); 55 NodePrinter(void); 65 56 66 57 /// 67 58 /// @brief Destructor 68 59 /// 69 virtual ~Node(void); 70 71 /// 72 /// @brief Get the author of the latest commit. 73 /// 74 std::string author(void) const; 75 76 77 /** 78 @brief Check whether node is binary. 79 80 @return True if node is binary. 81 */ 82 inline bool binary(void) const { return binary_; } 83 84 /// 85 /// @return true if directory 86 /// 87 virtual bool dir(void) const; 88 89 /// 90 /// @return href to this node 91 /// 92 virtual std::string href(void) const=0; 93 94 void html_tablerow(std::ostream&, const std::string&, 95 const std::string& css, 96 const std::string& user) const; 97 98 /** 99 @brief Check whether node should be ignored in statistics. 100 101 If a node is to be ignored the statistics implementer should 102 respect this state. Currently binary files and items with 103 property svndigest:ignore are to be ignored by svndigest. If 104 the node is a directory then the direcotry and its siblings 105 should be ignored by statistics. 106 107 @return True of node should be ignored by statistics. 108 109 @see SVNproperty::svndigest_ingorable 110 */ 111 inline bool ignore(void) const 112 { return binary_ || svndigest_ignore_ || link_; } 113 114 /** 115 Create the TinyStats based on the stored CollectionStats 116 */ 117 void init_tiny_stats(void); 118 119 /// 120 /// @brief Get the revision number of the latest commit. 121 /// 122 virtual svn_revnum_t last_changed_rev(void) const=0; 123 124 /** 125 @return log of this node in a recursive manner. 126 */ 127 const SVNlog& log(void) const; 128 129 /** 130 @return The explicit string identifying the underlying derived 131 class. 132 */ 133 virtual std::string node_type(void) const=0; 134 135 /// 136 /// @return 137 /// 138 inline const std::string& local_path(void) const { return local_path_; } 139 140 /// 141 /// Function returning everything after the last '/' 142 /// 143 /// @return name of node (not full path) 144 /// 145 std::string name(void) const; 60 virtual ~NodePrinter(void); 146 61 147 62 /** … … 154 69 155 70 /** 156 @return output path for example 'lib/Node .h.html' for this file71 @return output path for example 'lib/NodePrinter.h.html' for this file 157 72 */ 158 73 virtual std::string output_path(void) const=0; 159 160 ///161 /// @todo doc162 ///163 inline const std::string& path(void) const { return path_; }164 74 165 75 /// … … 173 83 const SVNlog&) const; 174 84 175 /**176 \return true if svncopyright::ignore property was set177 */178 bool svncopyright_ignore(void) const;179 180 /**181 @brief Check if item used to create this object has been182 assigned property svndigest:ignore.183 184 Currently files with property svndigest:ignore are to be185 ignored by svndigest. It is the responsibility of the186 statistics implementer to obey the ignore state.187 188 @return True if item property svndigest:ignore was set.189 */190 inline bool svndigest_ignore(void) const { return svndigest_ignore_; }191 192 /**193 */194 const StatsCollection& stats(void) const;195 196 StatsCollection& stats(void);197 198 /**199 Access point for a NodeVisitor to start traversing Node and its200 daughter nodes.201 */202 virtual void traverse(NodeVisitor& visitor)=0;203 204 /**205 \see SVNinfo::url(void)206 */207 std::string url(void) const;208 209 inline const SVNinfo& svn_info(void) const { return svninfo_; }210 211 85 protected: 212 86 /// … … 215 89 void path_anchor(std::ostream& os) const; 216 90 217 unsigned int level_;218 std::string output_dir_;219 std::string path_; // absolute path220 static std::string project_;221 StatsCollection stats_;222 TinyStats tiny_stats_;223 224 91 private: 225 92 /// 226 93 /// @brief Copy Constructor, not implemented 227 94 /// 228 Node (const Node&);95 NodePrinter(const NodePrinter&); 229 96 230 void html_tabletd(std::ostream&, const std::string& stats_type, 231 const std::string& user, 232 LineTypeParser::line_type lt) const; 233 234 virtual void log_core(SVNlog&) const=0; 97 virtual const Node& node(void) const=0; 235 98 236 99 virtual void print_core(bool verbose=false) const=0; … … 245 108 const SVNlog&) const=0; 246 109 247 bool binary_;248 bool link_;249 std::string local_path_; // path from root250 mutable SVNlog* log_;251 bool svndigest_ignore_;252 bool svncopyright_ignore_;253 SVNinfo svninfo_;254 110 }; 255 111 256 /** 257 \brief Functor class to compare pointers of Nodes 258 */ 259 struct NodePtrLess 260 { 261 /** 262 @return true if first and second are of same type (Directory or 263 File) and name of first is (alphabetically) less than name of 264 second; or if first is a Directory and second is a File. 265 */ 266 inline bool operator()(const Node* first, const Node* second) const 267 { 268 if (first->dir()==second->dir()) 269 return first->name()<second->name(); 270 return first->dir(); 271 } 272 }; 112 113 273 114 274 115 }} // end of namespace svndigest and namespace theplu -
trunk/lib/Stats.cc
r1280 r1290 27 27 #include "Configuration.h" 28 28 #include "Functor.h" 29 #include "Graph.h"30 29 #include "SVNblame.h" 31 30 #include "SVNinfo.h" … … 404 403 assert(comment_or_copy_stats().size()); 405 404 assert(other_stats().size()); 406 }407 408 409 std::string Stats::plot(const std::string& filename,410 const std::string& linetype) const411 {412 const std::string& format = Configuration::instance().image_format();413 if (format=="none")414 return filename;415 plot(filename, linetype, format);416 const std::string& anchor_format =417 Configuration::instance().image_anchor_format();418 419 if (format!=anchor_format)420 plot(filename, linetype, anchor_format);421 return filename;422 }423 424 425 void Stats::plot(const std::string& filename,426 const std::string& linetype,427 const std::string& format) const428 {429 Graph gp(filename+"."+format, format);430 const Author2Vector* stat=NULL;431 if (linetype=="total")432 stat = &total_stats();433 else if (linetype=="code")434 stat = &code_stats();435 else if (linetype=="comments")436 stat = &comment_or_copy_stats();437 else if (linetype=="empty")438 stat = &other_stats();439 assert(stat);440 assert(stat->size());441 assert(stat->find("all")!=stat->end());442 const SumVector& total=get_vector(*stat, "all");443 double yrange_max=1.03 * max_element(total) +1.0;444 gp.ymax(yrange_max);445 446 typedef std::vector<std::pair<std::string, SumVector> > vec_type;447 vec_type author_cont;448 author_cont.reserve(stat->size());449 for (std::set<std::string>::const_iterator i=authors_.begin();450 i != authors_.end(); ++i) {451 assert(stat->find(*i)!=stat->end());452 const SumVector& vec = get_vector(*stat,*i);453 if (max_element(vec)) {454 author_cont.push_back(std::make_pair(*i,vec));455 }456 }457 458 LessReversed<SumVector> lr;459 PairSecondCompare<std::string, SumVector, LessReversed<SumVector> >460 compare(lr);461 std::sort(author_cont.begin(), author_cont.end(), compare);462 463 vec_type::iterator end(author_cont.end());464 vec_type::iterator i(author_cont.begin());465 const vec_type::size_type maxauthors=8;466 int authskip=author_cont.size()-maxauthors;467 if (authskip>1) {468 // only use others if there is more than 1 author to be skipped,469 // there is no reason to add only 1 author to others.470 vec_type::iterator j(i);471 i+=authskip;472 SumVector others;473 sum(j, i, others, PairValuePlusAssign<std::string, SumVector>());474 unsigned char r, g, b;475 std::string label("others");476 Colors::instance().get_color(label, r,g,b);477 gp.current_color(r,g,b);478 gp.plot(others, label, others.back());479 }480 for ( ; i!=end; ++i) {481 unsigned char r, g, b;482 Colors::instance().get_color(i->first,r,g,b);483 gp.current_color(r,g,b);484 gp.plot(i->second, i->first, get_back(*stat, i->first));485 }486 gp.current_color(255,0,0);487 gp.plot(total, "total", get_back(*stat, "all"));488 }489 490 491 void Stats::plot_summary(const std::string& filename) const492 {493 const std::string& format = Configuration::instance().image_format();494 if (format=="none")495 return;496 plot_summary(filename, format);497 const std::string& anchor_format =498 Configuration::instance().image_anchor_format();499 500 if (format!=anchor_format)501 plot_summary(filename, anchor_format);502 }503 504 505 void Stats::plot_summary(const std::string& filename,506 const std::string& format) const507 {508 Graph gp(filename+"."+format, format);509 const SumVector& total = get_vector(total_stats(), "all");510 double yrange_max=1.03*max_element(total)+1;511 gp.ymax(yrange_max);512 513 const SumVector& x(get_vector(code_stats(), "all"));514 gp.current_color(255,255,0);515 gp.plot(x, "code", x.back());516 517 const SumVector& y = get_vector(comment_or_copy_stats(), "all");518 gp.current_color(0,0,255);519 gp.plot(y, "comment", y.back());520 521 const SumVector& z = get_vector(other_stats(), "all");522 gp.current_color(0,255,0);523 gp.plot(z, "other", z.back());524 525 gp.current_color(255,0,0);526 gp.plot(total, "total", total.back());527 405 } 528 406 -
trunk/lib/Stats.h
r1194 r1290 106 106 */ 107 107 void parse(const std::string& path, svn_revnum_t rev=0); 108 109 ///110 /// Create statistics graph.111 ///112 std::string plot(const std::string&, const std::string&) const;113 114 ///115 /// Plotting code, comment, other, and total in same plot (for116 /// 'all' not individual authors).117 ///118 void plot_summary(const std::string& output) const;119 108 120 109 /** … … 241 230 svn_revnum_t load_cache8(std::istream&); 242 231 243 /**244 called from plot(2)245 */246 // FIXME: why should Stats know about plotting?247 void plot(const std::string& basename, const std::string& linetype,248 const std::string& format) const;249 250 /**251 called from plot_summary(1)252 */253 // FIXME: why should Stats know about plotting?254 void plot_summary(const std::string& basename,255 const std::string& format) const;256 257 232 // Change this string if cache format is changed in such a way 258 233 // that all old cache files are obsolete. … … 285 260 Stats& operator=(const Stats&); 286 261 262 friend class StatsPlotter; 287 263 }; 288 264 }} // end of namespace svndigest end of namespace theplu -
trunk/lib/SvndigestVisitor.cc
r1234 r1290 23 23 24 24 #include "Directory.h" 25 #include "DirectoryPrinter.h" 25 26 #include "File.h" 27 #include "FilePrinter.h" 26 28 #include "NodeVisitor.h" 27 29 … … 48 50 dir.collect_stats(); 49 51 dir.init_tiny_stats(); 50 dir.print(verbose_); 52 DirectoryPrinter dp(dir); 53 dp.print(verbose_); 51 54 } 52 55 } … … 59 62 if (report_) { 60 63 file.init_tiny_stats(); 61 if (!file.ignore()) 62 file.print(verbose_); 64 if (!file.ignore()) { 65 FilePrinter fp(file); 66 fp.print(verbose_); 67 } 63 68 } 64 69 } -
trunk/lib/first_page.cc
r1254 r1290 34 34 #include "Stats.h" 35 35 #include "StatsCollection.h" 36 #include "StatsPlotter.h" 36 37 #include "SVNlog.h" 37 38 #include "Trac.h" … … 250 251 { 251 252 std::string name("summary_plot"); 252 stats.plot_summary(name);253 StatsPlotter(stats).plot_summary(name); 253 254 os << "<div class=\"main\">\n"; 254 255 os << image(name); -
trunk/test/Makefile.am
r1267 r1290 62 62 63 63 LDADD = $(builddir)/libsvndigesttest.a \ 64 $(top_builddir)/lib/libsvndigest .a \64 $(top_builddir)/lib/libsvndigest_core.a \ 65 65 $(top_builddir)/yat/libyat.a \ 66 66 $(SVN_LIBS) $(APR_LIBS) $(PLPLOT_LIBS) 67 68 ## graph test needs to link against Graph class 69 graph_test_LDADD = $(LDADD) $(top_builddir)/lib/libsvndigest.a 70 67 71 AM_LDFLAGS = $(SVNDIGEST_LDFLAGS) 68 72
Note: See TracChangeset
for help on using the changeset viewer.