Warning, /sdk/kde-dev-scripts/cvscheck is written in an unsupported language. File is not indexed.

0001 #! /usr/bin/env perl
0002 
0003 use POSIX qw(mktime ctime);
0004 use Time::Local qw( timegm );
0005 
0006 # Offline check for status of files in a checked-out
0007 # CVS module. 
0008 # Artistic License, Dirk Mueller <mueller@kde.org> 2001-2003
0009 
0010 # based on cvschanged by
0011 # Sirtaj Singh Kang <taj@kde.org> Nov 1998.
0012 
0013 if ( defined $ARGV[0] && $ARGV[0] =~ /(?:-h|--help)/) {
0014   print "cvscheck (c) 2001-2003 Dirk Mueller <mueller\@kde.org>\n\nUsage:\n";
0015   print "   cvscheck [options] <dirs>\n\n";
0016   print "Prints information about the status of your local CVS checkout without\n";
0017   print "communicating with the server (therefore in speed only limited by your\n";
0018   print "hard-disk throughput, much unlike cvs -n up).\n\n";
0019   print "Every file is printed with a status character in front of its name:\n";
0020   print "? foobar.c   file is not known to CVS - maybe you should add it?\n";
0021   print "M foobar.c   file is for sure locally modified.\n";
0022   print "m foobar.c   file *might* have local changes (needs a diff with the server).\n";
0023   print "C foobar.c   file has a CVS conflict and therefore cannot be committed.\n";
0024   print "U foobar.c   file is in CVS but its somehow missing in your local checkout.\n";
0025   print "T foobar.c   file has an unusual sticky CVS tag.\n";
0026   print "A foobar.c   you cvs add'ed this file but did not yet commit.\n";
0027   print "R foobar.c   you cvs rm'ed this file but did not yet commit.\n";
0028 
0029 print <<EOF;
0030 
0031 
0032 Options: 
0033 
0034 -u | --unknown    Show only unknown (?) files
0035 -m | --modified   Show only modified (m/M) files
0036 --missing         Show only missing (U) files
0037 -t | --tagged     Show only tagged (T) files
0038 -a | --added      Show only added (A) files
0039 -r | --removed    Show only removed (R) files
0040 -c | --conflicts  Show only conflict (C) files
0041 
0042 If no option is given, it defaults to show all files and diagnostic messages.
0043 EOF
0044   exit;
0045 }
0046 
0047 # default is HEAD
0048 $standardtag = "";
0049 %defaulttag = ();
0050 @dirqueue = ();
0051 @merged = ();
0052 @uncommitted = ();
0053 @missing = ();
0054 @tagged = ();
0055 @removed = ();
0056 @unknown = ();
0057 @modified = ();
0058 @conflicts = ();
0059 
0060 %months = ( 'Jan' => 0, 'Feb' => 1, 'Mar' => 2, 'Apr' => 3, 'May' => 4,
0061             'Jun' => 5, 'Jul' => 6, 'Aug' => 7, 'Sep' => 8, 'Oct' => 9,
0062             'Nov' => 10, 'Dec' => 11);
0063 
0064 %showoptions = ();
0065 $optionlocal = 0;
0066 
0067 sub printinfo($)
0068 {
0069   print @_ if (defined($showoptions{"all"}));
0070 }
0071 
0072 # convert text stamp to GMT
0073 sub strToTime
0074 {
0075         my( $timestr ) = @_;
0076 
0077         if( ! ($timestr =~ 
0078                 /^(\w+)\s*(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)/) ) {
0079 
0080                 return -1;
0081         }
0082 
0083         # CVS timestamps are in GMT.
0084 
0085         my( $tm ) = timegm( $6, $5, $4, $3, $months{ $2 }, $7 - 1900);
0086 
0087         return $tm;
0088 }
0089 
0090 sub processEntries
0091 {
0092         my ( $dir ) = @_;
0093         my %dirunknown = ();
0094 
0095         opendir (DIR, "$dir") || warn "Couldn't read '$dir'";
0096         # first assume all are unknown
0097         while ( $e = readdir(DIR) ) {
0098           next if ($e eq ".");
0099           next if ($e eq "..");
0100           next if ($e eq "RCS");
0101           next if ($e eq "SCCS");
0102           next if ($e eq "CVS");
0103           next if ($e eq "CVS.adm");
0104           next if ($e eq "RCSLOG");
0105           next if ($e eq "tags");
0106           next if ($e eq "TAGS");
0107           next if ($e eq ".make.state");
0108           next if ($e eq ".nse_depinfo");
0109           next if ($e eq "core");
0110           next if ($e eq ".libs");
0111           next if ($e eq ".deps");
0112           next if ($e =~ /^.+~$/);
0113           next if ($e =~ /^\#.+$/);
0114           next if ($e =~ /^\.\#.+$/);
0115           next if ($e =~ /^,.+$/);
0116           next if ($e =~ /^_\$.+$/);
0117           next if ($e =~ /^.+\$$/);
0118           next if ($e =~ /^.+\.old$/);
0119           next if ($e =~ /^.+\.bak$/);
0120           next if ($e =~ /^.+\.BAK$/);
0121           next if ($e =~ /^.+\.orig$/);
0122           next if ($e =~ /^.+\.rej$/);
0123           next if ($e =~ /^\.del-.+$/);
0124           next if ($e =~ /^.+\.a$/);
0125           next if ($e =~ /^.+\.olb$/);
0126           next if ($e =~ /^.+\.o$/);
0127           next if ($e =~ /^.*\.obj$/);
0128           next if ($e =~ /^.+\.so$/);
0129           next if ($e =~ /^.+\.Z$/);
0130           next if ($e =~ /^.+\.elc$/);
0131           next if ($e =~ /^.+\.ln$/);
0132           next if ($e =~ /^cvslog\..*$/);
0133 
0134           # kde specific entries
0135           # TODO read from CVSROOT/cvsignore - if it's been checked out!
0136           next if ($e eq "config.cache");
0137           next if ($e eq "config.log");
0138           next if ($e eq "config.status");
0139           next if ($e eq "index.cache.bz2");
0140           next if ($e eq ".memdump");
0141           next if ($e eq "autom4te.cache");
0142           next if ($e eq "autom4te.cache");
0143           next if ($e eq "Makefile.rules");
0144           next if ($e eq "Makefile.calls");
0145           next if ($e eq "Makefile.rules.in");
0146           next if ($e eq "Makefile.calls.in");
0147           next if ($e =~ /^.*\.moc$/);
0148           next if ($e =~ /^.+\.gmo$/);
0149           next if ($e =~ /^.+\.moc\.[^\.]+$/);
0150           next if ($e =~ /^.+\.lo$/);
0151           next if ($e =~ /^.+\.la$/);
0152           next if ($e =~ /^.+\.rpo$/);
0153           next if ($e =~ /^.+\.closure$/);
0154           next if ($e =~ /^.+\.all_cpp\.cpp$/);
0155           next if ($e =~ /^.+\.all_C\.C$/);
0156           next if ($e =~ /^.+\.all_cc\.cc$/);
0157           next if ($e =~ /^.+_meta_unload\.[^\.]+$/);
0158           next if ($e =~ /^.+\.kidl$/);
0159           next if ($e =~ /^.+_skel\.[^\.]+$/);
0160 
0161           # Qt specific entries
0162           next if ($e eq ".ui");
0163           next if ($e eq ".moc");
0164           next if ($e eq ".obj");
0165 
0166           $dirunknown{$e} = 1;
0167         }
0168         closedir(DIR);
0169         if( open(CVSIGNORE, $dir."/.cvsignore") ) {
0170           while(<CVSIGNORE>) {
0171             s/\s*$//;
0172             my $line = $_;
0173             foreach my $entry ( split(/ /,$line) ) {
0174               if ($entry =~ /[\*\?]/) {
0175                 my $pattern = quotemeta $entry;
0176                 $pattern =~ s/\\\*/.*/g;
0177                 $pattern =~ s/\\\?/./g;
0178                 foreach $m (keys (%dirunknown)) {
0179                   $dirunknown{$m} = 0 if ($m =~ /^$pattern$/);
0180                 }
0181                 next;
0182               }
0183               $dirunknown{$entry} = 0;
0184             }
0185           }
0186           close(CVSIGNORE);
0187         }
0188 
0189         if ( !open( ENTRIES, $dir."/CVS/Entries" ) ) {
0190           &printinfo("I CVS/Entries missing in $dir\n");
0191           return;
0192         }
0193         my $oldstandardtag = defined($defaulttag{$dir}) ? $defaulttag{$dir} : "";
0194         my $staginfo = "";
0195         if( open(CVSTAG, $dir."/CVS/Tag" ) ) {
0196           my $line = <CVSTAG>;
0197           if($line =~ /^[TDN](.+)$/) {
0198             $standardtag = $1;
0199             $staginfo = $1;
0200           }
0201           else {
0202             # something with D - assume HEAD
0203             $oldstandardtag = $standardtag = ""; # its HEAD
0204             &printinfo("I $dir has unknown stickyness: $line");
0205           }
0206           close(CVSTAG);
0207         }
0208         else {
0209           $standardtag = ""; # its HEAD
0210           $staginfo = "(HEAD)";
0211         }
0212         &printinfo("I $dir has sticky tag $staginfo\n") if($standardtag ne $oldstandardtag);
0213         while( <ENTRIES> ) {
0214           if ( m#^\s*D/([^/]+)/# ) {
0215                if (-d "$dir/$1" && !$optionlocal) {
0216                  push ( @dirqueue, "$dir/$1" );
0217                  $defaulttag{"$dir/$1"} = $standardtag;
0218                }
0219                $dirunknown{$1} = 0;
0220                next;
0221             }
0222 
0223           next if !m#^\s*/([^/]+)/([-]*[\d\.]*)/([^/]+)/([^/]*)/(\S*)$#;
0224           $fname = $1;
0225           $ver = $2;
0226           $stamp = $3;
0227           $options = $4;
0228           $tag = $5;
0229           $tag = $1 if ($tag =~ /^[TD](.+)$/);
0230 
0231           $dirunknown{$fname} = 0;
0232 
0233           my $taginfo="";
0234           if(defined($showoptions{"all"})) {
0235             if ( $tag ne $standardtag ) {
0236               if ($tag eq "") {
0237                 $taginfo = " (HEAD)";
0238               }
0239               else {
0240                 $taginfo = " ($tag)";
0241               }
0242             }
0243             if ($options =~ /^\-k(.)$/) {
0244               $taginfo .= " (no RCS-tags)" if($1 eq "o");
0245               $taginfo .= " (RCS binary file)" if($1 eq "b");
0246               $taginfo .= " (RCS values only)" if($1 eq "v");
0247               $taginfo .= " (RCS keywords only)" if($1 eq "k");
0248             }
0249           }
0250           my $state = $stamp;
0251           if( $stamp =~ m(^(.+)\+(.+)$) ) {
0252             $state = $1;
0253             $stamp = $2;
0254           }
0255           if ( $state =~ /merge/ ) {
0256             # modified version merged with update from server
0257             # check for a conflict
0258             if ( open (F, "$dir/$fname") ) {
0259               my @conflict = grep /^<<<<<<</, <F>;
0260               close (F);
0261               if( @conflict ) {
0262                 push @conflicts, "$dir/$fname$taginfo";
0263                 next;
0264               }
0265             } 
0266             else {
0267               push @missing, "$dir/$fname$taginfo";
0268               next;
0269             }
0270           }
0271           if ( $ver =~ /^\-.*/ ) {
0272             push @removed, "$dir/$fname$taginfo";
0273             next;
0274           }
0275           $mtm = strToTime( $stamp );
0276           if( $mtm < 0 ) {
0277             if ( $ver eq "0" ) {
0278               push @uncommitted, "$dir/$fname$taginfo";
0279             }
0280             else {
0281               push @merged, "$dir/$fname$taginfo";
0282             }
0283             next;
0284           }
0285           @sparams = lstat( "$dir/$fname" );
0286 
0287           if ( $#sparams < 0 ) {
0288             push @missing, "$dir/$fname$taginfo";
0289             next;
0290           }
0291           if( $mtm < $sparams[ 9 ] ) {
0292             push @modified, "$dir/$fname$taginfo";
0293             next;
0294           }
0295           if ( $tag ne $standardtag ) {
0296             push @tagged, "$dir/$fname$taginfo";
0297           }
0298         }
0299         close( ENTRIES );
0300 
0301         my @unknownlist = sort keys (%dirunknown);
0302         foreach $entry (@unknownlist) {
0303           next if ($dirunknown{$entry} == 0);
0304           # ignore unusual files
0305           next if (-l "$dir/$entry" );
0306           # its a CVS directory ? might be a different module
0307           if (-d "$dir/$entry" and -d "$dir/$entry/CVS") {
0308             $defaulttag{"$dir/$entry"} = $standardtag;
0309             push ( @dirqueue, "$dir/$entry" );
0310             next;
0311           }
0312           push @unknown, "$dir/$entry";
0313         }
0314 }
0315 
0316 sub printlist($$@)
0317 {
0318   my ($status, $type, @flist) = @_;
0319 
0320   return if (not defined($showoptions{"all"}) and 
0321              not defined($showoptions{"$type"}));
0322 
0323   if(defined($showoptions{"all"})) {
0324     foreach (@flist) {
0325       s/\.\///;
0326       print "$status $_\n";
0327     }
0328   }
0329   else {
0330     foreach(@flist) {
0331       print "$_\n";
0332     }
0333   }
0334 }
0335 
0336 foreach $f ( @unknown ) {
0337   $f =~ s/^\.\///;
0338   print "? $f\n";
0339 }
0340 foreach (@ARGV) {
0341    $showoptions{"unknown"}++ if(/^(?:-u|--unknown)$/);
0342    $showoptions{"modified"}++ if(/^(?:-m|--modified)$/);
0343    $showoptions{"missing"}++ if(/^(?:--missing)$/);
0344    $showoptions{"tagged"}++ if(/^(?:-t|--tagged)$/);
0345    $showoptions{"added"}++ if(/^(?:-a|--added)$/);
0346    $showoptions{"removed"}++ if(/^(?:-r|--removed)$/);
0347    $showoptions{"conflicts"}++ if(/^(?:-c|--conflicts)$/);
0348    $optionlocal++ if(/^(?:-l|--local)$/);
0349 
0350    next if (/^-/);
0351    push (@dirqueue, "./$_");
0352 }
0353 
0354 # if no special flags set, show all files
0355 $showoptions{"all"}++ if(scalar(keys(%showoptions)) == 0);
0356 
0357 # Try current directory if none specified
0358 push(@dirqueue, ".") if( $#dirqueue < 0 );
0359 
0360 # process directory queue
0361 while ($#dirqueue >= 0) {
0362   processEntries( pop @dirqueue );
0363 }
0364 
0365 &printlist("?", "unknown", @unknown);
0366 &printlist("M", "modified", @modified);
0367 &printlist("m", "modified", @merged);
0368 &printlist("U", "missing", @missing);
0369 &printlist("T", "tagged", @tagged);
0370 &printlist("A", "added", @uncommitted);
0371 &printlist("R", "removed", @removed);
0372 &printlist("C", "conflicts", @conflicts);
0373 
0374 =head1 NAME
0375 
0376 cvscheck -- Lists all files in checked out CVS modules that have been
0377 edited or changed locally. No connection is required to the CVS server,
0378 therefore being extremely fast. 
0379 
0380 =head1 AUTHOR
0381 
0382 Dirk Mueller <mueller@kde.org>
0383 based on cvschanged by Sirtaj Singh Kang <taj@kde.org>
0384 
0385 =cut