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