source: trunk/lib/CopyrightVisitor.cc @ 1457

Last change on this file since 1457 was 1457, checked in by Peter Johansson, 9 years ago

if all copyright worthy revs are set to be ignored, do not touch the file. refs #387

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