#!/usr/bin/perl -w # # postdiff: run diff after some other process on both files # # 2006-10-30: Written by Steven J. DeRose, sderose@acm.org. # 2006-12-28 sjd: Add -t -blank -comment -doctype, -l, $version, rid for -i. # 2007-01-05 sjd: Fix some bugs, add -v, randomize temp file names. # 2007-01-09 sjd: Rename options, add noattrpat, nogenid, split noid/norid, # organize option parsing, help, and code to same order. # 2007-12-07 sjd: strict. Drop all the built-in processing (done better by # normalizeXML). # 2007-12-31 sjd: Getopt. # 2008-01-25 sjd: Add -cvs, and various pass-through options. # 2008-09-24 sjd: Port to BSD. # 2010-09-12 sjd: Cleanup. # # To do: use strict; use Getopt::Long; my $version = "2010-09-12"; my $dft_normalize = "normalizeXML -q -i -ic -btext -ballattrs -btags "; my $cvs = 0; my $diffOptions = ""; my $pre = ""; my $preserve = 0; my $quiet = 0; my $r = ""; my $verbose = 0; my $xml = 0; # Process options # Getopt::Long::Configure ("ignore_case"); my $result = GetOptions( # Pass-throughs to 'diff': "b" => sub { $diffOptions .= " -b"; }, "d" => sub { $diffOptions .= " -d"; }, "E" => sub { $diffOptions .= " -E"; }, "i" => sub { $diffOptions .= " -i"; }, "n" => sub { $diffOptions .= " -n"; }, "q" => sub { $diffOptions .= " -q"; }, "t" => sub { $diffOptions .= " -t"; }, "w" => sub { $diffOptions .= " -w"; }, "y" => sub { $diffOptions .= " -y"; }, # Pass-through to 'cvs update': "r=s" => \$r, # Our own options: "cmd=s" => \$pre, "cvs!" => \$cvs, "do=s" => \$diffOptions, "h|help|?" => sub { system "perldoc postdiff"; exit; }, "preserve!" => \$preserve, "xml!" => \$xml, "v|verbose+" => \$verbose, "version" => sub { die "Version of $version, by Steven J. DeRose.\n"; } ); ($result) || die "Bad options.\n"; ############################################################################### # if ($r) { $cvs = 1; } if ($xml) { $pre = $dft_normalize; } elsif ($pre eq "") { die "No pre-processing commands to run.\n"; } if ($diffOptions =~ m/ -b/) { $diffOptions .= " -W $ENV{COLUMNS}"; } #if ($ENV{USE_COLOR}) { $diffOptions = " -color=auto $diffOptions"; } ############################################################################### # Check that we've got some files to work with # my $file1 = $ARGV[0]; my $file2 = $ARGV[1]; my $tmpfile = "/tmp/postdiff_$file1\_" . int(rand(100000)); if ($cvs) { $file2 = $file1; $file1 = $tmpfile; my $cvscmd = "cvs update -p $r $file2 >$tmpfile"; ($verbose) && warn "Retrieving cvs version with: $cvscmd\n"; system "$cvscmd" || die "Failed.\n"; } else { (-e $file1) || die "Couldn't find file 1: '$file1'.\n"; (-e $file2) || die "Couldn't find file 2: '$file2'.\n"; } # Set up output files # my $rr = int(rand(100000)); my $o1 = "/tmp/$ENV{USER}_postdiff_$rr.file1"; my $o2 = "/tmp/$ENV{USER}_postdiff_$rr.file2"; # Set up the pre-processing for both input files my $cmd1; my $cmd2; if ($pre =~ m/\{\}/) { $cmd1 = "$pre >$o1"; $cmd1 =~ s/\{\}/$file1/g; $cmd2 = "$pre >$o2"; $cmd2 =~ s/\{\}/$file2/g; } else { $cmd1 = "$pre $file1 >$o1"; $cmd2 = "$pre $file2 >$o2"; } # Pre-process ($verbose) && warn "Running: $cmd1\n"; system "$cmd1"; ($verbose) && warn "Running: $cmd2\n"; system "$cmd2"; # Diff the pre-processed files my $cmd = "diff $diffOptions $o1 $o2"; ($verbose) && warn "Running: $cmd\n"; system "$cmd"; if (!$preserve) { system "rm $o1 $o2"; system "rm $tmpfile 2>/dev/null"; } else { warn "Temp files are: $o1 $o2 " . ($cvs ? $tmpfile:"") . "\n"; } ($verbose) && warn "Done.\n"; exit; ############################################################################### # sub showUsage() { print " =head1 Usage postdiff [options] file1 file2 Runs some command(s) on both files, then diffs the results. Put '{}' wherever you want the filenames to appear in the command you give. If there is no '{}', the filenames will be appended to the command. =head1 Options =over =item * B<-cmd 'cmd'> A command or pipe to run on the files. =item * B<-cvs> Retrieve CVS file like 'cvs diff' (not finished). =item * B<-do 'foo'> Pass 'foo' on to diff (some options can also be specified directly: -b -d -E -i -n -q -t -w -y). =item * B<-preserve> Don't erase the temp files when done. =item * B<-r '...'> With -cvs, pass through to cvs update -r option. =item * B<-v> Add more detailed messages. =item * B<-version> Display version info and exit. =item * B<-x> Shorthand for use with XML files. Same as: -c '$dft_normalize' =back =head1 Related commands normalizeXML re-breaks XML files in a standard way, allowing them to be compared without worrying about whitespace variation, attribute quoting, etc. Supports cvs, but not yet svn. =head1 Known bugs and lmitations Recursive diffing is not supported. =head1 Ownership This work by Steven J. DeRose is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. For further information on this license, see http://creativecommons.org/licenses/by-sa/3.0/. The author's present email is sderose at acm.org. For the most recent version, see http://www.derose.net/steve/utilities/. =cut "; }