xref: /openbsd-src/gnu/usr.bin/cvs/contrib/rcslock.in (revision 43c1707e6f6829177cb1974ee6615ce6c1307689)
1*43c1707eStholo#! @PERL@
2*43c1707eStholo# -*-Perl-*-
3*43c1707eStholo
4*43c1707eStholo# Author: John Rouillard (rouilj@cs.umb.edu)
5*43c1707eStholo# Supported: Yeah right. (Well what do you expect for 2 hours work?)
6*43c1707eStholo# Blame-to: rouilj@cs.umb.edu
7*43c1707eStholo# Complaints to: Anybody except Brian Berliner, he's blameless for
8*43c1707eStholo#		 this script.
9*43c1707eStholo# Acknowlegements: The base code for this script has been acquired
10*43c1707eStholo# 		   from the log.pl script.
11*43c1707eStholo
12*43c1707eStholo# rcslock.pl - A program to prevent commits when a file to be ckecked
13*43c1707eStholo# 	       in is locked in the repository.
14*43c1707eStholo
15*43c1707eStholo# There are times when you need exclusive access to a file.  This
16*43c1707eStholo# often occurs when binaries are checked into the repository, since
17*43c1707eStholo# cvs's (actually rcs's) text based merging mechanism won't work. This
18*43c1707eStholo# script allows you to use the rcs lock mechanism (rcs -l) to make
19*43c1707eStholo# sure that no changes to a repository are able to be committed if
20*43c1707eStholo# those changes would result in a locked file being changed.
21*43c1707eStholo
22*43c1707eStholo# WARNING:
23*43c1707eStholo# This script will work only if locking is set to strict.
24*43c1707eStholo#
25*43c1707eStholo
26*43c1707eStholo# Setup:
27*43c1707eStholo# Add the following line to the commitinfo file:
28*43c1707eStholo
29*43c1707eStholo#         ALL /local/location/for/script/lockcheck [options]
30*43c1707eStholo
31*43c1707eStholo# Where ALL is replaced by any suitable regular expression.
32*43c1707eStholo# Options are -v for verbose info, or -d for debugging info.
33*43c1707eStholo# The %s will provide the repository directory name and the names of
34*43c1707eStholo# all changed files.
35*43c1707eStholo
36*43c1707eStholo# Use:
37*43c1707eStholo# When a developer needs exclusive access to a version of a file, s/he
38*43c1707eStholo# should use "rcs -l" in the repository tree to lock the version they
39*43c1707eStholo# are working on.  CVS will automagically release the lock when the
40*43c1707eStholo# commit is performed.
41*43c1707eStholo
42*43c1707eStholo# Method:
43*43c1707eStholo# An "rlog -h" is exec'ed to give info on all about to be
44*43c1707eStholo# committed files.  This (header) information is parsed to determine
45*43c1707eStholo# if any locks are outstanding and what versions of the file are
46*43c1707eStholo# locked.  This filename, version number info is used to index an
47*43c1707eStholo# associative array.  All of the files to be committed are checked to
48*43c1707eStholo# see if any locks are outstanding.  If locks are outstanding, the
49*43c1707eStholo# version number of the current file (taken from the CVS/Entries
50*43c1707eStholo# subdirectory) is used in the key to determine if that version is
51*43c1707eStholo# locked. If the file being checked in is locked by the person doing
52*43c1707eStholo# the checkin, the commit is allowed, but if the lock is held on that
53*43c1707eStholo# version of a file by another person, the commit is not allowed.
54*43c1707eStholo
55*43c1707eStholo$ext = ",v";  # The extension on your rcs files.
56*43c1707eStholo
57*43c1707eStholo$\="\n";  # I hate having to put \n's at the end of my print statements
58*43c1707eStholo$,=' ';   # Spaces should occur between arguments to print when printed
59*43c1707eStholo
60*43c1707eStholo# turn off setgid
61*43c1707eStholo#
62*43c1707eStholo$) = $(;
63*43c1707eStholo
64*43c1707eStholo#
65*43c1707eStholo# parse command line arguments
66*43c1707eStholo#
67*43c1707eStholorequire 'getopts.pl';
68*43c1707eStholo
69*43c1707eStholo&Getopts("vd"); # verbose or debugging
70*43c1707eStholo
71*43c1707eStholo# Verbose is useful when debugging
72*43c1707eStholo$opt_v = $opt_d if defined $opt_d;
73*43c1707eStholo
74*43c1707eStholo# $files[0] is really the name of the subdirectory.
75*43c1707eStholo# @files = split(/ /,$ARGV[0]);
76*43c1707eStholo@files = @ARGV[0..$#ARGV];
77*43c1707eStholo$cvsroot = $ENV{'CVSROOT'};
78*43c1707eStholo
79*43c1707eStholo#
80*43c1707eStholo# get login name
81*43c1707eStholo#
82*43c1707eStholo$login = getlogin || (getpwuid($<))[0] || "nobody";
83*43c1707eStholo
84*43c1707eStholo#
85*43c1707eStholo# save the current directory since we have to return here to parse the
86*43c1707eStholo# CVS/Entries file if a lock is found.
87*43c1707eStholo#
88*43c1707eStholo$pwd = `/bin/pwd`;
89*43c1707eStholochop $pwd;
90*43c1707eStholo
91*43c1707eStholoprint "Starting directory is $pwd" if defined $opt_d ;
92*43c1707eStholo
93*43c1707eStholo#
94*43c1707eStholo# cd to the repository directory and check on the files.
95*43c1707eStholo#
96*43c1707eStholoprint "Checking directory ", $files[0] if defined $opt_v ;
97*43c1707eStholo
98*43c1707eStholoif ( $files[0] =~ /^\// )
99*43c1707eStholo{
100*43c1707eStholo   print "Directory path is $files[0]" if defined $opt_d ;
101*43c1707eStholo   chdir $files[0] || die "Can't change to repository directory $files[0]" ;
102*43c1707eStholo}
103*43c1707eStholoelse
104*43c1707eStholo{
105*43c1707eStholo   print "Directory path is $cvsroot/$files[0]" if defined $opt_d ;
106*43c1707eStholo   chdir ($cvsroot . "/" . $files[0]) ||
107*43c1707eStholo         die "Can't change to repository directory $files[0] in $cvsroot" ;
108*43c1707eStholo}
109*43c1707eStholo
110*43c1707eStholo
111*43c1707eStholo# Open the rlog process and apss all of the file names to that one
112*43c1707eStholo# process to cut down on exec overhead.  This may backfire if there
113*43c1707eStholo# are too many files for the system buffer to handle, but if there are
114*43c1707eStholo# that many files, chances are that the cvs repository is not set up
115*43c1707eStholo# cleanly.
116*43c1707eStholo
117*43c1707eStholoprint "opening rlog -h @files[1..$#files] |" if defined $opt_d;
118*43c1707eStholo
119*43c1707eStholoopen( RLOG, "rlog -h @files[1..$#files] |") || die "Can't run rlog command" ;
120*43c1707eStholo
121*43c1707eStholo# Create the locks associative array.  The elements in the array are
122*43c1707eStholo# of two types:
123*43c1707eStholo#
124*43c1707eStholo#  The name of the RCS file with a value of the total number of locks found
125*43c1707eStholo#            for that file,
126*43c1707eStholo# or
127*43c1707eStholo#
128*43c1707eStholo# The name of the rcs file concatenated with the version number of the lock.
129*43c1707eStholo# The value of this element is the name of the locker.
130*43c1707eStholo
131*43c1707eStholo# The regular expressions used to split the rcs info may have to be changed.
132*43c1707eStholo# The current ones work for rcs 5.6.
133*43c1707eStholo
134*43c1707eStholo$lock = 0;
135*43c1707eStholo
136*43c1707eStholowhile (<RLOG>)
137*43c1707eStholo{
138*43c1707eStholo	chop;
139*43c1707eStholo	next if /^$/; # ditch blank lines
140*43c1707eStholo
141*43c1707eStholo	if ( $_ =~ /^RCS file: (.*)$/ )
142*43c1707eStholo	{
143*43c1707eStholo	   $curfile = $1;
144*43c1707eStholo	   next;
145*43c1707eStholo	}
146*43c1707eStholo
147*43c1707eStholo	if ( $_ =~ /^locks: strict$/ )
148*43c1707eStholo	{
149*43c1707eStholo  	  $lock = 1 ;
150*43c1707eStholo	  next;
151*43c1707eStholo	}
152*43c1707eStholo
153*43c1707eStholo	if ( $lock )
154*43c1707eStholo	{
155*43c1707eStholo	  # access list: is the line immediately following the list of locks.
156*43c1707eStholo	  if ( /^access list:/ )
157*43c1707eStholo	  { # we are done getting lock info for this file.
158*43c1707eStholo	    $lock = 0;
159*43c1707eStholo	  }
160*43c1707eStholo	  else
161*43c1707eStholo	  { # We are accumulating lock info.
162*43c1707eStholo
163*43c1707eStholo	    # increment the lock count
164*43c1707eStholo	    $locks{$curfile}++;
165*43c1707eStholo	    # save the info on the version that is locked. $2 is the
166*43c1707eStholo            # version number $1 is the name of the locker.
167*43c1707eStholo	    $locks{"$curfile" . "$2"} = $1
168*43c1707eStholo				if /[ 	]*([a-zA-Z._]*): ([0-9.]*)$/;
169*43c1707eStholo
170*43c1707eStholo	    print "lock by $1 found on $curfile version $2" if defined $opt_d;
171*43c1707eStholo
172*43c1707eStholo	  }
173*43c1707eStholo	}
174*43c1707eStholo}
175*43c1707eStholo
176*43c1707eStholo# Lets go back to the starting directory and see if any locked files
177*43c1707eStholo# are ones we are interested in.
178*43c1707eStholo
179*43c1707eStholochdir $pwd;
180*43c1707eStholo
181*43c1707eStholo# fo all of the file names (remember $files[0] is the directory name
182*43c1707eStholoforeach $i (@files[1..$#files])
183*43c1707eStholo{
184*43c1707eStholo  if ( defined $locks{$i . $ext} )
185*43c1707eStholo  { # well the file has at least one lock outstanding
186*43c1707eStholo
187*43c1707eStholo     # find the base version number of our file
188*43c1707eStholo     &parse_cvs_entry($i,*entry);
189*43c1707eStholo
190*43c1707eStholo     # is our version of this file locked?
191*43c1707eStholo     if ( defined $locks{$i . $ext . $entry{"version"}} )
192*43c1707eStholo     { # if so, it is by us?
193*43c1707eStholo	if ( $login ne ($by = $locks{$i . $ext . $entry{"version"}}) )
194*43c1707eStholo	{# crud somebody else has it locked.
195*43c1707eStholo	   $outstanding_lock++ ;
196*43c1707eStholo	   print "$by has file $i locked for version " , $entry{"version"};
197*43c1707eStholo	}
198*43c1707eStholo	else
199*43c1707eStholo	{ # yeah I have it locked.
200*43c1707eStholo	   print "You have a lock on file $i for version " , $entry{"version"}
201*43c1707eStholo		if defined $opt_v;
202*43c1707eStholo	}
203*43c1707eStholo     }
204*43c1707eStholo  }
205*43c1707eStholo}
206*43c1707eStholo
207*43c1707eStholoexit $outstanding_lock;
208*43c1707eStholo
209*43c1707eStholo
210*43c1707eStholo### End of main program
211*43c1707eStholo
212*43c1707eStholosub parse_cvs_entry
213*43c1707eStholo{ # a very simple minded hack at parsing an entries file.
214*43c1707eSthololocal ( $file, *entry ) = @_;
215*43c1707eSthololocal ( @pp );
216*43c1707eStholo
217*43c1707eStholo
218*43c1707eStholoopen(ENTRIES, "< CVS/Entries") || die "Can't open entries file";
219*43c1707eStholo
220*43c1707eStholowhile (<ENTRIES>)
221*43c1707eStholo {
222*43c1707eStholo  if ( $_  =~ /^\/$file\// )
223*43c1707eStholo  {
224*43c1707eStholo	@pp = split('/');
225*43c1707eStholo
226*43c1707eStholo	$entry{"name"} = $pp[1];
227*43c1707eStholo	$entry{"version"} = $pp[2];
228*43c1707eStholo	$entry{"dates"} = $pp[3];
229*43c1707eStholo	$entry{"name"} = $pp[4];
230*43c1707eStholo	$entry{"name"} = $pp[5];
231*43c1707eStholo	$entry{"sticky"} = $pp[6];
232*43c1707eStholo	return;
233*43c1707eStholo  }
234*43c1707eStholo }
235*43c1707eStholo}
236