Rev 1295 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#! /usr/bin/perl# -*-Perl-*-### Perl filter to handle pre-commit checking of files. This program# records the last directory where commits will be taking place for# use by the log_accum.pl script. For new files, it forces the# existence of a RCS "Id" keyword in the first ten lines of the file.# For existing files, it checks version number in the "Id" line to# prevent losing changes because an old version of a file was copied# into the direcory.## Possible future enhancements:## Check for cruft left by unresolved conflicts. Search for# "^<<<<<<<$", "^-------$", and "^>>>>>>>$".## Look for a copyright and automagically update it to the# current year. [[ bad idea! -- woods ]]### Contributed by David Hampton <hampton@cisco.com>## Hacked on lots by Greg A. Woods <woods@web.net>## Configurable options## Constants (remember to protect strings from RCS keyword substitution)#$LAST_FILE = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl$ENTRIES = "CVS/Entries";# Patterns to find $Log keywords in files#$LogString1 = "\\\$\\Log: .* \\\$";$LogString2 = "\\\$\\Log\\\$";$NoLog = "%s - contains an RCS \$Log keyword. It must not!\n";# pattern to match an RCS Id keyword line with an existing ID#$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";$NoId = "%s - Does not contain a properly formatted line with the keyword \"Id:\".I.e. no lines match \"" . $IDstring . "\".Please see the template files for an example.\n";# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)#$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";$NoName = "%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"for a newly created file.\n";$BadName = "%s - The file name '%s' in the ID line does not matchthe actual filename.\n";$BadVersion = "%s - How dare you!!! You replaced your copy of the file '%s',which was based upon version %s, with an %s version basedupon %s. Please move your '%s' out of the way, perform anupdate to get the current version, and them merge your changesinto that file, then try the commit again.\n";## Subroutines#sub write_line {local($filename, $line) = @_;open(FILE, ">$filename") || die("Cannot open $filename, stopped");print(FILE $line, "\n");close(FILE);}sub check_version {local($i, $id, $rname, $version);local($filename, $cvsversion) = @_;open(FILE, "<$filename") || return(0);@all_lines = ();$idpos = -1;$newidpos = -1;for ($i = 0; <FILE>; $i++) {chop;push(@all_lines, $_);if ($_ =~ /$IDstring/) {$idpos = $i;}if ($_ =~ /$NewId/) {$newidpos = $i;}}if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {print STDERR sprintf($NoLog, $filename);return(1);}if ($debug != 0) {print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});}if ($cvsversion{$filename} == 0) {if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {print STDERR sprintf($NoName, $filename);return(1);}return(0);}if ($idpos == -1) {print STDERR sprintf($NoId, $filename);return(1);}$line = $all_lines[$idpos];$pos = index($line, "Id: ");if ($debug != 0) {print STDERR sprintf("%d in '%s'.\n", $pos, $line);}($id, $rname, $version) = split(' ', substr($line, $pos));if ($rname ne "$filename,v") {print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));return(1);}if ($cvsversion{$filename} < $version) {print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},"newer", $version, $filename);return(1);}if ($cvsversion{$filename} > $version) {print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},"older", $version, $filename);return(1);}return(0);}## Main Body#$id = getpgrp(); # You *must* use a shell that does setpgrp()!# Check each file (except dot files) for an RCS "Id" keyword.#$check_id = 0;# Record the directory for later use by the log_accumulate stript.#$record_directory = 0;# parse command line arguments#while (@ARGV) {$arg = shift @ARGV;if ($arg eq '-d') {$debug = 1;print STDERR "Debug turned on...\n";} elsif ($arg eq '-c') {$check_id = 1;} elsif ($arg eq '-r') {$record_directory = 1;} else {push(@files, $arg);}}$directory = shift @files;if ($debug != 0) {print STDERR "dir - ", $directory, "\n";print STDERR "files - ", join(":", @files), "\n";print STDERR "id - ", $id, "\n";}# Suck in the CVS/Entries file#open(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");while (<ENTRIES>) {local($filename, $version) = split('/', substr($_, 1));$cvsversion{$filename} = $version;}# Now check each file name passed in, except for dot files. Dot files# are considered to be administrative files by this script.#if ($check_id != 0) {$failed = 0;foreach $arg (@files) {if (index($arg, ".") == 0) {next;}$failed += &check_version($arg);}if ($failed) {print STDERR "\n";exit(1);}}# Record this directory as the last one checked. This will be used# by the log_accumulate script to determine when it is processing# the final directory of a multi-directory commit.#if ($record_directory != 0) {&write_line("$LAST_FILE.$id", $directory);}exit(0);