summaryrefslogtreecommitdiff
path: root/scripts/cvscheck
Unidiff
Diffstat (limited to 'scripts/cvscheck') (more/less context) (ignore whitespace changes)
-rwxr-xr-xscripts/cvscheck344
1 files changed, 344 insertions, 0 deletions
diff --git a/scripts/cvscheck b/scripts/cvscheck
new file mode 100755
index 0000000..1b7ba0b
--- a/dev/null
+++ b/scripts/cvscheck
@@ -0,0 +1,344 @@
1#!/usr/bin/perl
2
3use POSIX qw(mktime ctime);
4use Time::Local qw( timegm );
5
6# Offline check for status of files in a checked-out
7# CVS module.
8# Dirk Mueller <mueller@kde.org> Oct 2001
9
10# based on cvschanged by
11# Sirtaj Singh Kang <taj@kde.org> Nov 1998.
12
13if ( defined $ARGV[0] && $ARGV[0] eq "--help") {
14 print "cvscheck (c) 2001 Dirk Mueller <mueller\@kde.org>\n\nUsage:\n";
15 print " cvscheck <dir>\n\n";
16 print "Prints information about the status of your local CVS checkout without\n";
17 print "communicating with the server (therefore in speed only limited by your\n";
18 print "hard-disk throughput, much unlike cvs -n up).\n\n";
19 print "Every file is printed with a status character in front of its name:\n";
20 print "? foobar.c file is not known to CVS - maybe you should add it?\n";
21 print "M foobar.c file is for sure locally modified.\n";
22 print "m foobar.c file *might* have local changes (needs a diff with the server).\n";
23 print "C foobar.c file has a CVS conflict and therefore cannot be committed.\n";
24 print "U foobar.c file is in CVS but its somehow missing in your local checkout.\n";
25 print "T foobar.c file has an unusual sticky CVS tag.\n";
26 print "A foobar.c you cvs add'ed this file but did not yet commit.\n";
27 print "R foobar.c you cvs rm'ed this file but did not yet commit.\n";
28
29 exit;
30}
31
32# default is HEAD
33$standardtag = "";
34@dirqueue = @ARGV;
35@merged = ();
36@uncommitted = ();
37@missing = ();
38@tagged = ();
39@removed = ();
40@unknown = ();
41@modified = ();
42@conflicts = ();
43
44@monthlist = ( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
45 "Sep", "Oct", "Nov", "Dec" );
46%months = ();
47
48# convert text stamp to GMT
49sub strToTime
50{
51 my( $timestr ) = @_;
52
53 if( ! ($timestr =~
54 /^(\w+)\s*(\w+)\s*(\d+)\s*(\d+):(\d+):(\d+)\s*(\d+)/) ) {
55
56 return -1;
57 }
58
59 # CVS timestamps are in GMT.
60
61 my( $tm ) = timegm( $6, $5, $4, $3, $months{ $2 }, $7 - 1900);
62
63 return $tm;
64}
65
66sub processEntries
67{
68 my ( $dir ) = @_;
69 my %dirunknown = ();
70
71 opendir (DIR, "$dir") || warn "Couldn't read '$dir'";
72 # first assume all are unknown
73 while ( $e = readdir(DIR) ) {
74 next if ($e eq ".");
75 next if ($e eq "..");
76 next if ($e eq "RCS");
77 next if ($e eq "SCCS");
78 next if ($e eq "CVS");
79 next if ($e eq "CVS.adm");
80 next if ($e eq "RCSLOG");
81 next if ($e eq "tags");
82 next if ($e eq "TAGS");
83 next if ($e eq ".make.state");
84 next if ($e eq ".nse_depinfo");
85 next if ($e eq "core");
86 next if ($e eq ".libs");
87 next if ($e eq ".deps");
88 next if ($e =~ /^.+~$/);
89 next if ($e =~ /^\#.+$/);
90 next if ($e =~ /^\.\#.+$/);
91 next if ($e =~ /^,.+$/);
92 next if ($e =~ /^_\$.+$/);
93 next if ($e =~ /^.+\$$/);
94 next if ($e =~ /^.+\.old$/);
95 next if ($e =~ /^.+\.bak$/);
96 next if ($e =~ /^.+\.BAK$/);
97 next if ($e =~ /^.+\.orig$/);
98 next if ($e =~ /^.+\.rej$/);
99 next if ($e =~ /^\.del-.+$/);
100 next if ($e =~ /^.+\.a$/);
101 next if ($e =~ /^.+\.olb$/);
102 next if ($e =~ /^.+\.o$/);
103 next if ($e =~ /^.*\.obj$/);
104 next if ($e =~ /^.+\.so$/);
105 next if ($e =~ /^.+\.Z$/);
106 next if ($e =~ /^.+\.elc$/);
107 next if ($e =~ /^.+\.ln$/);
108 next if ($e =~ /^cvslog\..*$/);
109
110 # kde specific entries
111 # TODO read from CVSROOT/cvsignore !
112 next if ($e eq "config.cache");
113 next if ($e eq "config.log");
114 next if ($e eq "config.status");
115 next if ($e eq "index.cache.bz2");
116 next if ($e eq ".memdump");
117 next if ($e eq "autom4te.cache");
118 next if ($e eq "autom4te.cache");
119 next if ($e eq "Makefile.rules.in");
120 next if ($e =~ /^.*\.moc$/);
121 next if ($e =~ /^.+\.gmo$/);
122 next if ($e =~ /^.+\.moc\.[^\.]+$/);
123 next if ($e =~ /^.+\.lo$/);
124 next if ($e =~ /^.+\.la$/);
125 next if ($e =~ /^.+\.rpo$/);
126 next if ($e =~ /^.+\.closure$/);
127 next if ($e =~ /^.+\.all_cpp\.cpp$/);
128 next if ($e =~ /^.+\.all_C\.C$/);
129 next if ($e =~ /^.+\.all_cc\.cc$/);
130 next if ($e =~ /^.+_meta_unload\.[^\.]+$/);
131 next if ($e =~ /^.+\.kidl$/);
132 next if ($e =~ /^.+_skel\.[^\.]+$/);
133 next if ($e eq "Makefile.rules.in");
134
135 $dirunknown{$e} = 1;
136 }
137 closedir(DIR);
138 if( open(CVSIGNORE, $dir."/.cvsignore") ) {
139 while(<CVSIGNORE>) {
140 next if (! /^(\S+)\s*$/ );
141 my $entry = $1;
142 if ($entry =~ /[\*\?]/) {
143 my $pattern = quotemeta $entry;
144 $pattern =~ s/\\\*/.*/g;
145 $pattern =~ s/\\\?/./g;
146 foreach $m (keys (%dirunknown)) {
147 $dirunknown{$m} = 0 if ($m =~ /^$pattern$/);
148 }
149 next;
150 }
151 $dirunknown{$entry} = 0;
152 }
153 close(CVSIGNORE);
154 }
155
156 if ( !open( ENTRIES, $dir."/CVS/Entries" ) ) {
157 print "I CVS/Entries missing in $dir\n";
158 return;
159 }
160 my $oldstandardtag = $standardtag;
161 my $staginfo = "";
162 if( open(CVSTAG, $dir."/CVS/Tag" ) ) {
163 my $line = <CVSTAG>;
164 if($line =~ /^[TN](.+)$/) {
165 $standardtag = $1;
166 $staginfo = $1;
167 }
168 else {
169 # something with D - assume HEAD
170 $oldstandardtag = $standardtag = ""; # its HEAD
171 print "I $dir has sticky date: $line\n";
172 }
173 close(CVSTAG);
174 }
175 else {
176 $standardtag = ""; # its HEAD
177 $staginfo = "(HEAD)";
178 }
179 print "I $dir has sticky tag $staginfo\n" if($standardtag ne $oldstandardtag);
180 while( <ENTRIES> ) {
181 if ( m#^\s*D/([^/]+)/# ) {
182 push ( @dirqueue, "$dir/$1" ) if (-d "$dir/$1");
183 $dirunknown{$1} = 0;
184 next;
185 }
186
187 next if !m#^\s*/([^/]+)/([-]*[\d\.]*)/([^/]+)/([^/]*)/(\S*)$#;
188 $fname = $1;
189 $ver = $2;
190 $stamp = $3;
191 $options = $4;
192 $tag = $5;
193 $tag = $1 if ($tag =~ /^T(.+)$/);
194
195 $dirunknown{$fname} = 0;
196
197 my $taginfo="";
198 if ( $tag ne $standardtag ) {
199 if ($tag eq "") {
200 $taginfo = " (HEAD)";
201 }
202 else {
203 $taginfo = " ($tag)";
204 }
205 }
206 if ($options =~ /^\-k(.)$/) {
207 $taginfo .= " (no RCS-tags)" if($1 eq "o" or $1 eq "b");
208 $taginfo .= " (RCS values only)" if($1 eq "v");
209 $taginfo .= " (RCS keywords only)" if($1 eq "k");
210 }
211 my $state = $stamp;
212 if( $stamp =~ m(^(.+)\+(.+)$) ) {
213 $state = $1;
214 $stamp = $2;
215 }
216 if ( $state =~ /merge/ ) {
217 # modified version merged with update from server
218 # check for a conflict
219 if ( open (F, "$dir/$fname") ) {
220 my @conflict = grep /^<<<<<<</, <F>;
221 close (F);
222 if( @conflict ) {
223 push @conflicts, "$dir/$fname$taginfo";
224 next;
225 }
226 }
227 else {
228 push @missing, "$dir/$fname$taginfo";
229 next;
230 }
231 }
232 if ( $ver =~ /^\-.*/ ) {
233 push @removed, "$dir/$fname$taginfo";
234 next;
235 }
236 $mtm = strToTime( $stamp );
237 if( $mtm < 0 ) {
238 if ( $ver eq "0" ) {
239 push @uncommitted, "$dir/$fname$taginfo";
240 }
241 else {
242 push @merged, "$dir/$fname$taginfo";
243 }
244 next;
245 }
246 @sparams = lstat( "$dir/$fname" );
247
248 if ( $#sparams < 0 ) {
249 push @missing, "$dir/$fname$taginfo";
250 next;
251 }
252 if( $mtm < $sparams[ 9 ] ) {
253 push @modified, "$dir/$fname$taginfo";
254 next;
255 }
256 if ( $tag ne $standardtag ) {
257 push @tagged, "$dir/$fname$taginfo";
258 }
259 }
260 close( ENTRIES );
261
262 my @unknownlist = sort keys (%dirunknown);
263 foreach $entry (@unknownlist) {
264 next if ($dirunknown{$entry} == 0);
265 # ignore unusual files
266 next if (-l "$dir/$entry" );
267 # ifnore if its a directory in CVS
268 next if (-d "$dir/$entry" and -d "$dir/$entry/CVS");
269 push @unknown, "$dir/$entry";
270 }
271}
272
273# month assoc array for name -> index lookups
274$mctr = 0;
275
276foreach $month ( @monthlist ) {
277 $months{ $month } = $mctr;
278 $mctr++;
279}
280
281# Try current directory if none specified
282
283if( $#dirqueue < 0 ) {
284 push( @dirqueue, "." );
285}
286
287# process directory queue
288foreach $dir ( @dirqueue ) {
289 processEntries( $dir );
290}
291
292foreach $f ( @unknown ) {
293 $f =~ s/^\.\///;
294 print "? $f\n";
295}
296
297foreach $f( @modified ) {
298 $f =~ s/^\.\///;
299 print "M $f\n";
300}
301
302foreach $f ( @missing ) {
303 $f =~ s/^\.\///;
304 print "U $f\n";
305}
306
307foreach $f ( @merged ) {
308 $f =~ s/^\.\///;
309 print "m $f\n";
310}
311
312foreach $f ( @tagged ) {
313 $f =~ s/^\.\///;
314 print "T $f\n";
315}
316
317foreach $f ( @uncommitted ) {
318 $f =~ s/^\.\///;
319 print "A $f\n";
320}
321
322foreach $f ( @removed ) {
323 $f =~ s/^\.\///;
324 print "R $f\n";
325}
326
327foreach $f ( @conflicts ) {
328 $f =~ s/^\.\///;
329 print "C $f\n";
330}
331
332
333=head1 NAME
334
335cvscheck -- Lists all files in checked out CVS modules that have been
336edited or changed locally. No connection is required to the CVS server,
337therefore being extremely fast.
338
339=head1 AUTHOR
340
341Dirk Mueller <mueller@kde.org>
342based on cvschanged by Sirtaj Singh Kang <taj@kde.org>
343
344=cut