Annotation of loncom/build/filecompare.pl, revision 1.15

1.1       harris41    1: #!/usr/bin/perl
                      2: 
1.5       harris41    3: # The LearningOnline Network with CAPA
1.10      harris41    4: # filecompare.pl - script used to help probe and compare file statistics
                      5: #
1.15    ! raeburn     6: # $Id: filecompare.pl,v 1.14 2004/07/02 22:04:50 albertel Exp $
1.10      harris41    7: #
                      8: # Copyright Michigan State University Board of Trustees
                      9: #
                     10: # This file is part of the LearningOnline Network with CAPA (LON-CAPA).
                     11: #
                     12: # LON-CAPA is free software; you can redistribute it and/or modify
                     13: # it under the terms of the GNU General Public License as published by
                     14: # the Free Software Foundation; either version 2 of the License, or
                     15: # (at your option) any later version.
                     16: #
                     17: # LON-CAPA is distributed in the hope that it will be useful,
                     18: # but WITHOUT ANY WARRANTY; without even the implied warranty of
                     19: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     20: # GNU General Public License for more details.
1.4       harris41   21: #
1.10      harris41   22: # You should have received a copy of the GNU General Public License
                     23: # along with LON-CAPA; if not, write to the Free Software
                     24: # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
                     25: #
                     26: # /home/httpd/html/adm/gpl.txt
                     27: #
                     28: # http://www.lon-capa.org/
1.4       harris41   29: #
1.1       harris41   30: # YEAR=2001
1.4       harris41   31: # 9/27, 10/24, 10/25, 11/4 Scott Harrison
                     32: # 11/14 Guy Albertelli
1.8       harris41   33: # 11/16,11/17 Scott Harrison
1.9       harris41   34: # 12/3,12/5 Scott Harrison
1.4       harris41   35: #
                     36: ###
1.1       harris41   37: 
1.5       harris41   38: ###############################################################################
                     39: ##                                                                           ##
                     40: ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
                     41: ##                                                                           ##
                     42: ## 1. Invocation                                                             ##
                     43: ## 2. Notes                                                                  ##
                     44: ## 3. Dependencies                                                           ##
                     45: ## 4. Process command line arguments                                         ##
                     46: ## 5. Process file/dir location arguments                                    ##
                     47: ## 6. Process comparison restrictions                                        ##
                     48: ## 7. Define output and measure subroutines                                  ##
                     49: ## 8. Loop through files and calculate differences                           ##
                     50: ## 9. Subroutines                                                            ##
                     51: ## 10. POD (plain old documentation, CPAN style)                             ##
                     52: ##                                                                           ##
                     53: ###############################################################################
                     54: 
1.4       harris41   55: # ------------------------------------------------------------------ Invocation
1.1       harris41   56: my $invocation=<<END;
1.4       harris41   57: filecompare.pl [ options ... ] [FILE1] [FILE2] [ restrictions ... ]
                     58: or
                     59: filecompare.pl [ options ... ] [DIR1] [DIR2] [ restrictions ... ]
1.9       harris41   60: or
                     61: filecompare.pl [ options ... ] -s TARGET=[target] SOURCE=[source] MODE=[mode]
                     62:     LOC1 LOC2
1.4       harris41   63: 
                     64: Restrictions: a list of space separated values (after the file/dir names)
                     65: can restrict the comparison.
                     66: These values can be: existence, cvstime, age, md5sum, size, lines,
                     67: and/or diffs.
                     68: 
                     69: Options (before file/dir names):
                     70: -p show all files that have the same comparison
                     71: -n show all files that have different comparisons
                     72: -a show all files (with comparisons)
                     73: -q only show file names (based on first file/dir)
                     74: -v verbose mode (default)
1.13      harris41   75: -bN buildmode (controls EXIT code of this script; 0 unless...)
1.6       harris41   76:    N=1: md5sum=same --> 1; cvstime<0 --> 2
1.5       harris41   77:    N=2: same as N=1 except without md5sum
                     78:    N=3: md5sum=same --> 1; age<0 --> 2
                     79:    N=4: cvstime>0 --> 2
