aboutsummaryrefslogblamecommitdiffstats
path: root/CVSROOT/edithook
blob: 900093025dcc000655e2665407bd08d821bc9ab9 (plain) (tree)































































































































































































































































































































































































                                                                                                                           
#!/usr/bin/perl
#
#   $Id$
#

# Perl filter to handle cvs editinfo preparation of log messge

# This filter should be named in the $CVSROOT/CVSROOT/editinfo file
# for any modules you wish to add the gnats bug system bugid and
# header.
# A line like "DEFAULT      /path/to/this/perl/script"
# will do the trick.

# Some tracking information may be logged
$debugging = 0;         # used in sub debug   for tracking
$logging   = 0;         # used in sub log     for tracking

$debugging = 1 if (defined $ENV{'CVSDEBUGEDIT'});

#########################################################################
#
# derrived information needed below
#
#########################################################################

$login = (getpwuid($<))[0] || "Anonymous"; # get user's login name


#########################################################################
#
# Paths to utilities
#
#########################################################################

$defaultEditorCmd  = '/usr/bin/vi'; # use env $EDITOR to override
$editorCmd         = ((defined $ENV{'EDITOR'}) ?
                      $ENV{'EDITOR'} :
              ((defined $ENV{'EDITOR'}) ?
               $ENV{'EDITOR'} : $defaultEditorCmd));


#########################################################################
#
# Constants
#
#########################################################################
$BadTmpDir = "
It is a very bad idea for the environment variable TMPDIR
currently set to \'$ENV{'TMPDIR'}\' to be a relative pathname.
Please choose something with a leading slash (/tmp) for example
\n";

$MissingTmpDir = "
It is a very bad idea for the environment variable TMPDIR
currently set to \'$ENV{'TMPDIR'}\' to be directory which does not
exist. Please create this directory and give it read-write permissions
to group cisco.
\n";


#########################################################################
#
# Inter-filter communication file names
#
#########################################################################

# Do not change these constants without changing them in the other
# scripts as well.

$pgrp          = getpgrp();     # parent process id

if (defined $ENV{'TMPDIR'}) {
    # trivial sanity check, are we able to write into this directory?
    if ($ENV{'TMPDIR'} !~ /^\//) {
    &debug("Bad... TMPDIR is not a full pathname");
    &abort($BadTmpDir);
    }
    elsif ( -d $ENV{'TMPDIR'} && -w _ ) {
    &debug("Good.. TMPDIR references a directory we can use");
    $tmpDir = $ENV{'TMPDIR'};
    }
    else {
    &debug("Bad... TMPDIR is not a directory in which we can write files");
    &abort($MissingTmpDir);
    }
}
else {
    $tmpDir = '/tmp';
    if ( -d $tmpDir && -w _ ) {
    &debug("Good.. $tmpDir looks like we can use it");
    }
    else {
    &debug("Bad... $tmpDir is not a directory in which we can write files");
    &abort("This system is in real trouble $tmpDir is not writable");
    }
}

$gnatsReportFile   = $tmpDir . '/' . $login . '.cvsgnats'    . $pgrp;
$logFile       = $tmpDir . '/' . $login . '.cvslog'      . $pgrp;

#########################################################################
#
# main
#
#########################################################################

if (! @ARGV) {
    &abort( "No message filename was given. Usage: $0 cvs-log-file\n" );
}

$userLogMessageFile = $ARGV[0];

&create_timestamps();
$hostname = `hostname`;
chop($hostname);

if ($logging) {
    if (!open(LOGFILE, ">> $logFile")) {
    warn "Cannot open log file: $logFile\nturning logging off";
    $logging = 0;
    }

    &log("Start: sys_editinfo attempt by $login at $date");
    &log("Command: $0" . join(' ',@ARGV));
}

&debug("Command: $0 \'" . join('\' \'',@ARGV).'\'');

