10 print "Usage: git chart\n";
17 print "Gathering data ...\n";
21 open my $fd, '-|', qw(git log --date=short), '--pretty=%ad,%s', @{$options->{cmdline}};
22 die "failed to get revs" unless $fd;
26 my ($date, $sub) = split ',', $_, 2;
27 if (exists $perday{$date}) {
36 print "...done, $commits commits in $groups days. Grouping\n";
38 my $step=$options->{step}*24*3600; # days to seconds
40 my @keys = sort keys %perday;
42 my $to = $keys[@keys-1];
49 while (my $key = shift @keys) {
50 my $day = str2time($key);
53 $next = $first + $step;
56 $val += $perday{$key};
58 # TODO what do we put as key?
59 $dataset{$first} = $val;
60 $max = $val if $max < $val;
61 while ($day >= $next) {
63 $next = $first + $step;
64 $dataset{$first} = 0 unless $day < $next;
69 $dataset{$first} = $val;
70 $max = $val if $max < $val;
72 $options->{max} = $max;
76 # functions to plot the datasets.
77 # each function can be called with either one or two parameters.
78 # when called with two parameters, the first is assumed to be the dataset, and the second the options
79 # (array and hash ref respectively).
80 # when called with a single parameter, it is assumed to be an options hash ref, and the dataset is
81 # created by calling gather_data with the passed options.
84 # TODO needs a lot of customization
85 sub google_chart($;$) {
88 if (! defined $options) {
90 $dataset = gather_data($options);
93 my $height=$options->{chart_height};
94 my $max = $options->{max};
96 my @keys = sort keys %$dataset;
98 my $to = $keys[@keys-1];
101 while (my $key = shift @keys) {
102 push @data, $dataset->{$key};
105 my $width=ceil(4*$height/3);
107 my $url="https://chart.googleapis.com/chart?chs=${width}x${height}&cht=bvg&chd=t:%s&chds=0,$max&chbh=a&chxt=y&chxr=0,0,$max";
109 my $launch = sprintf $url, join(",",@data);
111 # `git web--browse "$launch"`
115 sub gnuplot_chart($;$) {
118 if (! defined $options) {
120 $dataset = gather_data($options);
123 my @keys = sort keys %$dataset;
125 my $to = $keys[@keys-1];
127 while (my $key = shift @keys) {
128 $data .= "$key $dataset->{$key}\n";
130 my $max = $options->{max};
132 # TODO allow customization
133 # in particular, detect (lack of) display and set term to dumb accordingly
134 my $termcmd = $options->{gnuplot_term};
136 my $plotsetup = $options->{gnuplot_setup};
137 $plotsetup .= "\nset yrange [0:$max]\n";
138 $plotsetup .= "set xrange ['$from':'$to']\n";
139 my $plotstyle = $options->{gnuplot_style};
140 my $plotoptions = $options->{gnuplot_plotwith};
142 open my $gp, "|gnuplot -persist";
144 my $gp_script = <<GPCMD
148 set format x "%b\\n%Y"
151 plot "-" using 1:2 $plotoptions
156 print STDOUT $gp_script;
157 print $gp $gp_script;
165 # charting/plotting options
166 plotter => \&gnuplot_chart,
169 gnuplot_setup => "set nokey",
170 gnuplot_style => 'set style data histeps',
171 gnuplot_plotwith => '',
183 if (exists $steps{$key}) {
184 $options{step} = $steps{$key};
187 die "this can't happen ($key)" unless $key eq 'step';
189 if ($step =~/^\d+$/) {
190 $options{step} = 0 + $step;
193 if (exists $steps{$step}) {
194 $options{step} = $steps{$step};
197 die "unknown step $step";
201 # read our options first
202 Getopt::Long::Configure('pass_through');
204 'daily' => \&parse_step,
205 'weekly' => \&parse_step,
206 'monthly' => \&parse_step,
207 'step=s' => sub { parse_step(@_) },
208 'chart-height=i' => sub { $options{chart_height} = @_[1]},
209 google => sub { $options{plotter} = \&google_chart },
210 gnuplot => sub { $options{plotter} = \&gnuplot_chart },
213 # if anything was left, check for log options
215 $options{cmdline} = \@ARGV;
218 die "step must be strictly positive!" unless $options{step} > 0;
220 $options{plotter}->(\%options);