Changeset 1290 for trunk


Ignore:
Timestamp:
Nov 12, 2010, 5:01:35 AM (10 years ago)
Author:
Peter Johansson
Message:

closes #457. Lifting out plotting functions in Stats into a new class
StatsPlotter?. In same manner lifting out print functions from
Node/Directory/File? into a new hierarchy
NodePrinter/DirectoryPrinter/FilePrinter?. To accomplish these splits
without to much recoding some friendships are introduced. These new
classes are only needed for svndigest (not svncopyright) and are
therefore placed in a library named libsvndigest together with Graph
class and first_page functions. Remaining functionality, shared
between svncopyright and svndigest, are located in libsvndigest_core
and linked into both binaries.

Location:
trunk
Files:
2 added
14 edited
6 copied

Legend:

Unmodified
Added
Removed
  • trunk/bin/Makefile.am

    r1267 r1290  
    3131EXTRA_DIST = svndigest-copy-cache.as
    3232
    33 LDADD = $(top_builddir)/lib/libsvndigest.a \
    34   $(top_builddir)/yat/libyat.a $(SVN_LIBS) $(APR_LIBS) $(PLPLOT_LIBS)
     33LDADD = $(top_builddir)/lib/libsvndigest_core.a \
     34  $(top_builddir)/yat/libyat.a $(SVN_LIBS) $(APR_LIBS)
    3535AM_LDFLAGS = $(SVNDIGEST_LDFLAGS)
    3636
     
    3838AM_CXXFLAGS = $(SVNDIGEST_CXXFLAGS)
    3939
    40 ##svndigest_LDADD = $(LDADD) $(PLPLOT_LIBS)
     40svndigest_LDADD = $(top_builddir)/lib/libsvndigest.a $(LDADD) $(PLPLOT_LIBS)
    4141##svndigest_LDFLAGS = $(AM_LDFLAGS) $(PLPLOT_LDFLAGS)
    4242##svndigest_CPPFLAGS  = $(AM_CPPFLAGS) $(PLPLOT_CPPFLAGS)
  • trunk/bin/svndigest.cc

    r1280 r1290  
    130130
    131131    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);
    134134
    135135  }
  • trunk/lib/Directory.cc

    r1289 r1290  
    146146
    147147
    148   std::string Directory::output_path(void) const
    149   {
    150     return output_dir()+"index.html";
    151   }
    152 
    153 
    154   void Directory::print_core(const bool verbose) const
    155   {
    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) const
    163   {
    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     else
    182       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     else
    193       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 nodes
    225     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       else
    230         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 
    270148  void Directory::traverse(NodeVisitor& visitor)
    271149  {
  • trunk/lib/Directory.h

    r1264 r1290  
    111111    Directory(const Directory&);
    112112
    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 
    119113    typedef std::vector<Node*> NodeContainer;
    120114    typedef NodeContainer::iterator NodeIterator;
    121115    typedef NodeContainer::const_iterator NodeConstIterator;
    122116    NodeContainer daughters_;
     117
     118    friend class DirectoryPrinter;
    123119  };
    124120
  • trunk/lib/DirectoryPrinter.cc

    r1289 r1290  
    2020*/
    2121
    22 #include "Directory.h"
     22#include "DirectoryPrinter.h"
    2323
    2424#include "Alias.h"
    2525#include "Configuration.h"
     26#include "Directory.h"
    2627#include "File.h"
    2728#include "html_utility.h"
    2829#include "Node.h"
    2930#include "NodeVisitor.h"
     31#include "StatsPlotter.h"
    3032#include "SVN.h"
    3133#include "SVNlog.h"
     
    5153
    5254
    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)
    5657  {
    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.h
    63     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.h
    69     while ((entry=readdir(directory)))       // C API from dirent.h
    70       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.h
    82           lstat(fullpath,&nodestat);   // C api from sys/stat.h
    83           if (S_ISDIR(nodestat.st_mode))       // C api from sys/stat.h
    84             daughters_.push_back(new Directory(level_+1,fullpath,local_path()));
    85           else
    86             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 nothing
    91         }
    92       }
    93     std::sort(daughters_.begin(), daughters_.end(), NodePtrLess());
    9458  }
    9559
    9660
    97   Directory::~Directory(void)
     61  DirectoryPrinter::~DirectoryPrinter(void)
    9862  {
    99     for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
    100       delete *i;
    10163  }
    10264
    10365
    104   void Directory::collect_stats(void)
     66  const Node& DirectoryPrinter::node(void) const
    10567  {
    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_;
    11269  }
    11370
    11471
    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
    14973  {
    15074    return output_dir()+"index.html";
     
    15276
    15377
    154   void Directory::print_core(const bool verbose) const
     78  void DirectoryPrinter::print_core(const bool verbose) const
    15579  {
    15680  }
    15781
    15882
    159   void Directory::print_core(const std::string& stats_type,
     83  void DirectoryPrinter::print_core(const std::string& stats_type,
    16084                             const std::string& user,
    16185                             const std::string& line_type,
     
    16387  {
    16488
    165     const Stats& stats = stats_[stats_type];
     89    const Stats& stats = directory_.stats_[stats_type];
    16690    std::string imagedir = stats_type+"/"+"images/"+line_type;
    16791    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();
    17195    }
    17296    mkdir_p(outdir);
     
    176100    std::ofstream os(html_name.c_str());
    177101    assert(os.good());
    178     if (local_path().empty())
    179       print_header(os, name(), 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",
    180104                   stats_type);
    181105    else
    182       print_header(os, name(), 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);
    184108    path_anchor(os);
    185109
    186110    std::stringstream ss;
    187     for (size_t i=0; i<level_; ++i)
     111    for (size_t i=0; i<directory_.level_; ++i)
    188112      ss << "../";
    189113    ss << "../../../";
    190114    if (user=="all")
    191       ss << stats.plot(imagedir+"/index", line_type);
     115      ss << StatsPlotter(stats).plot(imagedir+"/index", line_type);
    192116    else
    193117      ss << imagedir << "/index";
     
    214138
    215139    std::string color("light");
    216     if (level_){
     140    if (directory_.level_){
    217141      os << "<tr class=\"light\">\n";
    218142      os << "<td class=\"directory\" colspan=\"7\">";
     
    223147
    224148    // 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);
    227153      if (color=="dark")
    228154        color = "light";
     
    256182      os << "</td>\n";
    257183    }
    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";
    260186    os << "</tr>\n";
    261187    os << "</tbody>\n";
     
    268194
    269195
    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 
    280196}} // 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_
    33
    44// $Id$
     
    2424*/
    2525
    26 #include "Node.h"
     26#include "NodePrinter.h"
    2727
    2828#include <map>
     
    3333namespace svndigest{
    3434
    35   class NodeVisitor;
     35  class Directory;
     36  class Node;
    3637
    3738  ///
    3839  /// Class taking care of directories.
    3940  ///
    40   class Directory : public Node
     41  class DirectoryPrinter : public NodePrinter
    4142  {
    4243  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&);
    6248
    6349    /**
    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
    8351    */
    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);
    9053
    9154    /**
     
    9457    std::string output_path(void) const;
    9558
    96     /**
    97        Calls visitor.enter(*this). If enter returns true, daughter
    98        nodes are traverses. Finally visitor visitor.leave(*this) i called.
    99      */
    100     void traverse(NodeVisitor& visitor);
    101 
    10259  private:
    103     /**
    104        add union of logs from daughter nodes.
    105     */
    106     void log_core(SVNlog&) const;
    107 
    10860    ///
    10961    /// @brief Copy Constructor, not implemented
    11062    ///
    111     Directory(const Directory&);
     63    DirectoryPrinter(const DirectoryPrinter&);
     64
     65    const Node& node(void) const;
    11266
    11367    void print_core(bool verbose=false) const;
     
    11771
    11872
     73   
     74
     75    const Directory& directory_;
    11976    typedef std::vector<Node*> NodeContainer;
    12077    typedef NodeContainer::iterator NodeIterator;
    12178    typedef NodeContainer::const_iterator NodeConstIterator;
    122     NodeContainer daughters_;
    12379  };
    12480
  • trunk/lib/File.cc

    r1288 r1290  
    2727#include "Configuration.h"
    2828#include "Date.h"
    29 #include "Graph.h"
    3029#include "html_utility.h"
    3130#include "HtmlStream.h"
     
    6261
    6362
    64   std::string File::blame_output_file_name(void) const
    65   {
    66     return "blame_output/" + local_path() + ".html";
    67   }
    68 
    69 
    7063  std::string File::href(void) const
    7164  {
     
    8881  {
    8982    return std::string("file");
    90   }
    91 
    92 
    93   std::string File::output_path(void) const
    94   {
    95     return output_dir()+name()+".html";
    9683  }
    9784
     
    126113
    127114
    128   void File::print_blame(std::ofstream& os) const
    129   {
    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_iterator
    157       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 + m
    173     // 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       else
    182         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=\"#" << color
    189          << 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()+1
    211          << "</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) const
    223   {
    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) const
    239   {
    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     else
    261       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 
    278115  void File::traverse(NodeVisitor& visitor)
    279116  {
  • trunk/lib/File.h

    r1267 r1290  
    2626#include "Node.h"
    2727
    28 #include <map>
    2928#include <string>
    3029
     
    6059    std::string node_type(void) const;
    6160
    62     /**
    63        @return output path for example 'lib/File.h.html' for this file
    64      */
    65     std::string output_path(void) const;
    66 
    6761    ///
    6862    /// @brief Parsing out information from svn repository
     
    7872
    7973  private:
    80     std::string blame_output_file_name(void) const;
    81 
    8274    /**
    8375       do nothing
     
    9082    File(const File&);
    9183
    92     ///
    93     /// @brief Parsing svn blame output
    94     ///
    95     /// @return true if parsing is succesful
    96     ///
    97     bool blame(void) const;
    98 
    99     /**
    100        @brief Print blame output
    101     */
    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_style
    108     /// (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 
    11384  };
    11485
  • trunk/lib/FilePrinter.cc

    r1289 r1290  
    2020  along with svndigest. If not, see <http://www.gnu.org/licenses/>.
    2121*/
     22
     23#include "FilePrinter.h"
    2224
    2325#include "File.h"
     
    3234#include "NodeVisitor.h"
    3335#include "Stats.h"
     36#include "StatsPlotter.h"
    3437#include "SVNblame.h"
    3538#include "SVNlog.h"
     
    5154namespace svndigest{
    5255
    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>";
    13183    os << "<div class=\"blame_legend\">\n";
    13284    os << "<dl>\n";
     
    14698    os << "<tbody>\n";
    14799    HtmlStream hs(os);
    148     SVNblame blame(path_);
    149     LineTypeParser parser(path_);
     100    SVNblame blame(node().path_);
     101    LineTypeParser parser(node().path_);
    150102    while (blame.valid()) {
    151103      parser.parse(blame.line());
     
    205157        os << "line-code";
    206158      else {
    207         std::string msg="File::print_blame(): unexpected line type found";
     159        std::string msg="FilePrinter::print_blame(): unexpected line type found";
    208160        throw std::runtime_error(msg);
    209161      }
     
    220172
    221173
    222   void File::print_core(const bool verbose) const
     174  void FilePrinter::print_core(const bool verbose) const
    223175  {
    224176    if (!Configuration::instance().output_blame_information())
     
    227179    std::ofstream os(blame_output_file_name().c_str());
    228180    assert(os.good());
    229     print_html_start(os, "svndigest", level_+1);
     181    print_html_start(os, "svndigest", file_.level_+1);
    230182    print_blame(os);
    231183    print_footer(os);
     
    234186
    235187
    236   void File::print_core(const std::string& stats_type,
     188  void FilePrinter::print_core(const std::string& stats_type,
    237189                        const std::string& user, const std::string& line_type,
    238190                        const SVNlog& log) const
    239191  {
    240     std::string lpath = local_path();
     192    std::string lpath = node().local_path();
    241193    if (lpath.empty())
    242194      lpath = "index";
     
    248200    std::ofstream os(html_name.c_str());
    249201    assert(os);
    250     print_header(os, name(), level_+3, user, line_type, lpath+".html",
     202    print_header(os, node().name(), file_.level_+3, user, line_type, lpath+".html",
    251203                 stats_type);
    252204    path_anchor(os);
    253205
    254206    std::stringstream ss;
    255     for (size_t i=0; i<level_; ++i)
     207    for (size_t i=0; i<file_.level_; ++i)
    256208      ss << "../";
    257209    ss << "../../../";
    258210    if (user=="all")
    259       ss << stats_[stats_type].plot(imagefile,line_type);
     211      ss << StatsPlotter(file_.stats_[stats_type]).plot(imagefile,line_type);
    260212    else
    261213      ss << imagefile;
     
    264216    os << "</p>\n";
    265217
    266     print_author_summary(os, stats_[stats_type], line_type, log);
     218    print_author_summary(os, file_.stats_[stats_type], line_type, log);
    267219    os << "\n";
    268220    if (Configuration::instance().output_blame_information())
    269221      os << "<h3>"
    270          << anchor(blame_output_file_name(), "Blame Information", level_+3)
     222         << anchor(blame_output_file_name(), "Blame Information", file_.level_+3)
    271223         << "</h3>\n";
    272224
     
    276228
    277229
    278   void File::traverse(NodeVisitor& visitor)
    279   {
    280     visitor.visit(*this);
    281   }
    282 
    283230}} // 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_
    33
    44// $Id$
     
    2424*/
    2525
    26 #include "Node.h"
     26#include "NodePrinter.h"
    2727
    28 #include <map>
    2928#include <string>
    3029
     
    3231namespace svndigest{
    3332
    34   class NodeVisitor;
     33  class File;
    3534
    36   class File : public Node
     35  class FilePrinter : public NodePrinter
    3736  {
    3837  public:
     
    4039    /// @brief Default Constructor
    4140    ///
    42     File(const unsigned int level, const std::string& path,
    43          const std::string& output="");
     41    explicit FilePrinter(const File& file);
    4442
    4543    /**
    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
    6445     */
    6546    std::string output_path(void) const;
    66 
    67     ///
    68     /// @brief Parsing out information from svn repository
    69     ///
    70     /// @return Stats object of the file
    71     ///
    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);
    7847
    7948  private:
     
    8857    /// @brief Copy Constructor, not implemented
    8958    ///
    90     File(const File&);
     59    FilePrinter(const FilePrinter&);
    9160
    9261    ///
     
    11180                    const std::string& line_type, const SVNlog&) const;
    11281
     82    const Node& node(void) const;
     83
     84    const File& file_;
     85
    11386  };
    11487
  • trunk/lib/Makefile.am

    r1254 r1290  
    2828AM_CXXFLAGS = $(SVNDIGEST_CXXFLAGS)
    2929
    30 noinst_LIBRARIES = libsvndigest.a
     30noinst_LIBRARIES = libsvndigest.a libsvndigest_core.a
    3131
    3232noinst_HEADERS = AddStats.h Alias.h BlameStats.h ClassicStats.h \
    3333  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 \
    3536  Graph.h \
    3637  HtmlBuf.h HtmlStream.h html_utility.h LineTypeParser.h \
    37   main_utility.h Node.h NodeCounter.h NodeVisitor.h \
     38  main_utility.h Node.h NodeCounter.h NodePrinter.h NodeVisitor.h \
    3839  OptionVersion.h rmdirhier.h \
    3940  Stats.h StatsCollection.h subversion_info.h \
     
    4243  Trac.h utility.h Vector.h
    4344
    44 libsvndigest_a_SOURCES = AddStats.cc Alias.cc BlameStats.cc \
     45libsvndigest_a_SOURCES =
     46libsvndigest_a_SOURCES += DirectoryPrinter.cc
     47libsvndigest_a_SOURCES += FilePrinter.cc
     48libsvndigest_a_SOURCES += first_page.cc
     49libsvndigest_a_SOURCES += Graph.cc
     50libsvndigest_a_SOURCES += NodePrinter.cc
     51libsvndigest_a_SOURCES += StatsPlotter.cc
     52libsvndigest_a_SOURCES += SvndigestVisitor.cc
     53
     54libsvndigest_core_a_SOURCES = AddStats.cc Alias.cc BlameStats.cc \
    4555  ClassicStats.cc Colors.cc \
    4656  Commitment.cc Configuration.cc CopyrightVisitor.cc \
    47   css.cc Date.cc Directory.cc File.cc first_page.cc\
    48   Functor.cc Graph.cc HtmlBuf.cc HtmlStream.cc \
     57  css.cc Date.cc Directory.cc File.cc \
     58  Functor.cc HtmlBuf.cc HtmlStream.cc \
    4959  html_utility.cc LineTypeParser.cc main_utility.cc Node.cc \
    5060  NodeCounter.cc OptionVersion.cc \
    5161  rmdirhier.cc Stats.cc StatsCollection.cc subversion_info.cc SVN.cc \
    52   SVNblame.cc SVNdiff.cc SvndigestVisitor.cc SVNinfo.cc \
     62  SVNblame.cc SVNdiff.cc SVNinfo.cc \
    5363  SVNlog.cc SVNproperty.cc TinyStats.cc \
    5464  Trac.cc utility.cc Vector.cc
  • trunk/lib/Node.cc

    r1264 r1290  
    105105      os << name() << " (<i>link</i>)";
    106106    // 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))
    108109      os << name();
    109     else if (!Configuration::instance().output_file() && !this->dir())
     110    else if (!Configuration::instance().output_file() && !dir())
    110111      os << name();
    111112    else
     
    124125
    125126
    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,
    127129                          const std::string& user,
    128130                          LineTypeParser::line_type lt) const
    129131  {
    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)) << "%)";
    134136    os << "</td>\n";
    135137  }
     
    163165
    164166
    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
    172   {
    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 path
    181         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) const
    197   {
    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) const
    229   {
    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 authors
    254     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       else
    260         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       else
    288         os << anchor("all/"+line_type+"/"+local_path()+"/index.html"
    289                      ,"Total", level_+2, "View statistics for all");
    290     else
    291       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  
    309167  const StatsCollection& Node::stats(void) const
    310168  {
     
    324182  }
    325183
    326 
    327   std::string Node::url(void) const
    328   {
    329     return svninfo_.url();
    330   }
    331 
    332184}} // end of namespace svndigest and namespace theplu
  • trunk/lib/Node.h

    r1280 r1290  
    9292    virtual std::string href(void) const=0;
    9393
    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,
    9699                       const std::string& user) const;
    97100
     
    127130    const SVNlog& log(void) const;
    128131
     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
    129144    /**
    130145       @return The explicit string identifying the underlying derived
     
    132147    */
    133148    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;
    146 
    147     /**
    148        Note that returned string always end with '/' with the
    149        exception when an empty string is returned.
    150 
    151        @return output dir for example 'lib/' for this file
    152      */
    153     std::string output_dir(void) const;
    154 
    155     /**
    156        @return output path for example 'lib/Node.h.html' for this file
    157      */
    158     virtual std::string output_path(void) const=0;
    159149
    160150    ///
     
    163153    inline const std::string& path(void) const { return path_; }
    164154
    165     ///
    166     /// Function printing HTML in current working directory
    167     ///
    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 
    175155    /**
    176156       \return true if svncopyright::ignore property was set
     
    194174    const StatsCollection& stats(void) const;
    195175
     176    /**
     177     */
    196178    StatsCollection& stats(void);
    197179
     
    203185
    204186    /**
    205        \see SVNinfo::url(void)
    206     */
    207     std::string url(void) const;
    208    
     187     */
    209188    inline const SVNinfo& svn_info(void) const { return svninfo_; }
    210189
     190    /**
     191     */
     192    const TinyStats& tiny_stats(void) const { return tiny_stats_; }
     193
    211194  protected:
    212     ///
    213     /// print path in html format (with anchors) to @a os
    214     ///
    215     void path_anchor(std::ostream& os) const;
    216 
    217195    unsigned int level_;
    218196    std::string output_dir_;
     
    228206    Node(const Node&);
    229207
    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,
    231212                      const std::string& user,
    232213                      LineTypeParser::line_type lt) const;
    233214
    234215    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_style
    240     /// (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;
    246216
    247217    bool binary_;
     
    252222    bool svncopyright_ignore_;
    253223    SVNinfo svninfo_;
     224
     225    friend class FilePrinter;
     226    friend class DirectoryPrinter;
     227    friend class NodePrinter;
    254228  };
    255229
  • trunk/lib/NodePrinter.cc

    r1289 r1290  
    2121*/
    2222
    23 #include "Node.h"
     23#include "NodePrinter.h"
    2424
    2525#include "Configuration.h"
     
    2828#include "html_utility.h"
    2929#include "LineTypeParser.h"
     30#include "Node.h"
    3031#include "SVNlog.h"
    3132#include "SVNproperty.h"
     
    4546namespace svndigest{
    4647
    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
    17264  {
    17365    os << "<h2 class=\"path\">\n";
    17466    std::vector<std::string> words;
    175     words.reserve(level_+1);
     67    words.reserve(node().level_+1);
    17668    std::string word;
    17769    words.push_back(Node::project_);
    178     std::stringstream ss(local_path());
     70    std::stringstream ss(node().local_path());
    17971    while(getline(ss,word,'/'))
    18072      if (!word.empty()) // ignore double slash in path
     
    18476    else {
    18577      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]);
    18779        os << "<span class=\"sep\">/</span>";
    18880      }
    189       os << anchor(href(), words.back(), level_+2-words.size(),
     81      os << anchor(node().href(), words.back(), node().level_+2-words.size(),
    19082             "View " + words.back());
    19183    }
     
    19486
    19587
    196   void Node::print(const bool verbose) const
    197   {
    198     if (ignore())
     88  void NodePrinter::print(const bool verbose) const
     89  {
     90    if (node().ignore())
    19991      return;
    200     if (!Configuration::instance().output_file() && !this->dir())
     92    if (!Configuration::instance().output_file() && !node().dir())
    20193      return;
    20294    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();
    20597    typedef std::map<std::string, Stats*>::const_iterator iter;
    20698
    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){
    209101      print_core(i->first, "all", "total", log);
    210102      print_core(i->first, "all", "code", log);
     
    223115
    224116
    225   void Node::print_author_summary(std::ostream& os,
     117  void NodePrinter::print_author_summary(std::ostream& os,
    226118                                  const Stats& stats,
    227119                                  const std::string& line_type,
     
    244136
    245137    std::string color("light");
    246     if (!dir()) {
     138    if (!node().dir()) {
    247139      os << "<tr class=\"" << color << "\">\n";
    248140      os << "<td class=\"directory\" colspan=\"7\">";
     
    261153      os << "<tr class=\"" << color << "\"><td>";
    262154      os << anchor(*i+"/"+line_type+"/"+output_path()
    263                    ,*i, level_+2, "View statistics for "+*i);
     155                   ,*i, node().level_+2, "View statistics for "+*i);
    264156      os << "</td><td>" << stats.lines(*i)
    265157         << "</td><td>" << stats.code(*i)
     
    281173    os << "<tr class=\"" << color << "\">\n";
    282174    os << "<td>";
    283     if (dir())
    284       if (local_path().empty())
     175    if (node().dir())
     176      if (node().local_path().empty())
    285177        os << anchor("all/"+line_type+"/index.html"
    286                      ,"Total", level_+2, "View statistics for all");
     178                     ,"Total", node().level_+2, "View statistics for all");
    287179      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");
    290182    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");
    293185    os << "</td>\n";
    294186    os << "<td>" << stats.lines() << "</td>\n";
     
    307199
    308200 
    309   const StatsCollection& Node::stats(void) const
    310   {
    311     return stats_;
    312   }
    313 
    314 
    315   StatsCollection& Node::stats(void)
    316   {
    317     return stats_;
    318   }
    319 
    320 
    321   bool Node::svncopyright_ignore(void) const
    322   {
    323     return svncopyright_ignore_;
    324   }
    325 
    326 
    327   std::string Node::url(void) const
    328   {
    329     return svninfo_.url();
    330   }
    331 
    332201}} // 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_
    33
    44// $Id$
     
    4141namespace svndigest{
    4242
    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;
    5244
    5345  ///
    54   /// Abstract Base Class for files.
     46  /// Base class for FilePrinter and DirectoryPrinter
    5547  ///
    56   class Node
     48  class NodePrinter
    5749  {
    5850  public:
     
    6153    /// @brief Constructor
    6254    ///
    63     Node(const unsigned int, const std::string&, const std::string&,
    64          const std::string& = "");
     55    NodePrinter(void);
    6556
    6657    ///
    6758    /// @brief Destructor
    6859    ///
    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);
    14661
    14762    /**
     
    15469
    15570    /**
    156        @return output path for example 'lib/Node.h.html' for this file
     71       @return output path for example 'lib/NodePrinter.h.html' for this file
    15772     */
    15873    virtual std::string output_path(void) const=0;
    159 
    160     ///
    161     /// @todo doc
    162     ///
    163     inline const std::string& path(void) const { return path_; }
    16474
    16575    ///
     
    17383                              const SVNlog&) const;
    17484
    175     /**
    176        \return true if svncopyright::ignore property was set
    177      */
    178     bool svncopyright_ignore(void) const;
    179 
    180     /**
    181        @brief Check if item used to create this object has been
    182        assigned property svndigest:ignore.
    183 
    184        Currently files with property svndigest:ignore are to be
    185        ignored by svndigest. It is the responsibility of the
    186        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 its
    200        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 
    21185  protected:
    21286    ///
     
    21589    void path_anchor(std::ostream& os) const;
    21690
    217     unsigned int level_;
    218     std::string output_dir_;
    219     std::string path_; // absolute path
    220     static std::string project_;
    221     StatsCollection stats_;
    222     TinyStats tiny_stats_;
    223 
    22491  private:
    22592    ///
    22693    /// @brief Copy Constructor, not implemented
    22794    ///
    228     Node(const Node&);
     95    NodePrinter(const NodePrinter&);
    22996
    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;
    23598
    23699    virtual void print_core(bool verbose=false) const=0;
     
    245108                            const SVNlog&) const=0;
    246109
    247     bool binary_;
    248     bool link_;
    249     std::string local_path_; // path from root
    250     mutable SVNlog* log_;
    251     bool svndigest_ignore_;
    252     bool svncopyright_ignore_;
    253     SVNinfo svninfo_;
    254110  };
    255111
    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
    273114
    274115}} // end of namespace svndigest and namespace theplu
  • trunk/lib/Stats.cc

    r1280 r1290  
    2727#include "Configuration.h"
    2828#include "Functor.h"
    29 #include "Graph.h"
    3029#include "SVNblame.h"
    3130#include "SVNinfo.h"
     
    404403    assert(comment_or_copy_stats().size());
    405404    assert(other_stats().size());
    406   }
    407 
    408 
    409   std::string Stats::plot(const std::string& filename,
    410                           const std::string& linetype) const
    411   {
    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) const
    428   {
    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) const
    492   {
    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) const
    507   {
    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());
    527405  }
    528406
  • trunk/lib/Stats.h

    r1194 r1290  
    106106    */
    107107    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 (for
    116     /// 'all' not individual authors).
    117     ///
    118     void plot_summary(const std::string& output) const;
    119108
    120109    /**
     
    241230    svn_revnum_t load_cache8(std::istream&);
    242231
    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 
    257232    // Change this string if cache format is changed in such a way
    258233    // that all old cache files are obsolete.
     
    285260    Stats& operator=(const Stats&);
    286261
     262    friend class StatsPlotter;
    287263  };
    288264}} // end of namespace svndigest end of namespace theplu
  • trunk/lib/SvndigestVisitor.cc

    r1234 r1290  
    2323
    2424#include "Directory.h"
     25#include "DirectoryPrinter.h"
    2526#include "File.h"
     27#include "FilePrinter.h"
    2628#include "NodeVisitor.h"
    2729
     
    4850      dir.collect_stats();
    4951      dir.init_tiny_stats();
    50       dir.print(verbose_);
     52      DirectoryPrinter dp(dir);
     53      dp.print(verbose_);
    5154    }
    5255  }
     
    5962    if (report_) {
    6063      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      }
    6368    }
    6469  }
  • trunk/lib/first_page.cc

    r1254 r1290  
    3434#include "Stats.h"
    3535#include "StatsCollection.h"
     36#include "StatsPlotter.h"
    3637#include "SVNlog.h"
    3738#include "Trac.h"
     
    250251  {
    251252    std::string name("summary_plot");
    252     stats.plot_summary(name);
     253    StatsPlotter(stats).plot_summary(name);
    253254    os << "<div class=\"main\">\n";
    254255    os << image(name);
  • trunk/test/Makefile.am

    r1267 r1290  
    6262
    6363LDADD = $(builddir)/libsvndigesttest.a \
    64   $(top_builddir)/lib/libsvndigest.a \
     64  $(top_builddir)/lib/libsvndigest_core.a \
    6565  $(top_builddir)/yat/libyat.a \
    6666  $(SVN_LIBS) $(APR_LIBS) $(PLPLOT_LIBS)
     67
     68## graph test needs to link against Graph class
     69graph_test_LDADD = $(LDADD) $(top_builddir)/lib/libsvndigest.a
     70
    6771AM_LDFLAGS = $(SVNDIGEST_LDFLAGS)
    6872
Note: See TracChangeset for help on using the changeset viewer.