in reply to A directory diff
use File::Find; use File::Spec::Functions; #for perl2exe use File::Spec::Unix; use strict; use vars qw($A $B $a $attrib $content $dir $dirty $f $n $patchdir); unless( scalar @ARGV == 2){ print STDERR qq(usage: dirdiff [-f] [-A] [-B] [-a|-n] [-dir] [ +-attrib[=2 |4|6]] [-content[=2]] [-patchdir] [-dirty] dir1 dir2 Compare two directories -A Specify filename to use for dir1 checksums. -B Specify filename to use for dir2 checksums. -a An alias for: -dir -content=2 -attrib=4 -attrib Files are deemed to be different if any of (mode, uid, gid, size) is different. If the 4's bit is set, the differences in the attribs are di +splayed If the 2's bit is set, the differences in the mtime are disp +layed -content Display which files have been modified (determined by MD5 ch +ecksum) If equal to 2 the output of diff -u is included -dir Display which files have been added/removed. -dirty Work in a dirty/mixed environment. Files in the dir1 and dir +2 proper are excluded from checking. -f Force new checksums to be calculated. -n An alias for: -dir -content -patchdir A directory to save the individual patches from -content sav +ed to. NOTE: dir1 and dir2 MUST be fully qualified paths for -attrib to wo +rk. NOTE: You may encounter problems with paths containing spaces. ); exit 0; } #PREP my(%alpha, %beta, %diff); my $PWD = $ENV{PWD} || `pwd`; #need some portable method chomp($PWD); my $alpha = $A; #Default non-qualified filenames to PWD unless( $alpha ){ $alpha = $ARGV[0]; $alpha =~ s%/$%%; $alpha =~ tr[/][%]; $alpha =~ s/\.\./,,/g; } unless( $alpha =~ m%^/.*/% ){ $alpha = "$PWD/$alpha"; } my $beta = $B; #Default non-qualified filenames to PWD unless( $beta ){ $beta = $ARGV[1]; $beta =~ s%/$%%; $beta =~ tr[/][%]; $beta =~ s/\.\./,,/g; } unless( $beta =~ m%^/.*/% ){ $beta = "$PWD/$beta"; } if( $a ){ $dir |= 1; $content |= 2; $attrib |= 4; } if( $n ){ $dir |= 1; $content |= 1; } { my %found; foreach my $prog ( ('md5sum', 'patch') ){ foreach my $dir ( split(':', $ENV{PATH}) ){ $found{$prog}++ if -e "$dir/$prog"; } } unless( $found{md5sum} ){ print STDERR "dirdiff: md5sum is not your path, exiting\n\n"; exit 0; } unless( $found{patch} ){ print STDERR "dirdiff: patch is not your path, disbaling -cont +ent\n\n"; $content = $content ? 1 : 0; $patchdir = 0; } } if( $patchdir ){ die("-patchdir requires -content=2") unless $content>1; mkdir($patchdir,0755) unless -d $patchdir; } ##DATA ACCQUISITION if( ! -s $alpha || $f ){ my(@F, @G, %ARC); chdir($ARGV[0]); if( $dirty ){ opendir(DIR, "."); %ARC = map { sprintf("./%s", $_) => 1 } readdir(DIR); close(DIR); } find(sub{ push @G, $File::Find::name if -d $_; push @F, $File::Find::name if -f $_;}, "."); if( $dirty ){ @F = grep(!exists($ARC{$_}), @F); } my $files = join(" ", @F); #potential overflow... `md5sum $files > $alpha`; open(OUT, ">>$alpha"); print OUT map("I_AM_A_DIRECTORY0123456789abcdef $_\n", @G); close(OUT); } open(IN,$alpha); while(<IN>){ my($val, $key)=split(/\s+/, $_); $alpha{$key}=$val; } close(IN); chdir($PWD); if( ! -s $beta || $f ){ my(@F, @G, %ARC); chdir($ARGV[1]); if( $dirty ){ opendir(DIR, "."); %ARC = map { sprintf("./%s", $_) => 1 } readdir(DIR); close(DIR); } find(sub{ push @G, $File::Find::name if -d $_; push @F, $File::Find::name if -f $_;}, "."); if( $dirty ){ @F = grep(!exists($ARC{$_}), @F); } my $files = join(" ", @F); #potential overflow... `md5sum $files > $beta`; open(OUT, ">>$beta"); print OUT map("I_AM_A_DIRECTORY0123456789abcdef $_\n", @G); close(OUT); } open(IN,$beta); while(<IN>){ my($val, $key)=split(/\s+/, $_); $beta{$key}=$val; } close(IN); ##CHECKS if( $dir ){ foreach my $key0 ( sort {$a cmp $b} keys %alpha ){ print "----- ", canonpath("$ARGV[0]/$key0"), "\n" unless $beta +{$key0}; } foreach my $key1 ( sort {$a cmp $b} keys %beta ){ $_ = canonpath("$ARGV[1]/$key1"); if( -d $_ ){ $_ = "mkdir $_"; } print "+++++ ", $_, "\n" unless $alpha{$key1}; } } if( $content ){ foreach my $key ( sort {$a cmp $b} keys %alpha ){ if( exists($beta{$key}) && $alpha{$key} ne $beta{$key} ){ my $fileB = canonpath("$ARGV[1]/$key"); print "~~~~~ $fileB\n"; my $fileA = canonpath("$ARGV[0]/$key"); if( $content > 1 ){ $diff{$fileB} = 1; my $patchContent = `diff -u $fileA $fileB`; print $patchContent; if( $patchdir ){ my $patchName = $k +ey; $patchName =~ s/^\.//; $patchName =~ tr[/][%]; open(OUT, ">$patchdir/$patchName"); print OUT $patchContent; } } } } } if( $attrib ){ my @check = $attrib%4==2 ? (2,4,5,7,9) : (2,4,5,7); foreach my $key ( sort {$a cmp $b} keys %beta ){ if( -d canonpath("$ARGV[1]/$key") ){ $alpha{$key} = $beta{$key}; } } foreach my $key ( sort {$a cmp $b} keys %alpha ){ my @F = (stat("$ARGV[0]/$key"))[@check]; my @G = (stat("$ARGV[1]/$key"))[@check]; if( exists($beta{$key}) && (join(',', @F) ne join(',', @G) ) ){ my $fileB = canonpath("$ARGV[1]/$key"); my $fileA = canonpath("$ARGV[0]/$key"); if( $attrib > 1 ){ if( ! (($attrib%4)%2) ){ if( $G[0] != $F[0] ){ $F[0]%=16384; $G[0]%=16384; # if( -f $fileB){ # $F[0]-=32768; $G[0]-=32768; } # if( -d $fileB ){ # $F[0]-=16384; $G[0]-=16384; } printf "~~~~~ chmod %o $fileB #%o\n", $G[0], $ +F[0]; } if( $G[1] != $F[1] || $G[2] != $F[2] ){ print "~~~~~ chown $G[1]:$G[2] $fileB #$F[1]:$ +F[2]\n"; } if( $G[3] != $F[3] ){ print "~~~~~ $fileB #Size differs!\n" unless $ +diff{$file B}; } } if( $G[4] != $F[4] && $attrib%4 ){ print qq(~~~~~ touch -m --date="), scalar localtim +e($G[4]), qq(" $fileB #), scalar localtime($F[4]), "\n"; } } else{ print "~~~~~ $fileB\n"; } } } } if( $patchdir ){ print STDERR qq( You may wish to include in your installer for sharc something along the lines of: cd $patchdir; for file in *; do file2=`echo \$file | tr % /` /usr/bin/patch "/\$file2" \$file done cd ..; assuming $patchdir is a subdirectory of the source directory for sha +rc and the patch files have been renamed to match the files they are mean +t to patch with / being replaced by %. ) }
--
I'm not belgian but I play one on TV.
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re^2: A directory diff
by hsmyers (Canon) on Aug 26, 2004 at 12:52 UTC | |
by belg4mit (Prior) on Aug 26, 2004 at 13:23 UTC | |
by hsmyers (Canon) on Aug 26, 2004 at 13:31 UTC |