Changeset 185


Ignore:
Timestamp:
Sep 6, 2006, 4:39:18 AM (12 years ago)
Author:
jari
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.