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