# $gnatsReportFile will already have built by commitinfo
if ( -e $gnatsReportFile ) {
    &debug("using existing gnats report: $gnatsReportFile");

    # Get bug Id from gnats report
    $bugId = '';
    $bugBranch = '';
    ($bugId, $bugBranch, $headline) =
    &getBugId_from_gnatsreport( $gnatsReportFile );
    $bugBranch =~ s/^-//;   # remove leading dash

    &log("Bug Id $bugId extracted from $gnatsReportFile");
    &log("Headline $headline extracted from $gnatsReportFile");
    &log("Branch \'$bugBranch\' extracted from $gnatsReportFile");

    # If we have a valid bug id, complete bug file names
    if ( $bugId eq '' ) {
    warn "Bug Id not found in GNATS report $gnatsReportFile";
    }
}

@loglines = &read_file( $userLogMessageFile );
if (($bugId ne '') && ($bugId ne 'sync') && ($bugId ne 'new') &&
    ($bugId ne 'placeholder')) {
    if (! grep(/$bugId/, @loglines)) {
    &debug("adding bugid and headline to $userLogMessageFile");
    &debug(">>>$bugId: $headline");
    push(@loglines, $bugId.': '.$headline);
    &write_file( $userLogMessageFile, @loglines );
    }
}
if ($bugBranch ne '') {
    if (! grep(/^Branch:/, @loglines)) {
    &debug("adding Branch information to $userLogMessageFile");
    &debug(">>>Branch: $bugBranch");
    push(@loglines, 'Branch: '.$bugBranch);
    &write_file( $userLogMessageFile, @loglines );
    }
}

$doedit = 1;
while ($doedit) {
    $doedit = 0;
    $diff = 0;

    while (&editFile( $editorCmd, $userLogMessageFile )) {
    print "A non-zero return code usually means that either something\n";
    print "went wrong with your edit session, or you were using vi\n";
    print "and executed a bad command. You may wish to edit $userLogMessageFile\n";
    print "from some other window before answering this next query.\n";
    print "a \'y\' will try the edit command once more and a \'n\'\n";
    print "will fall through and proces the log message at once\n";
    print "Do you wish me to run the command\n";
    $ans = &yes_no("$editorCmd $userLogMessageFile ?", 'n');
    last if ($ans eq 'n');
    }

    @statlines = grep(/^Reviewed by:\s*\S+|^Submitted by:\s*\S+|Obtained from:\s*\S+/, &read_file ( $userLogMessageFile ));

    @loglines = grep(!/^CVS:|^Reviewed by:|^Submitted by:|^Obtained from:/, &read_file( $userLogMessageFile ));

    $orig = join("\n", @loglines);
    $maxlen = 0;
    foreach (@loglines) {
    $save = $_;
    s/[ \t\n]+$//;      # delete trailing space
    1 while s/\t+/' 'x (length($&) * 8 - length($`) % 8)/e; # expand tabs
    s,/\*,/ *,g;        # defuse C Comment start
    s,\*/,* /,g;        # defuse C Comment end
    $diff = 1 if ($save ne $_);
    $maxlen = length($_) if (length($_) > $maxlen);
    }

    if ($maxlen > 72) {
    &write_file( $userLogMessageFile, @loglines );
    open(FMT, "fmt -s $userLogMessageFile |")
        || die "unable to use fmt: $!";
    @loglines = <FMT>;
    close(FMT);

    foreach (@loglines) {
        chop;
        1 while s/\t+/' 'x (length($&) * 8 - length($`) % 8)/e; # expand tabs
    }
    }

    $leading = 200;
    foreach (@loglines) {
    next if /^$/;
    # notice leading whitespace
    ($tmp = $_) =~ s/^(\s*).*$/$1/;
    $leading = length($tmp) if (length($tmp) < $leading);
    }

    # nuke $leading blanks
    if ($leading > 0) {
    &debug("removing $leading leading spaces");
    $tmp = ' ' x $leading;
    foreach (@loglines) {
        s/^$tmp//;
    }
    }
    
    $new = join("\n",@loglines);
    if ($orig ne $new) {
    @loglines = ( @statlines, @loglines );
    &write_file( $userLogMessageFile, @loglines );

    print STDERR "=============== New log text ===============\n";
    print STDERR join("\n", @loglines);
    print STDERR "\n=============== end log text ===============\n\n";
    $ans = &yes_no("Formated log differs from original text. Use it?", 'y');
    exit(0) if ($ans eq 'y');
    $ans = &yes_no("Do you wish to edit the text?", 'y');
    if ($ans eq 'n') {
        $ans = &yes_no("Ok to abort?", 'n');
        &abort("terminated by user request") if ($ans eq 'y');
    }
    $doedit = 1;
    }
}