1.15    ! raeburn    80:    N=5: md5sum=same --> 1; cvstime<0 and sha1sum from dns_checksums=different --> 2;
        !            81:    N=6: md5sum=same --> 1; age<0 and sha1sum from dns_checksums=different --> 2;   
1.9       harris41   82: 
                     83: The third way to pass arguments is set by the -s flag.
                     84: filecompare.pl -s SOURCE=[source] TARGET=[target] MODE=[mode] LOC1 LOC2
                     85: 
                     86: TARGET corresponds to the root path of LOC2.  SOURCE corresponds to
                     87: the root path of LOC1.  MODE can either be file, directory, link, or fileglob.
                     88: 
1.1       harris41   89: END
                     90: unless (@ARGV) {
                     91:     print $invocation;
                     92:     exit 1;
                     93: }
1.5       harris41   94: 
1.1       harris41   95: # ----------------------------------------------------------------------- Notes
                     96: #
                     97: # What are all the different ways to compare two files and how to look
                     98: # at the differences?
                     99: #
                    100: # Ways of comparison:
                    101: #   existence similarity
1.6       harris41  102: #   cvs time similarity (1st arg treated as CVS source; only for buildmode)
1.1       harris41  103: #   age similarity (modification time)
                    104: #   md5sum similarity
                    105: #   size similarity (bytes)
                    106: #   line count difference
                    107: #   number of different lines
1.15    ! raeburn   108: #   sha1sum similarity to checksum for same file in installed version
1.1       harris41  109: #
                    110: # Quantities of comparison:
                    111: #   existence (no,yes); other values become 'n/a'
1.2       harris41  112: #   cvstime in seconds
1.1       harris41  113: #   age in seconds
                    114: #   md5sum ("same" or "different")
                    115: #   size similarity (byte difference)
                    116: #   line count difference (integer)
                    117: #   number of different lines (integer)
1.15    ! raeburn   118: #   sha1sum ("same" or "different") 
1.1       harris41  119: 
1.5       harris41  120: # ---------------------------------------------------------------- Dependencies
1.1       harris41  121: # implementing from unix command line (assuming bash)
1.15    ! raeburn   122: # md5sum, diff, wc -l, sha1sum
1.1       harris41  123: 
                    124: # ---------------------------------------------- Process command line arguments
                    125: # Flags (before file/dir names):
                    126: # -p show all files the same
                    127: # -n show all files different
                    128: # -a show all files (with comparisons)
                    129: # -q only show file names (based on first file/dir)
                    130: # -v verbose mode (default)
1.5       harris41  131: # -bN build/install mode (returns exitcode)
1.9       harris41  132: # -s status checking mode for lpml
                    133: 
1.1       harris41  134: my $verbose='1';
                    135: my $show='all';
1.2       harris41  136: my $buildmode=0;
1.9       harris41  137: my $statusmode=0;
1.6       harris41  138: ALOOP: while (@ARGV) {
1.1       harris41  139:     my $flag;
                    140:     if ($ARGV[0]=~/^\-(\w)/) {
                    141: 	$flag=$1;
1.5       harris41  142: 	if ($flag eq 'b') {
                    143: 	    $ARGV[0]=~/^\-\w(\d)/;
                    144: 	    $buildmode=$1;
1.6       harris41  145: 	    shift @ARGV;
                    146: 	    next ALOOP;
1.5       harris41  147: 	}
1.1       harris41  148: 	shift @ARGV;
                    149:       SWITCH: {
                    150: 	  $verbose=0, last SWITCH if $flag eq 'q';
                    151: 	  $verbose=1, last SWITCH if $flag eq 'v';
                    152: 	  $show='same', last SWITCH if $flag eq 'p';
                    153: 	  $show='different', last SWITCH if $flag eq 'n';
                    154: 	  $show='all', last SWITCH if $flag eq 'a';
1.9       harris41  155: 	  $statusmode=1, last SWITCH if $flag eq 's';
1.1       harris41  156: 	  print($invocation), exit(1);
                    157:       }
                    158:     }
                    159:     else {
                    160: 	last;
                    161:     }
                    162: }
