Diff for /loncom/build/filecompare.pl between versions 1.3 and 1.7

version 1.3, 2001/11/14 13:19:36 version 1.7, 2001/11/17 21:29:24
Line 1 Line 1
 #!/usr/bin/perl  #!/usr/bin/perl
   
 # Scott Harrison  # The LearningOnline Network with CAPA
   #
   # filecompare.pl - script used to help probe and compare file statistics
   #
 # YEAR=2001  # YEAR=2001
 # 9/27, 10/24, 10/25, 11/4  # 9/27, 10/24, 10/25, 11/4 Scott Harrison
   # 11/14 Guy Albertelli
   # 11/16 Scott Harrison
   #
   # $Id$
   ###
   
   ###############################################################################
   ##                                                                           ##
   ## ORGANIZATION OF THIS PERL SCRIPT                                          ##
   ##                                                                           ##
   ## 1. Invocation                                                             ##
   ## 2. Notes                                                                  ##
   ## 3. Dependencies                                                           ##
   ## 4. Process command line arguments                                         ##
   ## 5. Process file/dir location arguments                                    ##
   ## 6. Process comparison restrictions                                        ##
   ## 7. Define output and measure subroutines                                  ##
   ## 8. Loop through files and calculate differences                           ##
   ## 9. Subroutines                                                            ##
   ## 10. POD (plain old documentation, CPAN style)                             ##
   ##                                                                           ##
   ###############################################################################
   
 my $invocation=<<END;  
 # ------------------------------------------------------------------ Invocation  # ------------------------------------------------------------------ Invocation
 # filecompare.pl FILE1 FILE2  my $invocation=<<END;
 # or  filecompare.pl [ options ... ] [FILE1] [FILE2] [ restrictions ... ]
 # filecompare.pl DIR1 DIR2  or
 #  filecompare.pl [ options ... ] [DIR1] [DIR2] [ restrictions ... ]
 # A list of space separated values (after the file/dir names)  
 # can restrict the comparison.  Restrictions: a list of space separated values (after the file/dir names)
 # These values can be: existence, cvstime, age, md5sum, size, lines,  can restrict the comparison.
 # and/or diffs.  These values can be: existence, cvstime, age, md5sum, size, lines,
 #  and/or diffs.
 # Flags (before file/dir names):  
 # -p show all files the same  Options (before file/dir names):
 # -n show all files different  -p show all files that have the same comparison
 # -a show all files (with comparisons)  -n show all files that have different comparisons
 # -q only show file names (based on first file/dir)  -a show all files (with comparisons)
 # -v verbose mode (default)  -q only show file names (based on first file/dir)
   -v verbose mode (default)
   -bN buildmode (controls exit code of this script; 0 unless...)
      N=1: md5sum=same --> 1; cvstime<0 --> 2
      N=2: same as N=1 except without md5sum
      N=3: md5sum=same --> 1; age<0 --> 2
      N=4: cvstime>0 --> 2
 END  END
 unless (@ARGV) {  unless (@ARGV) {
     print $invocation;      print $invocation;
     exit 1;      exit 1;
 }  }
   
 # ----------------------------------------------------------------------- Notes  # ----------------------------------------------------------------------- Notes
 #  #
 # What are all the different ways to compare two files and how to look  # What are all the different ways to compare two files and how to look
