source: trunk/lib/Directory.cc @ 1236

Last change on this file since 1236 was 1236, checked in by Peter Johansson, 11 years ago

Remove parse from Node interface as we now use visitor pattern and only need to rase with File and 'collect_stats()' with Directory. refs 476

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.0 KB
Line 
1// $Id: Directory.cc 1236 2010-10-23 21:30:17Z peter $
2
3/*
4  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Jari Häkkinen, Peter Johansson
5
6  This file is part of svndigest, http://dev.thep.lu.se/svndigest
7
8  svndigest is free software; you can redistribute it and/or modify it
9  under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12
13  svndigest is distributed in the hope that it will be useful, but
14  WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with svndigest. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "Directory.h"
23
24#include "Alias.h"
25#include "Configuration.h"
26#include "File.h"
27#include "html_utility.h"
28#include "Node.h"
29#include "NodeVisitor.h"
30#include "SVN.h"
31#include "SVNlog.h"
32#include "TinyStats.h"
33#include "utility.h"
34
35#include <algorithm>
36#include <cassert>
37#include <fstream>
38#include <functional>
39#include <iostream>
40#include <iterator>
41#include <list>
42#include <map>
43#include <sstream>
44
45#include <cerrno> // Needed to check error state below.
46#include <dirent.h>
47#include <sys/stat.h>
48
49namespace theplu{
50namespace svndigest{
51
52
53  Directory::Directory(const unsigned int level, const std::string& path, 
54                       const std::string& output)
55    : Node(level,path,output)
56  {
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());
94  }
95
96
97  Directory::~Directory(void)
98  {
99    for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
100      delete *i;
101  }
102
103
104  void Directory::collect_stats(void)
105  {
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      }
112  }
113
114
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
149  {
150    return output_dir()+"index.html";
151  }
152
153
154  void Directory::print_core(const bool verbose) const
155  {
156    //mkdir("blame_output/" + local_path());
157    // print daughter nodes
158    //for (NodeConstIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
159    //  (*i)->print(verbose);
160  }
161
162
163  void Directory::print_core(const std::string& stats_type,
164                             const std::string& user, 
165                             const std::string& line_type,
166                             const SVNlog& log) const
167  {
168
169    const Stats& stats = stats_[stats_type];
170    std::string imagedir = stats_type+"/"+"images/"+line_type;
171    std::string outdir   = stats_type+"/"+user+"/" +line_type;
172    if (local_path()!="") {
173      imagedir += "/"+local_path();
174      outdir   += "/"+local_path();
175    }
176    mkdir_p(outdir);
177    if (user=="all")
178      mkdir_p(imagedir);
179    std::string html_name = outdir+"/index.html";
180    std::ofstream os(html_name.c_str());
181    assert(os.good());
182    if (local_path().empty())
183      print_header(os, name(), level_+3, user, line_type, "index.html", 
184                   stats_type);
185    else
186      print_header(os, name(), level_+3, user, line_type, 
187                   local_path()+"/index.html", stats_type);
188    path_anchor(os);
189
190    std::stringstream ss;
191    for (size_t i=0; i<level_; ++i)
192      ss << "../";
193    ss << "../../../";
194    if (user=="all")
195      ss << stats.plot(imagedir+"/index", line_type);
196    else
197      ss << imagedir << "/index";
198    os << "<p class=\"plot\">\n"; 
199    os << image(ss.str());
200    os << "</p>\n";
201
202    os << "<h3>File Summary";
203    if (user!="all")
204      os << " for " << user;
205    os << "</h3>";     
206    os << "<table class=\"listings\">\n";
207    os << "<thead>\n";
208    os << "<tr>\n";
209    os << "<th>Node</th>\n";
210    os << "<th>Lines</th>\n";
211    os << "<th>Code</th>\n";
212    os << "<th>Comments</th>\n";
213    os << "<th>Other</th>\n";
214    os << "<th>Revision</th>\n";
215    os << "<th>Author</th>\n";
216    os << "</tr>\n</thead>\n";
217    os << "<tbody>\n";
218
219    std::string color("light");
220    if (level_){
221      os << "<tr class=\"light\">\n";
222      os << "<td class=\"directory\" colspan=\"7\">";
223      os << anchor("../index.html", "../");
224      os << "</td>\n</tr>\n";
225      color = "dark";
226    }
227
228    // print html links to daughter nodes
229    for (NodeConstIterator d = daughters_.begin(); d!=daughters_.end(); ++d) {
230      (*d)->html_tablerow(os,stats_type, color, user);
231      if (color=="dark")
232        color = "light";
233      else
234        color = "dark";
235    }
236    os << "<tr class=\"" << color << "\">\n";
237    os << "<td>Total</td>\n";
238    if (user=="all"){
239      os << "<td>" << stats.lines() << "</td>\n";
240      os << "<td>" << stats.code() << "</td>\n";
241      os << "<td>" << stats.comments() << "</td>\n";
242      os << "<td>" << stats.empty() << "</td>\n";
243    }
244    else {
245      os << "<td>" << stats.lines(user); 
246      if (stats.lines(user)) 
247        os << " (" << percent(stats.lines(user),stats.lines()) << "%)"; 
248      os << "</td>\n";
249      os << "<td>" << stats.code(user); 
250      if (stats.code(user)) 
251        os << " (" << percent(stats.code(user),stats.code()) << "%)"; 
252      os << "</td>\n";
253      os << "<td>" << stats.comments(user); 
254      if (stats.comments(user)) 
255        os << " (" << percent(stats.comments(user),stats.comments()) << "%)"; 
256      os << "</td>\n";
257      os << "<td>" << stats.empty(user); 
258      if (stats.empty(user)) 
259        os << " (" << percent(stats.empty(user),stats.empty()) << "%)"; 
260      os << "</td>\n";
261    }
262    os << "<td>" << trac_revision(last_changed_rev()) << "</td>\n";
263    os << "<td>" << author() << "</td>\n";
264    os << "</tr>\n";
265    os << "</tbody>\n";
266    os << "</table>\n";
267    print_author_summary(os, stats, line_type, log);
268    os << "\n";
269    print_footer(os);
270    os.close(); 
271  }
272
273
274  void Directory::print_copyright(std::map<std::string, Alias>& alias, 
275                                  bool verbose,
276                                  const std::map<int,svn_revnum_t>& y2r) const 
277  {
278    if (!ignore() && !svncopyright_ignore()) {
279      // print daughter nodes, i.e, this function is recursive
280      for (NodeConstIterator i = daughters_.begin(); i!=daughters_.end(); ++i)
281        (*i)->print_copyright(alias, verbose, y2r);
282    }
283  }
284
285
286  void Directory::traverse(NodeVisitor& visitor)
287  {
288    visitor.enter(*this);
289    for (NodeIterator first=daughters_.begin(), end=daughters_.end();
290         first!=end; ++first)
291      (*first)->traverse(visitor);
292    visitor.leave(*this);
293  }
294
295
296}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.