source: branches/0.9-stable/lib/Directory.cc @ 1464

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

closes #512

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 8.0 KB
Line 
1// $Id: Directory.cc 1464 2012-03-11 07:20:18Z peter $
2
3/*
4  Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Jari Häkkinen, Peter Johansson
5  Copyright (C) 2012 Peter Johansson
6
7  This file is part of svndigest, http://dev.thep.lu.se/svndigest
8
9  svndigest is free software; you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 3 of the License, or
12  (at your option) any later version.
13
14  svndigest is distributed in the hope that it will be useful, but
15  WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with svndigest. If not, see <http://www.gnu.org/licenses/>.
21*/
22
23#include "Directory.h"
24
25#include "Alias.h"
26#include "Configuration.h"
27#include "File.h"
28#include "html_utility.h"
29#include "Node.h"
30#include "NodeVisitor.h"
31#include "SVN.h"
32#include "SVNinfo.h"
33#include "SVNlog.h"
34#include "TinyStats.h"
35#include "utility.h"
36
37#include <algorithm>
38#include <cassert>
39#include <fstream>
40#include <functional>
41#include <iostream>
42#include <iterator>
43#include <list>
44#include <map>
45#include <sstream>
46
47#include <cerrno> // Needed to check error state below.
48#include <dirent.h>
49#include <sys/stat.h>
50
51namespace theplu{
52namespace svndigest{
53
54
55  Directory::Directory(const unsigned int level, const std::string& path, 
56                       const std::string& output, const std::string& project)
57    : Node(level,path,output,project)
58  {
59    output_dir_=local_path();
60    if (!output_dir_.empty())
61      output_dir_+='/';
62
63    using namespace std;
64    DIR* directory=opendir(path.c_str());    // C API from dirent.h
65    if (!directory)
66      throw NodeException("ERROR: opendir() failed; " + path +
67                          " is not a directory");
68    list<string> entries;
69    struct dirent* entry;
70    errno=0;  // Global variable used by C to track errors, from errno.h
71    while ((entry=readdir(directory)))       // C API from dirent.h
72      entries.push_back(string(entry->d_name));
73    if (errno)
74      throw NodeException("ERROR: readdir() failed on " + path);
75    closedir(directory);
76
77    SVN* svn=SVN::instance();
78    std::string mother_url = SVNinfo(path).url();
79    assert(mother_url.size());
80    // ensure trailing trailing '/'
81    if (mother_url[mother_url.size()-1]!='/')
82      mother_url.push_back('/');
83    for (list<string>::iterator i=entries.begin(); i!=entries.end(); ++i)
84      if ((*i)!=string(".") && (*i)!=string("..") && (*i)!=string(".svn")) {
85        string fullpath(path_+'/'+(*i));
86        switch (svn->version_controlled(fullpath)) {
87        case SVN::uptodate:
88          struct stat nodestat;                // C api from sys/stat.h
89          lstat(fullpath,&nodestat);   // C api from sys/stat.h
90          if (S_ISDIR(nodestat.st_mode)) {     // C api from sys/stat.h
91            // ignore directory if it is not a daughter of 'path' in repo
92            std::string url = SVNinfo(fullpath).url();
93            if (mother_url != directory_name(url))
94              continue;
95            daughters_.push_back(new Directory(level_+1,fullpath,local_path()));
96          }
97          else
98            daughters_.push_back(new File(level_,fullpath,local_path()));
99          break;
100        case SVN::unresolved:
101          throw NodeException(fullpath+" is not up to date");
102        case SVN::unversioned: ; // do nothing
103        }
104      }
105    std::sort(daughters_.begin(), daughters_.end(), NodePtrLess());
106  }
107
108
109  Directory::~Directory(void)
110  {
111    for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
112      delete *i;
113  }
114
115
116  void Directory::collect_stats(void)
117  {
118    stats_.reset();
119    for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
120      if (!(*i)->ignore()) {
121        stats_ += (*i)->stats();
122        (*i)->stats().reset();
123      }
124  }
125
126
127  bool Directory::dir(void) const
128  {
129    return true;
130  }
131
132
133  std::string Directory::href(void) const
134  { 
135    return name() + "/index.html";
136  }
137
138
139  svn_revnum_t Directory::last_changed_rev(void) const
140  {
141    svn_revnum_t res = svn_info().last_changed_rev();
142    for (NodeConstIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
143      res = std::max(res, (*i)->last_changed_rev());
144    return res;
145  }
146
147
148  void Directory::log_core(SVNlog& log) const
149  {
150    for (NodeConstIterator i(daughters_.begin()); i != daughters_.end(); ++i)
151      log += (*i)->log();
152  }
153
154  std::string Directory::node_type(void) const
155  {
156    return std::string("directory");
157  }
158
159
160  std::string Directory::output_path(void) const
161  {
162    return output_dir()+"index.html";
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::traverse(NodeVisitor& visitor)
287  {
288    if (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.