File Coverage

blib/lib/SVK/Command/Churn.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package SVK::Command::Churn;
2 2     2   11605 use v5.8.8;
  2         8  
  2         113  
3 2     2   14 use strict;
  2         4  
  2         77  
4 2     2   22 use base qw( SVK::Command );
  2         5  
  2         1254  
5 2     2   981 use SVK::Command::Log;
  0            
  0            
6             use Chart::Strip;
7             use Date::Parse;
8             use IO::All;
9             use Quantum::Superpositions;
10              
11             our $VERSION = '0.05';
12              
13             sub options {
14             ('q|quiet' => 'quiet',
15             't|type=s' => 'chart_type',
16             'o|output=s' => 'output',
17             );
18             }
19              
20             sub parse_arg {
21             my $self=shift;
22             my @arg = @_;
23             @arg = ('') if $#arg < 0;
24             return $self->arg_co_maybe (@arg);
25             }
26              
27             sub run {
28             my ( $self, $target ) = @_;
29             $self->{output} ||= 'churn.png';
30             $self->{chart_type} ||= "loc";
31             my $method = $self->{chart_type} . "_graph";
32             if ( $self->can($method) ) {
33             my $chart = Chart::Strip->new(
34             title => "Churn result of $target->{path}",
35             draw_data_labels => 1,
36             );
37             $self->$method( $chart, $self->{xd}, $target );
38             io( $self->{output} )->print( eval '$chart->png()' );
39             print STDERR "$self->{output} saved\n" unless $self->{quiet};
40             }
41             else {
42             print
43             "Unknown chart type: $self->{chart_type}. (Must be one of 'commits','committers', or 'loc')\n";
44             }
45             return 0;
46             }
47              
48             sub trace_svklog {
49             my $self = shift;
50             my ( $xd, $target, $callback, $data ) = @_;
51             SVK::Command::Log::_get_logs(
52             root => $target->root,
53             path => $target->path_anchor,
54             fromrev => 0,
55             torev => $target->revision,
56             verbose => 1,
57             cross => 0,
58             cb_log => $callback
59             );
60             @$data = sort { $a->{time} <=> $b->{time} } @$data;
61             return $data;
62             }
63              
64             sub loc_graph {
65             my $self = shift;
66             my ($chart,$xd,$target) = @_;
67             my (@ladd,@lremoved,@revs);
68             my $append = sub {
69             my ($rev, $root, $props) = @_;
70             my ($date,$author) = @{$props}{qw/svn:date svn:author/};
71             my $time = str2time($date);
72             push @revs,{time=>$time,value=>$rev}
73             if $author && !($author eq 'svm');
74             };
75             $self->trace_svklog($xd, $target, $append, \@revs);
76              
77             my $full_path = "/" . $target->depotname . $target->path;
78             my $output = "";
79             my $svk = SVK->new(xd => $xd, output => \$output);
80             for my $i (1..$#revs) {
81             $svk->diff(-r => "$revs[$i-1]->{value}:$revs[$i]->{value}",
82             $full_path);
83              
84             my @lines = split/\n/,$output;
85             my ($add,$rm)=(0,0);
86             for(@lines) {
87             next if /^[-+]{3,3} \S/;
88             $add++ if/^\+/;
89             $rm++ if/^\-/;
90             }
91             print STDERR "Rev $i, $add lines added ,$rm lines removed\n"
92             unless $self->{quiet};
93             push @ladd, {time=>$revs[$i]->{time},value=>$add};
94             push @lremoved,{time=>$revs[$i]->{time},value=>$rm };
95             $output = "";
96             }
97             $chart->{y_label} = "Lines of Codes";
98             $chart->add_data(\@ladd,{style=>'line',label=>'Lines Added',color=>'00FF00'});
99             $chart->add_data(\@lremoved,{style=>'line',label=>'Lines Removed',color=>'FF0000'});
100             return $chart;
101             }
102              
103             sub commits_graph {
104             my $self = shift;
105             my ($chart,$xd,$target) = @_;
106             my (@data,$commit);
107             my $append = sub {
108             my ($rev, $root, $props) = @_;
109             my ($date,$author) = @{$props}{qw/svn:date svn:author/};
110             my $time = str2time($date);
111             push @data,{time=>$time,value=>$commit++}
112             if $author && !($author eq 'svm');
113             };
114             $self->trace_svklog($xd,$target,$append,\@data);
115             $chart->{y_label} = "Number of Commits";
116             $chart->add_data(\@data,{style=>'line',color=>'FF0000'});
117             return $chart;
118             }
119              
120             sub committers_graph {
121             my $self = shift;
122             my ($chart,$xd,$target) = @_;
123             my (@data,%authors);
124             my $append = sub {
125             my ($rev, $root, $props) = @_;
126             my ($author,$date) = @{$props}{qw/svn:author svn:date/};
127             my $time = str2time($date);
128             if($author && !($author eq 'svm')) {
129             $authors{$author}++;
130             push @data,{time=>$time,value=>scalar(keys %authors)};
131             }
132             };
133             $self->trace_svklog($xd,$target,$append,\@data);
134             $chart->{y_label} = "Number of Committers";
135             $chart->add_data(\@data,{style=>'line',color=>'FF0000'});
136             return $chart;
137             }
138              
139             1;
140              
141             =head1 NAME
142              
143             SVK::Command::Churn - Generate SVK Statistics graph.
144              
145             =head1 SYNTAX
146              
147             svk [OPTIONS] churn //depotpath
148              
149             =head1 OPTIONS
150              
151             -t chart type, one of "commits","committers","loc"
152             default to "loc" (lines of codes)
153             -q quiet
154             -o output filename
155              
156             =head1 DESCRIPTION
157              
158             This module helps you to understand yor SVK repository developing
159             statistics. It'll generate a file named C under
160             current directory unless C<-o> parameter is given.
161              
162             SVK is a decentralized version control system built on top of the
163             robust Subversion filesystem. For more information, please visit
164             L.
165              
166             =head1 API
167              
168             All sub-routines defined in this modules is supposed to be invoked
169             by SVK internally, not to be called directly by developers. They
170             are all internal methods. If you must call them, please understand
171             what you are doing.
172              
173             =over 4
174              
175             =item options
176              
177             Define command line options.
178              
179             =item parse_arg
180              
181             Parse command line argument string.
182              
183             =item run
184              
185             Run this churn command. This methods simply dispatch to one of the
186             following 3 methods according to user's command line argument.
187              
188             =item commits_graph
189              
190             Generate 'commits' churn graph.
191              
192             =item committers_graph
193              
194             Generate churn graph in the respect of comitters.
195              
196             =item loc_graph
197              
198             Generate churn graph in the respect of lines of code.
199              
200             =item trace_svklog
201              
202             General 'svk log' traversing rounine use internally inside this module.
203              
204             =back
205              
206             =head1 SEE ALSO
207              
208             L, L, L
209              
210             =head1 AUTHOR
211              
212             Kang-min Liu
213              
214             =head1 COPYRIGHT
215              
216             Copyright 2005,2006,2007 by Kang-min Liu .
217              
218             This program is free software; you can redistribute it and/or modify
219             it under the same terms as Perl itself.
220              
221             See
222              
223             =cut