1.2       harris41  163: dowarn('Verbose: '.$verbose."\n");
                    164: dowarn('Show: '.$show."\n");
1.1       harris41  165: 
1.9       harris41  166: my @files;
                    167: my $loc1;
                    168: my $loc2;
1.10      harris41  169: my $dirmode='directories';
1.9       harris41  170: # ----------------------------------------- If status checking mode for lpml
                    171: my ($sourceroot,$targetroot,$mode,$sourceglob,$targetglob);
                    172: my ($source,$target);
                    173: if ($statusmode==1) {
                    174:     ($sourceroot,$targetroot,$mode,$sourceglob,$targetglob)=splice(@ARGV,0,5);
                    175:     $targetroot.='/' if $targetroot!~/\/$/;
                    176:     $sourceroot=~s/^SOURCE\=//;
                    177:     $targetroot=~s/^TARGET\=//;
                    178:     $source=$sourceroot.'/'.$sourceglob;
                    179:     $target=$targetroot.''.$targetglob;
                    180: #    print "SOURCE: $source\n";
                    181: #    print "TARGET: $target\n";
                    182:     if ($mode eq 'MODE=fileglob') {
1.10      harris41  183: 	$loc1=$source;$loc1=~s/\/[^\/]*$// if length($loc1)>2;
                    184: 	$loc2=$target;$loc2=~s/\/[^\/]*$// if length($loc2)>2;
                    185: 	@files=map {s/^$loc1\///;$_} glob($source);
                    186: 	$dirmode='directories';
                    187:     }
                    188:     elsif ($mode eq 'MODE=file') {
                    189: 	$loc1=$source;
                    190: 	$loc2=$target;
                    191: 	$dirmode='files';
                    192: 	@files=($loc1);
1.9       harris41  193:     }
                    194: }
                    195: else {
                    196: 
1.5       harris41  197: # ----------------------------------------- Process file/dir location arguments
1.1       harris41  198: # FILE1 FILE2 or DIR1 DIR2
1.9       harris41  199: $loc1=shift @ARGV;
                    200: $loc2=shift @ARGV;
1.1       harris41  201: unless ($loc1 and $loc2) {
1.9       harris41  202:     print "LOC1: $loc1\nLOC2: $loc2\n";
1.1       harris41  203:     print($invocation), exit(1);
                    204: }
                    205: if (-f $loc1) {
                    206:     $dirmode='files';
                    207:     @files=($loc1);
                    208: }
                    209: else {
                    210:     if (-e $loc1) {
                    211: 	@files=`find $loc1 -type f`;
                    212:     }
                    213:     else {
                    214: 	@files=($loc1);
                    215:     }
                    216:     map {chomp; s/^$loc1\///; $_} @files;
                    217: }
1.2       harris41  218: dowarn('Processing for mode: '.$dirmode."\n");
                    219: dowarn('Location #1: '.$loc1."\n");
                    220: dowarn('Location #2: '.$loc2."\n");
1.9       harris41  221: }
1.5       harris41  222: # --------------------------------------------- Process comparison restrictions
1.1       harris41  223: # A list of space separated values (after the file/dir names)
                    224: # can restrict the comparison.
1.5       harris41  225: my %rhash=('existence'=>0,'cvstime'=>0,'md5sum'=>0,'age'=>0,'size'=>0,
                    226: 	      'lines'=>0,'diffs'=>0);
1.1       harris41  227: my %restrict;
                    228: while (@ARGV) {
                    229:     my $r=shift @ARGV;
1.5       harris41  230:     if ($rhash{$r}==0) {$restrict{$r}=1;}
                    231:     else {print($invocation), exit(1);}
1.1       harris41  232: }
                    233: if (%restrict) {
1.5       harris41  234:     dowarn('Restricting comparison to: '.
1.1       harris41  235: 	 join(' ',keys %restrict)."\n");
                    236: }
                    237: 
1.5       harris41  238: # --------------------------------------- Define output and measure subroutines
1.1       harris41  239: my %OUTPUT=(
1.4       harris41  240:          'existence'=>( sub {print 'existence: '.@_[0]; return;}),
                    241: 	 'md5sum'=>(sub {print 'md5sum: '.@_[0];return;}),
                    242:          'cvstime'=>(sub {print 'cvstime: '.@_[0];return;}),
                    243:          'age'=>(sub {print 'age: '.@_[0];return;}),
                    244:          'size'=>(sub {print 'size: '.@_[0];return;}),
                    245:          'lines'=>(sub {print 'lines: '.@_[0];return;}),
                    246:          'diffs'=>(sub {print 'diffs: '.@_[0];return;}),
1.15    ! raeburn   247:          'sha1sum'=>(sub {print 'sha1sum: '.@_[0];return;}),
1.1       harris41  248: );
                    249: 
                    250: my %MEASURE=(
1.4       harris41  251: 	 'existence' => ( sub { my ($file1,$file2)=@_;
1.1       harris41  252: 		        my $rv1=(-e $file1)?'yes':'no';
                    253: 			my $rv2=(-e $file2)?'yes':'no';
1.4       harris41  254: 			return ($rv1,$rv2); } ),
                    255: 	 'md5sum'=>( sub { my ($file1,$file2)=@_;
1.3       albertel  256: 			my ($rv1)=split(/ /,`md5sum $file1`); chop $rv1;
                    257: 			my ($rv2)=split(/ /,`md5sum $file2`); chop $rv2;
1.4       harris41  258: 			return ($rv1,$rv2); } ),
                    259: 	 'cvstime'=>( sub { my ($file1,$file2)=@_;
1.2       harris41  260: 			my $rv1=&cvstime($file1);
                    261: 			my @a=stat($file2); my $gmt=gmtime($a[9]);
                    262: 			my $rv2=&utctime($gmt);
1.4       harris41  263: 			return ($rv1,$rv2); } ),
                    264:          'age'=>( sub {	my ($file1,$file2)=@_;
1.2       harris41  265: 			my @a=stat($file1); my $rv1=$a[9];
                    266: 			@a=stat($file2); my $rv2=$a[9];
1.4       harris41  267: 			return ($rv1,$rv2); } ),
                    268:          'size'=>( sub { my ($file1,$file2)=@_;
1.1       harris41  269: 			my @a=stat($file1); my $rv1=$a[7];
                    270: 			@a=stat($file2); my $rv2=$a[7];
1.4       harris41  271: 			return ($rv1,$rv2); } ),
                    272:          'lines'=>( sub { my ($file1,$file2)=@_;
1.1       harris41  273: 			my $rv1=`wc -l $file1`; chop $rv1;
                    274: 			my $rv2=`wc -l $file2`; chop $rv2;
1.4       harris41  275: 			return ($rv1,$rv2); } ),
                    276:          'diffs'=>( sub { my ($file1,$file2)=@_;
1.14      albertel  277: 			return (0,0);
1.1       harris41  278: 			my $rv1=`diff $file1 $file2 | grep '^<' | wc -l`;
                    279: 			chop $rv1; $rv1=~s/^\s+//; $rv1=~s/\s+$//;
                    280: 			my $rv2=`diff $file1 $file2 | grep '^>' | wc -l`;
                    281: 			chop $rv2; $rv2=~s/^\s+//; $rv2=~s/\s+$//;
1.4       harris41  282: 			return ($rv1,$rv2); } ),
1.15    ! raeburn   283:          'sha1sum'=>( sub { my ($file1,$file2)=@_;
        !           284:                           if (open(my $fh,"</etc/loncapa-release.prev")) {
        !           285:                               my $loncaparev = <$fh>;
        !           286:                               close($fh);
        !           287:                               chomp($loncaparev);
        !           288:                               $loncaparev =~ s/^\QLON-CAPA release \E//;
        !           289:                               $loncaparev =~ s/\-\d{8}$//;
        !           290:                               my ($rv1)=split(/ /,`sha1sum $file2`); chomp $rv1;
        !           291:                               my $checksum;
        !           292:                               if ($loncaparev eq 'CVS_HEAD') {
        !           293:                                   return ($rv1,$checksum);
        !           294:                               }
        !           295:                               elsif (open(my $fh,"<../../loncom/dns_checksums/$loncaparev.tab")) {
        !           296:                                   while (<$fh>) {
        !           297:                                       chomp();
        !           298:                                       if (/^\Q$file2\E,[\d\.]+,(\w+)$/) {
        !           299:                                           $checksum = $1;
        !           300:                                           last;
        !           301:                                       }
        !           302:                                   }
        !           303:                                   close($fh);
        !           304:                                   return ($rv1,$checksum);
        !           305:                               }
        !           306:                           }
        !           307:                           return('n/a','n/a'); }),
1.1       harris41  308: );
                    309: 
1.5       harris41  310: FLOOP: foreach my $file (@files) {
1.1       harris41  311:     my $file1;
                    312:     my $file2;
                    313:     if ($dirmode eq 'directories') {
                    314:         $file1=$loc1.'/'.$file;
                    315:         $file2=$loc2.'/'.$file;
                    316:     }
                    317:     else {
                    318:         $file1=$loc1;
                    319:         $file2=$loc2;
                    320:     }
                    321:     my ($existence1,$existence2)=&{$MEASURE{'existence'}}($file1,$file2);
                    322:     my $existence=$existence1.':'.$existence2;
1.15    ! raeburn   323:     my ($cvstime,$md5sum,$age,$size,$lines,$diffs,$sha1sum);
1.1       harris41  324:     if ($existence1 eq 'no' or $existence2 eq 'no') {
                    325:         $md5sum='n/a';
                    326:         $age='n/a';
1.2       harris41  327:         $cvstime='n/a';
1.1       harris41  328:         $size='n/a';
                    329:         $lines='n/a';
                    330:         $diffs='n/a';
1.15    ! raeburn   331:         $sha1sum='n/a';
1.1       harris41  332:     }
                    333:     else {
1.6       harris41  334: 	if ($buildmode) {
                    335: 	    my ($cvstime1,$cvstime2)=&{$MEASURE{'cvstime'}}($file1,$file2);
                    336: 	    $cvstime=$cvstime1-$cvstime2;
1.15    ! raeburn   337:             my ($sha1sumfile,$checksum) = &{$MEASURE{'sha1sum'}}($file1,$file2); 
        !           338:             $sha1sum='n/a';
        !           339:             unless ($checksum eq 'n/a') {
        !           340:                 if ($sha1sumfile && $checksum) { 
        !           341:                     if ($sha1sumfile eq $checksum) {
        !           342:                         $sha1sum='same';
        !           343:                     }
        !           344:                     else {
        !           345:                         $sha1sum='different';
        !           346:                     }
        !           347:                 }
        !           348: 	    }
        !           349:         }
1.6       harris41  350: 	else {
                    351: 	    $cvstime='n/a';
1.15    ! raeburn   352:             $sha1sum='n/a';
1.6       harris41  353: 	}
1.1       harris41  354:         my ($age1,$age2)=&{$MEASURE{'age'}}($file1,$file2);
                    355:         $age=$age1-$age2;
                    356:         my ($md5sum1,$md5sum2)=&{$MEASURE{'md5sum'}}($file1,$file2);
1.3       albertel  357:         if ($md5sum1 eq $md5sum2) {
1.1       harris41  358:             $md5sum='same';
                    359:             $size=0;
                    360:             $lines=0;
1.6       harris41  361:             $diffs='0:0';
1.1       harris41  362: 	}
1.3       albertel  363:         elsif ($md5sum1 ne $md5sum2) {
1.1       harris41  364:             $md5sum='different';
                    365:             my ($size1,$size2)=&{$MEASURE{'size'}}($file1,$file2);
                    366:             $size=$size1-$size2;
                    367:             my ($lines1,$lines2)=&{$MEASURE{'lines'}}($file1,$file2);
                    368:             $lines=$lines1-$lines2;
                    369:             my ($diffs1,$diffs2)=&{$MEASURE{'diffs'}}($file1,$file2);
                    370:             $diffs=$diffs1.':'.$diffs2;
                    371:         }
                    372:     }
                    373:     my $showflag=0;
                    374:     if ($show eq 'all') {
                    375:         $showflag=1;
                    376:     }
                    377:     if ($show eq 'different') {
                    378:         my @ks=(keys %restrict);
                    379:         unless (@ks) {
1.2       harris41  380: 	    @ks=('existence','cvstime','md5sum','age','size','lines','diffs');
1.1       harris41  381: 	}
1.5       harris41  382:         FLOOP2: for my $key (@ks) {
1.1       harris41  383: 	    if ($key eq 'existence') {
                    384: 		if ($existence ne 'yes:yes') {
                    385: 		    $showflag=1;
                    386: 		}
                    387: 	    }
                    388: 	    elsif ($key eq 'md5sum') {
                    389: 		if ($md5sum ne 'same') {
                    390: 		    $showflag=1;
                    391: 		}
                    392: 	    }
1.6       harris41  393: 	    elsif ($key eq 'cvstime' and $buildmode) {
1.2       harris41  394: 		if ($cvstime!=0) {
                    395: 		    $showflag=1;
                    396: 		}
                    397: 	    }
1.1       harris41  398: 	    elsif ($key eq 'age') {
                    399: 		if ($age!=0) {
                    400: 		    $showflag=1;
                    401: 		}
                    402: 	    }
                    403: 	    elsif ($key eq 'size') {
                    404: 		if ($size!=0) {
                    405: 		    $showflag=1;
                    406: 		}
                    407: 	    }
                    408: 	    elsif ($key eq 'lines') {
                    409: 		if ($lines!=0) {
                    410: 		    $showflag=1;
                    411: 		}
                    412: 	    }
                    413: 	    elsif ($key eq 'diffs') {
                    414: 		if ($diffs ne '0:0') {
                    415: 		    $showflag=1;
                    416: 		}
                    417: 	    }
                    418: 	    if ($showflag) {
1.5       harris41  419: 		last FLOOP2;
1.1       harris41  420: 	    }
                    421:         }
                    422:     }
                    423:     elsif ($show eq 'same') {
                    424:         my @ks=(keys %restrict);
                    425:         unless (@ks) {
1.2       harris41  426: 	    @ks=('existence','md5sum','cvstime','age','size','lines','diffs');
1.1       harris41  427: 	}
                    428:         my $showcount=length(@ks);
1.6       harris41  429: 	$showcount-- unless $buildmode;
1.5       harris41  430:         FLOOP3: for my $key (@ks) {
1.1       harris41  431: 	    if ($key eq 'existence') {
                    432: 		if ($existence ne 'yes:yes') {
                    433: 		    $showcount--;
                    434: 		}
                    435: 	    }
                    436: 	    elsif ($key eq 'md5sum') {
                    437: 		if ($md5sum ne 'same') {
                    438: 		    $showcount--;
                    439: 		}
                    440: 	    }
1.6       harris41  441: 	    elsif ($key eq 'cvstime' and $buildmode) {
1.2       harris41  442: 		if ($cvstime!=0) {
                    443: 		    $showcount--;
                    444: 		}
                    445: 	    }
1.1       harris41  446: 	    elsif ($key eq 'age') {
                    447: 		if ($age!=0) {
                    448: 		    $showcount--;
                    449: 		}
                    450: 	    }
                    451: 	    elsif ($key eq 'size') {
                    452: 		if ($size!=0) {
                    453: 		    $showcount--;
                    454: 		}
                    455: 	    }
                    456: 	    elsif ($key eq 'lines') {
                    457: 		if ($lines!=0) {
                    458: 		    $showcount--;
                    459: 		}
                    460: 	    }
                    461: 	    elsif ($key eq 'diffs') {
                    462: 		if ($diffs ne '0:0') {
                    463: 		    $showcount--;
                    464: 		}
                    465: 	    }
                    466:         }
                    467:         if ($showcount==0) {
                    468: 	    $showflag=1;
                    469: 	}
                    470:     }
1.13      harris41  471:     if ($buildmode==1) { # -b1
1.2       harris41  472:         if ($md5sum eq 'same') {
                    473: 	    exit(1);
                    474: 	}
                    475:         elsif ($cvstime<0) {
                    476: 	    exit(2);
                    477: 	}
                    478:         else {
                    479: 	    exit(0);
                    480: 	}
                    481:     }
1.13      harris41  482:     elsif ($buildmode==2) { # -b2
1.2       harris41  483:         if ($cvstime<0) {
                    484: 	    exit(2);
                    485: 	}
                    486:         else {
                    487: 	    exit(0);
                    488: 	}
                    489:     }
1.13      harris41  490:     elsif ($buildmode==3) { # -b3
1.2       harris41  491:         if ($md5sum eq 'same') {
                    492: 	    exit(1);
                    493: 	}
                    494:         elsif ($age<0) {
                    495: 	    exit(2);
                    496: 	}
                    497:         else {
                    498: 	    exit(0);
                    499: 	}
                    500:     }
1.13      harris41  501:     elsif ($buildmode==4) { # -b4
1.7       harris41  502: 	if ($existence=~/no$/) {
                    503: 	    exit(3);
                    504: 	}
                    505:         elsif ($cvstime>0) {
1.2       harris41  506: 	    exit(2);
1.7       harris41  507: 	}
                    508: 	elsif ($existence=~/^no/) {
                    509: 	    exit(1);
1.2       harris41  510: 	}
                    511:         else {
                    512: 	    exit(0);
                    513: 	}
                    514:     }
1.15    ! raeburn   515:     elsif ($buildmode==5) { # -b5
        !           516:         if ($md5sum eq 'same') {
        !           517:             exit(1);
        !           518:         }
        !           519:         elsif ($cvstime<0) {
        !           520:             if ($sha1sum eq 'same') {
        !           521:                 exit(0);
        !           522:             }
        !           523:             else {
        !           524:                 exit(2);
        !           525:             }
        !           526:         }
        !           527:         else {
        !           528:             exit(0);
        !           529:         }
        !           530:     }
        !           531:     elsif ($buildmode==6) { # -b6
        !           532:         if ($md5sum eq 'same') {
        !           533:             exit(1);
        !           534:         }
        !           535:         elsif ($age<0) {
        !           536:             if ($sha1sum eq 'same') {
        !           537:                 exit(0);
        !           538:             }
        !           539:             else {
        !           540:                 exit(2);
        !           541:             }
        !           542:         }
        !           543:         else {
        !           544:             exit(0);
        !           545:         }
        !           546:     }
        !           547: 
1.6       harris41  548:     if ($showflag) {
                    549: 	print "$file";
                    550: 	if ($verbose==1) {
                    551: 	    print "\t";
                    552: 	    print &{$OUTPUT{'existence'}}($existence);
                    553: 	    print "\t";
                    554: 	    print &{$OUTPUT{'cvstime'}}($cvstime);
                    555: 	    print "\t";
                    556: 	    print &{$OUTPUT{'age'}}($age);
                    557: 	    print "\t";
                    558: 	    print &{$OUTPUT{'md5sum'}}($md5sum);
1.15    ! raeburn   559:             print "\t";
        !           560:             print &{$OUTPUT{'sha1sum'}}($sha1sum);
1.6       harris41  561: 	    print "\t";
                    562: 	    print &{$OUTPUT{'size'}}($size);
                    563: 	    print "\t";
                    564: 	    print &{$OUTPUT{'lines'}}($lines);
                    565: 	    print "\t";
                    566: 	    print &{$OUTPUT{'diffs'}}($diffs);
1.15    ! raeburn   567:             
1.6       harris41  568: 	}
                    569: 	print "\n";
1.1       harris41  570:     }
                    571: }
                    572: 
1.5       harris41  573: # ----------------------------------------------------------------- Subroutines
                    574: 
1.2       harris41  575: sub cvstime {
                    576:     my ($f)=@_;
                    577:     my $path; my $file;
                    578:     if ($f=~/^(.*\/)(.*?)$/) {
                    579: 	$f=~/^(.*\/)(.*?)$/;
                    580: 	($path,$file)=($1,$2);
                    581:     }
                    582:     else {
                    583: 	$file=$f; $path='';
                    584:     }
                    585:     my $cvstime;
                    586:     if ($buildmode!=3) {
1.12      harris41  587: 	my $entry=`grep '^/$file/' ${path}CVS/Entries 2>/dev/null`;
1.11      harris41  588: # or
                    589: #	    die('*** WARNING *** cannot grep against '.${path}.
                    590: #		'CVS/Entries for ' .$file . "\n");
                    591: 	if ($entry) {
                    592: 	    my @fields=split(/\//,$entry);
                    593: 	    $cvstime=`date -d '$fields[3] UTC' --utc +"%s"`;
                    594: 	    chomp $cvstime;
                    595: 	}
                    596: 	else {
                    597: 	    $cvstime='n/a';
                    598: 	}
1.2       harris41  599:     }
                    600:     else {
                    601: 	$cvstime='n/a';
                    602:     }
                    603:     return $cvstime;
                    604: }
1.1       harris41  605: 
1.2       harris41  606: sub utctime {
                    607:     my ($f)=@_;
                    608:     my $utctime=`date -d '$f UTC' --utc +"%s"`;
                    609:     chomp $utctime;
                    610:     return $utctime;
                    611: }
1.1       harris41  612: 
1.2       harris41  613: sub dowarn {
                    614:     my ($msg)=@_;
                    615:     warn($msg) unless $buildmode;
                    616: }
1.5       harris41  617: 
                    618: # ----------------------------------- POD (plain old documentation, CPAN style)
1.4       harris41  619: 
                    620: =head1 NAME
                    621: 
                    622: filecompare.pl - script used to help probe and compare file statistics
                    623: 
                    624: =head1 SYNOPSIS
                    625: 
                    626: filecompare.pl [ options ... ] [FILE1] [FILE2] [ restrictions ... ]
                    627: 
                    628: or
                    629: 
                    630: filecompare.pl [ options ... ] [DIR1] [DIR2] [ restrictions ... ]
                    631: 
                    632: Restrictions: a list of space separated values (after the file/dir names)
                    633: can restrict the comparison.
                    634: These values can be: existence, cvstime, age, md5sum, size, lines,
                    635: and/or diffs.
                    636: 
                    637: Options (before file/dir names):
                    638: 
                    639:  -p show all files that have the same comparison
                    640: 
                    641:  -n show all files that have different comparisons
                    642: 
                    643:  -a show all files (with comparisons)
                    644: 
                    645:  -q only show file names (based on first file/dir)
                    646: 
                    647:  -v verbose mode (default)
                    648: 
                    649: =head1 DESCRIPTION
                    650: 
                    651: filecompare.pl can work in two modes: file comparison mode, or directory
                    652: comparison mode.
                    653: 
                    654: Comparisons can be a function of:
                    655: * existence similarity
                    656: * cvs time similarity (first argument treated as CVS source)
                    657: * age similarity (modification time)
                    658: * md5sum similarity
                    659: * size similarity (bytes)
                    660: * line count difference
                    661: * number of different lines
                    662: 
                    663: filecompare.pl integrates smoothly with the LPML installation language
                    664: (linux packaging markup language).  filecompare.pl is a tool that can
                    665: be used for safe CVS source-to-target installations.
                    666: 
                    667: =head1 README
                    668: 
                    669: filecompare.pl integrates smoothly with the LPML installation language
                    670: (linux packaging markup language).  filecompare.pl is a tool that can
                    671: be used for safe CVS source-to-target installations.
                    672: 
                    673: The unique identifier is considered to be the file name(s) independent
                    674: of the directory path.
                    675: 
                    676: =head1 PREREQUISITES
                    677: 
                    678: =head1 COREQUISITES
                    679: 
                    680: =head1 OSNAMES
                    681: 
                    682: linux
                    683: 
                    684: =head1 SCRIPT CATEGORIES
                    685: 
                    686: Packaging/Administrative
                    687: 
                    688: =cut

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>