xref: /openbsd-src/gnu/usr.bin/cvs/contrib/commit_prep.in (revision 43c1707e6f6829177cb1974ee6615ce6c1307689)
1*43c1707eStholo#! @PERL@
2*43c1707eStholo# -*-Perl-*-
3*43c1707eStholo#
4*43c1707eStholo#
5*43c1707eStholo# Perl filter to handle pre-commit checking of files.  This program
6*43c1707eStholo# records the last directory where commits will be taking place for
7*43c1707eStholo# use by the log_accum.pl script.  For new files, it forces the
8*43c1707eStholo# existence of a RCS "Id" keyword in the first ten lines of the file.
9*43c1707eStholo# For existing files, it checks version number in the "Id" line to
10*43c1707eStholo# prevent losing changes because an old version of a file was copied
11*43c1707eStholo# into the direcory.
12*43c1707eStholo#
13*43c1707eStholo# Possible future enhancements:
14*43c1707eStholo#
15*43c1707eStholo#    Check for cruft left by unresolved conflicts.  Search for
16*43c1707eStholo#    "^<<<<<<<$", "^-------$", and "^>>>>>>>$".
17*43c1707eStholo#
18*43c1707eStholo#    Look for a copyright and automagically update it to the
19*43c1707eStholo#    current year.  [[ bad idea!  -- woods ]]
20*43c1707eStholo#
21*43c1707eStholo#
22*43c1707eStholo# Contributed by David Hampton <hampton@cisco.com>
23*43c1707eStholo#
24*43c1707eStholo# Hacked on lots by Greg A. Woods <woods@web.net>
25*43c1707eStholo
26*43c1707eStholo#
27*43c1707eStholo#	Configurable options
28*43c1707eStholo#
29*43c1707eStholo
30*43c1707eStholo# Constants (remember to protect strings from RCS keyword substitution)
31*43c1707eStholo#
32*43c1707eStholo$LAST_FILE     = "/tmp/#cvs.lastdir"; # must match name in log_accum.pl
33*43c1707eStholo$ENTRIES       = "CVS/Entries";
34*43c1707eStholo
35*43c1707eStholo# Patterns to find $Log keywords in files
36*43c1707eStholo#
37*43c1707eStholo$LogString1 = "\\\$\\Log: .* \\\$";
38*43c1707eStholo$LogString2 = "\\\$\\Log\\\$";
39*43c1707eStholo$NoLog = "%s - contains an RCS \$Log keyword.  It must not!\n";
40*43c1707eStholo
41*43c1707eStholo# pattern to match an RCS Id keyword line with an existing ID
42*43c1707eStholo#
43*43c1707eStholo$IDstring = "\"@\\(#\\)[^:]*:.*\\\$\Id: .*\\\$\"";
44*43c1707eStholo$NoId = "
45*43c1707eStholo%s - Does not contain a properly formatted line with the keyword \"Id:\".
46*43c1707eStholo	I.e. no lines match \"" . $IDstring . "\".
47*43c1707eStholo	Please see the template files for an example.\n";
48*43c1707eStholo
49*43c1707eStholo# pattern to match an RCS Id keyword line for a new file (i.e. un-expanded)
50*43c1707eStholo#
51*43c1707eStholo$NewId = "\"@(#)[^:]*:.*\\$\Id\\$\"";
52*43c1707eStholo
53*43c1707eStholo$NoName = "
54*43c1707eStholo%s - The ID line should contain only \"@(#)module/path:\$Name\$:\$\Id\$\"
55*43c1707eStholo	for a newly created file.\n";
56*43c1707eStholo
57*43c1707eStholo$BadName = "
58*43c1707eStholo%s - The file name '%s' in the ID line does not match
59*43c1707eStholo	the actual filename.\n";
60*43c1707eStholo
61*43c1707eStholo$BadVersion = "
62*43c1707eStholo%s - How dare you!!!  You replaced your copy of the file '%s',
63*43c1707eStholo	which was based upon version %s, with an %s version based
64*43c1707eStholo	upon %s.  Please move your '%s' out of the way, perform an
65*43c1707eStholo	update to get the current version, and them merge your changes
66*43c1707eStholo	into that file, then try the commit again.\n";
67*43c1707eStholo
68*43c1707eStholo#
69*43c1707eStholo#	Subroutines
70*43c1707eStholo#
71*43c1707eStholo
72*43c1707eStholosub write_line {
73*43c1707eStholo    local($filename, $line) = @_;
74*43c1707eStholo    open(FILE, ">$filename") || die("Cannot open $filename, stopped");
75*43c1707eStholo    print(FILE $line, "\n");
76*43c1707eStholo    close(FILE);
77*43c1707eStholo}
78*43c1707eStholo
79*43c1707eStholosub check_version {
80*43c1707eStholo    local($i, $id, $rname, $version);
81*43c1707eStholo    local($filename, $cvsversion) = @_;
82*43c1707eStholo
83*43c1707eStholo    open(FILE, "<$filename") || return(0);
84*43c1707eStholo
85*43c1707eStholo    @all_lines = ();
86*43c1707eStholo    $idpos = -1;
87*43c1707eStholo    $newidpos = -1;
88*43c1707eStholo    for ($i = 0; <FILE>; $i++) {
89*43c1707eStholo	chop;
90*43c1707eStholo	push(@all_lines, $_);
91*43c1707eStholo	if ($_ =~ /$IDstring/) {
92*43c1707eStholo	    $idpos = $i;
93*43c1707eStholo	}
94*43c1707eStholo	if ($_ =~ /$NewId/) {
95*43c1707eStholo	    $newidpos = $i;
96*43c1707eStholo	}
97*43c1707eStholo    }
98*43c1707eStholo
99*43c1707eStholo    if (grep(/$LogString1/, @all_lines) || grep(/$LogString2/, @all_lines)) {
100*43c1707eStholo	print STDERR sprintf($NoLog, $filename);
101*43c1707eStholo	return(1);
102*43c1707eStholo    }
103*43c1707eStholo
104*43c1707eStholo    if ($debug != 0) {
105*43c1707eStholo	print STDERR sprintf("file = %s, version = %d.\n", $filename, $cvsversion{$filename});
106*43c1707eStholo    }
107*43c1707eStholo
108*43c1707eStholo    if ($cvsversion{$filename} == 0) {
109*43c1707eStholo	if ($newidpos != -1 && $all_lines[$newidpos] !~ /$NewId/) {
110*43c1707eStholo	    print STDERR sprintf($NoName, $filename);
111*43c1707eStholo	    return(1);
112*43c1707eStholo	}
113*43c1707eStholo	return(0);
114*43c1707eStholo    }
115*43c1707eStholo
116*43c1707eStholo    if ($idpos == -1) {
117*43c1707eStholo	print STDERR sprintf($NoId, $filename);
118*43c1707eStholo	return(1);
119*43c1707eStholo    }
120*43c1707eStholo
121*43c1707eStholo    $line = $all_lines[$idpos];
122*43c1707eStholo    $pos = index($line, "Id: ");
123*43c1707eStholo    if ($debug != 0) {
124*43c1707eStholo	print STDERR sprintf("%d in '%s'.\n", $pos, $line);
125*43c1707eStholo    }
126*43c1707eStholo    ($id, $rname, $version) = split(' ', substr($line, $pos));
127*43c1707eStholo    if ($rname ne "$filename,v") {
128*43c1707eStholo	print STDERR sprintf($BadName, $filename, substr($rname, 0, length($rname)-2));
129*43c1707eStholo	return(1);
130*43c1707eStholo    }
131*43c1707eStholo    if ($cvsversion{$filename} < $version) {
132*43c1707eStholo	print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
133*43c1707eStholo			     "newer", $version, $filename);
134*43c1707eStholo	return(1);
135*43c1707eStholo    }
136*43c1707eStholo    if ($cvsversion{$filename} > $version) {
137*43c1707eStholo	print STDERR sprintf($BadVersion, $filename, $filename, $cvsversion{$filename},
138*43c1707eStholo			     "older", $version, $filename);
139*43c1707eStholo	return(1);
140*43c1707eStholo    }
141*43c1707eStholo    return(0);
142*43c1707eStholo}
143*43c1707eStholo
144*43c1707eStholo#
145*43c1707eStholo#	Main Body
146*43c1707eStholo#
147*43c1707eStholo
148*43c1707eStholo$id = getpgrp();		# You *must* use a shell that does setpgrp()!
149*43c1707eStholo
150*43c1707eStholo# Check each file (except dot files) for an RCS "Id" keyword.
151*43c1707eStholo#
152*43c1707eStholo$check_id = 0;
153*43c1707eStholo
154*43c1707eStholo# Record the directory for later use by the log_accumulate stript.
155*43c1707eStholo#
156*43c1707eStholo$record_directory = 0;
157*43c1707eStholo
158*43c1707eStholo# parse command line arguments
159*43c1707eStholo#
160*43c1707eStholowhile (@ARGV) {
161*43c1707eStholo    $arg = shift @ARGV;
162*43c1707eStholo
163*43c1707eStholo    if ($arg eq '-d') {
164*43c1707eStholo	$debug = 1;
165*43c1707eStholo	print STDERR "Debug turned on...\n";
166*43c1707eStholo    } elsif ($arg eq '-c') {
167*43c1707eStholo	$check_id = 1;
168*43c1707eStholo    } elsif ($arg eq '-r') {
169*43c1707eStholo	$record_directory = 1;
170*43c1707eStholo    } else {
171*43c1707eStholo	push(@files, $arg);
172*43c1707eStholo    }
173*43c1707eStholo}
174*43c1707eStholo
175*43c1707eStholo$directory = shift @files;
176*43c1707eStholo
177*43c1707eStholoif ($debug != 0) {
178*43c1707eStholo    print STDERR "dir   - ", $directory, "\n";
179*43c1707eStholo    print STDERR "files - ", join(":", @files), "\n";
180*43c1707eStholo    print STDERR "id    - ", $id, "\n";
181*43c1707eStholo}
182*43c1707eStholo
183*43c1707eStholo# Suck in the CVS/Entries file
184*43c1707eStholo#
185*43c1707eStholoopen(ENTRIES, $ENTRIES) || die("Cannot open $ENTRIES.\n");
186*43c1707eStholowhile (<ENTRIES>) {
187*43c1707eStholo    local($filename, $version) = split('/', substr($_, 1));
188*43c1707eStholo    $cvsversion{$filename} = $version;
189*43c1707eStholo}
190*43c1707eStholo
191*43c1707eStholo# Now check each file name passed in, except for dot files.  Dot files
192*43c1707eStholo# are considered to be administrative files by this script.
193*43c1707eStholo#
194*43c1707eStholoif ($check_id != 0) {
195*43c1707eStholo    $failed = 0;
196*43c1707eStholo    foreach $arg (@files) {
197*43c1707eStholo	if (index($arg, ".") == 0) {
198*43c1707eStholo	    next;
199*43c1707eStholo	}
200*43c1707eStholo	$failed += &check_version($arg);
201*43c1707eStholo    }
202*43c1707eStholo    if ($failed) {
203*43c1707eStholo	print STDERR "\n";
204*43c1707eStholo	exit(1);
205*43c1707eStholo    }
206*43c1707eStholo}
207*43c1707eStholo
208*43c1707eStholo# Record this directory as the last one checked.  This will be used
209*43c1707eStholo# by the log_accumulate script to determine when it is processing
210*43c1707eStholo# the final directory of a multi-directory commit.
211*43c1707eStholo#
212*43c1707eStholoif ($record_directory != 0) {
213*43c1707eStholo    &write_line("$LAST_FILE.$id", $directory);
214*43c1707eStholo}
215*43c1707eStholoexit(0);
216