source: trunk/lib/Directory.cc @ 1234

Last change on this file since 1234 was 1234, checked in by Peter Johansson, 12 years ago

refs #476. Merged visitor branch into trunk. Used 'svn merge /branches/visitor' because --reintegrate did (currently) not work on our repo. Since I could not merge as suggested in subversion manual, I reverted all mergeinfo properties to avoid future confusion by svn-client. This means (I think) that there will be no connection about this commit and the visitor branch, but to svn-client this will look like a large changeset (just like a merge in the old days).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.3 KB
Line 
1// $Id: Directory.cc 1234 2010-10-23 16:41:33Z 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  const StatsCollection& Directory::parse(bool verbose, bool ignore)
154  {
155    stats_.reset();
156    assert(0 && "we are not using this function, are we?");
157    /*
158    for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
159      if (!(*i)->ignore())
160        stats_ += (*i)->parse(verbose, ignore);
161    */
162    return stats_;
163  }
164
165
166  void Directory::print_core(const bool verbose) const
167  {
168    //mkdir("blame_output/" + local_path());
169    // print daughter nodes
170    //for (NodeConstIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
171    //  (*i)->print(verbose);
172  }
173
174
175  void Directory::print_core(const std::string& stats_type,
176                             const std::string& user, 
177                             const std::string& line_type,
178                             const SVNlog& log) const
179  {
180
181    const Stats& stats = stats_[stats_type];
182    std::string imagedir = stats_type+"/"+"images/"+line_type;
183    std::string outdir   = stats_type+"/"+user+"/" +line_type;
184    if (local_path()!="") {
185      imagedir += "/"+local_path();
186      outdir   += "/"+local_path();
187    }
188    mkdir_p(outdir);
189    if (user=="all")
190      mkdir_p(imagedir);
191    std::string html_name = outdir+"/index.html";
192    std::ofstream os(html_name.c_str());
193    assert(os.good());
194    if (local_path().empty())
195      print_header(os, name(), level_+3, user, line_type, "index.html", 
196                   stats_type);
197    else
198      print_header(os, name(), level_+3, user, line_type, 
199                   local_path()+"/index.html", stats_type);
200    path_anchor(os);
201
202    std::stringstream ss;
203    for (size_t i=0; i<level_; ++i)
204      ss << "../";
205    ss << "../../../";
206    if (user=="all")
207      ss << stats.plot(imagedir+"/index", line_type);
208    else
209      ss << imagedir << "/index";
210    os << "<p class=\"plot\">\n"; 
211    os << image(ss.str());
212    os << "</p>\n";
213
214    os << "<h3>File Summary";
215    if (user!="all")
216      os << " for " << user;
217    os << "</h3>";     
218    os << "<table class=\"listings\">\n";
219    os << "<thead>\n";
220    os << "<tr>\n";
221    os << "<th>Node</th>\n";
222    os << "<th>Lines</th>\n";
223    os << "<th>Code</th>\n";
224    os << "<th>Comments</th>\n";
225    os << "<th>Other</th>\n";
226    os << "<th>Revision</th>\n";
227    os << "<th>Author</th>\n";
228    os << "</tr>\n</thead>\n";
229    os << "<tbody>\n";
230
231    std::string color("light");
232    if (level_){
233      os << "<tr class=\"light\">\n";
234      os << "<td class=\"directory\" colspan=\"7\">";
235      os << anchor("../index.html", "../");
236      os << "</td>\n</tr>\n";
237      color = "dark";
238    }
239
240    // print html links to daughter nodes
241    for (NodeConstIterator d = daughters_.begin(); d!=daughters_.end(); ++d) {
242      (*d)->html_tablerow(os,stats_type, color, user);
243      if (color=="dark")
244        color = "light";
245      else
246        color = "dark";
247    }
248    os << "<tr class=\"" << color << "\">\n";
249    os << "<td>Total</td>\n";
250    if (user=="all"){
251      os << "<td>" << stats.lines() << "</td>\n";
252      os << "<td>" << stats.code() << "</td>\n";
253      os << "<td>" << stats.comments() << "</td>\n";
254      os << "<td>" << stats.empty() << "</td>\n";
255    }
256    else {
257      os << "<td>" << stats.lines(user); 
258      if (stats.lines(user)) 
259        os << " (" << percent(stats.lines(user),stats.lines()) << "%)"; 
260      os << "</td>\n";
261      os << "<td>" << stats.code(user); 
262      if (stats.code(user)) 
263        os << " (" << percent(stats.code(user),stats.code()) << "%)"; 
264      os << "</td>\n";
265      os << "<td>" << stats.comments(user); 
266      if (stats.comments(user)) 
267        os << " (" << percent(stats.comments(user),stats.comments()) << "%)"; 
268      os << "</td>\n";
269      os << "<td>" << stats.empty(user); 
270      if (stats.empty(user)) 
271        os << " (" << percent(stats.empty(user),stats.empty()) << "%)"; 
272      os << "</td>\n";
273    }
274    os << "<td>" << trac_revision(last_changed_rev()) << "</td>\n";
275    os << "<td>" << author() << "</td>\n";
276    os << "</tr>\n";
277    os << "</tbody>\n";
278    os << "</table>\n";
279    print_author_summary(os, stats, line_type, log);
280    os << "\n";
281    print_footer(os);
282    os.close(); 
283  }
284
285
286  void Directory::print_copyright(std::map<std::string, Alias>& alias, 
287                                  bool verbose,
288                                  const std::map<int,svn_revnum_t>& y2r) const 
289  {
290    if (!ignore() && !svncopyright_ignore()) {
291      // print daughter nodes, i.e, this function is recursive
292      for (NodeConstIterator i = daughters_.begin(); i!=daughters_.end(); ++i)
293        (*i)->print_copyright(alias, verbose, y2r);
294    }
295  }
296
297
298  void Directory::traverse(NodeVisitor& visitor)
299  {
300    visitor.enter(*this);
301    for (NodeIterator first=daughters_.begin(), end=daughters_.end();
302         first!=end; ++first)
303      (*first)->traverse(visitor);
304    visitor.leave(*this);
305  }
306
307
308}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.