#!/usr/bin/perl use strict; use warnings; use POSIX qw(ceil); use Getopt::Long; sub usage() { print "Usage: git chart\n"; } sub gather_data($) { my $options = shift; my @dataset; print "Gathering data ...\n"; my $day=$options->{from}; my $to =$options->{to}; my $step=$options->{step}; my $max=$options->{max} || 0; while ($day < $to) { my $next = $day + $step; my $val = `git log --pretty=%s --since="$next days ago" --until="$day days ago" | wc -l`; chomp $val; push @dataset, $val; $max = $val if $max < $val; $day = $next; } $options->{max} = $max; print "...done\n"; return \@dataset; } # functions to plot the datasets. # each function can be called with either one or two parameters. # when called with two parameters, the first is assumed to be the dataset, and the second the options # (array and hash ref respectively). # when called with a single parameter, it is assumed to be an options hash ref, and the dataset is # created by calling gather_data with the passed options. # google chart API # TODO needs a lot of customization sub google_chart($;$) { my $dataset = shift; my $options = shift; if (! defined $options) { $options = $dataset; $dataset = gather_data($options); } my $height=$options->{chart_height}; my $max = $options->{max}; my $from = $options->{from}; my $to = $options->{to}; my $step = $options->{step}; my $width=($step < 20 ? 20 : $step)*@$dataset; my $url="https://chart.googleapis.com/chart?chs=${width}x${height}&cht=bvg&chd=t:%s&chds=0,$max&chbh=a&chxt=y,x&chxr=0,0,$max|1,$to,$from,-$step"; my $launch = sprintf $url, join(",",reverse @$dataset); # print $launch, "\n"; `git web--browse "$launch"` } # gnuplot sub gnuplot_chart($;$) { my $dataset = shift; my $options = shift; if (! defined $options) { $options = $dataset; $dataset = gather_data($options); } my $max = $options->{max}; my $from = $options->{from}; my $to = $options->{to}; my $step = $options->{step}; # TODO allow customization # in particular, detect (lack of) display and set term to dumb accordingly my $termcmd = $options->{gnuplot_term}; my $plotsetup = $options->{gnuplot_setup}; $plotsetup .="\nset yrange [0:$max]\nset xrange [$from:$to]"; my $plotstyle = $options->{gnuplot_style}; my $plotoptions = $options->{gnuplot_plotwith}; my $data = join("\n", reverse @$dataset); open my $gp, "|gnuplot -persist"; print $gp < 0, to => 31, step => 1, # charting/plotting options chart_height => 144, gnuplot_term => '', gnuplot_setup => "set nokey", gnuplot_style => 'set style fill solid 1.0 border -1', gnuplot_plotwith => 'with boxes', ); my $daily=0; my $weekly=0; my $monthly=0; my $from=0; my $to=0; my $step=0; GetOptions( daily => \$daily, weekly => \$weekly, monthly => \$monthly, 'from=s' => \$from, 'to=s' => \$to, 'step=s' => \$step, ); $options{from} = parse_from($from) if $from; if ($monthly) { $options{to} = $options{from} + 365; $options{step} = 30; } elsif ($weekly) { $options{to} = $options{from} + 6*30; $options{step} = 30; } elsif ($daily) { $options{to} = $options{from} + 31; $options{step} = 1; } $options{to} = parse_to($to) if $to; $options{step} = parse_step($step) if $step; die "step must be strictly positive!" unless $options{step} > 0; gnuplot_chart(\%options);