diff options
Diffstat (limited to 'scripts/cvscheck')
-rwxr-xr-x | scripts/cvscheck | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/scripts/cvscheck b/scripts/cvscheck new file mode 100755 index 00000000..1e1da5a8 --- /dev/null +++ b/scripts/cvscheck @@ -0,0 +1,385 @@ +#! /usr/bin/env perl + +use POSIX qw(mktime ctime); +use Time::Local qw( timegm ); + +# Offline check for status of files in a checked-out +# CVS module. +# Artistic License, Dirk Mueller <mueller@kde.org> 2001-2003 + +# based on cvschanged by +# Sirtaj Singh Kang <taj@kde.org> Nov 1998. + +if ( defined $ARGV[0] && $ARGV[0] =~ /(?:-h|--help)/) { + print "cvscheck (c) 2001-2003 Dirk Mueller <mueller\@kde.org>\n\nUsage:\n"; + print " cvscheck [options] <dirs>\n\n"; + print "Prints information about the status of your local CVS checkout without\n"; + print "communicating with the server (therefore in speed only limited by your\n"; + print "hard-disk throughput, much unlike cvs -n up).\n\n"; + print "Every file is printed with a status character in front of its name:\n"; + print "? foobar.c file is not known to CVS - maybe you should add it?\n"; + print "M foobar.c file is for sure locally modified.\n"; + print "m foobar.c file *might* have local changes (needs a diff with the server).\n"; + print "C foobar.c file has a CVS conflict and therefore cannot be committed.\n"; + print "U foobar.c file is in CVS but its somehow missing in your local checkout.\n"; + print "T foobar.c file has an unusual sticky CVS tag.\n"; + print "A foobar.c you cvs add'ed this file but did not yet commit.\n"; + print "R foobar.c you cvs rm'ed this file but did not yet commit.\n"; + +print <<EOF; + + +Options: + +-u | --unknown Show only unknown (?) files +-m | --modified Show only modified (m/M) files +--missing Show only missing (U) files +-t | --tagged Show only tagged (T) files +-a | --added Show only added (A) files +-r | --removed Show only removed (R) files +-c | --conflicts Show only conflict (C) files + +If no option is given, it defaults to show all files and diagnostic messages. +EOF + exit; +} + +# default is HEAD +$standardtag = ""; +%defaulttag = (); +@dirqueue = (); +@merged = (); +@uncommitted = (); +@missing = (); +@tagged = (); +@removed = (); +@unknown = (); +@modified = (); +@conflicts = (); + +%months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4, + 'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9, + 'Nov' => 10, 'Dec' => 11); + +%showoptions = (); +$optionlocal = 0; + +sub printinfo($) +{ + print @_ if (defined($showoptions{"all"})); +} + +# convert text stamp to GMT +sub strToTime +{ + my( $timestr ) = @_; + + if( ! ($timestr =~ + /^(\w+)\s*(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)/) ) { + + return -1; + } + + # CVS timestamps are in GMT. + + my( $tm ) = timegm( $6, $5, $4, $3, $months{ $2 }, $7 - 1900); + + return $tm; +} + +sub processEntries +{ + my ( $dir ) = @_; + my %dirunknown = (); + + opendir (DIR, "$dir") || warn "Couldn't read '$dir'"; + # first assume all are unknown + while ( $e = readdir(DIR) ) { + next if ($e eq "."); + next if ($e eq ".."); + next if ($e eq "RCS"); + next if ($e eq "SCCS"); + next if ($e eq "CVS"); + next if ($e eq "CVS.adm"); + next if ($e eq "RCSLOG"); + next if ($e eq "tags"); + next if ($e eq "TAGS"); + next if ($e eq ".make.state"); + next if ($e eq ".nse_depinfo"); + next if ($e eq "core"); + next if ($e eq ".libs"); + next if ($e eq ".deps"); + next if ($e =~ /^.+~$/); + next if ($e =~ /^\#.+$/); + next if ($e =~ /^\.\#.+$/); + next if ($e =~ /^,.+$/); + next if ($e =~ /^_\$.+$/); + next if ($e =~ /^.+\$$/); + next if ($e =~ /^.+\.old$/); + next if ($e =~ /^.+\.bak$/); + next if ($e =~ /^.+\.BAK$/); + next if ($e =~ /^.+\.orig$/); + next if ($e =~ /^.+\.rej$/); + next if ($e =~ /^\.del-.+$/); + next if ($e =~ /^.+\.a$/); + next if ($e =~ /^.+\.olb$/); + next if ($e =~ /^.+\.o$/); + next if ($e =~ /^.*\.obj$/); + next if ($e =~ /^.+\.so$/); + next if ($e =~ /^.+\.Z$/); + next if ($e =~ /^.+\.elc$/); + next if ($e =~ /^.+\.ln$/); + next if ($e =~ /^cvslog\..*$/); + + # kde specific entries + # TODO read from CVSROOT/cvsignore - if it's been checked out! + next if ($e eq "config.cache"); + next if ($e eq "config.log"); + next if ($e eq "config.status"); + next if ($e eq "index.cache.bz2"); + next if ($e eq ".memdump"); + next if ($e eq "autom4te.cache"); + next if ($e eq "autom4te.cache"); + next if ($e eq "Makefile.rules"); + next if ($e eq "Makefile.calls"); + next if ($e eq "Makefile.rules.in"); + next if ($e eq "Makefile.calls.in"); + next if ($e =~ /^.*\.moc$/); + next if ($e =~ /^.+\.gmo$/); + next if ($e =~ /^.+\.moc\.[^\.]+$/); + next if ($e =~ /^.+\.lo$/); + next if ($e =~ /^.+\.la$/); + next if ($e =~ /^.+\.rpo$/); + next if ($e =~ /^.+\.closure$/); + next if ($e =~ /^.+\.all_cpp\.cpp$/); + next if ($e =~ /^.+\.all_C\.C$/); + next if ($e =~ /^.+\.all_cc\.cc$/); + next if ($e =~ /^.+_meta_unload\.[^\.]+$/); + next if ($e =~ /^.+\.kidl$/); + next if ($e =~ /^.+_skel\.[^\.]+$/); + + # Qt specific entries + next if ($e eq ".ui"); + next if ($e eq ".moc"); + next if ($e eq ".obj"); + + $dirunknown{$e} = 1; + } + closedir(DIR); + if( open(CVSIGNORE, $dir."/.cvsignore") ) { + while(<CVSIGNORE>) { + s/\s*$//; + my $line = $_; + foreach my $entry ( split(/ /,$line) ) { + if ($entry =~ /[\*\?]/) { + my $pattern = quotemeta $entry; + $pattern =~ s/\\\*/.*/g; + $pattern =~ s/\\\?/./g; + foreach $m (keys (%dirunknown)) { + $dirunknown{$m} = 0 if ($m =~ /^$pattern$/); + } + next; + } + $dirunknown{$entry} = 0; + } + } + close(CVSIGNORE); + } + + if ( !open( ENTRIES, $dir."/CVS/Entries" ) ) { + &printinfo("I CVS/Entries missing in $dir\n"); + return; + } + my $oldstandardtag = defined($defaulttag{$dir}) ? $defaulttag{$dir} : ""; + my $staginfo = ""; + if( open(CVSTAG, $dir."/CVS/Tag" ) ) { + my $line = <CVSTAG>; + if($line =~ /^[TDN](.+)$/) { + $standardtag = $1; + $staginfo = $1; + } + else { + # something with D - assume HEAD + $oldstandardtag = $standardtag = ""; # its HEAD + &printinfo("I $dir has unknown stickyness: $line"); + } + close(CVSTAG); + } + else { + $standardtag = ""; # its HEAD + $staginfo = "(HEAD)"; + } + &printinfo("I $dir has sticky tag $staginfo\n") if($standardtag ne $oldstandardtag); + while( <ENTRIES> ) { + if ( m#^\s*D/([^/]+)/# ) { + if (-d "$dir/$1" && !$optionlocal) { + push ( @dirqueue, "$dir/$1" ); + $defaulttag{"$dir/$1"} = $standardtag; + } + $dirunknown{$1} = 0; + next; + } + + next if !m#^\s*/([^/]+)/([-]*[\d\.]*)/([^/]+)/([^/]*)/(\S*)$#; + $fname = $1; + $ver = $2; + $stamp = $3; + $options = $4; + $tag = $5; + $tag = $1 if ($tag =~ /^[TD](.+)$/); + + $dirunknown{$fname} = 0; + + my $taginfo=""; + if(defined($showoptions{"all"})) { + if ( $tag ne $standardtag ) { + if ($tag eq "") { + $taginfo = " (HEAD)"; + } + else { + $taginfo = " ($tag)"; + } + } + if ($options =~ /^\-k(.)$/) { + $taginfo .= " (no RCS-tags)" if($1 eq "o"); + $taginfo .= " (RCS binary file)" if($1 eq "b"); + $taginfo .= " (RCS values only)" if($1 eq "v"); + $taginfo .= " (RCS keywords only)" if($1 eq "k"); + } + } + my $state = $stamp; + if( $stamp =~ m(^(.+)\+(.+)$) ) { + $state = $1; + $stamp = $2; + } + if ( $state =~ /merge/ ) { + # modified version merged with update from server + # check for a conflict + if ( open (F, "$dir/$fname") ) { + my @conflict = grep /^<<<<<<</, <F>; + close (F); + if( @conflict ) { + push @conflicts, "$dir/$fname$taginfo"; + next; + } + } + else { + push @missing, "$dir/$fname$taginfo"; + next; + } + } + if ( $ver =~ /^\-.*/ ) { + push @removed, "$dir/$fname$taginfo"; + next; + } + $mtm = strToTime( $stamp ); + if( $mtm < 0 ) { + if ( $ver eq "0" ) { + push @uncommitted, "$dir/$fname$taginfo"; + } + else { + push @merged, "$dir/$fname$taginfo"; + } + next; + } + @sparams = lstat( "$dir/$fname" ); + + if ( $#sparams < 0 ) { + push @missing, "$dir/$fname$taginfo"; + next; + } + if( $mtm < $sparams[ 9 ] ) { + push @modified, "$dir/$fname$taginfo"; + next; + } + if ( $tag ne $standardtag ) { + push @tagged, "$dir/$fname$taginfo"; + } + } + close( ENTRIES ); + + my @unknownlist = sort keys (%dirunknown); + foreach $entry (@unknownlist) { + next if ($dirunknown{$entry} == 0); + # ignore unusual files + next if (-l "$dir/$entry" ); + # its a CVS directory ? might be a different module + if (-d "$dir/$entry" and -d "$dir/$entry/CVS") { + $defaulttag{"$dir/$entry"} = $standardtag; + push ( @dirqueue, "$dir/$entry" ); + next; + } + push @unknown, "$dir/$entry"; + } +} + +sub printlist($$@) +{ + my ($status, $type, @flist) = @_; + + return if (not defined($showoptions{"all"}) and + not defined($showoptions{"$type"})); + + if(defined($showoptions{"all"})) { + foreach (@flist) { + s/\.\///; + print "$status $_\n"; + } + } + else { + foreach(@flist) { + print "$_\n"; + } + } +} + +foreach $f ( @unknown ) { + $f =~ s/^\.\///; + print "? $f\n"; +} +foreach (@ARGV) { + $showoptions{"unknown"}++ if(/^(?:-u|--unknown)$/); + $showoptions{"modified"}++ if(/^(?:-m|--modified)$/); + $showoptions{"missing"}++ if(/^(?:--missing)$/); + $showoptions{"tagged"}++ if(/^(?:-t|--tagged)$/); + $showoptions{"added"}++ if(/^(?:-a|--added)$/); + $showoptions{"removed"}++ if(/^(?:-r|--removed)$/); + $showoptions{"conflicts"}++ if(/^(?:-c|--conflicts)$/); + $optionlocal++ if(/^(?:-l|--local)$/); + + next if (/^-/); + push (@dirqueue, "./$_"); +} + +# if no special flags set, show all files +$showoptions{"all"}++ if(scalar(keys(%showoptions)) == 0); + +# Try current directory if none specified +push(@dirqueue, ".") if( $#dirqueue < 0 ); + +# process directory queue +while ($#dirqueue >= 0) { + processEntries( pop @dirqueue ); +} + +&printlist("?", "unknown", @unknown); +&printlist("M", "modified", @modified); +&printlist("m", "modified", @merged); +&printlist("U", "missing", @missing); +&printlist("T", "tagged", @tagged); +&printlist("A", "added", @uncommitted); +&printlist("R", "removed", @removed); +&printlist("C", "conflicts", @conflicts); + +=head1 NAME + +cvscheck -- Lists all files in checked out CVS modules that have been +edited or changed locally. No connection is required to the CVS server, +therefore being extremely fast. + +=head1 AUTHOR + +Dirk Mueller <mueller@kde.org> +based on cvschanged by Sirtaj Singh Kang <taj@kde.org> + +=cut |