lib/CopyrightVisitor.cc

Code
Comments
Other
Rev Date Author Line
1225 17 Oct 10 peter 1 // $Id$
1225 17 Oct 10 peter 2
1225 17 Oct 10 peter 3 /*
1635 30 Mar 23 peter 4   Copyright (C) 2010, 2011, 2012, 2023 Peter Johansson
1225 17 Oct 10 peter 5
1225 17 Oct 10 peter 6   This file is part of svndigest, http://dev.thep.lu.se/svndigest
1225 17 Oct 10 peter 7
1225 17 Oct 10 peter 8   svndigest is free software; you can redistribute it and/or modify it
1225 17 Oct 10 peter 9   under the terms of the GNU General Public License as published by
1225 17 Oct 10 peter 10   the Free Software Foundation; either version 3 of the License, or
1225 17 Oct 10 peter 11   (at your option) any later version.
1225 17 Oct 10 peter 12
1225 17 Oct 10 peter 13   svndigest is distributed in the hope that it will be useful, but
1225 17 Oct 10 peter 14   WITHOUT ANY WARRANTY; without even the implied warranty of
1225 17 Oct 10 peter 15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1225 17 Oct 10 peter 16   General Public License for more details.
1225 17 Oct 10 peter 17
1225 17 Oct 10 peter 18   You should have received a copy of the GNU General Public License
1225 17 Oct 10 peter 19   along with svndigest. If not, see <http://www.gnu.org/licenses/>.
1225 17 Oct 10 peter 20 */
1225 17 Oct 10 peter 21
1619 12 Mar 23 peter 22 #include <config.h>
1619 12 Mar 23 peter 23
1225 17 Oct 10 peter 24 #include "CopyrightVisitor.h"
1225 17 Oct 10 peter 25
1239 23 Oct 10 peter 26 #include "Configuration.h"
1358 31 May 11 peter 27 #include "CopyrightStats.h"
1225 17 Oct 10 peter 28 #include "Directory.h"
1225 17 Oct 10 peter 29 #include "File.h"
1225 17 Oct 10 peter 30 #include "NodeVisitor.h"
1321 28 Nov 10 peter 31 #include "utility.h"
1225 17 Oct 10 peter 32
1437 20 Dec 11 peter 33 #include <cassert>
1321 28 Nov 10 peter 34 #include <fstream>
1321 28 Nov 10 peter 35
1225 17 Oct 10 peter 36 namespace theplu {
1225 17 Oct 10 peter 37 namespace svndigest {
1225 17 Oct 10 peter 38
1437 20 Dec 11 peter 39   CopyrightVisitor::CopyrightVisitor(std::map<std::string, Alias>& alias,
1225 17 Oct 10 peter 40                                      bool verbose,
1227 17 Oct 10 peter 41                                      const std::map<int,svn_revnum_t>& year2rev,
1227 17 Oct 10 peter 42                                      bool ignore_cache)
1227 17 Oct 10 peter 43     : NodeVisitor(), alias_(alias), verbose_(verbose), year2rev_(year2rev),
1227 17 Oct 10 peter 44       ignore_cache_(ignore_cache)
1225 17 Oct 10 peter 45   {}
1225 17 Oct 10 peter 46
1225 17 Oct 10 peter 47
1456 24 Dec 11 peter 48   void CopyrightVisitor::add(RevisionSet& a, const RevisionSet& b) const
1456 24 Dec 11 peter 49   {
1456 24 Dec 11 peter 50     for (RevisionSet::const_iterator i=b.begin(); i!=b.end(); ++i)
1456 24 Dec 11 peter 51       a.insert_merge(*i);
1456 24 Dec 11 peter 52   }
1456 24 Dec 11 peter 53
1456 24 Dec 11 peter 54
1437 20 Dec 11 peter 55   std::string
1239 23 Oct 10 peter 56   CopyrightVisitor::copyright_block(const std::map<int, std::set<Alias> >& year_authors,
1239 23 Oct 10 peter 57                                     const std::string& prefix) const
1239 23 Oct 10 peter 58   {
1239 23 Oct 10 peter 59     using namespace std;
1239 23 Oct 10 peter 60     stringstream ss;
1239 23 Oct 10 peter 61     for (map<int, set<Alias> >::const_iterator i(year_authors.begin());
1239 23 Oct 10 peter 62          i!=year_authors.end();) {
1239 23 Oct 10 peter 63       ss << prefix << Configuration::instance().copyright_string() << " "
1239 23 Oct 10 peter 64          << 1900+i->first;
1239 23 Oct 10 peter 65       map<int, set<Alias> >::const_iterator j = i;
1239 23 Oct 10 peter 66       assert(i!=year_authors.end());
1437 20 Dec 11 peter 67       while (++j!=year_authors.end() &&
1239 23 Oct 10 peter 68              i->second == j->second){
1239 23 Oct 10 peter 69         ss << ", " << 1900+(j->first);
1239 23 Oct 10 peter 70       }
1239 23 Oct 10 peter 71       // printing authors
1239 23 Oct 10 peter 72       std::vector<Alias> vec_alias;
1239 23 Oct 10 peter 73       back_insert_iterator<std::vector<Alias> > ii(vec_alias);
1239 23 Oct 10 peter 74       std::copy(i->second.begin(), i->second.end(), ii);
1239 23 Oct 10 peter 75       // sort with respect to id
1239 23 Oct 10 peter 76       std::sort(vec_alias.begin(), vec_alias.end(), IdCompare());
1239 23 Oct 10 peter 77       for (std::vector<Alias>::iterator a=vec_alias.begin();
1239 23 Oct 10 peter 78            a!=vec_alias.end(); ++a){
1239 23 Oct 10 peter 79         if (a!=vec_alias.begin())
1239 23 Oct 10 peter 80           ss << ",";
1239 23 Oct 10 peter 81         ss << " " << a->name();
1239 23 Oct 10 peter 82       }
1239 23 Oct 10 peter 83       ss << "\n";
1239 23 Oct 10 peter 84       i = j;
1239 23 Oct 10 peter 85     }
1239 23 Oct 10 peter 86     return ss.str();
1239 23 Oct 10 peter 87   }
1239 23 Oct 10 peter 88
1239 23 Oct 10 peter 89
1239 23 Oct 10 peter 90   bool CopyrightVisitor::detect_copyright(const std::string& path,
1437 20 Dec 11 peter 91                                           std::string& block,
1239 23 Oct 10 peter 92                                           size_t& start_at_line,
1437 20 Dec 11 peter 93                                           size_t& end_at_line,
1239 23 Oct 10 peter 94                                           std::string& prefix) const
1239 23 Oct 10 peter 95   {
1239 23 Oct 10 peter 96     using namespace std;
1239 23 Oct 10 peter 97     LineTypeParser parser(path);
1239 23 Oct 10 peter 98     std::ifstream is(path.c_str());
1239 23 Oct 10 peter 99     std::string line;
1437 20 Dec 11 peter 100     while (std::getline(is, line))
1239 23 Oct 10 peter 101       parser.parse(line);
1239 23 Oct 10 peter 102     if (!parser.copyright_found())
1239 23 Oct 10 peter 103       return false;
1239 23 Oct 10 peter 104     block = parser.block();
1239 23 Oct 10 peter 105     start_at_line = parser.start_line();
1239 23 Oct 10 peter 106     end_at_line = parser.end_line();
1239 23 Oct 10 peter 107     prefix = parser.prefix();
1239 23 Oct 10 peter 108     return true;
1239 23 Oct 10 peter 109   }
1239 23 Oct 10 peter 110
1239 23 Oct 10 peter 111
1437 20 Dec 11 peter 112   bool CopyrightVisitor::enter(Directory& dir)
1225 17 Oct 10 peter 113   {
1449 22 Dec 11 peter 114     if (dir.svncopyright_ignore())
1225 17 Oct 10 peter 115       return false;
1456 24 Dec 11 peter 116
1456 24 Dec 11 peter 117     RevisionSet ignore = dir.property().svncopyright_ignore_rev();
1456 24 Dec 11 peter 118
1456 24 Dec 11 peter 119     typedef std::map<std::string, RevisionSet> Map;
1456 24 Dec 11 peter 120     Map::const_iterator mother = path2ignore_.find(directory_name(dir.path()));
1456 24 Dec 11 peter 121     if (mother!=path2ignore_.end())
1456 24 Dec 11 peter 122       add(ignore, mother->second);
1456 24 Dec 11 peter 123
1456 24 Dec 11 peter 124     if (!ignore.empty())
1456 24 Dec 11 peter 125       path2ignore_[dir.path()] = ignore;
1456 24 Dec 11 peter 126
1225 17 Oct 10 peter 127     return true;
1225 17 Oct 10 peter 128   }
1225 17 Oct 10 peter 129
1437 20 Dec 11 peter 130
1437 20 Dec 11 peter 131   void CopyrightVisitor::leave(Directory& dir)
1225 17 Oct 10 peter 132   {
1225 17 Oct 10 peter 133   }
1225 17 Oct 10 peter 134
1437 20 Dec 11 peter 135
1239 23 Oct 10 peter 136   void CopyrightVisitor::update_copyright(const File& file)
1239 23 Oct 10 peter 137   {
1239 23 Oct 10 peter 138     std::string old_block;
1239 23 Oct 10 peter 139     size_t start_line=0;
1239 23 Oct 10 peter 140     size_t end_line=0;
1239 23 Oct 10 peter 141     std::string prefix;
1239 23 Oct 10 peter 142     if (!detect_copyright(file.path(),old_block, start_line, end_line, prefix)){
1239 23 Oct 10 peter 143       if (Configuration::instance().missing_copyright_warning())
1459 09 Jan 12 peter 144         std::cerr << "svncopyright: warning: no copyright statement found in '"
1239 23 Oct 10 peter 145                   << file.path() << "'\n";
1239 23 Oct 10 peter 146       return;
1239 23 Oct 10 peter 147     }
1358 31 May 11 peter 148     if (verbose_)
1358 31 May 11 peter 149       std::cout << "Parsing '" << file.path() << "'\n";
1456 24 Dec 11 peter 150
1456 24 Dec 11 peter 151     RevisionSet ignore_revs = file.property().svncopyright_ignore_rev();
1456 24 Dec 11 peter 152
1456 24 Dec 11 peter 153     typedef std::map<std::string, RevisionSet> Map;
1456 24 Dec 11 peter 154     Map::const_iterator mother = path2ignore_.find(directory_name(file.path()));
1456 24 Dec 11 peter 155     if (mother!=path2ignore_.end())
1456 24 Dec 11 peter 156       add(ignore_revs, mother->second);
1456 24 Dec 11 peter 157
1451 22 Dec 11 peter 158     CopyrightStats stats(file.path(), ignore_cache_, year2rev_, ignore_revs);
1457 24 Dec 11 peter 159     if (stats.map().empty())
1457 24 Dec 11 peter 160       return;
1376 14 Jun 11 peter 161     const std::map<int, std::set<std::string> >& year2users = stats.map();
1376 14 Jun 11 peter 162     assert(!year2users.empty());
1376 14 Jun 11 peter 163     std::map<int, std::set<Alias> > year2alias;
1376 14 Jun 11 peter 164     translate(year2users, year2alias);
1376 14 Jun 11 peter 165     std::string new_block = copyright_block(year2alias, prefix);
1239 23 Oct 10 peter 166     if (old_block==new_block)
1239 23 Oct 10 peter 167       return;
1239 23 Oct 10 peter 168     if (verbose_)
1437 20 Dec 11 peter 169       std::cout << "Updating copyright in '" << file.path() << "'" << std::endl;
1239 23 Oct 10 peter 170     update_copyright(file.path(), new_block, start_line, end_line);
1239 23 Oct 10 peter 171   }
1239 23 Oct 10 peter 172
1239 23 Oct 10 peter 173
1239 23 Oct 10 peter 174   void CopyrightVisitor::update_copyright(const std::string& path,
1239 23 Oct 10 peter 175                                           const std::string& new_block,
1437 20 Dec 11 peter 176                                           size_t start_at_line,
1239 23 Oct 10 peter 177                                           size_t end_at_line) const
1239 23 Oct 10 peter 178   {
1239 23 Oct 10 peter 179     // embrace filename with brackets #filename#
1239 23 Oct 10 peter 180     std::string tmpname = concatenate_path(directory_name(path),
1239 23 Oct 10 peter 181                                            "#" + file_name(path) + "#");
1239 23 Oct 10 peter 182     std::ofstream tmp(tmpname.c_str());
1239 23 Oct 10 peter 183     assert(tmp);
1239 23 Oct 10 peter 184     using namespace std;
1239 23 Oct 10 peter 185     ifstream is(path.c_str());
1239 23 Oct 10 peter 186     assert(is.good());
1239 23 Oct 10 peter 187     string line;
1239 23 Oct 10 peter 188     // Copy lines before block
1239 23 Oct 10 peter 189     for (size_t i=1; i<start_at_line; ++i){
1239 23 Oct 10 peter 190       assert(is.good());
1239 23 Oct 10 peter 191       getline(is, line);
1239 23 Oct 10 peter 192       tmp << line << "\n";
1239 23 Oct 10 peter 193     }
1239 23 Oct 10 peter 194     // Printing copyright statement
1239 23 Oct 10 peter 195     tmp << new_block;
1239 23 Oct 10 peter 196     // Ignore old block lines
1239 23 Oct 10 peter 197     for (size_t i=start_at_line; i<end_at_line; ++i){
1239 23 Oct 10 peter 198       assert(is.good());
1239 23 Oct 10 peter 199       getline(is, line);
1239 23 Oct 10 peter 200     }
1239 23 Oct 10 peter 201     // Copy lines after block
1239 23 Oct 10 peter 202     while(is.good()) {
1239 23 Oct 10 peter 203       char ch=is.get();
1239 23 Oct 10 peter 204       if (is.good())
1239 23 Oct 10 peter 205         tmp.put(ch);
1239 23 Oct 10 peter 206     }
1239 23 Oct 10 peter 207
1239 23 Oct 10 peter 208     is.close();
1239 23 Oct 10 peter 209     tmp.close();
1437 20 Dec 11 peter 210
1437 20 Dec 11 peter 211     // finally rename file
1392 12 Jul 11 peter 212     struct stat nodestat;
1392 12 Jul 11 peter 213     stat(path.c_str(), &nodestat);
1239 23 Oct 10 peter 214     rename(tmpname, path);
1392 12 Jul 11 peter 215     chmod(path, nodestat.st_mode);
1239 23 Oct 10 peter 216   }
1239 23 Oct 10 peter 217
1376 14 Jun 11 peter 218
1225 17 Oct 10 peter 219   void CopyrightVisitor::visit(File& file)
1225 17 Oct 10 peter 220   {
1449 22 Dec 11 peter 221     if (file.svncopyright_ignore())
1229 17 Oct 10 peter 222       return;
1239 23 Oct 10 peter 223     update_copyright(file);
1225 17 Oct 10 peter 224   }
1225 17 Oct 10 peter 225
1376 14 Jun 11 peter 226
1437 20 Dec 11 peter 227   void CopyrightVisitor::translate(const std::set<std::string>& users,
1376 14 Jun 11 peter 228                                    std::set<Alias>& aliases)
1376 14 Jun 11 peter 229   {
1437 20 Dec 11 peter 230     for (std::set<std::string>::const_iterator user=users.begin();
1376 14 Jun 11 peter 231          user!=users.end(); ++user) {
1376 14 Jun 11 peter 232       std::map<std::string, Alias>::const_iterator i = alias_.find(*user);
1376 14 Jun 11 peter 233       // if alias not found for author
1376 14 Jun 11 peter 234       if (i==alias_.end()) {
1459 09 Jan 12 peter 235         std::cerr << "svncopyright: warning: no copyright alias found for '"
1376 14 Jun 11 peter 236                   << *user << "'\n";
1376 14 Jun 11 peter 237         // insert alias to avoid multiple warnings.
1376 14 Jun 11 peter 238         Alias a(*user, alias_.size());
1376 14 Jun 11 peter 239         alias_[*user] = a;
1376 14 Jun 11 peter 240       }
1376 14 Jun 11 peter 241       else {
1376 14 Jun 11 peter 242         // FIXME: perhaps use hint
1376 14 Jun 11 peter 243         aliases.insert(i->second);
1376 14 Jun 11 peter 244       }
1376 14 Jun 11 peter 245     }
1376 14 Jun 11 peter 246   }
1376 14 Jun 11 peter 247
1376 14 Jun 11 peter 248
1437 20 Dec 11 peter 249   void
1437 20 Dec 11 peter 250   CopyrightVisitor::translate(const std::map<int, std::set<std::string> >& y2u,
1376 14 Jun 11 peter 251                               std::map<int, std::set<Alias> >& y2a)
1376 14 Jun 11 peter 252   {
1376 14 Jun 11 peter 253     using std::map;
1376 14 Jun 11 peter 254     using std::set;
1376 14 Jun 11 peter 255     using std::string;
1437 20 Dec 11 peter 256     for (map<int, set<string> >::const_iterator yu=y2u.begin();
1376 14 Jun 11 peter 257          yu!=y2u.end();++yu) {
1376 14 Jun 11 peter 258       set<Alias>& alias = y2a[yu->first];
1376 14 Jun 11 peter 259       translate(yu->second, alias);
1376 14 Jun 11 peter 260     }
1376 14 Jun 11 peter 261   }
1437 20 Dec 11 peter 262
1225 17 Oct 10 peter 263 }} // end of namespace svndigest and namespace theplu