source: trunk/lib/CopyrightVisitor.cc @ 1358

Last change on this file since 1358 was 1358, checked in by Peter Johansson, 10 years ago

rewrite of svncopyright to use its own Stats class, which means it's no longer using the cache. This version is slow and there are lots of space for speed-ups and there is no cache functionality yet. refs #385

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 7.1 KB
Line 
1// $Id: CopyrightVisitor.cc 1358 2011-05-31 23:38:22Z peter $
2
3/*
4  Copyright (C) 2010, 2011 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 "CopyrightVisitor.h"
23
24#include "Configuration.h"
25#include "CopyrightStats.h"
26#include "Directory.h"
27#include "File.h"
28#include "NodeVisitor.h"
29#include "utility.h"
30
31#include <fstream>
32
33namespace theplu {
34namespace svndigest {
35
36  CopyrightVisitor::CopyrightVisitor(std::map<std::string, Alias>& alias, 
37                                     bool verbose,
38                                     const std::map<int,svn_revnum_t>& year2rev,
39                                     bool ignore_cache)
40    : NodeVisitor(), alias_(alias), verbose_(verbose), year2rev_(year2rev),
41      ignore_cache_(ignore_cache)
42  {}
43
44
45  std::string
46  CopyrightVisitor::copyright_block(const std::map<int, std::set<Alias> >& year_authors,
47                                    const std::string& prefix) const
48  {
49    using namespace std;
50    stringstream ss;
51    for (map<int, set<Alias> >::const_iterator i(year_authors.begin());
52         i!=year_authors.end();) {
53      ss << prefix << Configuration::instance().copyright_string() << " "
54         << 1900+i->first;
55      map<int, set<Alias> >::const_iterator j = i;
56      assert(i!=year_authors.end());
57      while (++j!=year_authors.end() && 
58             i->second == j->second){
59        ss << ", " << 1900+(j->first);
60      }
61      // printing authors
62      std::vector<Alias> vec_alias;
63      back_insert_iterator<std::vector<Alias> > ii(vec_alias);
64      std::copy(i->second.begin(), i->second.end(), ii);
65      // sort with respect to id
66      std::sort(vec_alias.begin(), vec_alias.end(), IdCompare());
67      for (std::vector<Alias>::iterator a=vec_alias.begin();
68           a!=vec_alias.end(); ++a){
69        if (a!=vec_alias.begin())
70          ss << ",";
71        ss << " " << a->name();
72      }
73      ss << "\n";
74      i = j;
75    }
76    return ss.str();
77  }
78
79
80  void CopyrightVisitor::create_year2alias(std::map<int, std::set<Alias> >& m,
81                                           const File& file)
82  {
83    using namespace std;
84    const Stats& stats = file.stats()["add"];
85
86    // loop over all years
87    for (std::map<int, svn_revnum_t>::const_iterator rev_iter=year2rev_.begin();
88         rev_iter!=year2rev_.end(); ++rev_iter) {
89
90      svn_revnum_t last_rev_this_year = rev_iter->second;
91      svn_revnum_t last_rev_last_year = 0;
92      if (rev_iter != year2rev_.begin()) {
93        last_rev_last_year = (--rev_iter)->second;
94        ++rev_iter;
95      }
96      // do not go beyond BASE rev of file
97      last_rev_this_year = std::min(last_rev_this_year,file.last_changed_rev());
98      last_rev_last_year = std::min(last_rev_last_year,file.last_changed_rev());
99      // loop over authors
100      for (std::set<std::string>::const_iterator a_iter=stats.authors().begin();
101           a_iter!=stats.authors().end(); ++a_iter) {
102
103        // check if anything has been added since last year
104        if ( (stats(LineTypeParser::code, *a_iter, last_rev_this_year) >
105              stats(LineTypeParser::code, *a_iter, last_rev_last_year)) || 
106             (stats(LineTypeParser::comment, *a_iter, last_rev_this_year) >
107              stats(LineTypeParser::comment, *a_iter, last_rev_last_year)) ) {
108       
109       
110          // find username in map of aliases
111          std::map<string,Alias>::iterator name(alias_.lower_bound(*a_iter));
112         
113          // if alias exist insert alias
114          if (name != alias_.end() && name->first==*a_iter)
115            m[rev_iter->first].insert(name->second);
116          else {
117            // else insert user name
118            Alias a(*a_iter,alias_.size());
119            m[rev_iter->first].insert(a);
120            std::cerr << "svncopyright: warning: no copyright alias found for `" 
121                      << *a_iter << "'\n";
122            // insert alias to avoid multiple warnings.
123            alias_.insert(name, std::make_pair(*a_iter, a));
124          }
125        }
126      }
127    }
128  }
129
130
131  bool CopyrightVisitor::detect_copyright(const std::string& path,
132                                          std::string& block, 
133                                          size_t& start_at_line,
134                                          size_t& end_at_line, 
135                                          std::string& prefix) const
136  {
137    using namespace std;
138    LineTypeParser parser(path);
139    std::ifstream is(path.c_str());
140    std::string line;
141    while (std::getline(is, line)) 
142      parser.parse(line);
143    if (!parser.copyright_found())
144      return false;
145    block = parser.block();
146    start_at_line = parser.start_line();
147    end_at_line = parser.end_line();
148    prefix = parser.prefix();
149    return true;
150  }
151
152
153  bool CopyrightVisitor::enter(Directory& dir) 
154  {
155    if (dir.ignore() || dir.svncopyright_ignore())
156      return false;
157    return true;
158  }
159 
160
161  void CopyrightVisitor::leave(Directory& dir) 
162  {
163  }
164 
165
166  void CopyrightVisitor::update_copyright(const File& file)
167  {
168    std::string old_block;
169    size_t start_line=0;
170    size_t end_line=0;
171    std::string prefix;
172    if (!detect_copyright(file.path(),old_block, start_line, end_line, prefix)){
173      if (Configuration::instance().missing_copyright_warning())
174        std::cerr << "svncopyright: warning: no copyright statement found in `" 
175                  << file.path() << "'\n";
176      return;
177    }
178    if (verbose_)
179      std::cout << "Parsing '" << file.path() << "'\n";
180    CopyrightStats stats(file.path(), ignore_cache_, alias_, year2rev_);
181    const std::map<int, std::set<Alias> >& map = stats.map();
182    assert(!map.empty());
183    std::string new_block = copyright_block(map, prefix);
184    if (old_block==new_block)
185      return;
186    if (verbose_)
187      std::cout << "Updating copyright in '" << file.path() << "'" << std::endl; 
188    update_copyright(file.path(), new_block, start_line, end_line);
189  }
190
191
192  void CopyrightVisitor::update_copyright(const std::string& path,
193                                          const std::string& new_block,
194                                          size_t start_at_line, 
195                                          size_t end_at_line) const
196  {
197    // embrace filename with brackets #filename#
198    std::string tmpname = concatenate_path(directory_name(path),
199                                           "#" + file_name(path) + "#");
200    std::ofstream tmp(tmpname.c_str());
201    assert(tmp);
202    using namespace std;
203    ifstream is(path.c_str());
204    assert(is.good());
205    string line;
206    // Copy lines before block
207    for (size_t i=1; i<start_at_line; ++i){
208      assert(is.good());
209      getline(is, line);
210      tmp << line << "\n";
211    }
212    // Printing copyright statement
213    tmp << new_block;
214    // Ignore old block lines
215    for (size_t i=start_at_line; i<end_at_line; ++i){
216      assert(is.good());
217      getline(is, line);
218    }
219    // Copy lines after block
220    while(is.good()) {
221      char ch=is.get();
222      if (is.good())
223        tmp.put(ch);
224    }
225
226    is.close();
227    tmp.close();
228   
229    // finally rename file
230    rename(tmpname, path);
231  }
232
233  void CopyrightVisitor::visit(File& file)
234  {
235    if (file.ignore() || file.svncopyright_ignore())
236      return;
237    update_copyright(file);
238
239    //file.parse(verbose_, ignore_cache_);
240    //update_copyright(file);
241    //file.stats().reset();
242  }
243
244}} // end of namespace svndigest and namespace theplu
Note: See TracBrowser for help on using the repository browser.