#! /opt/shareware/svr4/bin/perl
# -*-Perl-*-
#$Header$
#
# Developed using perl, version 5.004_04 built for sun4-solaris
#
#
# This program 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, or (at your option)
# any later version.
#
# This program 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.
#
#
# Adapted from the log_accum.pl script provided in CVS 1.10 contrib
# directory written by David Hampton and Greg A. Woods
# 
# Copyright 2000 David Martin http://www.scm-professionals.com
#
#
################################################################################
#
# Perl script automatically tag files checked in based on their
# revision log message content.  If the log message includes "SCR #:", and/or
# "Defect #:" and/or "Change Request #:", one or more tags will be applied
# (or moved) to the tip of the trunk or to the branch being
# checked in.
#
# Usage: autotag.pl [-d] [-f logfile]
#	-d		- turn on debugging
#	-f logfile	- write commit messages to logfile too
#

use locale;

#########################
# Begin Main Body
#

# Initialize basic variables
#
$debug = 0;
$cvsroot = "/export/home/project/repository/cvs_repository";
$cvs = "/opt/sw/cvs/cvs-1.10.8/bin/cvs";
$modulename = "";

# parse command line arguments (file list is seen as one arg)
#
while (@ARGV) {
    $arg = shift @ARGV;

    if ($arg eq '-d') {
	$debug = 1;
	print STDERR "Debug turned on...\n";
    } elsif ($arg eq '-f') {
	($commitlog) && die("Too many '-f' args\n");
	$commitlog = shift @ARGV;
    } else {
	($donefiles) && die("Too many arguments!  Check usage.\n");
	$donefiles = 1;
	@files = split(/ /, $arg);
    }
}

# for now, the first "file" is the repository directory being committed,
# relative to the $CVSROOT location
#
@path = split('/', $files[0]);

# XXX There are some ugly assumptions in here about module names and
# XXX directories relative to the $CVSROOT location -- really should
# XXX read $CVSROOT/CVSROOT/modules, but that's not so easy to do, since
# XXX we have to parse it backwards.
# XXX 
# XXX Fortunately it's relatively easy for the user to specify the
# XXX module name as appropriate with a '-M' via the directory
# XXX matching in autotag.
#
if ($modulename eq "") {
    $modulename = $path[0];	# I.e. the module name == top-level dir
}
if ($#path == 0) {
    $dir = ".";
} else {
    $dir = join('/', @path);
}
$dir = $dir . "/";

if ($debug) {
    print STDERR "module - ", $modulename, "\n";
    print STDERR "dir    - ", $dir, "\n";
    print STDERR "path   - ", join(":", @path), "\n";
    print STDERR "files  - ", join(":", @files), "\n";
}

# Check for a new directory first.  This appears with files set as follows:
#
#    files[0] - "path/name/newdir"
#    files[1] - "-"
#    files[2] - "New"
#    files[3] - "directory"
#
if ($files[2] =~ /New/ && $files[3] =~ /directory/) {
    local(@text);

    @text = ();
    push(@text, "New");
    push(@text, "");
    push(@text, $files[0]);
    push(@text, "");

    while (<STDIN>) {
	chop;			# Drop the newline
	push(@text, $_);
    }

    &process_log(@text);

    exit 0;
}

# Check for an import command.  This appears with files set as follows:
#
#    files[0] - "path/name"
#    files[1] - "-"
#    files[2] - "Imported"
#    files[3] - "sources"
#
if ($files[2] =~ /Imported/ && $files[3] =~ /sources/) {
    local(@text);

    @text = ();
    push(@text, "Import");
    push(@text, "");
    push(@text, $files[0]);
    push(@text, "");

    while (<STDIN>) {
	chop;			# Drop the newline
	push(@text, $_);
    }

    &process_log(@text);

    exit 0;
}

# Iterate over the body of the message collecting information.
#
while (<STDIN>) {
    chop;			# Drop the newline

    if (/^In directory/) {
	next;
    }

    if (/^Modified Files/) { $state = $STATE_CHANGED; next; }
    if (/^Added Files/)    { $state = $STATE_ADDED; next; }
    if (/^Removed Files/)  { $state = $STATE_REMOVED; next; }
    if (/^Log Message/)    { $state = $STATE_LOG; next; }

    s/^[ \t\n]+//;		# delete leading whitespace
    s/[ \t\n]+$//;		# delete trailing whitespace
    
#    if ($state == $STATE_CHANGED) { push(@changed_files, split); }
#    if ($state == $STATE_ADDED)   { push(@added_files,   split); }
#    if ($state == $STATE_REMOVED) { push(@removed_files, split); }
     if ($state == $STATE_LOG)     { push(@log_lines,     $_); }
}

