source: trunk/lib/CopyrightStats.cc @ 1378

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

include configuration string in svncopyright cache.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 5.3 KB
Line 
1// $Id: CopyrightStats.cc 1378 2011-06-14 02:18:09Z peter $
2
3/*
4  Copyright (C) 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 "CopyrightStats.h"
23
24#include "Configuration.h"
25#include "LineTypeParser.h"
26#include "SVNblame.h"
27#include "SVNinfo.h"
28#include "SVNlog.h"
29#include "utility.h"
30
31#include <yat/utility/utility.h>
32
33#include <subversion-1/svn_types.h>
34
35#include <cassert>
36#include <fstream>
37#include <iostream>
38
39namespace theplu {
40namespace svndigest {
41
42  CopyrightStats::CopyrightStats(const std::string& path, bool ignore_cache,
43                                 const std::map<int, svn_revnum_t>& year2rev)
44    : path_(path)
45  {
46    cache_file_ = concatenate_path(concatenate_path(directory_name(path), 
47                                                    ".svndigest"),
48                                   file_name(path)+".svncopyright-cache");
49    config_ = Configuration::instance().code(path_);
50    init(ignore_cache, year2rev);
51  }
52
53
54  void CopyrightStats::init(bool ignore_cache, 
55                            const std::map<int, svn_revnum_t>& year2rev)
56  {
57    svn_revnum_t cache_rev = 0;
58    if (!ignore_cache)
59      cache_rev = load_cache();
60    SVNinfo info(path_);
61    if (cache_rev >= info.last_changed_rev())
62      return;
63
64    // reset stats if cache was invalid
65    if (cache_rev == 0) 
66      reset();
67
68    parse(cache_rev+1, year2rev);
69    write_cache();
70  }
71
72
73  svn_revnum_t CopyrightStats::load_cache(void)
74  {
75    std::ifstream is(cache_file_.c_str());
76
77    std::string line;
78    getline(is, line);
79    if (line!="SVNCOPYRIGHT CACHE VERSION 1")
80      return 0;
81    getline(is, line);
82    if (line!=config_) {
83      std::cout << "cache file is for different configuration.\n"
84                << "config code: '" << config_ << "'\n"
85                << "config code in cache file: '" << line << "'\n"
86                << "retrieving statistics from repository.\n";
87      return 0;
88    }
89
90    svn_revnum_t rev = 0;
91    try {
92      getline(is, line);
93      size_t nof_years = yat::utility::convert<size_t>(line);
94      for (size_t i=0; i<nof_years; ++i) {
95        getline(is, line);
96        int year = yat::utility::convert<size_t>(line);
97        std::set<std::string>& users = year2user_[year];
98        getline(is, line);
99        size_t nof_users = yat::utility::convert<size_t>(line);
100        for (size_t i=0; i<nof_users; ++i) {
101          getline(is, line);
102          users.insert(line);
103        }
104      }
105      getline(is, line);
106      rev = yat::utility::convert<svn_revnum_t>(line);
107      getline(is, line);
108      if (line!="SVNCOPYRIGHT CACHE")
109        return 0;
110      return rev;
111    }
112    catch (yat::utility::runtime_error e) {
113      return 0;
114    }
115    return 0;
116  }
117
118
119  const std::map<int, std::set<std::string> >& CopyrightStats::map(void) const
120  {
121    return year2user_;
122  }
123
124
125  void CopyrightStats::parse(svn_revnum_t first_rev,
126                             const std::map<int, svn_revnum_t>& year2rev)
127  {
128    std::map<int, svn_revnum_t>::const_iterator yearrev=year2rev.begin();
129    SVNlog log(path_);
130    typedef SVNlog::container::const_iterator log_iterator;
131    log_iterator commit = log.commits().begin();
132    while (commit->revision() < first_rev)
133      ++commit;
134    assert(commit->revision() >= first_rev);
135    log_iterator end = log.commits().end();
136    // loop over all commits
137    for ( ; commit!=end; ++commit) {
138      // assure yearrev correspond to commit
139      while (yearrev->second < commit->revision()) {
140        ++yearrev;
141        assert(yearrev!=year2rev.end());
142      }
143      assert(yearrev!=year2rev.end());
144      assert(yearrev->second >= commit->revision());
145     
146      const std::string& name = commit->author();
147      // skip if alias already has copyright for this year.
148      std::map<int, std::set<std::string> >::const_iterator year_users = 
149        year2user_.find(yearrev->first);
150      if (year_users!=year2user_.end() 
151          && year_users->second.count(name))
152        continue;
153     
154      SVNblame svn_blame(path_, commit->revision());
155      LineTypeParser parser(path_);
156
157      // loop over lines
158      while (svn_blame.valid()) {
159        int lt = parser.parse(svn_blame.line());
160        if ((lt==LineTypeParser::code || lt==LineTypeParser::comment) && 
161            svn_blame.revision()==commit->revision()) {
162          year2user_[yearrev->first].insert(name);
163          break;
164        }
165        svn_blame.next_line();
166      }
167    }
168  }
169
170
171  void CopyrightStats::reset(void)
172  {
173    year2user_.clear();
174  }
175
176
177  void CopyrightStats::write_cache(void)
178  {
179    mkdir_p(directory_name(cache_file_));
180    std::ofstream os(cache_file_.c_str());
181    assert(os.good());
182
183    os << "SVNCOPYRIGHT CACHE VERSION 1\n";
184    os << config_ << "\n";
185    os << year2user_.size() << "\n";
186    using std::map;
187    using std::set;
188    using std::string;
189    for (map<int, set<string> >::const_iterator i=year2user_.begin();
190         i!=year2user_.end(); ++i) {
191      os << i->first << "\n";
192      os << i->second.size() << "\n";
193      for (set<string>::const_iterator j=i->second.begin(); 
194           j!=i->second.end(); ++j) {
195        os << *j << "\n";
196      }
197    }
198
199    SVNinfo info(path_);
200    os << info.last_changed_rev() << "\n";
201    os << "SVNCOPYRIGHT CACHE\n";
202    os.close();
203  }
204
205}}
Note: See TracBrowser for help on using the repository browser.