source: trunk/lib/Stats.cc @ 118

Last change on this file since 118 was 118, checked in by Peter Johansson, 15 years ago

fixes #46 #45 #26 #40

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.6 KB
RevLine 
[84]1// $Id: Stats.cc 118 2006-07-03 07:44:49Z peter $
[14]2
[84]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
[14]25#include "Stats.h"
[73]26#include "GnuplotFE.h"
[14]27#include "utility.h"
28
[41]29#include <algorithm>
[65]30#include <cassert>
[63]31#include <cstdlib>
[73]32#include <fstream>
[60]33#include <iostream>
[14]34#include <map>
35#include <numeric>
[39]36#include <sstream>
[14]37#include <string>
[44]38#include <unistd.h>
[23]39#include <utility>
[14]40#include <vector>
41
[63]42
[14]43namespace theplu{
44namespace svnstat{
45
46
[80]47  Stats::Stats(const std::string& path)
48  {
49    // Make sure latest revision is set properly
50    std::map<std::string,std::string> svn_info = info(path);
51    std::stringstream ss;
52    ss << (svn_info.count("Revision") ? svn_info["Revision"] : "0");
[112]53    ss >> revision_;
54    ss.clear();
55    ss << (svn_info.count("Last Changed Rev") ? svn_info["Last Changed Rev"] : "0");
56    ss >> last_changed_rev_;
[80]57  }
58
59
[118]60  std::vector<u_int> Stats::accumulated(const Map_& map) const
[14]61  {
[36]62    // sum of all users
[118]63    std::vector<u_int> sum(revision_+1);
64    sum=std::accumulate(map.begin(), map.end(), sum,
[36]65                        PairValuePlus<std::string,u_int>());
[14]66
67    // calculate accumulated sum
[74]68    std::vector<u_int> accum(sum.size());
[60]69    std::partial_sum(sum.begin(),sum.end(),accum.begin());
[63]70    assert(sum.size()==accum.size());
[14]71    return accum;
72  }
73
[118]74  std::vector<u_int> Stats::accumulated(const Map_& map, 
75                                        const std::string& user) const
[14]76  {
[118]77    if (!map.count(user))
[74]78      return std::vector<u_int>();
[118]79    std::vector<u_int> vec=(map.find(user))->second;
[41]80 
[112]81    if (vec.size() < revision_+1)
82      vec.insert(vec.end(), revision_+1-vec.size(), 0);
[35]83
[74]84    std::vector<u_int> accum(vec.size());
[14]85    std::partial_sum(vec.begin(),vec.end(),accum.begin());
86    return accum;
87  }
88
[118]89  void Stats::add(const std::string& user, const u_int& rev, 
90                  const Parser::line_type lt)
[14]91  {
[118]92    authors_.insert(user);
93
94    std::vector<u_int>* total = &(total_[user]);
95    if (total->size() < rev+1){
96      total->reserve(revision_ + 1);
97      total->insert(total->end(), rev - total->size(), 0);
98      total->push_back(1);
[14]99    }
100    else
[118]101      (*total)[rev]++;
102
103    std::vector<u_int>* code = &(code_[user]);
104    if (code->size() < rev+1){
105      code->reserve(revision_ + 1);
106      code->insert(code->end(), rev - code->size(), 0);
107      if (lt == Parser::code)
108        code->push_back(1);
109      else 
110        code->push_back(0);
111    }
112    else if (lt == Parser::code)
113      (*code)[rev]++;
114
115    std::vector<u_int>* comments = &(comments_[user]);
116    if (comments->size() < rev+1){
117      comments->reserve(revision_ + 1);
118      comments->insert(comments->end(), rev - comments->size(), 0);
119      if (lt == Parser::comment)
120        comments->push_back(1);
121      else 
122        comments->push_back(0);
123    }
124    else if (lt == Parser::comment)
125      (*comments)[rev]++;
[14]126  }
127
[60]128
[72]129  bool Stats::parse(const std::string& path)
[60]130  {
131    // Calling svn blame
132    if (blame(path))
133      return true;
134
135    // Check if file is binary
[118]136    std::ifstream is("/tmp/svnstat.tmp");
[60]137    std::string line;
138    getline(is,line,' ');
139    if (line==std::string("Skipping")){
140      getline(is,line,' ');
141      if (line==std::string("binary")){
142        is.close();
[72]143        return true;
[60]144      }
145    }
146    is.close();
147
[118]148    Parser parser(path);
149    std::vector<Parser::line_type>::const_iterator count=parser.type().begin();
150
151    is.open("/tmp/svnstat.tmp");
[60]152    while (getline(is,line, '\n')){
153      if (!line.size()) // skip empty line
154        continue;
155      std::stringstream ss(line);
156      u_int revision;
157      std::string user;
158      ss >> revision;
159      ss >> user;
[118]160      // to handle symbolic links
161      if (count==parser.type().end())
162        add(user, revision, Parser::empty);
163      else 
164        add(user, revision, *count);
165      count++;
[60]166    }
167    is.close();
[118]168   
[60]169    return false;
170  }
171
172
[101]173  std::string Stats::plot(const std::string& filename,
174                          const std::string& title) const
[34]175  {
[73]176    GnuplotFE* gp=GnuplotFE::instance();
[113]177    gp->command("set term png transparent");
178    gp->command("set output '"+filename+"'");
179    gp->command("set title '"+title+"'");
180    gp->command("set xtics nomirror");
181    gp->command("set ytics nomirror");
[73]182    gp->command("set key default");
183    gp->command("set key left Left reverse");
184    gp->command("set multiplot");
[118]185    std::vector<u_int> total=accumulated(total_);   
[76]186    double yrange_max=1.03*total.back()+1;
[74]187    gp->yrange(yrange_max);
188    size_t plotno=1;
[77]189    std::stringstream ss;
[118]190    for (MapConstIter_ i= total_.begin(); i != total_.end(); i++) {
[77]191      ss.str("");
192      ss << "set key height " << 2*plotno;
193      gp->command(ss.str());
[118]194      std::vector<u_int> x=accumulated(total_, i->first);
[77]195      ss.str("");
196      ss << x.back() << " " << i->first;
[74]197      gp->yrange(yrange_max);
[77]198      gp->linetitle(ss.str());
199      ss.str("");
200      ss << "steps " << ++plotno;
201      gp->linestyle(ss.str());
[73]202      gp->plot(x);
[39]203    }
[77]204    ss.str("");
205    ss << total.back() << " total";
[76]206    gp->command("set key height 0");
[77]207    gp->linetitle(ss.str());
[76]208    gp->linestyle("steps 1");
209    gp->plot(total);
210
[73]211    gp->command("unset multiplot");
[74]212    gp->yrange();
[36]213
[101]214    return filename;
[34]215  }
216
[118]217
[14]218  Stats& Stats::operator+=(const Stats& other)
219  {
[118]220    for (MapConstIter_ o_i= other.code_.begin(); 
221         o_i != other.code_.end(); ++o_i)
[14]222    {
[118]223      std::pair<MapIter_,bool> result = code_.insert(*o_i);
[14]224      if (!result.second)
[118]225        code_[(*(result.first)).first] = 
[23]226          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
[14]227 
228    }
[118]229 
230    for (MapConstIter_ o_i= other.comments_.begin(); 
231         o_i != other.comments_.end(); ++o_i)
232    {
233      std::pair<MapIter_,bool> result = comments_.insert(*o_i);
234      if (!result.second)
235        comments_[(*(result.first)).first] = 
236          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
237 
238    }
239   
240    for (MapConstIter_ o_i= other.total_.begin(); 
241         o_i != other.total_.end(); ++o_i)
242    {
243      std::pair<MapIter_,bool> result = total_.insert(*o_i);
244      if (!result.second)
245        total_[(*(result.first)).first] = 
246          VectorPlus<u_int>()( (*(result.first)).second, (*o_i).second );
247 
248    }
249   
250    if (!other.authors().empty())
251      authors_.insert(other.authors().begin(), other.authors().end());
[14]252    return *this;
253  }
254
255}} // end of namespace svnstat and namespace theplu
Note: See TracBrowser for help on using the repository browser.