10 print "Usage: git chart\n";
17 print "Gathering data ...\n";
22 my $step=$options->{step}*24*3600; # days to seconds
24 open my $fd, '-|', qw(git log --date=raw), '--pretty=%ad %s', @{$options->{cmdline}};
25 die "failed to get revs" unless $fd;
29 my ($date, $tz, $sub) = split ' ', $_, 3;
32 my $key = $date - ($date % $step);
33 if (exists $dataset{$key}) {
42 print "...done, $commits commits in $groups groups.\n";
44 # fill missing steps and find max
45 my @keys = sort keys %dataset;
48 while (my $key = shift @keys) {
49 $max = $dataset{$key} if $max < $dataset{$key};
50 my $next = $key + $step;
51 while (! exists $dataset{$next}) {
54 last if $next >= $last;
58 $options->{max} = $max;
62 # functions to plot the datasets.
63 # each function can be called with either one or two parameters.
64 # when called with two parameters, the first is assumed to be the dataset, and the second the options
65 # (array and hash ref respectively).
66 # when called with a single parameter, it is assumed to be an options hash ref, and the dataset is
67 # created by calling gather_data with the passed options.
70 # TODO needs a lot of customization
71 sub google_chart($;$) {
74 if (! defined $options) {
76 $dataset = gather_data($options);
79 my $height=$options->{chart_height};
80 my $max = $options->{max};
82 my @keys = sort keys %$dataset;
84 my $to = $keys[@keys-1];
87 while (my $key = shift @keys) {
88 push @data, $dataset->{$key};
91 my $width=ceil(4*$height/3);
93 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";
95 my $launch = sprintf $url, join(",",@data);
97 # `git web--browse "$launch"`
101 sub gnuplot_chart($;$) {
104 if (! defined $options) {
106 $dataset = gather_data($options);
109 my @keys = sort keys %$dataset;
111 my $to = $keys[@keys-1];
113 while (my $key = shift @keys) {
114 $data .= "$key $dataset->{$key}\n";
116 my $max = $options->{max};
118 # TODO allow customization
119 # in particular, detect (lack of) display and set term to dumb accordingly
120 my $termcmd = $options->{gnuplot_term};
122 my $plotsetup = $options->{gnuplot_setup};
123 $plotsetup .= "\nset yrange [0:$max]\n";
124 $plotsetup .= "set xrange ['$from':'$to']\n";
125 my $plotstyle = $options->{gnuplot_style};
126 my $plotoptions = $options->{gnuplot_plotwith};
128 open my $gp, "|gnuplot -persist";
130 my $gp_script = <<GPCMD
134 set format x "%b\\n%Y"
137 plot "-" using 1:2 $plotoptions
142 print STDOUT $gp_script;
143 print $gp $gp_script;
151 # charting/plotting options
152 plotter => \&gnuplot_chart,
155 gnuplot_setup => "set nokey",
156 gnuplot_style => 'set style data histeps',
157 gnuplot_plotwith => '',
169 if (exists $steps{$key}) {
170 $options{step} = $steps{$key};
173 die "this can't happen ($key)" unless $key eq 'step';
175 if ($step =~/^\d+$/) {
176 $options{step} = 0 + $step;
179 if (exists $steps{$step}) {
180 $options{step} = $steps{$step};
183 die "unknown step $step";
187 # read our options first
188 Getopt::Long::Configure('pass_through');
190 'daily' => \&parse_step,
191 'weekly' => \&parse_step,
192 'monthly' => \&parse_step,
193 'step=s' => sub { parse_step(@_) },
194 'chart-height=i' => sub { $options{chart_height} = $_[1]},
195 google => sub { $options{plotter} = \&google_chart },
196 gnuplot => sub { $options{plotter} = \&gnuplot_chart },
199 # if anything was left, check for log options
201 $options{cmdline} = \@ARGV;
204 die "step must be strictly positive!" unless $options{step} > 0;
206 $options{plotter}->(\%options);