Changeset 185


Ignore:
Timestamp:
Sep 6, 2006, 4:39:18 AM (15 years ago)
Author:
Jari Häkkinen
Message:

Fixes #65 and #60. Added support for svndigest:ignore. Uppdated documentation. Reworked binary file treatment.

Location:
trunk
Files:
2 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/ChangeLog

    r171 r185  
    2424
    2525version pre0.5:
     26  - Updated documentation.
     27  - Reworked treatment of binary files.
     28  - Added support for svndigest:ignore property.
    2629  - Creation of static svndigest binary is now supported, use
    2730    --enable-staticbin.
  • trunk/README

    r162 r185  
    2121USA.
    2222======================================================================
     23
     24
     250  What is svndigest?
     26
     27svndigest is a tool to extract development information and statistics
     28from a subversion repository. A slightly more detailed explanation is
     29available in doc/readme.txt
    2330
    2431
     
    5158
    5259
    53 3  Acknowledgements
     603  Running svndigest
     61
     62To get a listing of available options issue 'svndigest -h'. Simply run
     63the program with
     64
     65   svndigest -r /path/to/a/subversion/WC -t /path/whereto/write/output -v
     66
     67The -v option will produce some output to stdout and can be omitted.
     68
     69
     704  Acknowledgements
    5471
    5572svndigest uses a C++ interface to Gnuplot inspired by Rajarshi Guha.
  • trunk/doc/readme.txt

    r149 r185  
    11$Id$
    22
     3======================================================================
    34Copyright (C) 2005, 2006 Jari Häkkinen
    45
     
    1213svndigest is distributed in the hope that it will be useful, but
    1314WITHOUT ANY WARRANTY; without even the implied warranty of
    14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    1516General Public License for more details.
    1617
     
    1920Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
    2021USA.
    21 
     22======================================================================
    2223
    2324
    2425svndigest traverses a directory structure (controlled by subversion)
    2526and calculates developer statistics for all subversion controlled
    26 entries. The result is written to a sub-directory that will be created
    27 in the current working directory.
     27entries. The result is written to a sub-directory of an user
     28specifiable target directory (defualt is the current working
     29directory).
    2830
    2931To understand what statistics is calculated by svndigest this
    3032definition is needed: The developer who made the latest change to a
    31 line still in use in the latest (checked out) revision, is considered
    32 as the contributor of that line regardless of who actually originally
    33 created that line.
     33line still in use in the latest revision, is considered as the
     34contributor of that line regardless of who actually originally created
     35that line.
    3436
    3537The statistics calculated is the number of lines contributed from each
     
    3941There are many different types of files and for many file types it
    4042does not make sense to define lines. Source code, documentation, and
    41 other human readable files can be treated on line basis whereas
    42 symbolic links and binary files cannot. svndigest treats non-line based
    43 files as one-line files, i.e. the developer that made the last change
    44 to this type of files gets a one-line credit for it.
     43other human readable files can be treated in single line basis whereas
     44symbolic links and binary files cannot. svndigest treats binary files
     45as zero-line files, whereas symbolic links are treated as one-line
     46files. There is a possiblity to exclude files from the statistics, the
     47use of the property svndigest:ignore.
    4548
    46 How should we exclude un-reasonable credit for large line based files?
    47 We could add a property to that file, tagging it as a file that should
    48 be treated as an non-line base file.
     49Sometimes large test files and xml files are added to the repository
     50that should not really be counted in the statistics. This is solved
     51with the svndigest:ignore property. Files with this property are
     52excluded from statistics. Setting the svndigest:ignore propertu to a
     53directory will exclude all siblings to that directory from svndigest
     54treatment.
    4955
    50 The current design assumes that the subversion repository to be
    51 analysed is checked out, maybe one would want to run the analysis
    52 agains a subversion repositoy directly.
     56svndigest requires the subversion repository to be checked out before
     57analysis, i.e., svndigest will not run directly against a repository,
     58and up to date with the repository.
     59
    5360
    5461The current flow of the program is.
    5562
    56 i) Extract the directory structure starting from the directory given
    57    at the command line.
     63i) Check that we are working with a WC in subversion control.
    5864
    59 ii) Parse the directory structure, removing files and direcotries that
    60    is not in subversion control. After this step, only valid
    61    subversion entries will be allowed in the tree. Beware, 'svn blame'
    62    chokes on directories, and the directories are still a part of the
    63    tree.
     65ii) Build the requested directory structure ignoring not subversion
     66   controlled items. During the directory structure creation a check
     67   is made that the WC is up to date with the repository.
    6468
    6569iii) Walk through the directory structure and calculate statistics for
    6670   each entry.
    6771
    68 iv) Compile statistics as discussed. This step may be intermingled
    69    with step iii).
    70 
    71 v) Create the html presentation as discussed.
     72iv) Create the plots and html presentation.
  • trunk/lib/Directory.cc

    r182 r185  
    9191  }
    9292
    93   bool Directory::binary(void) const
    94   {
    95     return false;
    96   }
    97 
    9893  bool Directory::dir(void) const
    9994  {
     
    109104  {
    110105    stats_.reset();
    111 
    112     // Directories give no contribution to statistics.
     106    // Directories themselved give no contribution to statistics.
    113107    for (NodeIterator i=daughters_.begin(); i!=daughters_.end(); ++i)
    114       stats_ += (*i)->parse(verbose);
     108      if (!(*i)->ignore())
     109        stats_ += (*i)->parse(verbose);
    115110    return stats_;
    116111  }
  • trunk/lib/Directory.h

    r182 r185  
    8585    Directory(const Directory&);
    8686
    87     ///
    88     /// @return false
    89     ///
    90     bool binary(void) const;
    91 
    9287    typedef std::list<Node*> NodeContainer;
    9388    typedef NodeContainer::iterator NodeIterator;
  • trunk/lib/File.cc

    r182 r185  
    3333namespace svndigest{
    3434
    35   bool File::binary(void) const
    36   {
    37     return binary_;
    38   }
    39 
    4035
    4136  std::string File::href(void) const
     
    5146
    5247
    53   const Stats& File::parse(const bool verbose)
    54   {
     48  const Stats& File::parse(const bool verbose)
     49  {
    5550    if (verbose)
    5651      std::cout << "Parsing " << path_ << std::endl;
    57     stats_.reset();
    58     binary_ = stats_.parse(path_);
     52    stats_.reset();
     53    stats_.parse(path_);
    5954    return stats_;
    60   }
     55  }
     56
    6157
    6258  void File::print(const bool verbose) const
    6359  {
    6460    // no output page for binary files
    65     if (binary_)
     61    if (ignore())
    6662      return;
    6763    std::string output(output_name() + ".html");
     
    9187    dark=!dark;
    9288   
    93 
    9489    // print authors
    9590    for (std::set<std::string>::const_iterator i=stats_.authors().begin();
  • trunk/lib/File.h

    r182 r185  
    4040    File(const u_int level, const std::string& path,
    4141         const std::string& output="")
    42       : Node(level,path,output), binary_(false), ignore_(false) {}
     42      : Node(level,path,output) {}
    4343
    4444    ///
     
    6565
    6666  private:
    67     ///
    68     /// @return true if file is binary
    69     ///
    70     bool binary(void) const;
    7167
    7268    ///
     
    8278    File(const File&);
    8379
    84     bool binary_;
    85     bool ignore_;
    8680  };
    8781
  • trunk/lib/Makefile.am

    r177 r185  
    2727noinst_HEADERS = Directory.h File.h Gnuplot.h GnuplotFE.h html_utility.h
    2828  Node.h  \
    29   Parser.h rmdirhier.h Stats.h SVN.h SVNblame.h SVNinfo.h utility.h
     29  Parser.h rmdirhier.h Stats.h SVN.h SVNblame.h SVNinfo.h         \
     30  SVNproperty.h utility.h
    3031
    3132libsvndigest_la_SOURCES = Directory.cc File.cc Gnuplot.cc GnuplotFE.cc  \
    3233  html_utility.cc \
    3334  Node.cc Parser.cc rmdirhier.cc Stats.cc SVN.cc SVNblame.cc  \
    34   SVNinfo.cc utility.cc
     35  SVNinfo.cc SVNproperty.cc utility.cc
    3536
    3637clean-local:
  • trunk/lib/Node.cc

    r182 r185  
    2424#include "Node.h"
    2525#include "html_utility.h"
     26#include "SVNproperty.h"
    2627#include "utility.h"
    2728#include <config.h> // this header file is created by configure
     
    2930#include <ctime>
    3031#include <fstream>
    31 #include <iostream>
    3232#include <sstream>
    3333
     
    3939    : level_(level), path_(path), stats_(path), svninfo_(path)
    4040  {
     41    SVNproperty property(path);
     42    binary_=property.binary();
     43    svndigest_ignore_=property.svndigest_ignore();
    4144    output_name_ = output+file_name(path_);
    4245  }
     46
    4347
    4448  bool Node::dir(void) const
     
    4650    return false;
    4751  }
     52
    4853
    4954  void Node::path_anchor(std::ostream& os) const
     
    6368  }
    6469
     70
    6571  void Node::html_tablerow(std::ostream& os,
    6672                           const std::string& css_class) const
     
    6874    os << "<tr class=\"" << css_class << "\">\n"
    6975       << "<td class=\"" << node_type() << "\">";
    70     if (binary())
     76    if (svndigest_ignore())
     77      os << name() << " (<i>svndigest:ignore</i>)";
     78    else if (binary())
    7179      os << name() << " (<i>binary</i>)";
    7280    else
     
    8088       << "</tr>\n";
    8189  }
     90
    8291
    8392  void Node::print_footer(std::ostream& os) const
  • trunk/lib/Node.h

    r182 r185  
    6767    { return svninfo_.last_changed_author(); }
    6868
     69    /**
     70       @brief Check whether node is binary.
     71
     72       @return True if node is binary.
     73    */
     74    inline bool binary(void) const { return binary_; }
     75
    6976    ///
    7077    /// @return true if directory
     
    7784    virtual std::string href(void) const=0;
    7885
    79     ///
    80     ///
    81     ///
    8286    void html_tablerow(std::ostream&, const std::string&) const;
     87
     88    /**
     89       @brief Check whether node should be ignored in statistics.
     90
     91       If a node is to be ignored the statistics implementer should
     92       respect this state. Currently binary files and items with
     93       property svndigest:ignore are to be ignored by svndigest. If
     94       the node is a directory then the direcotry and its siblings
     95       should be ignored by statistics.
     96
     97       @return True of node should be ignored by statistics.
     98
     99       @see SVNproperty::svndigest_ingorable
     100    */
     101    inline bool ignore(void) const { return binary_ || svndigest_ignore_; }
    83102
    84103    ///
     
    113132    virtual void print(const bool verbose=false) const=0;
    114133
     134    /**
     135       @brief Check if item used to create this object has been
     136       assigned property svndigest:ignore.
     137
     138       Currently files with property svndigest:ignore are to be
     139       ignored by svndigest. It is the responsibility of the
     140       statistics implementer to obey the ignore state.
     141
     142       @return True if item property svndigest:digest was set.
     143    */
     144    inline bool svndigest_ignore(void) const { return svndigest_ignore_; }
     145
    115146  protected:
    116 
    117     ///
    118     /// @note Directories are not consider binary.
    119     ///
    120     virtual bool binary(void) const=0;
    121147
    122148    ///
     
    153179    void path_anchor(std::ostream& os) const;
    154180
     181    bool binary_;
     182    bool svndigest_ignore_;
    155183    SVNinfo svninfo_;
    156184  };
  • trunk/lib/SVN.cc

    r164 r185  
    2424#include "SVN.h"
    2525
     26#include <map>
    2627#include <string>
     28#include <vector>
    2729
    2830#include <apr_allocator.h>
     
    3335#include <subversion-1/svn_pools.h>
    3436#include <subversion-1/svn_wc.h>
     37#include <subversion-1/svn_subst.h>
    3538
    3639namespace theplu {
     
    129132                                       subpool);
    130133    if (err && err->apr_err!=SVN_ERR_CLIENT_IS_BINARY_FILE) {
    131       svn_handle_error2(err, stderr, false, "svndigest: ");
    132       svn_error_clear(err);
    133       svn_pool_destroy(subpool);
     134      cleanup(err,subpool);
    134135      throw SVNException("SVN::client_blame: svn_client_blame3 failed");
    135136    }
     
    145146    if (svn_error_t *err=svn_client_info(path.c_str(), NULL, NULL, receiver,
    146147                                         baton, false, context_, subpool)) {
    147       svn_handle_error2(err, stderr, false, "svndigest: ");
    148       svn_error_clear(err);
    149       svn_pool_destroy(subpool);
     148      cleanup(err,subpool);
    150149      throw SVNException("repository: svn_client_info failed");
     150    }
     151    svn_pool_destroy(subpool);
     152  }
     153
     154
     155  void SVN::client_proplist(const std::string& path,
     156                            std::map<std::string, std::string>& property)
     157  {
     158    svn_opt_revision_t peg, revision;
     159    peg.kind=svn_opt_revision_unspecified;
     160    revision.kind=svn_opt_revision_head;
     161    apr_pool_t *subpool = svn_pool_create(pool_);
     162    apr_array_header_t * properties;
     163    svn_error_t *err=svn_client_proplist2(&properties, path.c_str(), &peg,
     164                                          &revision, false, context_, subpool);
     165    if (err) {
     166      cleanup(err,subpool);
     167      throw SVNException("repository: svn_client_proplist2 failed");
     168    }
     169    for (int j = 0; j < properties->nelts; ++j) {
     170      svn_client_proplist_item_t *item =
     171        ((svn_client_proplist_item_t **)properties->elts)[j];
     172      for (apr_hash_index_t *hi = apr_hash_first(subpool, item->prop_hash); hi;
     173           hi = apr_hash_next (hi)) {
     174        const void *key;
     175        void *val;
     176        apr_hash_this (hi, &key, NULL, &val);
     177        svn_string_t *value;
     178        err=svn_subst_detranslate_string(&value,
     179                                         static_cast<const svn_string_t*>(val),
     180                                         false, subpool);
     181        if (err) {
     182          cleanup(err,subpool);
     183          throw SVNException("property: svn_subst_detranslate_string failed");
     184        }
     185        property[static_cast<const char*>(key)]=value->data;
     186      }
    151187    }
    152188    svn_pool_destroy(subpool);
     
    174210    if ((err=svn_ra_get_latest_revnum(ra_session_, &(head.value.number),
    175211                                      subpool))) {
    176       svn_handle_error2(err, stderr, false, "svndigest: ");
    177       svn_error_clear(err);
    178       svn_pool_destroy(subpool);
     212      cleanup(err,subpool);
    179213      throw SVNException("commit_dates: svn_ra_get_latest_revnum failed");
    180214    }
     
    187221                             log_message_receiver, static_cast<void*>(&lb),
    188222                             context_, subpool))) {
    189       svn_handle_error2(err, stderr, false, "svndigest: ");
    190       svn_error_clear(err);
    191       svn_pool_destroy(subpool);
     223      cleanup(err,subpool);
    192224      throw SVNException("commit_dates: svn_client_log3 failed");
    193225    }
     
    197229
    198230
    199   void SVN::cleanup_failed_initialization(svn_error_t *err)
     231  void SVN::cleanup(svn_error_t *err,apr_pool_t *pool)
    200232  {
    201233    svn_handle_error2(err,stderr,false,"svndigest:");
    202234    svn_error_clear(err);
    203     svn_pool_destroy(pool_);
     235    svn_pool_destroy(pool);
     236  }
     237
     238
     239  void SVN::cleanup_failed_initialization(svn_error_t *err)
     240  {
     241    cleanup(err,pool_);
    204242    apr_allocator_destroy(allocator_);
    205243  }
     
    224262    if (svn_error_t *err=svn_client_open_ra_session(&ra_session_, path.c_str(),
    225263                                                    context_,pool_)) {
     264      // cleanup could be called if a null pool can be passed to
     265      // svn_pool_destroy (which is just a #define to apr_pool_destroy
    226266      svn_handle_error2(err,stderr,false,"svndigest:");
    227267      svn_error_clear(err);
     
    239279                                          false, -1, context_->cancel_func,
    240280                                          context_->cancel_baton, pool_)) {
     281      // cleanup could be called if a null pool can be passed to
     282      // svn_pool_destroy (which is just a #define to apr_pool_destroy
    241283      svn_handle_error2(err,stderr,false,"svndigest:");
    242284      svn_error_clear(err);
     
    253295        svn_wc_status2(&status,svn_path_internal_style(path.c_str(), subpool),
    254296                       adm_access_, subpool)) {
    255       svn_handle_error2(err,stderr,false,"svndigest:");
    256       svn_error_clear(err);
    257       svn_pool_destroy(subpool);
     297      cleanup(err,subpool);
    258298      throw SVNException("version_controlled(): svn_config_get_config failed");
    259299    }
  • trunk/lib/SVN.h

    r165 r185  
    2525*/
    2626
     27#include <map>
    2728#include <stdexcept>
    2829#include <string>
     
    106107                     void *baton);
    107108
     109    /**
     110       @brief Get the properties for \a path.
     111
     112       The retrieved properties are stored in \a properties. To check
     113       whether \a is a binary item use SVNproperty::binary(void).
     114    */
     115    void client_proplist(const std::string& path,
     116                         std::map<std::string, std::string>& properties);
     117
    108118    ///
    109119    /// @brief Get revision dates.
     
    168178    SVN(const SVN&);
    169179
    170     ///
    171     /// Free resources when failing to reach end of constructor.
    172     ///
     180    /**
     181       @brief Free resources when svn API calls fail.
     182    */
     183    void cleanup(svn_error_t *err,apr_pool_t *pool);
     184
     185    /**
     186       @brief Free resources when failing to reach end of
     187       constructor.
     188    */
    173189    void cleanup_failed_initialization(svn_error_t *err);
    174190
  • trunk/lib/Stats.cc

    r183 r185  
    126126
    127127
    128   bool Stats::parse(const std::string& path)
     128  void Stats::parse(const std::string& path)
    129129  {
    130     SVNblame svn_blame(path);
    131     if (svn_blame.binary())
    132       return true;
    133 
    134130    Parser parser(path);
    135131    std::vector<Parser::line_type>::const_iterator count=parser.type().begin();
    136132
     133    SVNblame svn_blame(path);
    137134    while (const SVNblame::blame_information * bi=svn_blame.next()) {
    138135      // to handle symbolic links
     
    143140      ++count;
    144141    }
    145    
    146     return false;
    147142  }
    148143
  • trunk/lib/Stats.h

    r165 r185  
    8181    inline u_int last_changed_rev(void) const { return last_changed_rev_; }
    8282
    83     ///
    84     /// @return true if file is binary
    85     ///
    86     bool parse(const std::string&);
     83    void parse(const std::string&);
    8784
    8885    ///
Note: See TracChangeset for help on using the changeset viewer.