@loglines = &read_file( $userLogMessageFile );
if (($bugId ne '') && ($bugId ne 'sync') && ($bugId ne 'new') &&
    ($bugId ne 'placeholder')) {
    if (! grep(/$bugId/, @loglines)) {
    print STDERR "\n  Please note that removing $bugId\n";
    print STDERR "  from the log message is not good.\n\n";
    }
}

close(LOGFILE) if ($logging);

exit(0);


#########################################################################
#
# Subroutines
#
#########################################################################


sub abort {
    local( $abortMsg ) = @_;
    die ( "[ERROR] ", "$abortMsg\n" );
}

sub create_timestamps {
    ($sec,$min,$hour,$mday,$mon,$year) = localtime;
    $today  = sprintf("%02d/%02d/%02d", $mon+1, $mday, $year);
    $nowtime    = sprintf("%02d:%02d:%02d", $hour, $min, $sec);
    $date   = $today . ' ' . $nowtime;
}

sub debug {
    print @_, "\n" if ( $debugging );
}

sub editFile {
    local( $editor, $filename ) = @_;
    local( $return_code );

    &debug("editing file: $filename");
    print "invoking editor...\n$editor $filename\n";
    $return_code = system("$editor $filename");
    $return_code = $return_code / 256;
    if ($return_code) {
    print "$editor returned with an error code of $return_code\n";
    }
    $return_code;
}

sub log {
    print LOGFILE @_, "\n" if ($logging);
}

sub read_file {
    local($filename) = @_;
    local(@text);

    &debug("read file $filename");
    open(FILE, "<$filename") || return ();
    while (<FILE>) {
    chop;
    push(@text, $_);
    }
    close(FILE);
    @text;
}

sub write_file {
    local($filename, @lines) = @_;

    &debug("Writing file $filename");
    open(FILE, ">$filename") || die ("Cannot open log file $filename.\n");
    foreach (@lines) {
    print FILE $_, "\n";
    }
    close(FILE);
}

sub getBugId_from_gnatsreport {
    local( $diffsFile ) = @_;
    local( $bug_id, $branch, $headline );

    &debug( "Opening file $diffsFile to get Bug Id");
    open ( GNATSREPORT, $diffsFile ) ||
    &abort( "Can't open gnats report $diffsFile" );

    $bug_id = 'NULL';
    $branch = 'NULL';
    $headline = '';
    # Find the Bug Id
    while ( <GNATSREPORT> ) {
    chop;
    if ( /^Start: / ) {
        ($bug_id = $_) =~ s/[^:]*: //;
        &debug( "Bug Id = $bug_id" );
        $headline = 'syncronization commit' if ($bug_id eq 'sync');
    }
    elsif ( /^Headline:/) {
        ($headline = $_) =~ s/[^:]*://;
        &debug( "Headline = $headline" );
    }
    elsif ( /^Branch: / ) {
        ($branch = $_) =~ s/[^:]*: //;
        if ( $branch eq '' ) {
        &debug( "Branch = \'\' (main trunk)" );
        }
        else {
        &debug( "Branch = $branch" );
        }
    }
    last if (($bug_id ne 'NULL') && ($branch ne 'NULL') &&
         ($headline ne ''));
    }
    close ( GNATSREPORT );
    return ($bug_id, $branch, $headline);
}

# yes_no - ask the user the specified question - repeatedly, until
#      they answer with a valid answer (i.e. yes or no).  Returns
#      "n" or "y".
sub yes_no {
    local($ques, $default) = @_;

    for (;;) {
    print "$ques [$default] ";
    $_ = <STDIN>;
    chop;
    /^[yY]$/ && return "y";
    /^[nN]$/ && return "n";
    return $default if (!$_ && $default);
    }
}