#! /usr/bin/perl -w my $GNUPLOT = '/usr/bin/gnuplot' ; use strict ; use Repocafe ; my $DAYS = 7 ; my $DIFF = $DAYS * 24 * 60 * 60 ; my $SCALE = 1024 * 1024 ; my $prog = substr($0,rindex($0,'/')+1) ; my $Usage = < ---------------------------------------- - $prog - collect repocafe statistics. - For each repo, collect version and size into table repo_stats. - Program $prog should be run daily by cron. - Cronjob : ( cd ; perl mk_stats -f ) ---------------------------------------- USAGE sub Usage { die "$_[0]$Usage" ; } sub Error { die "$prog: $_[0]\n" ; } sub Warn { warn "$prog: $_[0]\n" ; } # usage: &GetOptions(ARG,ARG,..) defines $opt_ID as 1 or user spec'ed value # usage: &GetOptions(\%opt,ARG,ARG,..) defines $opt{ID} as 1 or user value # ARG = 'ID' | 'ID=SPC' | 'ID:SPC' for no-arg, required-arg or optional-arg # ID = perl identifier # SPC = i|f|s for integer, fixedpoint real or string argument use Getopt::Long ; Getopt::Long::config('no_ignore_case') ; our %opt = () ; Usage('') unless GetOptions ( \%opt, qw(v q d f t p c=s help) ) ; if ( $opt{help} ) { print $Usage ; exit 0 ; } Usage("Arg count\n") unless @ARGV == 0 ; $opt{v} ||= $opt{d} ; my $Cafe = make_cafe ( %opt ) ; my $conf = $Cafe -> conf ; my $REPO_DIR = $conf -> dir_repos ; my $PLOT_DIR = $conf -> dir_www . "/images" ; my $PLOT_TMP = $conf -> dir_admin . "/tmp" ; my $PLOT_DAT = "$PLOT_TMP/totals" ; sub aprx_eq { my ( $x, $y ) = @_ ; abs ( $x - $y ) < 500 ; } sub aprx_ne { my ( $x, $y ) = @_ ; not aprx_eq $x, $y ; } sub aprx_lt { my ( $x, $y ) = @_ ; $x < $y and aprx_ne $x, $y ; } sub aprx_le { my ( $x, $y ) = @_ ; $x < $y or aprx_eq $x, $y ; } sub date { my $time = shift ; my @date = gmtime $time ; $date [ 4 ] ++ ; $date [ 5 ] += 1900 ; sprintf "%4d-%02d-%02d", @date [ 5, 4, 3 ] ; } my $time = $^T ; my $date = date $time ; printf "time %s\ndate %s\n", $time, $date if $opt{d} ; my @repos = $Cafe -> repos -> select ; my $repo_stats = $Cafe -> stats ; my $repo_tots = $Cafe -> tots ; sub save_stat { my $repo_stats = shift ; my $repo = shift ; my $stat = shift ; my $rid = $repo -> id ; my $rev = $repo -> revision ; my $sav = ( defined $stat ) ? 'upd' : 'new' ; my $rec = $stat || $repo_stats -> new_rec ( { rid => $rid } ) ; $rec -> time ( $time ) ; $rec -> date ( $date ) ; unless ( defined ( $rec -> id ) and $rev == $rec -> rev ) { $rec -> rev ( $rev ) ; $rec -> size ( $repo -> size ) ; } ; if ( my $errs = $rec -> _check ) { $rec -> dmp ; die $errs ; } elsif ( $opt{d} ) { print "-----------\n" ; print "$sav on " ; $rec -> dmp ( -verb => 0 ) ; } $rec -> _save if $opt{f} ; $rec ; } sub save_all_stats { my $repo_stats = shift ; my $repo_tots = shift ; my $since = $^T - int ( 7.5 * 24 * 60 * 60 ) ; my $stats = $repo_stats -> get_upd_stats ( $since ) ; my $fmt = "%s %6s %5s %10s %-10s %s\n" ; my $tsize = 0 ; if ( $opt{v} ) { printf $fmt, 'x', 'rid', 'rev', 'size', 'last', 'name' ; } for my $repo ( sort { $a -> repo_name cmp $b -> repo_name } @repos ) { my $nam = $repo -> repo_name ; my $rid = $repo -> { id } ; my $last_stat = $stats -> { $rid } || $repo_stats -> select1 ( -where => "rid = $rid" , -order => "time DESC" ) ; my $lst = ( defined $last_stat ? $last_stat -> date : '' ) ; my $rev = ( defined $last_stat ? $last_stat -> rev : undef ) ; my $rec = save_stat $repo_stats, $repo, $stats -> { $rid } ; if ( $opt{v} ) { printf $fmt , ( exists ( $stats -> { $rid } ) ? ( defined $rev and $rec -> rev == $rev ? '=' : 'u' ) : 'I' ) , $rec -> rid , $rec -> rev , $rec -> size , $lst , $nam ; } $tsize += $rec -> size ; } my $rec = $repo_tots -> select1 ( -where => "date = '$date'" ) || $repo_tots -> new_rec ( { date => $date } ) ; $rec -> time ( $time ) ; $rec -> size ( $tsize ) ; $rec -> count ( scalar @repos ) ; my $sav = $rec -> id ? 'update' : 'insert' ; if ( my $errs = $rec -> _check ) { $rec -> dmp ; die $errs ; } elsif ( $opt{v} ) { print "-----------\n" if $opt{d} ; print "$sav : " ; $rec -> dmp ( -verb => 0 ) ; } $rec -> _save if $opt{f} ; print "-----------\n" if $opt{d} ; } sub mk_tots { my $repo_stats = shift ; my @stats = $repo_stats -> select ( -order => 'rid, time' ) ; my %size = () ; my %tots = () ; my %span = () ; my %rids = () ; for my $stat ( @stats ) { my $rid = $stat -> rid ; my $time = $stat -> time ; my $size = $stat -> size ; my $k = int ( ( $^T - $time ) / $DIFF + 0.5 ) ; my $mark = $^T - $k * $DIFF ; $rids { $rid } ++ ; $size { $mark } { $rid } = $size ; if ( exists $span { $rid } ) { $span { $rid } [ 1 ] = $mark if $span { $rid } [ 1 ] < $mark ; } else { $span { $rid } = [ $mark, $mark ] ; } } my $prev_mark ; for my $mark ( sort { $a <=> $b } keys %size ) { for my $rid ( sort { $a <=> $b } keys %rids ) { # fix holes in the record if ( ! exists $size { $mark } { $rid } and $span { $rid } [ 0 ] <= $mark and $mark <= $span { $rid } [ 1 ] ) { $size { $mark } { $rid } = $size { $prev_mark } { $rid } ; } $tots { $mark } += $size { $mark } { $rid } if exists $size { $mark } { $rid } ; } $prev_mark = $mark ; } my $tots_hash = $repo_tots -> select_hash ( 'date' ) ; for my $mark ( sort { $a <=> $b } keys %tots ) { my $date = date $mark ; my $rec = $tots_hash -> { $date } || $repo_tots -> new_rec ( { date => $date, time => $mark } ) ; my $size = $rec -> size ( $tots { $mark } ) ; my $count = $rec -> count ( scalar keys %{ $size { $mark } } ) ; printf "%5s %10d %5d %10d %s\n" , ( $rec -> id || 'new' ) , $mark, $count, $size, $date if $opt{v} ; $rec -> _save if $opt{f} ; } } sub gen_plot { my $repo_tots = shift ; my $tots = $repo_tots -> select_hash ( 'time' ) ; unless ( scalar keys %$tots ) { print "no points to plot ; exiting\n" unless $opt{q} ; exit ; } my $min_cnt = undef ; my $max_cnt = 0 ; my $min_siz = 0 ; my $max_siz = 0 ; open DAT, ">$PLOT_DAT" or Error "can't write $PLOT_DAT ($!)" ; for my $mark ( sort { $a <=> $b } keys %$tots ) { my $stat = $tots -> { $mark } ; my $size = $stat -> size / $SCALE ; my $count = $stat -> count ; my $line = sprintf "%d %4s %8.3f %s\n" , $mark , $count , $size , scalar ( localtime $mark ) ; print $line if $opt{d} ; print DAT $line ; $min_cnt = $count if ! defined $min_cnt or $count < $min_cnt ; $max_cnt = $count if $count > $max_cnt ; $min_siz = $size if $size < $min_siz ; $max_siz = $size if $size > $max_siz ; } close DAT ; $min_cnt *= 0.9 ; $max_cnt += int ( $max_cnt / 50 + 0.5 ) ; $max_siz *= 1.1 ; # '$PLOT_DAT' using 1:2 axes x1y1 notitle with points, \\ my $plot1 = <