Line 33  unless (@ARGV) { Line 64  unless (@ARGV) {
 #  #
 # Ways of comparison:  # Ways of comparison:
 #   existence similarity  #   existence similarity
 #   cvs time similarity (first argument treated as CVS source)  #   cvs time similarity (1st arg treated as CVS source; only for buildmode)
 #   age similarity (modification time)  #   age similarity (modification time)
 #   md5sum similarity  #   md5sum similarity
 #   size similarity (bytes)  #   size similarity (bytes)
Line 48  unless (@ARGV) { Line 79  unless (@ARGV) {
 #   size similarity (byte difference)  #   size similarity (byte difference)
 #   line count difference (integer)  #   line count difference (integer)
 #   number of different lines (integer)  #   number of different lines (integer)
 #     
 # Text output of comparison:  
 #   existence VALUE  
 #   cvstime VALUE  
 #   age VALUE  
 #   md5sum VALUE  
 #   size VALUE  
 #   lines VALUE  
 #   diffs VALUE  
 #  
 # Output of comparison:  
 #   exist  
 #   if md5sum not same, then different  
 #   if cvstime not 0, then older/newer  
 #   if age not 0, then older/newer  
 #   if size not 0, then bigger/smaller  
 #   if lines not 0, then more lines of code/less lines of code  
 #   if diffs not 0, then subtracted lines/added lines/changed lines  
   
   # ---------------------------------------------------------------- Dependencies
 # implementing from unix command line (assuming bash)  # implementing from unix command line (assuming bash)
 # md5sum, diff, wc -l  # md5sum, diff, wc -l
   
Line 77  unless (@ARGV) { Line 91  unless (@ARGV) {
 # -a show all files (with comparisons)  # -a show all files (with comparisons)
 # -q only show file names (based on first file/dir)  # -q only show file names (based on first file/dir)
 # -v verbose mode (default)  # -v verbose mode (default)
 # -b build/install mode (returns exitcode)  # -bN build/install mode (returns exitcode)
 my $verbose='1';  my $verbose='1';
 my $show='all';  my $show='all';
 my $buildmode=0;  my $buildmode=0;
 while (@ARGV) {  ALOOP: while (@ARGV) {
     my $flag;      my $flag;
     if ($ARGV[0]=~/^\-(\w)/) {      if ($ARGV[0]=~/^\-(\w)/) {
  $flag=$1;   $flag=$1;
    if ($flag eq 'b') {
       $ARGV[0]=~/^\-\w(\d)/;
       $buildmode=$1;
       shift @ARGV;
       next ALOOP;
    }
  shift @ARGV;   shift @ARGV;
       SWITCH: {        SWITCH: {
   $verbose=0, last SWITCH if $flag eq 'q';    $verbose=0, last SWITCH if $flag eq 'q';
Line 92  while (@ARGV) { Line 112  while (@ARGV) {
   $show='same', last SWITCH if $flag eq 'p';    $show='same', last SWITCH if $flag eq 'p';
   $show='different', last SWITCH if $flag eq 'n';    $show='different', last SWITCH if $flag eq 'n';
   $show='all', last SWITCH if $flag eq 'a';    $show='all', last SWITCH if $flag eq 'a';
   $buildmode=1, last SWITCH if $flag eq 'b';  
   $buildmode=2, last SWITCH if $flag eq 'B';  
   $buildmode=3, last SWITCH if $flag eq 'g';  
   $buildmode=4, last SWITCH if $flag eq 'G';  
   print($invocation), exit(1);    print($invocation), exit(1);
       }        }
     }      }
Line 106  while (@ARGV) { Line 122  while (@ARGV) {
 dowarn('Verbose: '.$verbose."\n");  dowarn('Verbose: '.$verbose."\n");
 dowarn('Show: '.$show."\n");  dowarn('Show: '.$show."\n");
   
   # ----------------------------------------- Process file/dir location arguments
 # FILE1 FILE2 or DIR1 DIR2  # FILE1 FILE2 or DIR1 DIR2
 my $loc1=shift @ARGV;  my $loc1=shift @ARGV;
 my $loc2=shift @ARGV;  my $loc2=shift @ARGV;
Line 131  dowarn('Processing for mode: '.$dirmode. Line 148  dowarn('Processing for mode: '.$dirmode.
 dowarn('Location #1: '.$loc1."\n");  dowarn('Location #1: '.$loc1."\n");
 dowarn('Location #2: '.$loc2."\n");  dowarn('Location #2: '.$loc2."\n");
   
   # --------------------------------------------- Process comparison restrictions
 # A list of space separated values (after the file/dir names)  # A list of space separated values (after the file/dir names)
 # can restrict the comparison.  # can restrict the comparison.
   my %rhash=('existence'=>0,'cvstime'=>0,'md5sum'=>0,'age'=>0,'size'=>0,
         'lines'=>0,'diffs'=>0);
 my %restrict;  my %restrict;
 while (@ARGV) {  while (@ARGV) {
     my $r=shift @ARGV;      my $r=shift @ARGV;
     if ($r eq 'existence' or      if ($rhash{$r}==0) {$restrict{$r}=1;}
  $r eq 'cvstime' or      else {print($invocation), exit(1);}
  $r eq 'md5sum' or  
  $r eq 'age' or  
  $r eq 'size' or  
  $r eq 'lines' or  
  $r eq 'diffs') {  
  $restrict{$r}=1;  
     }  
     else {  
  print($invocation), exit(1);  
     }  
 }  }
 if (%restrict) {  if (%restrict) {
     warn('Restricting comparison to: '.      dowarn('Restricting comparison to: '.
  join(' ',keys %restrict)."\n");   join(' ',keys %restrict)."\n");
 }  }
   
   # --------------------------------------- Define output and measure subroutines
 my %OUTPUT=(  my %OUTPUT=(
  'existence'=>(           'existence'=>( sub {print 'existence: '.@_[0]; return;}),
     sub {   'md5sum'=>(sub {print 'md5sum: '.@_[0];return;}),
  print 'existence: '.@_[0];           'cvstime'=>(sub {print 'cvstime: '.@_[0];return;}),
  return;           'age'=>(sub {print 'age: '.@_[0];return;}),
     }           'size'=>(sub {print 'size: '.@_[0];return;}),
          ),           'lines'=>(sub {print 'lines: '.@_[0];return;}),
  'md5sum'=>(           'diffs'=>(sub {print 'diffs: '.@_[0];return;}),
     sub {  
  print 'md5sum: '.@_[0];  
  return;  
     }  
          ),  
          'cvstime'=>(  
                     sub {  
                 print 'cvstime: '.@_[0];  
  return;  
     }  
          ),  
          'age'=>(  
                     sub {  
                 print 'age: '.@_[0];  
  return;  
     }  
          ),  
          'size'=>(  
                     sub {  
  print 'size: '.@_[0];  
  return;  
     }  
          ),  
          'lines'=>(  
                     sub {  
  print 'lines: '.@_[0];  
  return;  
     }  
          ),  
          'diffs'=>(  
                     sub {  
  print 'diffs: '.@_[0];  
  return;  
     }  
          ),  
 );  );
   
 my %MEASURE=(  my %MEASURE=(
  'existence' => (   'existence' => ( sub { my ($file1,$file2)=@_;
                     sub {  
  my ($file1,$file2)=@_;  
         my $rv1=(-e $file1)?'yes':'no';          my $rv1=(-e $file1)?'yes':'no';
  my $rv2=(-e $file2)?'yes':'no';   my $rv2=(-e $file2)?'yes':'no';
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }   'md5sum'=>( sub { my ($file1,$file2)=@_;
          ),  
  'md5sum'=>(  
     sub {  
  my ($file1,$file2)=@_;  
  my ($rv1)=split(/ /,`md5sum $file1`); chop $rv1;   my ($rv1)=split(/ /,`md5sum $file1`); chop $rv1;
  my ($rv2)=split(/ /,`md5sum $file2`); chop $rv2;   my ($rv2)=split(/ /,`md5sum $file2`); chop $rv2;
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }   'cvstime'=>( sub { my ($file1,$file2)=@_;
          ),  
  'cvstime'=>(  
     sub {  
  my ($file1,$file2)=@_;  
  my $rv1=&cvstime($file1);   my $rv1=&cvstime($file1);
  my @a=stat($file2); my $gmt=gmtime($a[9]);   my @a=stat($file2); my $gmt=gmtime($a[9]);
  my $rv2=&utctime($gmt);   my $rv2=&utctime($gmt);
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }           'age'=>( sub { my ($file1,$file2)=@_;
          ),  
          'age'=>(  
                     sub {  
  my ($file1,$file2)=@_;  
  my @a=stat($file1); my $rv1=$a[9];   my @a=stat($file1); my $rv1=$a[9];
  @a=stat($file2); my $rv2=$a[9];   @a=stat($file2); my $rv2=$a[9];
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }           'size'=>( sub { my ($file1,$file2)=@_;
          ),  
          'size'=>(  
                     sub {  
  my ($file1,$file2)=@_;  
  my @a=stat($file1); my $rv1=$a[7];   my @a=stat($file1); my $rv1=$a[7];
  @a=stat($file2); my $rv2=$a[7];   @a=stat($file2); my $rv2=$a[7];
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }           'lines'=>( sub { my ($file1,$file2)=@_;
          ),  
          'lines'=>(  
                     sub {  
  my ($file1,$file2)=@_;  
  my $rv1=`wc -l $file1`; chop $rv1;   my $rv1=`wc -l $file1`; chop $rv1;
  my $rv2=`wc -l $file2`; chop $rv2;   my $rv2=`wc -l $file2`; chop $rv2;
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }           'diffs'=>( sub { my ($file1,$file2)=@_;
          ),  
          'diffs'=>(  
                     sub {  
  my ($file1,$file2)=@_;  
  my $rv1=`diff $file1 $file2 | grep '^<' | wc -l`;   my $rv1=`diff $file1 $file2 | grep '^<' | wc -l`;
  chop $rv1; $rv1=~s/^\s+//; $rv1=~s/\s+$//;   chop $rv1; $rv1=~s/^\s+//; $rv1=~s/\s+$//;
  my $rv2=`diff $file1 $file2 | grep '^>' | wc -l`;   my $rv2=`diff $file1 $file2 | grep '^>' | wc -l`;
  chop $rv2; $rv2=~s/^\s+//; $rv2=~s/\s+$//;   chop $rv2; $rv2=~s/^\s+//; $rv2=~s/\s+$//;
  return ($rv1,$rv2);   return ($rv1,$rv2); } ),
     }  
          ),  
 );  );
   
 FLOP: foreach my $file (@files) {  FLOOP: foreach my $file (@files) {
     my $file1;      my $file1;
     my $file2;      my $file2;
     if ($dirmode eq 'directories') {      if ($dirmode eq 'directories') {
Line 284  FLOP: foreach my $file (@files) { Line 232  FLOP: foreach my $file (@files) {
         $diffs='n/a';          $diffs='n/a';
     }      }
     else {      else {
         my ($cvstime1,$cvstime2)=&{$MEASURE{'cvstime'}}($file1,$file2);   if ($buildmode) {
         $cvstime=$cvstime1-$cvstime2;      my ($cvstime1,$cvstime2)=&{$MEASURE{'cvstime'}}($file1,$file2);
       $cvstime=$cvstime1-$cvstime2;
    }
    else {
       $cvstime='n/a';
    }
         my ($age1,$age2)=&{$MEASURE{'age'}}($file1,$file2);          my ($age1,$age2)=&{$MEASURE{'age'}}($file1,$file2);
         $age=$age1-$age2;          $age=$age1-$age2;
         my ($md5sum1,$md5sum2)=&{$MEASURE{'md5sum'}}($file1,$file2);          my ($md5sum1,$md5sum2)=&{$MEASURE{'md5sum'}}($file1,$file2);
Line 293  FLOP: foreach my $file (@files) { Line 246  FLOP: foreach my $file (@files) {
             $md5sum='same';              $md5sum='same';
             $size=0;              $size=0;
             $lines=0;              $lines=0;
             $diffs=0;              $diffs='0:0';
  }   }
         elsif ($md5sum1 ne $md5sum2) {          elsif ($md5sum1 ne $md5sum2) {
             $md5sum='different';              $md5sum='different';
Line 314  FLOP: foreach my $file (@files) { Line 267  FLOP: foreach my $file (@files) {
         unless (@ks) {          unless (@ks) {
     @ks=('existence','cvstime','md5sum','age','size','lines','diffs');      @ks=('existence','cvstime','md5sum','age','size','lines','diffs');
  }   }
         FLOP2: for my $key (@ks) {          FLOOP2: for my $key (@ks) {
     if ($key eq 'existence') {      if ($key eq 'existence') {
  if ($existence ne 'yes:yes') {   if ($existence ne 'yes:yes') {
     $showflag=1;      $showflag=1;
Line 325  FLOP: foreach my $file (@files) { Line 278  FLOP: foreach my $file (@files) {
     $showflag=1;      $showflag=1;
  }   }
     }      }
     elsif ($key eq 'cvstime') {      elsif ($key eq 'cvstime' and $buildmode) {
  if ($cvstime!=0) {   if ($cvstime!=0) {
     $showflag=1;      $showflag=1;
  }   }
Line 351  FLOP: foreach my $file (@files) { Line 304  FLOP: foreach my $file (@files) {
  }   }
     }      }
     if ($showflag) {      if ($showflag) {
  last FLOP2;   last FLOOP2;
     }      }
         }          }
     }      }
Line 361  FLOP: foreach my $file (@files) { Line 314  FLOP: foreach my $file (@files) {
     @ks=('existence','md5sum','cvstime','age','size','lines','diffs');      @ks=('existence','md5sum','cvstime','age','size','lines','diffs');
  }   }
         my $showcount=length(@ks);          my $showcount=length(@ks);
         FLOP3: for my $key (@ks) {   $showcount-- unless $buildmode;
           FLOOP3: for my $key (@ks) {
     if ($key eq 'existence') {      if ($key eq 'existence') {
  if ($existence ne 'yes:yes') {   if ($existence ne 'yes:yes') {
     $showcount--;      $showcount--;
Line 372  FLOP: foreach my $file (@files) { Line 326  FLOP: foreach my $file (@files) {
     $showcount--;      $showcount--;
  }   }
     }      }
     elsif ($key eq 'cvstime') {      elsif ($key eq 'cvstime' and $buildmode) {
  if ($cvstime!=0) {   if ($cvstime!=0) {
     $showcount--;      $showcount--;
  }   }
Line 433  FLOP: foreach my $file (@files) { Line 387  FLOP: foreach my $file (@files) {
  }   }
     }      }
     elsif ($buildmode==4) {      elsif ($buildmode==4) {
         if ($cvstime>0) {   if ($existence=~/no$/) {
       exit(3);
    }
           elsif ($cvstime>0) {
     exit(2);      exit(2);
  }   }
    elsif ($existence=~/^no/) {
       exit(1);
    }
         else {          else {
     exit(0);      exit(0);
  }   }
     }      }
     print "$file";      if ($showflag) {
     if ($verbose==1) {   print "$file";
         print "\t";   if ($verbose==1) {
  print &{$OUTPUT{'existence'}}($existence);      print "\t";
         print "\t";      print &{$OUTPUT{'existence'}}($existence);
  print &{$OUTPUT{'cvstime'}}($cvstime);      print "\t";
         print "\t";      print &{$OUTPUT{'cvstime'}}($cvstime);
  print &{$OUTPUT{'age'}}($age);      print "\t";
         print "\t";      print &{$OUTPUT{'age'}}($age);
  print &{$OUTPUT{'md5sum'}}($md5sum);      print "\t";
         print "\t";      print &{$OUTPUT{'md5sum'}}($md5sum);
  print &{$OUTPUT{'size'}}($size);      print "\t";
         print "\t";      print &{$OUTPUT{'size'}}($size);
  print &{$OUTPUT{'lines'}}($lines);      print "\t";
         print "\t";      print &{$OUTPUT{'lines'}}($lines);
  print &{$OUTPUT{'diffs'}}($diffs);      print "\t";
       print &{$OUTPUT{'diffs'}}($diffs);
    }
    print "\n";
     }      }
     print "\n";  
 }  }
   
   # ----------------------------------------------------------------- Subroutines
   
 sub cvstime {  sub cvstime {
     my ($f)=@_;      my ($f)=@_;
     my $path; my $file;      my $path; my $file;
Line 496  sub dowarn { Line 460  sub dowarn {
     my ($msg)=@_;      my ($msg)=@_;
     warn($msg) unless $buildmode;      warn($msg) unless $buildmode;
 }  }
   
   # ----------------------------------- POD (plain old documentation, CPAN style)
   
   =head1 NAME
   
   filecompare.pl - script used to help probe and compare file statistics
   
   =head1 SYNOPSIS
   
   filecompare.pl [ options ... ] [FILE1] [FILE2] [ restrictions ... ]
   
   or
   
   filecompare.pl [ options ... ] [DIR1] [DIR2] [ restrictions ... ]
   
   Restrictions: a list of space separated values (after the file/dir names)
   can restrict the comparison.
   These values can be: existence, cvstime, age, md5sum, size, lines,
   and/or diffs.
   
   Options (before file/dir names):
   
    -p show all files that have the same comparison
   
    -n show all files that have different comparisons
   
    -a show all files (with comparisons)
   
    -q only show file names (based on first file/dir)
   
    -v verbose mode (default)
   
   =head1 DESCRIPTION
   
   filecompare.pl can work in two modes: file comparison mode, or directory
   comparison mode.
   
   Comparisons can be a function of:
   * existence similarity
   * cvs time similarity (first argument treated as CVS source)
   * age similarity (modification time)
   * md5sum similarity
   * size similarity (bytes)
   * line count difference
   * number of different lines
   
   filecompare.pl integrates smoothly with the LPML installation language
   (linux packaging markup language).  filecompare.pl is a tool that can
   be used for safe CVS source-to-target installations.
   
   =head1 README
   
   filecompare.pl integrates smoothly with the LPML installation language
   (linux packaging markup language).  filecompare.pl is a tool that can
   be used for safe CVS source-to-target installations.
   
   The unique identifier is considered to be the file name(s) independent
   of the directory path.
   
   =head1 PREREQUISITES
   
   =head1 COREQUISITES
   
   =head1 OSNAMES
   
   linux
   
   =head1 SCRIPT CATEGORIES
   
   Packaging/Administrative
   
   =cut

Removed from v.1.3  
changed lines
  Added in v.1.7


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