# Strip leading and trailing blank lines from the log message.  Also
# compress multiple blank lines in the body of the message down to a
# single blank line.
#
while ($#log_lines > -1) {
    last if ($log_lines[0] ne "");
    shift(@log_lines);
}
while ($#log_lines > -1) {
    last if ($log_lines[$#log_lines] ne "");
    pop(@log_lines);
}
for ($i = $#log_lines; $i > 0; $i--) {
    if (($log_lines[$i - 1] eq "") && ($log_lines[$i] eq "")) {
	splice(@log_lines, $i, 1);
    }
}

&process_log(@log_lines);

exit 0;

#
# End Main Body
#########################


#########################
# Begin Subroutines
#

sub process_log {

    local(@text) = @_;
    local(@info) = ();
    local($modfiles) = "";
    local($tagname) = "";
    local($defect) = "";
    local($cr) = "";
    local($scr) = "";
    local($defect_cmd) = "";
    local($cr_cmd) = "";
    local($scr_cmd) = "";

if ($debug) {
    print join("\n", @text), "\n";
}

# Search for strings of interest and strip leading and trailing spaces
    foreach $line (@text) {

        if ( $line =~ m/^Tag: / ) {
            $tagname=$line;
            $tagname=~s/^Tag: //;
            $tagname=~s/^\s+//;
            $tagname=~s/\s+$//;
        }
        if ( $line =~ m/^Defect #:/ ) {
            $defect_line=$line;
            $defect_line=~s/^Defect #://;
            $defect_line=~s/^\s+//;
            $defect_line=~s/\s+$//;
            @all_defects=split(/;|,| /, $defect_line);
        }
        if ( $line =~ m/^SCR #:/ ) {
            $scr_line=$line;
            $scr_line=~s/^SCR #://;
            $scr_line=~s/^\s+//;
            $scr_line=~s/\s+$//;
            @all_scrs=split(/;|,| /, $scr_line);
        }
        if ( $line =~ m/^Change Request #:/ ) {
            $cr_line=$line;
            $cr_line=~s/^Change Request #://;
            $cr_line=~s/^\s+//;
            $cr_line=~s/\s+$//;
            @all_crs=split(/;|,| /, $cr_line);
        }
    }

    for ( $i = 1; $i <= $#files; $i++ ) {
        $modfiles = $modfiles . "$files[0]/$files[$i] ";
    }
    $modfiles=~s/\s+$//;

    $dt = localtime(time());
    push( @info, "Date: $dt" );
    push( @info, "Files: $modfiles" );
    push( @info, "Tag: $tagname");

    for ( $i = 0; $i <= $#all_defects; $i++ ) {
        push( @info, "Defect: $all_defects[$i]");
        $defect_cmd = "";
	$defect = $all_defects[$i];
        $defect=~s/^\s+//;
        $defect=~s/\s+$//;
        if( $defect != "" ) {
            if( !( $tagname eq "" ) ) {
                $nobranch=$tagname;
                $nobranch=~s/_BRANCH$//;
                $defect_tag = $nobranch . "_SCR_" . $defect; 
                $defect_cmd = "$cvs -d $cvsroot rtag -F -r $tagname $defect_tag $modfiles";
            }
            else {
                $defect_tag = uc($modulename) . "_SCR_" . $defect; 
                $defect_cmd = "$cvs -d $cvsroot rtag -F $defect_tag $modfiles";
            }
            if ( ! ( $defect_cmd eq "" ) ){
                push ( @info, "Command: $defect_cmd" );
		$st=(2*($i));
                system("(sleep $st; $defect_cmd >> $commitlog 2>&1)&");
            }
        }
    }
    
    for ( $i = 0; $i <= $#all_crs; $i++ ) {
        push( @info, "CR: $all_crs[$i]");
	$cr_cmd = "";
	$cr = $all_crs[$i];
        $cr=~s/^\s+//;
        $cr=~s/\s+$//;
        if( $cr != "" ) {
            if( !( $tagname eq "" ) ) {
                $nobranch=$tagname;
                $nobranch=~s/_BRANCH$//;
                $cr_tag = $nobranch . "_SCR_" . $cr; 
                $cr_cmd = "$cvs -d $cvsroot rtag -F -r $tagname $cr_tag $modfiles";
            }
            else {
                $cr_tag = uc($modulename) . "_SCR_" . $cr; 
                $cr_cmd = "$cvs -d $cvsroot rtag -F $cr_tag $modfiles";
            }
        }
        if ( ! ( $cr_cmd eq "" ) ){
            push ( @info, "Command: $cr_cmd" );
            $st=(1+2*($i));
            system("(sleep $st; $cr_cmd >> $commitlog 2>&1)&");
        }
    }

    for ( $i = 0; $i <= $#all_scrs; $i++ ) {
        push( @info, "SCR: $all_scrs[$i]");
        $scr_cmd = "";
	$scr = $all_scrs[$i];
        $scr=~s/^\s+//;
        $scr=~s/\s+$//;
        if( $scr != "" ) {
            if( !( $tagname eq "" ) ) {
                $nobranch=$tagname;
                $nobranch=~s/_BRANCH$//;
                $scr_tag = $nobranch . "_SCR_" . $scr; 
                $scr_cmd = "$cvs -d $cvsroot rtag -F -r $tagname $scr_tag $modfiles";
            }
            else {
                $scr_tag = uc($modulename) . "_SCR_" . $scr; 
                $scr_cmd = "$cvs -d $cvsroot rtag -F $scr_tag $modfiles";
            }
            if ( ! ( $scr_cmd eq "" ) ){
                push ( @info, "Command: $scr_cmd" );
		$st=(2*($i));
                system("(sleep $st; $scr_cmd >> $commitlog 2>&1)&");
            }
        }
    }
    
    
    # Write to the commitlog file
    #
    if ($commitlog) {
        &write_commitlog($commitlog, @info);
    }


}

sub write_commitlog {
    local($logfile, @text) = @_;

    open(FILE, ">>$logfile");
    print FILE join("\n", @text), "\n";
    close(FILE);
}

#
# End Subroutines
#########################

