#!/usr/bin/perl -w # -*- perl -*- use P4CGI ; use strict ; # ################################################################# # CONFIGURATION INFORMATION # All config info should be in P4CGI.pm # ################################################################# # # P4 change browser # Depot statistics # ################################################################# ####### # Parameters: # ###### $| = 1 ; # # Get parameter(s) # my $FSPC = P4CGI::cgi()->param("FSPC") ; $FSPC = "//..." unless defined $FSPC ; my @FSPC = split(/\s*\+?\s*(?=\/\/)/,$FSPC) ; $FSPC = "<tt>".join("</tt> and <tt>",@FSPC)."</tt>" ; my $FSPCcmd = "\"" . join("\" \"",@FSPC) . "\"" ; ### ### subroutine findTime ### A (really) poor mans version of mktime(3). ### Parameters: year,month,day,hour,min ### Returns: time_t value that corresponds to above result (almost) sub findTime($$$$$) { my ($iyear,$imon,$iday,$ihour,$imin) = @_ ; $iyear -= 1900 ; $imon-- ; my $time = time() ; my $delta = int($time/2)+1 ; my $lastsgn = -1 ; my $n = 300 ; while($delta > 10) { last if $n-- == 0 ; my $sgn = 1 ; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time) ; my $i = ((((((((($iyear * 12) + $imon) * 32) + $iday) * 24) + $ihour) * 60) + $imin) * 60) + 30 ; my $o = ((((((((($year * 12) + $mon) * 32) + $mday) * 24) + $hour) * 60) + $min) * 60) + $sec ; last if $i == $o ; $sgn = -1 if $i < $o ; $time += ($sgn * $delta) ; $delta = int(($delta+1)/2) ; $lastsgn = $sgn ; } return $time ; } ; &P4CGI::SET_HELP_TARGET("DepotStats") ; print &P4CGI::start_page("Depot Statistics for<br><tt>". join("<br></tt>and<tt><br>\n",@FSPC) . "</tt>" , &P4CGI::ul_list(&P4CGI::ahref(-url => &P4CGI::cgi()->self_url . "#weekly", "Weekly Submit Statistics"), &P4CGI::ahref(-url => &P4CGI::cgi()->self_url . "#byuser", "Submit Statistics by user") )) ; sub printStat($$) { my $prompt = shift @_ ; my $data = shift @_ ; print &P4CGI::table_row({-type => "th", -align => "right", -valign => "top", -width => "50%", -text => "$prompt:"}, {-type => "td", -align => "left", -width => "50%", -text => $data}) ; }; print "<h2>Depot statistics</h2>", &P4CGI::start_table("") ; { my @counters ; &P4CGI::p4call(\@counters,"counters") ; # printStat("P4 counters","") ; foreach (@counters) { s/(\S+) = /P4 $1 counter = / ; &printStat(split(" = ","$_")) ; } } # Users my @users ; &P4CGI::p4call(\@users,"users") ; printStat("Users",@users) ; # Clients my @clients ; &P4CGI::p4call(\@clients,"clients") ; printStat("Clients",@clients) ; # Labels my @labels ; &P4CGI::p4call(\@labels,"labels") ; printStat("Labels",@labels) ; # branches my @branches ; &P4CGI::p4call(\@branches,"branches") ; printStat("Branches",@branches) ; # jobs my @jobs ; &P4CGI::p4call(\@jobs,"jobs") ; printStat("Jobs",@jobs) ; print &P4CGI::end_table(),"<hr>" ; # Get changes my @changes ; &P4CGI::p4call(\@changes,"changes -s submitted $FSPCcmd") ; # Sort and remove duplicates { my @ch = sort { $a =~ /Change (\d+)/ ; my $ac = $1 ; $b =~ /Change (\d+)/ ; my $bc = $1 ; $bc <=> $ac } @changes ; my $last="" ; @changes = grep {my $l = $last ; $last = $_ ; $_ ne $l } @ch ; } ## File list stats print "<h2>Statistics for \"$FSPC\"</h2>", &P4CGI::start_table("") ; printStat("Submitted changes",scalar @changes) ; # Data about first submit my $first = pop @changes ; push @changes,$first ; $first =~ s/Change (\d+).*/$1/ ; my %data ; my $firstTime = 0; my $firstDate = ""; my $daysSinceFirstSubmit = 0 ; &P4CGI::p4readform("change -o $first",\%data) ; if(exists $data{"Date"}) { $firstDate = $data{"Date"} ; if($data{"Date"} =~ /(\d+).(\d+).(\d+).(\d+).(\d+)/) { $firstTime = findTime($1,$2,$3,$4,$5) ; my $seconds = time() - $firstTime ; $daysSinceFirstSubmit = int($seconds/(24*3600)) ; } } # Last submit my $last = shift @changes ; unshift @changes,$last ; $last =~ s/Change (\d+).*/$1/ ; my $lastTime=0 ; my $lastDate="" ; my $daysSinceLastSubmit=0 ; &P4CGI::p4readform("change -o $last",\%data) ; if(exists $data{"Date"}) { $lastDate = $data{"Date"} ; if($data{"Date"} =~ /(\d+).(\d+).(\d+).(\d+).(\d+)/) { $lastTime = findTime($1,$2,$3,$4,$5) ; my $seconds = time() - $lastTime ; $daysSinceLastSubmit = int($seconds/(24*3600)) ; } } ; printStat("First submit","$first ($firstDate)") ; printStat("Latest submit","$last ($lastDate)") ; printStat("Days between first and latest submit",$daysSinceFirstSubmit-$daysSinceLastSubmit) ; if(($daysSinceFirstSubmit-$daysSinceLastSubmit) > 0) { printStat("Average submits per day", sprintf("%.2f",@changes/($daysSinceFirstSubmit-$daysSinceLastSubmit))) ; }; # Read and parse file list my $files=0 ; my $deletedFiles=0 ; my %revlevels ; my $maxrevlevel=0 ; my $totrevs=0 ; my $file ; foreach $file (@FSPC) { local *F ; &P4CGI::p4call(*F,"files \"$file\"") ; while(<F>) { $files++ ; /\#(\d+) - (\S+)/ ; my ($r,$s) = ($1,$2) ; $deletedFiles++ if $s eq "delete" ; $totrevs += $r ; $maxrevlevel = $r if $r > $maxrevlevel ; $revlevels{$r} = 0 unless exists $revlevels{$r} ; $revlevels{$r}++ ; } close F ; } printStat("Current number of files",$files) ; printStat("Deleted files",$deletedFiles) ; printStat("Average revision level for files ",sprintf("%.2f",$totrevs/$files)) ; printStat("Max revision level",$maxrevlevel) ; print &P4CGI::end_table(),"<hr>" ; # File revision statistics # print # "<a name=\"revstat\"><hr></a>", # &P4CGI::start_table("width=90%"), # &P4CGI::table_row(-type=>"th", # undef, # undef, # "File Revision Statistics"), # &P4CGI::table_row({-type=>"th", # -text => "Revision Level", # -width => "20%", # -align => "right"}, # {-text => "No. of<br>files", # -type=>"th", # -width => "10%"}, # {-text => " ", # -bgcolor=>&P4CGI::BGCOLOR()}), # &P4CGI::end_table() ; # #my $max = 0 ; # #foreach (keys %revlevels) { # $max = $revlevels{$_} if $max < $revlevels{$_} ; #} ; # # my $rev=$maxrevlevel ; # while($rev > 0) { # my $n = 0 ; # $n = $revlevels{$rev} if exists $revlevels{$rev} ; # my $w = int((65.0 * $n)/$max) ; # if($w == 0) { $w = 1 ; } ; # print # &P4CGI::start_table("colums=4 width=90% cellspacing=0"), # &P4CGI::table_row({-text => "$rev", # -width => "20%", # -align => "right"}, # {-text => $n==0?"-":"$n", # -align => "center", # -width => "10%"}, # {-text => " ", # -bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(), # -width => "$w\%"}, # {-text => " ", # -bgcolor=>&P4CGI::BGCOLOR()}) ; # print &P4CGI::end_table() ; # $rev-- ; # } my %dailySubStat ; my %userSubStat ; my $n ; #my $time = time() ; my $time = $lastTime ; my $ONE_DAY=3600*24 ; my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); while($wday != 0) { $time -= $ONE_DAY ; ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); } sub getNextDate() { my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime($time); $time -= $ONE_DAY * 7 ; my $day = sprintf("%4d/%02.2d/%02.2d",$year + 1900, $mon + 1, $mday) ; $dailySubStat{$day} = 0 ; return $day ; } ; # Read and parse change list my $day = getNextDate() ; my $max = 0 ; while(@changes > 0) { $_ = shift @changes ; if(/Change \d+ on (\S+) by (\S+)\@/) { my $d = $1 ; my $user = $2 ; while($d lt $day) { $day = getNextDate() ; } $dailySubStat{$day}++ ; $max = $dailySubStat{$day} if $dailySubStat{$day} > $max ; $userSubStat{$user} = 0 unless exists $userSubStat{$user} ; $userSubStat{$user}++ ; } } # Weekly Submit Statistics print "<a name=\"weekly\"></a><H2>Weekly Submit Rate for $FSPC</H2>", &P4CGI::start_table("width=90%"), &P4CGI::table_row({-type=>"th", -text => "Week starting", -width => "20%", -align => "right"}, {-text => "submits", -type=>"th", -width => "10%"}, {-text => " ", -bgcolor=>&P4CGI::BGCOLOR()}), &P4CGI::end_table() ; my $d ; foreach $d (sort { $b cmp $a } keys %dailySubStat) { print &P4CGI::start_table("colums=4 width=90% cellspacing=0") ; my $n = $dailySubStat{$d} ; my $w = int((65.0 * $n)/$max) ; if($w == 0) { $w = 1 ; } ; print &P4CGI::table_row({-text => "$d", -width => "20%", -align => "right"}, {-text => $n==0?"-":"$n", -align => "center", -width => "10%"}, {-text => " ", -bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(), -width => "$w\%"}, {-text => " ", -bgcolor=>&P4CGI::BGCOLOR()}) ; print &P4CGI::end_table() ; } # Submits per user print "<a name=\"byuser\"><hr></a><h2>Submits by user in $FSPC</h2>", &P4CGI::start_table("width=90%"), &P4CGI::table_row({-type=>"th", -text => "User", -width => "20%", -align => "right"}, {-text => "Submits", -type=>"th", -width => "10%"}, {-text => " ", -bgcolor=>&P4CGI::BGCOLOR()}), &P4CGI::end_table() ; # Get users my @listOfUsers = sort { uc($a) cmp uc ($b) } map { /^(\S+).*> \((.+)\) .*$/ ; $1 ; } @users ; my %userCvt = map { /^(\S+).*> \((.+)\) .*$/ ; ($1,$2) ; } @users ; my $u ; $max = 0 ; foreach $u (sort {$userSubStat{$b} <=> $userSubStat{$a} ; } keys %userSubStat) { my $n = $userSubStat{$u} ; $max = $n if $max == 0 ; my $w = int((65.0 * $n)/$max) ; if($w == 0) { $w = 1 ; } ; if(exists $userCvt{$u}) { my $fullUser = $userCvt{$u} ; $u = &P4CGI::ahref(-url => "userView.cgi", "USER=$u", $fullUser) ; } else { $u = "<b>Old user:</b> $u" } print &P4CGI::start_table("colums=4 width=90% cellspacing=0"), &P4CGI::table_row({-text => "$u", -width => "20%", -align => "right"}, {-text => $n==0?"-":"$n", -align => "center", -width => "10%"}, {-text => " ", -bgcolor => $n!=0?"blue":&P4CGI::BGCOLOR(), -width => "$w\%"}, {-text => " ", -bgcolor=>&P4CGI::BGCOLOR()}) ; print &P4CGI::end_table() ; } print &P4CGI::end_page() ; # # That's all folks #