source: trunk/lib/Stats.cc @ 131

Last change on this file since 131 was 131, checked in by Jari Häkkinen, 17 years ago

Added static_cast to remove annoying compiler warning.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.5 KB
Line 
1// $Id: Stats.cc 131 2006-08-02 19:18:44Z jari $
2
3/*
4  Copyright (C) 2005 Peter Johansson
5  Copyright (C) 2006 Jari Häkkinen, Peter Johansson
6
7  This file is part of svnstat, http://lev.thep.lu.se/trac/svnstat
8
9  svnstat is free software; you can redistribute it and/or modify it
10  under the terms of the GNU General Public License as published by
11  the Free Software Foundation; either version 2 of the License, or
12  (at your option) any later version.
13
14  svnstat is distributed in the hope that it will be useful, but
15  WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  General Public License for more details.
18
19  You should have received a copy of the GNU General Public License
20  along with this program; if not, write to the Free Software
21  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
22  02111-1307, USA.
23*/
24
25#include "Stats.h"
26
27#include "GnuplotFE.h"
28#include "SVNinfo.h"
29#include "utility.h"
30
31#include <algorithm>
32#include <cassert>
33#include <cstdlib>
34#include <fstream>
35#include <iostream>
36#include <map>
37#include <numeric>
38#include <string>
39#include <unistd.h>
40#include <utility>
41#include <vector>
42
43
44namespace theplu{
45namespace svnstat{
46
47
48  Stats::Stats(const std::string& path)
49  {
50    // Make sure latest revision is set properly
51    SVNinfo svn_info(path);
52    revision_=svn_info.rev();
53    last_changed_rev_=svn_info.last_changed_rev();
54  }
55
56
57  std::vector<u_int> Stats::accumulated(const Map_& map) const
58  {
59    // sum of all users
60    std::vector<u_int> sum(revision_+1);
61    sum=std::accumulate(map.begin(), map.end(), sum,
62                        PairValuePlus<std::string,u_int>());
63
64    // calculate accumulated sum
65    std::vector<u_int> accum(sum.size());
66    std::partial_sum(sum.begin(),sum.end(),accum.begin());
67    assert(sum.size()==accum.size());
68    return accum;
69  }
70
71  std::vector<u_int> Stats::accumulated(const Map_& map, 
72                                        const std::string& user) const
73  {
74    if (!map.count(user))
75      return std::vector<u_int>();
76    std::vector<u_int> vec=(map.find(user))->second;
77
78    // static_cast to remove annoying compiler warning
79    if (vec.size() < static_cast<size_t>(revision_+1))
80      vec.insert(vec.end(), revision_+1-vec.size(), 0);
81
82    std::vector<u_int> accum(vec.size());
83    std::partial_sum(vec.begin(),vec.end(),accum.begin());
84    return accum;
85  }
86
87  void Stats::add(const std::string& user, const u_int& rev, 
88                  const Parser::line_type lt)
89  {
90    authors_.insert(user);
91
92    std::vector<u_int>* total = &(total_[user]);
93    if (total->size() < rev+1){
94      total->reserve(revision_ + 1);
95      total->insert(total->end(), rev - total->size(), 0);
96      total->push_back(1);
97    }
98    else
99      (*total)[rev]++;
100
101    std::vector<u_int>* code = &(code_[user]);
102    if (code->size() < rev+1){
103      code->reserve(revision_ + 1);
104      code->insert(code->end(), rev - code->size(), 0);
105      if (lt == Parser::code)
106        code->push_back(1);
107      else 
108        code->push_back(0);
109    }
110    else if (lt == Parser::code)
111      (*code)[rev]++;
112
113    std::vector<u_int>* comments = &(comments_[user]);
114    if (comments->size() < rev+1){
115      comments->reserve(revision_ + 1);
116      comments->insert(comments->end(), rev - comments->size(), 0);
117      if (lt == Parser::comment)
118        comments->push_back(1);
119      else 
120        comments->push_back(0);
121    }
122    else if (lt == Parser::comment)
123      (*comments)[rev]++;
124  }
125
126
127  bool Stats::parse(const std::string& path)
128  {
129    // Calling svn blame
130    if (blame(path))
131      return true;
132
133    // Check if file is binary
134    std::ifstream is("/tmp/svnstat.tmp");
135    std::string line;
136    getline(is,line,' ');
137    if (line==std::string("Skipping")){
138      getline(is,line,' ');
139      if (line==std::string("binary")){
140        is.close();
141        return true;
142      }
143    }
144    is.close();
145
146    Parser parser(path);
147    std::vector<Parser::line_type>::const_iterator count=parser.type().begin();
148
149    is.open("/tmp/svnstat.tmp");
150    while (getline(is,line, '\n')){
151      if (!line.size()) // skip empty line
152        continue;
153      std::stringstream ss(line);
154      u_int revision;
155      std::string user;
156      ss >> revision;
157      ss >> user;
158      // to handle symbolic links
159      if (count==parser.type().end())
160        add(user, revision, Parser::empty);
161      else 
162        add(user, revision, *count);
163      count++;
164    }
165    is.close();
166   
167    return false;
168  }
169
170
171  std::string Stats::plot(const std::string& filename,
172                          const std::string& title) const
173  {
174    GnuplotFE* gp=GnuplotFE::instance();
175    gp->command("set term png transparent");
176    gp->command("set output '"+filename+"'");
177    gp->command("set title '"+title+"'");
178    gp->command("set xtics nomirror");
179    gp->command("set ytics nomirror");
180    gp->command("set key default");
181    gp->command("set key left Left reverse");
182    gp->command("set multiplot");
183    std::vector<u_int> total=accumulated(total_);   
184    double yrange_max=1.03*total.back()+1;
185    gp->yrange(yrange_max);
186    size_t plotno=1;
187    std::stringstream ss;
188    for (MapConstIter_ i= total_.begin(); i != total_.end(); i++) {
189      ss.str("");
190      ss << "set key height " << 2*plotno;
191      gp->command(ss.str());
192      std::vector<u_int> x=accumulated(total_, i->first);
193      ss.str("");
194      ss << x.back() << " " << i->first;
195      gp->yrange(yrange_max);
196      gp->linetitle(ss.str());
197      ss.str("");
198      ss << "steps " << ++plotno;
199      gp->linestyle(ss.str());
200      gp->plot(x);
201    }
202    ss.str("");
203    ss << total.back() << " total";
204    gp->command("set key height 0");
205    gp->linetitle(ss.str());
206    gp->linestyle("steps 1");
207    gp->plot(total);
208
209    gp->command("unset multiplot");
210    gp->yrange();
211
212    return filename;
213  }
214
215
216  Stats& Stats::operator+=(const Stats& other)
217  {
218    for (MapConstIter_ o_i= other.code_.begin(); 
219         o_i != other.code_.end(); ++o_i)
220    {
221      std::pair<MapIter_,bool> result = code_.insert(*o_i);
222      if (!result.second)
223        code_[(*(result.first)).first] = 
224          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
225 
226    }
227 
228    for (MapConstIter_ o_i= other.comments_.begin(); 
229         o_i != other.comments_.end(); ++o_i)
230    {
231      std::pair<MapIter_,bool> result = comments_.insert(*o_i);
232      if (!result.second)
233        comments_[(*(result.first)).first] = 
234          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
235 
236    }
237   
238    for (MapConstIter_ o_i= other.total_.begin(); 
239         o_i != other.total_.end(); ++o_i)
240    {
241      std::pair<MapIter_,bool> result = total_.insert(*o_i);
242      if (!result.second)
243        total_[(*(result.first)).first] = 
244          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
245 
246    }
247   
248    if (!other.authors().empty())
249      authors_.insert(other.authors().begin(), other.authors().end());
250    return *this;
251  }
252
253}} // end of namespace svnstat and namespace theplu
Note: See TracBrowser for help on using the repository browser.