source: trunk/lib/CopyrightVisitor.cc @ 1239

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

move 'update copyright' code from File class to CopyrightVisitor? class.

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