#!/usr/bin/perl
# Copyright (c) Xerox Corporation, Codendi Team, 2001-2009. All rights reserved
#
# This file is a part of Codendi.
#
# Codendi is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# Codendi is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Codendi. If not, see .
#
##
## cvs_history_parse.pl
##
## NIGHTLY SCRIPT
##
## Recurses through the /cvsroot directory tree and parses each projects
## '~/CVSROOT/history' file, building agregate stats on the number of
## checkouts, commits, and adds to each project over the past 24 hours.
##
##
##
##
#use strict;
use Time::Local;
use POSIX qw( strftime );
require("../include.pl");
my ($year, $month, $day, $day_begin, $day_end);
my ($group, $histline, $daily_log_file, $key, $verbose);
my $verbose = 1;
my $base_log_dir = $codendi_log."/cvslogs";
$|=0 if $verbose;
## Set the time to collect stats for
if ( $ARGV[0] && $ARGV[1] && $ARGV[2] ) {
$day_begin = timegm( 0, 0, 0, $ARGV[2], $ARGV[1] - 1, $ARGV[0] - 1900 );
$day_end = timegm( 0, 0, 0, (gmtime( $day_begin + 86400 ))[3,4,5] );
$year = $ARGV[0];
$month = $ARGV[1];
$day = $ARGV[2];
} else {
## Start at midnight last night.
$day_end = timegm( 0, 0, 0, (gmtime( time() ))[3,4,5] );
## go until midnight yesterday.
$day_begin = timegm( 0, 0, 0, (gmtime( time() - 86400 ))[3,4,5] );
$year = strftime("%Y", gmtime( $day_begin ) );
$month = strftime("%m", gmtime( $day_begin ) );
$day = strftime("%d", gmtime( $day_begin ) );
}
print "Parsing cvs logs looking for traffic on day $day, month $month, year $year.\n" if $verbose;
if ( -d $base_log_dir ) {
$daily_log_file = $base_log_dir . "/" . sprintf("%04d", $year);
if ( ! -d $daily_log_file ) {
print "Making dest dir \'$daily_log_file\'\n";
mkdir( $daily_log_file, 0755 ) || die("Could not mkdir $daily_log_file");
}
$daily_log_file .= "/" . sprintf("%02d", $month);
if ( ! -d $daily_log_file ) {
print "Making dest dir \'$daily_log_file\'\n";
mkdir( $daily_log_file, 0755 ) || die("Could not mkdir $daily_log_file");
}
$daily_log_file .= "/cvs_traffic_" . sprintf("%04d%02d%02d",$year,$month,$day) . ".log";
} else {
print "Base log directory \'$base_log_dir\' does not exist!";
exit;
}
open(DAYS_LOG, "> $daily_log_file") || die "Unable to open the log file \'$daily_log_file\'";
print "Opened log file at \'$daily_log_file\' for writing...\n";
print "Running tree at $cvs_prefix/\n";
chdir( $cvs_prefix ) || die("Unable to make $cvs_prefix the working directory.\n");
foreach $group ( glob("*") ) {
next if ( ! -d "$group" || $group eq 'lost+found' );
my ($cvs_co, $cvs_commit, $cvs_add, %usr_commit, %usr_add);
# LJ New variable to keep track of users and number of checkouts
my (%usr_names, %usr_co);
open(HISTORY, "< $cvs_prefix/$group/CVSROOT/history") or print "E::Unable to open history for $group\n";
while ( ) {
my ($time_parsed, $type, $cvstime, $user, $curdir, $module, $rev, $file );
## Split the cvs history entry into it's 6 fields.
($cvstime,$user,$curdir,$module,$rev,$file) = split(/\|/, $_, 6 );
$type = substr($cvstime, 0, 1);
$time_parsed = hex( substr($cvstime, 1, 8) );
## If the entry was made in the past 24 hours
## (i.e. - since the last run of this script...)
if ( ($time_parsed > $day_begin) && ($time_parsed < $day_end) ) {
## log commits
if ( $type eq "M" ) {
$cvs_commit++;
$usr_commit{$user}++;
$usr_names{$user}=1;
next;
}
## log adds
if ( $type eq "A" ) {
$cvs_add++;
$usr_add{$user}++;
$usr_names{$user}=1;
next;
}
## log checkouts
if ( $type eq "O" ) {
$cvs_co++;
## we don't care about checkouts on a per-user
## most of them will be anon anyhow.
## LJ Actually we do care on Codendi
$usr_co{$user}++;
$usr_names{$user}=1;
next;
}
} elsif ( $time_parsed > $day_end ) {
if ( $verbose >= 2 ) {
print "Short circuting execution, parsed date exceeded current threshold.\n";
}
last;
}
}
close( HISTORY );
## Now, we'll print all of the results for that project, in the following format:
## (G|U|E)::proj_name::user_name::checkouts::commits::adds
## If 'G', then record is group statistics, and field 2 is a space...
## If 'U', then record is per-user stats, and field 2 is the user name...
## If 'E', then record is an error, and field 1 is a description, there are no other fields.
if ( $cvs_co || $cvs_commit || $cvs_add ) {
print DAYS_LOG "G::" . $group . ":: ::" . ($cvs_co?$cvs_co:"0") . "::"
. ($cvs_commit?$cvs_commit:"0") . "::" . ($cvs_add?$cvs_add:"0") . "\n";
foreach $key ( keys %usr_names ) {
print DAYS_LOG "U::" . $group . "::" . $key
. "::" . ($usr_co{$key}?$usr_co{$key}:"0")
. "::" . ($usr_commit{$key}?$usr_commit{$key}:"0")
. "::" . ($usr_add{$key}?$usr_add{$key}:"0")
. "\n";
}
}
}
print "Done processing cvs history file for this date.\n" if $verbose;
##
## EOF
##