1107484Speter#! @PERL@ -w 2107484Speter######################################################################## 3107484Speter# Copyright (c) 2000, 2001 by Donald Sharp <sharpd@cisco.com> 4107484Speter# All Rights Reserved 5107484Speter# 6107484Speter# Permission is granted to copy and/or distribute this file, with or 7107484Speter# without modifications, provided this notice is preserved. 8107484Speter# 9107484Speter######################################################################## 10107484Speter 11107484Speter=head1 check_cvs.pl 12107484Speter 13107484Speter Script to check the integrity of the Repository 14107484Speter 15107484Speter=head1 SYNOPSIS 16107484Speter 17107484Speter check_cvs.pl 18107484Speter 19107484Speter=head1 DESCRIPTION 20107484Speter 21107484Speter This script will search through a repository and determine if 22107484Speter any of the files in it are corrupted. 23107484Speter 24107484Speter Please do not run this script inside of the repository itself, 25107484Speter it will cause it too fail. 26107484Speter 27107484Speter Also it currently can only be run over the entire repository, 28107484Speter so only point your CVSROOT at the actual CVSROOT. 29107484Speter 30107484Speter=head1 OPTIONS 31107484Speter 32107484Speter There are no options. 33107484Speter 34107484Speter=head1 EXAMPLES 35107484Speter 36107484Speter setenv CVSROOT /release/111/cvs 37107484Speter 38107484Speter # To see more verbose output 39107484Speter setenv CVSDEBUGEDIT 1 40107484Speter 41107484Speter check_cvs.pl 42107484Speter 43107484Speter=head1 SEE ALSO 44107484Speter 45107484Speter None 46107484Speter 47107484Speter=cut 48107484Speter 49107484Speter###################################################################### 50107484Speter# MODULES # 51107484Speter###################################################################### 52107484Speteruse strict; 53107484Speter 54107484Speteruse File::Find; 55107484Speteruse File::Basename; 56107484Speteruse File::Path; 57107484Speteruse Cwd; 58107484Speter 59107484Speter###################################################################### 60107484Speter# GLOBALS # 61107484Speter###################################################################### 62107484Speter 63107484Spetermy @list_of_broken_files; 64107484Spetermy @extra_files; 65107484Spetermy $verbose = 0; 66107484Speter 67107484Spetermy $total_revisions; 68107484Spetermy $total_interesting_revisions; 69107484Spetermy $total_files; 70128266Spetermy @ignore_files; 71107484Speter 72107484Speter###################################################################### 73107484Speter# SUBROUTINES # 74107484Speter###################################################################### 75107484Speter 76107484Speter###################################################################### 77107484Speter# 78107484Speter# NAME : 79107484Speter# main 80107484Speter# 81107484Speter# PURPOSE : 82107484Speter# To search the repository for broken files 83107484Speter# 84107484Speter# PARAMETERS : 85107484Speter# NONE 86107484Speter# 87107484Speter# GLOBALS : 88107484Speter# $ENV{ CVSROOT } - The CVS repository to search through 89107484Speter# $ENV{ CVSDEBUGEDIT } - Turn on Debugging. 90107484Speter# @list_of_broken_files - The list of files that need to 91107484Speter# be fixed. 92107484Speter# $verbose - is verbose mode on? 93107484Speter# $total_revisions - The number of revisions considered 94107484Speter# $total_interesting_revisions - The number of revisions used 95107484Speter# $total_files - The total number of files looked at. 96107484Speter# 97107484Speter# RETURNS : 98107484Speter# A list of broken files 99107484Speter# 100107484Speter# COMMENTS : 101107484Speter# Do not run this script inside the repository. Choose 102107484Speter# a nice safe spot( like /tmp ) outside of the repository. 103107484Speter# 104107484Speter###################################################################### 105107484Spetermy $directory_to_look_at; 106107484Speter 107107484Speterselect (STDOUT); $| = 1; # make unbuffered 108107484Speter 109107484Speter$total_revisions = 0; 110107484Speter$total_interesting_revisions = 0; 111107484Speter$total_files = 0; 112107484Speter 113107484Speterif( !exists( $ENV{ CVSROOT } ) ) 114107484Speter{ 115107484Speter die( "The script should be run with the CVSROOT environment variable set" ); 116107484Speter} 117107484Speter 118107484Speterif( exists( $ENV{ CVSDEBUGEDIT } ) ) 119107484Speter{ 120107484Speter $verbose = 1; 121107484Speter print( "Verbose Mode Turned On\n" ); 122107484Speter} 123107484Speter 124107484Speter$directory_to_look_at = $ENV{ CVSROOT }; 125128266Spetermy $sym_count = 0; 126128266Speterwhile( -l $directory_to_look_at ) 127107484Speter{ 128107484Speter $directory_to_look_at = readlink( $directory_to_look_at ); 129128266Speter $sym_count += 1; 130128266Speter if( $sym_count > 5 ) 131128266Speter { 132128266Speter die( "Encountered too many symlinks for $ENV{ CVSROOT }\n" ); 133128266Speter } 134107484Speter} 135107484Speter 136107484Speterprint( "Processing: $directory_to_look_at\n" ) if( $verbose ); 137128266Speter@ignore_files = &get_ignore_files_from_cvsroot( $directory_to_look_at ); 138107484Speterfind( \&process_file, $directory_to_look_at ); 139107484Speter 140107484Spetermy $num_files = @list_of_broken_files; 141107484Speterprint( "List of corrupted files\n" ) if( $num_files > 0 ); 142107484Speterforeach my $broken ( @list_of_broken_files ) 143107484Speter{ 144107484Speter print( "**** File: $broken\n" ); 145107484Speter} 146107484Speter 147107484Speter$num_files = @extra_files; 148107484Speterprint( "List of Files That Don't belong in Repository:\n" ) if( $num_files > 0 ); 149107484Speterforeach my $extra ( @extra_files ) 150107484Speter{ 151107484Speter print( "**** File: $extra\n" ); 152107484Speter} 153107484Speterprint( "Total Files: $total_files\n" ); 154107484Speterprint( "Total Revisions: $total_revisions Interesting Revisions: $total_interesting_revisions\n" ); 155107484Speter 156107484Speter###################################################################### 157107484Speter# 158107484Speter# NAME : 159107484Speter# process_file 160107484Speter# 161107484Speter# PURPOSE : 162107484Speter# This function is called by the find function, it's purpose 163107484Speter# is to decide if it is important to look at a file or not. 164107484Speter# We only care about files that have the ,v at the end. 165107484Speter# 166107484Speter# PARAMETERS : 167107484Speter# NONE 168107484Speter# 169107484Speter# GLOBALS : 170107484Speter# $ENV{ CVSROOT } - The CVS repository to search through 171107484Speter# 172107484Speter# RETURNS : 173107484Speter# NONE 174107484Speter# 175107484Speter# COMMENTS : 176107484Speter# NONE 177107484Speter# 178107484Speter###################################################################### 179107484Spetersub process_file 180107484Speter{ 181107484Speter my $path = $File::Find::name; 182107484Speter 183107484Speter $total_files += 1; 184107484Speter $path =~ s/^$directory_to_look_at\///; 185107484Speter 186107484Speter print( "\tProcessing File: $path\n" ) if( $verbose ); 187107484Speter if( $path =~ /,v$/ ) 188107484Speter { 189107484Speter $path =~ s/,v$//; 190107484Speter look_at_cvs_file( $path ); 191107484Speter } 192107484Speter elsif( ! -d $File::Find::name ) 193107484Speter { 194107484Speter my $save = 0; 195107484Speter 196107484Speter foreach my $ignore ( @ignore_files ) 197107484Speter { 198107484Speter if( $path =~ /$ignore/ ) 199107484Speter { 200107484Speter $save = 1; 201107484Speter last; 202107484Speter } 203107484Speter } 204107484Speter 205107484Speter if( !$save ) 206107484Speter { 207107484Speter push( @extra_files, $path ); 208107484Speter } 209107484Speter } 210107484Speter} 211107484Speter 212107484Speter###################################################################### 213107484Speter# 214107484Speter# NAME : 215107484Speter# look_at_cvs_file 216107484Speter# 217107484Speter# PURPOSE : 218107484Speter# To decide if a file is broken or not. The algorithm is: 219107484Speter# a) Get the revision history for the file. 220107484Speter# - If that fails the file is broken, save the fact 221107484Speter# and continue processing other files. 222107484Speter# - If that succeeds we have a list of revisions. 223107484Speter# b) For Each revision try to retrieve that version 224107484Speter# - If that fails the file is broken, save the fact 225107484Speter# and continue processing other files. 226107484Speter# c) Continue on 227107484Speter# 228107484Speter# PARAMETERS : 229107484Speter# $file - The file to look at. 230107484Speter# 231107484Speter# GLOBALS : 232107484Speter# NONE 233107484Speter# 234107484Speter# RETURNS : 235107484Speter# NONE 236107484Speter# 237107484Speter# COMMENTS : 238107484Speter# We have to handle Attic files in a special manner. 239107484Speter# Basically remove the Attic from the string if it 240107484Speter# exists at the end of the $path variable. 241107484Speter# 242107484Speter###################################################################### 243107484Spetersub look_at_cvs_file 244107484Speter{ 245107484Speter my( $file ) = @_; 246107484Speter my( $name, $path, $suffix ) = fileparse( $file ); 247107484Speter 248107484Speter if( $path =~ s/Attic\/$// ) 249107484Speter { 250107484Speter $file = $path . $name; 251107484Speter } 252107484Speter 253107484Speter my $revisions = get_history( $name ); 254107484Speter 255107484Speter if( !defined( $revisions ) ) 256107484Speter { 257107484Speter print( "\t$file is corrupted, this was determined via a cvs log command\n" ) if( $verbose ); 258107484Speter push( @list_of_broken_files, $file ); 259107484Speter return(); 260107484Speter } 261107484Speter 262107484Speter my @int_revisions = find_interesting_revisions( @$revisions ); 263107484Speter 264107484Speter foreach my $revision ( @int_revisions ) 265107484Speter { 266107484Speter print( "\t\tLooking at Revision: $revision\n" ) if( $verbose ); 267107484Speter if( !check_revision( $file, $revision ) ) 268107484Speter { 269107484Speter print( "\t$file is corrupted in revision: $revision\n" ) if( $verbose ); 270107484Speter push( @list_of_broken_files, $file ); 271107484Speter return(); 272107484Speter } 273107484Speter } 274107484Speter 275107484Speter} 276107484Speter 277107484Speter###################################################################### 278107484Speter# 279107484Speter# NAME : 280107484Speter# get_history 281107484Speter# 282107484Speter# PURPOSE : 283107484Speter# To retrieve a array of revision numbers. 284107484Speter# 285107484Speter# PARAMETERS : 286107484Speter# $file - The file to retrieve the revision numbers for 287107484Speter# 288107484Speter# GLOBALS : 289107484Speter# NONE 290107484Speter# 291107484Speter# RETURNS : 292107484Speter# On Success - Reference to the list of revision numbers 293107484Speter# On Failure - undef. 294107484Speter# 295107484Speter# COMMENTS : 296107484Speter# The $_ is saved off because The File::find functionality 297107484Speter# expects the $_ to not have been changed. 298107484Speter# The -N option for the rlog command means to spit out 299107484Speter# tags or branch names. 300107484Speter# 301107484Speter###################################################################### 302107484Spetersub get_history 303107484Speter{ 304107484Speter my( $file ) = @_; 305128266Speter $file =~ s/(["\$`\\])/\\$1/g; 306107484Speter my @revisions; 307107484Speter my $revision; 308128266Speter my $ignore = 1; 309107484Speter my $save_ = $_; 310107484Speter 311128266Speter open( FILE, "rlog -N \"$file\" 2>&1 |" ) or die( "unable to run rlog, help" ); 312107484Speter 313107484Speter while( <FILE> ) 314107484Speter { 315128266Speter #rlog outputs a "----" line before the actual revision 316128266Speter #without this we'll pick up peoples comments if they 317128266Speter #happen to start with revision 318128266Speter if( /^----------------------------$/ ) 319128266Speter { 320128266Speter $ignore = 0; 321128266Speter next; 322107484Speter } 323128266Speter 324128266Speter if( ( !$ignore ) && ( ( $revision ) = m/^revision (\S+)/ ) ) 325128266Speter { 326128266Speter push( @revisions, $revision ); 327128266Speter $ignore = 1; 328128266Speter } 329107484Speter } 330107484Speter 331107484Speter $_ = $save_; 332107484Speter 333107484Speter if( !close( FILE ) ) 334107484Speter { 335107484Speter return( undef ); 336107484Speter } 337107484Speter 338107484Speter return( \@revisions ); 339107484Speter} 340107484Speter 341107484Speter###################################################################### 342107484Speter# 343107484Speter# NAME : 344107484Speter# check_revision 345107484Speter# 346107484Speter# PURPOSE : 347107484Speter# Given a file and a revision number ensure that we can 348107484Speter# check out that file 349107484Speter# 350107484Speter# PARAMETERS : 351107484Speter# $file - The file to look at. 352107484Speter# $revision - The revision to look at. 353107484Speter# 354107484Speter# GLOBALS : 355107484Speter# NONE 356107484Speter# 357107484Speter# RETURNS : 358107484Speter# If we can get the File - 1 359107484Speter# If we can not get the File - 0 360107484Speter# 361107484Speter# COMMENTS : 362107484Speter# cvs command line options are as followed: 363107484Speter# -n - Do not run any checkout program as specified by the -o 364107484Speter# option in the modules file 365107484Speter# -p - Put all output to standard out. 366107484Speter# -r - The revision of the file that we would like to look at. 367107484Speter# Please note that cvs will return 0 for being able to successfully 368107484Speter# read the file and 1 for failure to read the file. 369107484Speter# 370107484Speter###################################################################### 371107484Spetersub check_revision 372107484Speter{ 373107484Speter my( $file, $revision ) = @_; 374128266Speter $file =~ s/(["\$`\\])/\\$1/g; 375107484Speter 376107484Speter my $cwd = getcwd(); 377107484Speter chdir( "/tmp" ); 378107484Speter 379128266Speter my $ret_code = 0xffff & system( "cvs co -n -p -r $revision \"$file\" > /dev/null 2>&1" ); 380107484Speter 381107484Speter chdir( $cwd ); 382107484Speter return( 1 ) if ( $ret_code == 0 ); 383107484Speter return( 0 ); 384107484Speter 385107484Speter return( $ret_code ); 386107484Speter} 387107484Speter 388107484Speter###################################################################### 389107484Speter# 390107484Speter# NAME : 391107484Speter# find_interesting_revisions 392107484Speter# 393107484Speter# PURPOSE : 394107484Speter# CVS stores information in a logical manner. We only really 395107484Speter# need to look at some interestin revisions. These are: 396107484Speter# The first version 397107484Speter# And the last version on every branch. 398107484Speter# This is because cvs stores changes descending from 399107484Speter# main line. ie suppose the last version on mainline is 1.6 400107484Speter# version 1.6 of the file is stored in toto. version 1.5 401107484Speter# is stored as a diff between 1.5 and 1.6. 1.4 is stored 402107484Speter# as a diff between 1.5 and 1.4. 403107484Speter# branches are stored a little differently. They are 404107484Speter# stored in ascending order. Suppose there is a branch 405107484Speter# on 1.4 of the file. The first branches revision number 406107484Speter# would be 1.4.1.1. This is stored as a diff between 407107484Speter# version 1.4 and 1.4.1.1. The 1.4.1.2 version is stored 408107484Speter# as a diff between 1.4.1.1 and 1.4.1.2. Therefore 409107484Speter# we are only interested in the earliest revision number 410107484Speter# and the highest revision number on a branch. 411107484Speter# 412107484Speter# PARAMETERS : 413107484Speter# @revisions - The list of revisions to find interesting ones 414107484Speter# 415107484Speter# GLOBALS : 416107484Speter# NONE 417107484Speter# 418107484Speter# RETURNS : 419107484Speter# @new_revisions - The list of revisions that we find interesting 420107484Speter# 421107484Speter# COMMENTS : 422107484Speter# 423107484Speter###################################################################### 424107484Spetersub find_interesting_revisions 425107484Speter{ 426107484Speter my( @revisions ) = @_; 427107484Speter my @new_revisions; 428107484Speter my %branch_revision; 429107484Speter my $branch_number; 430107484Speter my $branch_rev; 431107484Speter my $key; 432107484Speter my $value; 433107484Speter 434107484Speter START_OVER: 435107484Speter foreach my $revision( @revisions ) 436107484Speter { 437107484Speter my $start_over = 0; 438107484Speter ( $branch_number, $branch_rev ) = branch_split( $revision ); 439107484Speter 440107484Speter #if the number of elements in the branch is 1 441107484Speter #and the new branch is less than the old branch 442107484Speter if( elements_in_branch( $branch_number ) == 1 ) 443107484Speter { 444107484Speter ( $start_over, 445107484Speter %branch_revision ) = find_int_mainline_revision( $branch_number, 446107484Speter $branch_rev, 447107484Speter %branch_revision ); 448107484Speter next START_OVER if( $start_over ); 449107484Speter } 450107484Speter 451107484Speter %branch_revision = find_int_branch_revision( $branch_number, 452107484Speter $branch_rev, 453107484Speter %branch_revision ); 454107484Speter 455107484Speter } 456107484Speter 457107484Speter %branch_revision = remove_duplicate_branches( %branch_revision ); 458107484Speter 459107484Speter while( ( $key, $value ) = each ( %branch_revision ) ) 460107484Speter { 461107484Speter push( @new_revisions, $key . "." . $value ); 462107484Speter } 463107484Speter 464107484Speter my $nrc; 465107484Speter my $rc; 466107484Speter 467107484Speter $rc = @revisions; 468107484Speter $nrc = @new_revisions; 469107484Speter 470107484Speter $total_revisions += $rc; 471107484Speter $total_interesting_revisions += $nrc; 472107484Speter 473107484Speter print( "\t\tTotal Revisions: $rc Interesting Revisions: $nrc\n" ) if( $verbose ); 474107484Speter 475107484Speter return( @new_revisions ); 476107484Speter} 477107484Speter 478107484Speter######################################################################## 479107484Speter# 480107484Speter# NAME : 481107484Speter# remove_duplicate_branches 482107484Speter# 483107484Speter# PURPOSE : 484107484Speter# To remove from the list of branches that we are interested 485107484Speter# in duplication that will cause cvs to check a revision multiple 486107484Speter# times. For Instance revision 1.1.1.1 should be prefered 487107484Speter# to be checked over revision 1.1, as that v1.1.1.1 can 488107484Speter# only be retrieved by going through v1.1. Therefore 489107484Speter# we should remove v1.1 from the list of branches that 490107484Speter# are interesting. 491107484Speter# 492107484Speter# PARAMETERS : 493107484Speter# %branch_revisions - The hash of the interesting revisions 494107484Speter# 495107484Speter# GLOBALS : 496107484Speter# NONE 497107484Speter# 498107484Speter# RETURNS : 499107484Speter# %branch_revisions - The hash of the modified interesting revisions 500107484Speter# 501107484Speter# COMMENTS : 502107484Speter# NONE 503107484Speter# 504107484Speter######################################################################## 505107484Spetersub remove_duplicate_branches 506107484Speter{ 507107484Speter my( %branch_revisions ) = @_; 508107484Speter my $key; 509107484Speter my $value; 510107484Speter my $branch_comp; 511107484Speter my $branch; 512107484Speter 513107484Speter 514107484Speter RESTART: 515107484Speter { 516107484Speter my @keys = keys( %branch_revisions ); 517107484Speter while( ( $key, $value ) = each ( %branch_revisions ) ) 518107484Speter { 519107484Speter $branch_comp = $key . "." . $value; 520107484Speter foreach $branch ( @keys ) 521107484Speter { 522107484Speter if( $branch eq $key ) 523107484Speter { 524107484Speter next; 525107484Speter } 526107484Speter if( elements_in_branch( $branch_comp ) == 527107484Speter elements_in_branch( $branch ) - 1 ) 528107484Speter { 529107484Speter if( $branch =~ /^$branch_comp/ ) 530107484Speter { 531107484Speter delete( $branch_revisions{ $key } ); 532107484Speter goto RESTART; 533107484Speter } 534107484Speter } 535107484Speter } 536107484Speter } 537107484Speter } 538107484Speter 539107484Speter return( %branch_revisions ); 540107484Speter} 541107484Speter 542107484Speter###################################################################### 543107484Speter# 544107484Speter# NAME : 545107484Speter# find_int_branch_revision 546107484Speter# 547107484Speter# PURPOSE : 548107484Speter# To Find a interesting branch revision. 549107484Speter# Algorithm: 550107484Speter# If the $branch_revision exists in the interesting branch 551107484Speter# hash and the new $branch_rev is less than currently saved 552107484Speter# one replace it with the new $branch_rev. 553107484Speter# else if the $branch_revision doesn't exist in the interesting 554107484Speter# branch hash, then just store the $branch_number and $branch_rev 555107484Speter# 556107484Speter# PARAMETERS : 557107484Speter# $branch_number - The branch that we are looking at 558107484Speter# $branch_rev - The particular revision we are looking 559107484Speter# at on the $branch_number. 560107484Speter# %branch_revision - The hash storing the interesting branches 561107484Speter# and the revisions on them. 562107484Speter# 563107484Speter# GLOBALS : 564107484Speter# NONE 565107484Speter# 566107484Speter# RETURNS : 567107484Speter# %branch_revision - The modified hash that stores interesting 568107484Speter# branches. 569107484Speter# 570107484Speter# COMMENTS : 571107484Speter# NONE 572107484Speter# 573107484Speter###################################################################### 574107484Spetersub find_int_branch_revision 575107484Speter{ 576107484Speter my( $branch_number, $branch_rev, %branch_revision ) = @_; 577107484Speter 578107484Speter if( exists( $branch_revision{ $branch_number } ) ) 579107484Speter { 580107484Speter if( $branch_rev > $branch_revision{ $branch_number } ) 581107484Speter { 582107484Speter $branch_revision{ $branch_number } = $branch_rev; 583107484Speter } 584107484Speter } 585107484Speter else 586107484Speter { 587107484Speter $branch_revision{ $branch_number } = $branch_rev; 588107484Speter } 589107484Speter 590107484Speter return( %branch_revision ); 591107484Speter} 592107484Speter 593107484Speter###################################################################### 594107484Speter# 595107484Speter# NAME : 596107484Speter# find_int_mainline_revision 597107484Speter# 598107484Speter# PURPOSE : 599107484Speter# To Find a interesting mainline revision. 600107484Speter# Algorithm: 601107484Speter# if the $branch_number is less then a branch number 602107484Speter# with one element in it, then delete the old branch_number 603107484Speter# and return. 604107484Speter# if the $branch_number is greater than a branch number 605107484Speter# then return, and tell the calling function that we 606107484Speter# should skip this element, as that it's not important. 607107484Speter# if the $branch_number is the same as a branch number 608107484Speter# with one element in it, then check to see if the 609107484Speter# $branch_rev is less than the stored branch rev if 610107484Speter# it is replace with new $branch_rev. Else ignore revision 611107484Speter# 612107484Speter# PARAMETERS : 613107484Speter# $branch_number - The branch that we are looking at 614107484Speter# $branch_rev - The particular revision we are looking 615107484Speter# at on the $branch_number. 616107484Speter# %branch_revision - The hash storing the interesting branches 617107484Speter# and the revisions on them. 618107484Speter# 619107484Speter# GLOBALS : 620107484Speter# NONE 621107484Speter# 622107484Speter# RETURNS : 623107484Speter# ( $skip, %branch_revision ) - 624107484Speter# $skip - 1 if we need to ignore this particular $branch_number 625107484Speter# $branch_rev combo. Else 0. 626107484Speter# %branch_revision - The modified hash that stores interesting 627107484Speter# branches. 628107484Speter# 629107484Speter# COMMENTS : 630107484Speter# NONE 631107484Speter# 632107484Speter###################################################################### 633107484Spetersub find_int_mainline_revision 634107484Speter{ 635107484Speter my( $branch_number, $branch_rev, %branch_revision ) = @_; 636107484Speter 637107484Speter foreach my $key ( keys %branch_revision ) 638107484Speter { 639107484Speter if( elements_in_branch( $key ) == 1 ) 640107484Speter { 641107484Speter if( $branch_number < $key ) 642107484Speter { 643107484Speter delete( $branch_revision{ $key } ); 644107484Speter next; 645107484Speter } 646107484Speter 647107484Speter if( $branch_number > $key ) 648107484Speter { 649107484Speter return( 1, %branch_revision ); 650107484Speter } 651107484Speter if( ( exists( $branch_revision{ $branch_number } ) ) && 652107484Speter ( $branch_rev < $branch_revision{ $branch_number } ) ) 653107484Speter { 654107484Speter $branch_revision{ $branch_number } = $branch_rev; 655107484Speter return( 1, %branch_revision ); 656107484Speter } 657107484Speter } 658107484Speter } 659107484Speter 660107484Speter return( 0, %branch_revision ); 661107484Speter} 662107484Speter 663107484Speter###################################################################### 664107484Speter# 665107484Speter# NAME : 666107484Speter# elements_in_branch 667107484Speter# 668107484Speter# PURPOSE : 669107484Speter# Determine the number of elements in a revision number 670107484Speter# Elements are defined by numbers seperated by ".". 671107484Speter# the revision 1.2.3.4 would have 4 elements 672107484Speter# the revision 1.2.4.5.6.7 would have 6 elements 673107484Speter# 674107484Speter# PARAMETERS : 675107484Speter# $branch - The revision to look at. 676107484Speter# 677107484Speter# GLOBALS : 678107484Speter# NONE 679107484Speter# 680107484Speter# RETURNS : 681107484Speter# $count - The number of elements 682107484Speter# 683107484Speter# COMMENTS : 684107484Speter# NONE 685107484Speter# 686107484Speter###################################################################### 687107484Spetersub elements_in_branch 688107484Speter{ 689107484Speter my( $branch ) = @_; 690107484Speter my @split_rev; 691107484Speter 692107484Speter @split_rev = split /\./, $branch; 693107484Speter 694107484Speter my $count = @split_rev; 695107484Speter return( $count ); 696107484Speter} 697107484Speter 698107484Speter###################################################################### 699107484Speter# 700107484Speter# NAME : 701107484Speter# branch_split 702107484Speter# 703107484Speter# PURPOSE : 704107484Speter# To split up a revision number up into the branch part and 705107484Speter# the number part. For Instance: 706107484Speter# 1.1.1.1 - is split 1.1.1 and 1 707107484Speter# 2.1 - is split 2 and 1 708107484Speter# 1.3.4.5.7.8 - is split 1.3.4.5.7 and 8 709107484Speter# 710107484Speter# PARAMETERS : 711107484Speter# $revision - The revision to look at. 712107484Speter# 713107484Speter# GLOBALS : 714107484Speter# NONE 715107484Speter# 716107484Speter# RETURNS : 717107484Speter# ( $branch, $revision ) - 718107484Speter# $branch - The branch part of the revision number 719107484Speter# $revision - The revision part of the revision number 720107484Speter# 721107484Speter# COMMENTS : 722107484Speter# NONE 723107484Speter# 724107484Speter###################################################################### 725107484Spetersub branch_split 726107484Speter{ 727107484Speter my( $revision ) = @_; 728107484Speter my $branch; 729107484Speter my $version; 730107484Speter my @split_rev; 731107484Speter my $count; 732107484Speter 733107484Speter @split_rev = split /\./, $revision; 734107484Speter 735107484Speter my $numbers = @split_rev; 736107484Speter @split_rev = reverse( @split_rev ); 737107484Speter $branch = pop( @split_rev ); 738107484Speter for( $count = 0; $count < $numbers - 2 ; $count++ ) 739107484Speter { 740107484Speter $branch .= "." . pop( @split_rev ); 741107484Speter } 742107484Speter 743107484Speter return( $branch, pop( @split_rev ) ); 744107484Speter} 745128266Speter 746128266Speter###################################################################### 747128266Speter# 748128266Speter# NAME : 749128266Speter# get_ignore_files_from_cvsroot 750128266Speter# 751128266Speter# PURPOSE : 752128266Speter# Retrieve the list of files from the CVSROOT/ directory 753128266Speter# that should be ignored. 754128266Speter# These are the regular files (e.g., commitinfo, loginfo) 755128266Speter# and those specified in the checkoutlist file. 756128266Speter# 757128266Speter# PARAMETERS : 758128266Speter# The CVSROOT 759128266Speter# 760128266Speter# GLOBALS : 761128266Speter# NONE 762128266Speter# 763128266Speter# RETURNS : 764128266Speter# @ignore - the list of files to ignore 765128266Speter# 766128266Speter# COMMENTS : 767128266Speter# NONE 768128266Speter# 769128266Speter###################################################################### 770128266Spetersub get_ignore_files_from_cvsroot { 771128266Speter my( $cvsroot ) = @_; 772128266Speter my @ignore = ( 'CVS\/fileattr$', 773128266Speter '^CVSROOT\/loginfo', 774128266Speter '^CVSROOT\/.#loginfo', 775128266Speter '^CVSROOT\/rcsinfo', 776128266Speter '^CVSROOT\/.#rcsinfo', 777128266Speter '^CVSROOT\/editinfo', 778128266Speter '^CVSROOT\/.#editinfo', 779128266Speter '^CVSROOT\/verifymsg', 780128266Speter '^CVSROOT\/.#verifymsg', 781128266Speter '^CVSROOT\/commitinfo', 782128266Speter '^CVSROOT\/.#commitinfo', 783128266Speter '^CVSROOT\/taginfo', 784128266Speter '^CVSROOT\/.#taginfo', 785128266Speter '^CVSROOT\/cvsignore', 786128266Speter '^CVSROOT\/.#cvsignore', 787128266Speter '^CVSROOT\/checkoutlist', 788128266Speter '^CVSROOT\/.#checkoutlist', 789128266Speter '^CVSROOT\/cvswrappers', 790128266Speter '^CVSROOT\/.#cvswrappers', 791128266Speter '^CVSROOT\/notify', 792128266Speter '^CVSROOT\/.#notify', 793128266Speter '^CVSROOT\/modules', 794128266Speter '^CVSROOT\/.#modules', 795128266Speter '^CVSROOT\/readers', 796128266Speter '^CVSROOT\/.#readers', 797128266Speter '^CVSROOT\/writers', 798128266Speter '^CVSROOT\/.#writers', 799128266Speter '^CVSROOT\/passwd', 800128266Speter '^CVSROOT\/config', 801128266Speter '^CVSROOT\/.#config', 802128266Speter '^CVSROOT\/val-tags', 803128266Speter '^CVSROOT\/.#val-tags', 804128266Speter '^CVSROOT\/history' ); 805128266Speter my $checkoutlist_file = "$cvsroot\/CVSROOT\/checkoutlist"; 806128266Speter open( CHECKOUTLIST, "<$cvsroot\/CVSROOT\/checkoutlist" ) 807128266Speter or die( "Unable to read checkoutlist file: $!\n" ); 808128266Speter 809128266Speter my @list = <CHECKOUTLIST>; 810128266Speter chomp( @list ); 811128266Speter close( CHECKOUTLIST ) 812128266Speter or die( "Unable to close checkoutlist file: $!\n" ); 813128266Speter 814128266Speter foreach my $line( @list ) 815128266Speter { 816128266Speter next if( $line =~ /^#/ || $line =~ /^$/ ); 817128266Speter if( $line =~ /^\s*(\S*)\s*/ ) { $line = $1 }; 818128266Speter push( @ignore, "^CVSROOT\/$line", "^CVSROOT\/\.#$line" ); 819128266Speter } 820128266Speter 821128266Speter return @ignore; 822128266Speter} 823