Community technical support mailing list was retired 2010 and replaced with a professional technical support team. For assistance please contact: Pre-sales Technical support via email to sales@march-hare.com.
> Anyway, here it is. I know I've posted attachments in the past but the script didn't come through this time. Below is the code for anybody that wants to use or review it. --Aric Aric Czarnowski Unimax Systems Corporation 612-204-3634 #!perl.exe # ####################### BEGIN POD ############################################# # use strict; use warnings; =pod =head1 Description Takes a file name via the C<--file> argument, does a C<cvs log> of that file, parses that output and then does a C<cvs admin -o> for each rev of that file which is not on a branch, which is not tagged and which is not the tip. Originally implemented to remove intermediary binary revisions which only contribute to archive explosion and slow CVS response time. It should work against any CVS file though. =head1 Considerations =over 4 =item * It would be a good idea to backup the CVS archive's ,v file before running this to remove revisions just in case something goes wrong. =item * All branch revisions will remain from the branch point to that branch's tip. If your branches are long lived pruning could be less helpful than you are expecting. =item * This was orignally tested and used with a CVSNT 2.0.27 installations on Win32. There is no guarantee this will work with CVS or old CVSNT installations (though it should). =item * UNIX installations have not been tested but should also work. There are no Win32 specific shell commands used. =back =head1 Assumptions =over 4 =item * Intermediary revisions you are about to remove really are not needed. If diffs along the file's revision path could be useful in some way this is not the script for you. =item * You have a recent Perl installation with all core modules installed. This was originally developed against ActivePerl 5.6.1 but should work with any core Perl installation. =item * CVS is in your PATH. =back =head1 Input The filename under CVS control you would like excess revisions removed from. See the command line help using C<-h> for more details on options. =head1 Output All processing output goes to STDOUT. =head1 Version $Revision: 1.1 $ $Date: 2004/11/18 21:02:38 $ $Author: aczarnowski $ =cut # ####################### BEGIN PARAMS ########################################## # Usage my $usage = qq[ perl $FindBin::Script [--debug] --file <file> [-h|--help] [--noremove] --debug Print extra debugging information --file File on which you want the CVS revision history trimmed --help This help screen --noremove Only show revisions that would be removed (do not perform removal) Also see the POD in this file using pod2text. ]; ####################### BEGIN MAIN ############################################ use Cwd; use Data::Dumper; use FindBin; use Getopt::Long; # Read up command line options and validate them my $debug = 0; my $file = undef; my $help = 0; my $noRemove = 0; GetOptions( 'h|help' => \$help, 'debug' => \$debug, 'file=s' => \$file, 'noremove' => \$noRemove, ); if($help) { die "$usage\n"; } unless(defined($file) && -e $file) { die "ERROR: A valid file must be given via --file\n$usage"; } # Processing really starts here print "Starting $FindBin::Script (".localtime().")\n"; if($noRemove) { print "--noremove specified, revisions will not actually be removed\n\n"; } # Get directory stuff figured out and move next to the file if we need too my $startDir = cwd(); my ($fileName) = $file =~ m/.*[\\|\/](.*)/; my ($fileDir) = $file =~ m/(.*)[\\|\/]/; if(defined($fileDir) && $fileDir ne '') { chdir($fileDir) or die "ERROR: Cannot change to the file's directory '$fileDir': $!\n"; $fileDir = cwd(); } else { $fileName = $file; $fileDir = $startDir; } if($debug) { print "\$file = $file\n"; print "\$startDir = $startDir\n"; print "\$fileDir = $fileDir\n"; print "\$fileName = $fileName\n"; } # Get log information # # @revs will hold all the revisions of the file. %taggedRevs holds the unique # list of tagged revisions. Since we only grab the first two revision entries # (i.e. 1.2 for 1.2.0.2) a file revision out on a branch will collapse base to # its branch point and that branch point will be associated with the branch # name ending up in %taggedRevs. So branch points are tagged with the branch # name in %taggedRevs and are spared later. # print "Getting $file log information from CVS\n"; my $logCmd = "cvs log $fileName |"; if($debug) { print "$fileDir> $logCmd\n"; } open(LOG, $logCmd) or die "ERROR: Cannot log $fileName\n"; my @revs = (); my %taggedRevs = (); while(<LOG>) { my $line = $_; if($line =~ /\t(\w*)\: (\d+\.\d+)/) { $taggedRevs{$2} .= $1; } elsif($line =~ /revision (\d+\.\d+)/) { push(@revs, $1); } } close(LOG); # Figure out what the highest rev is so we don't blow away the HEAD revision $taggedRevs{$revs[0]} = 'TIP'; if($debug) { print "\@revs = ".Dumper(\@revs); print "\%taggedRevs = ". Dumper(\%taggedRevs); } # CVS out each rev that isn't interesting. Note that the regular expressions # above only pull the first two parts of a branch tag so full branches # should be preserved from their branch points on # if($noRemove) { print "Displaying revisions which would be pruned from $fileName\n"; } else { print "Pruning revisions from $fileName\n"; } foreach my $rev (@revs) { unless(exists($taggedRevs{$rev})) { if($noRemove) { print "$rev\n"; } else { my $cmd = "cvs admin -o $rev $fileName"; print "$fileDir> $cmd\n"; system($cmd); } } } # Confirm we are back where we started unless($startDir eq $fileDir) { chdir($startDir) or warn "WARNING: Cannot return to '$startDir': $!\n"; } # Exit gracefully print "Done with $FindBin::Script (".localtime().")\n"; exit(0); ####################### BEGIN SUBS ############################################