| Scenario: You are using ClearCase for configuration management in Linux, Unix, Windows or Mac OSX, and you want to graphically compare files and directories in your current view with those in another view. |
| Solution: Use this vvdiff script to quickly and easily compare one file, one directory, or even a directory tree. |
If you ever wanted to graphically compare, say, a thousand files in two different ClearCase views, then you might want to try the vvdiff script (in either bash or perl form). On an ancient Sun computer, 2400 files are compared in about two minutes.
Hints:
Before you can use vvdiff, you must install a generic open source software diff tool such as xxdiff or meld.
As of March 2006, similar scripts for CVS and Subversion using xxdiff are available at Helper Scripts for xxdiff. Thanks Martin!
The vvdiff script comes in bash and perl versions. Both versions use the either of two excellent diff tools (xxdiff or meld), with ClearCase. Copy vvdiff to some directory in your path (as shown by 'echo $PATH').
Bash version of vvdiff
#!/bin/bash
## vvdiff: Graphically compares a file or directory in two ClearCase views
## author: Mark Mitchell (http://home.earthlink.net/~mmc1919)
## requirements: xxdiff (http://xxdiff.sourceforge.net) or meld (http://meld.sourceforge.net/)
## bash shell
## options: documented in usage below and available by specifying "-h"
RENDEZVOUS_DIR="$HOME/.vvdiff_rndzvs"
## parse command line
OPTS=""
BAD=""
let i=1; # i=0 is vvdiff itself
let arg=0;
while [ -n "${!i}" ]; do
case "${!i}" in
"--help" | "-h")
BAD="yes";;
"--exclude" | "-e")
OPTS=$OPTS"${!i} "; let i=i+1; OPTS=$OPTS"${!i} ";;
"--exit-on-same" | "-D" |\
"--ignore-all-space" | "-w" |\
"--ignore-blank-lines" | "-B" |\
"--ignore-case" | "-i" |\
"--ignore-space-change" | "-b" |\
"--recursive" | "-r")
OPTS=$OPTS"${!i} ";;
*) if [ "${!i:0:1}" == "-" ]; then
BAD="yes";
else
let arg=arg+1;
ARGS[$arg]="${!i}";
fi;;
esac;
let i=i+1;
done
if test "$arg" -ne "2" -o -n "$BAD" -o ! -a "${ARGS[1]}" ; then
echo "Usage: vvdiff [OPTIONS] file | directory other_view"
echo ""
echo "Graphically compares a file or directory in one ClearCase view to another"
echo ""
echo "OPTIONS are:"
echo "--exclude, -e pattern Skip files whose basenames match pattern"
echo "--exit-on-same, -D Exit quietly if there are no differences"
echo "--help, -h Display this help"
echo "--ignore-all-space, -w Ignore white space when comparing lines"
echo "--ignore-blank-lines, -B Ignore blank lines"
echo "--ignore-case, -i Treat upper and lower case as identical"
echo "--ignore-space-change, -b Ignore white space when comparing lines"
echo "--recursive, -r List subdirectories recursively"
else
## clean up rendezvous directory
if [ -a $RENDEZVOUS_DIR ]; then
rm -rf $RENDEZVOUS_DIR/*;
else
mkdir $RENDEZVOUS_DIR;
fi
## copy from other view to rendezvous directory
echo "Comparing"`find ${ARGS[1]} | wc -l`" files"
cleartool setview -exec "cp -r ${ARGS[1]} $RENDEZVOUS_DIR" ${ARGS[2]};
## diff current view with other view. Replace xxdiff by meld if desired
xxdiff $OPTS ${ARGS[1]} $RENDEZVOUS_DIR/`basename ${ARGS[1]}`
fi
Perl version of vvdiff
#!/usr/bin/perl
# vvdiff: Graphically compares a file or directory in two ClearCase views
# hints: Try using a wrapper (such as vvdiff_filtered) that uses several '--exclude' filters
# to strip out unimportant files for a huge increase in speed. Removing object files,
# libraries and executables is highly recommended
# author: Mark Mitchell (http://home.earthlink.net/~mmc1919)
# requirements: xxdiff (http://xxdiff.sourceforge.net) or meld (http://meld.sourceforge.net)
# perl
# options: documented in usage below and available by specifying "-h"
# changes: 8/22/2005 m. mitchell replaced "cp -r" with "find" command so filtering
# would be performed before, rather than after, the copy. This required consolidating
# the copy commands into a new batch file so cleartool would still be invoked only
# once (rather than once per copied file), since each invocation seemed to be very slow
# 9/6/2005 m. mitchell fixed problem with copying single file or directory
# from a directory other than the current directory
my($rendezvousDir);
$rendezvousDir=$ENV{'HOME'} . '/.vvdiff_rndzvs';
$batchScript=$ENV{'HOME'} . '/.vvdiff_batch'; # consolidate copies into single script
# parse command line
my($opts)='';
my($isBad)=0;
my($argCount)=0;
my($isSecondArgument)=0; # true if next argument is a second argument to be passed through
my($isExcludeArgument)=0; # true if next argument is the argument to an --exclude
my($excludeFindFilters)="";
foreach $argnum (0 .. $#ARGV) {
my($arg)=$ARGV[$argnum];
CASE: {
(($arg eq "--help") || ($arg eq "-h")) && do {
$isBad=1;
last CASE;
};
(($arg eq "--exclude") || ($arg eq "-e")) && do {
$opts=$opts . $arg . " ";
$isSecondArgument=1;
$isExcludeArgument=1; # second argument that is also argument for --exclude
last CASE;
};
($isSecondArgument ||
($arg eq "--exit-on-same") || ($arg eq "-D") ||
($arg eq "--ignore-all-space") || ($arg eq "-w") ||
($arg eq "--ignore-blank-lines") || ($arg eq "-B") ||
($arg eq "--ignore-case") || ($arg eq "-i") ||
($arg eq "--ignore-space-change") || ($arg eq "-b") ||
($arg eq "--recursive") || ($arg eq "-r")) && do {
$opts=$opts . $arg . " ";
$isSecondArgument=0;
if ($isExcludeArgument eq 1) {
if ($excludeFindFilters ne "") {
$excludeFindFilters = $excludeFindFilters . " -a"; # prepend conjunction since not first
}
$excludeFindFilters = $excludeFindFilters . " ! -name '" . $arg . "'";
$isExcludeArgument=0;
}
last CASE;
};
do {
if ('-' eq substr($arg,0,1)) {
$isBad=1;
}
else {
$argCount=$argCount+1;
$args[$argCount]=$arg;
}
};
}
}
if ((2 != $argCount) || $isBad || (! -e $args[1])) {
print "Usage: vvdiff [OPTIONS] file | directory other_view\n";
print "\n";
print "Graphically compares a file or directory in one ClearCase view to another\n";
print "\n";
print "OPTIONS are:\n";
print "--exclude, -e pattern Skip files whose basenames match pattern\n";
print "--exit-on-same, -D Exit quietly if there are no differences\n";
print "--help, -h Display this help\n";
print "--ignore-all-space, -w Ignore white space when comparing lines\n";
print "--ignore-blank-lines, -B Ignore blank lines\n";
print "--ignore-case, -i Treat upper and lower case as identical\n";
print "--ignore-space-change, -b Ignore white space when comparing lines\n";
print "--recursive, -r List subdirectories recursively\n";
}
else {
# clean up rendezvous directory
use File::Find;
finddepth (sub {
if (-f $_) {
unlink $_;
} else {
rmdir $_;
}
}, $rendezvousDir);
# clean up trailing slash in first argument for dirname and basename
use File::Basename;
if (length($args[1]) > 1) {
if (substr($args[1],length($args[1])-1,1) eq '/') {
chop($args[1]);
}
}
# build find command using appropriate filtering
$fileCount=0;
my($excludeFindStartingPoint)="find $args[1]";
$excludeFindCmd = $excludeFindStartingPoint . $excludeFindFilters;
# create batch script from the filtered list of files, of the OTHER view
use File::Path;
my($cleartoolCmd)='cleartool setview -exec "'.$excludeFindCmd.'" '.$args[2]."\n";
open(FIND_OUT, $cleartoolCmd . "|") or die("Could not execute unix find command");
open(BATCH_SCRIPT, ">$batchScript") or die("Could not open batch script");
while(<FIND_OUT>) {
$sourcePath = $_;
chop($sourcePath);
$targetPath = $rendezvousDir.'/'.$sourcePath;
if (-f $sourcePath) {
# mirror directory from other view if necessary
$targetDir = dirname($targetPath);
if (! -d $targetDir) {
mkpath("$targetDir");
}
# copy file from other view to rendezvous directory. Use single quotes to allow spaces,
# and redirect stderr to prevent unimportant "cp: cannot access" errors for non-vobs objects
$copyCmd = "cp '$sourcePath' '$targetPath' 2>/dev/null;\n";
print BATCH_SCRIPT $copyCmd;
} else {
# mirror directory from other view
mkpath("$targetPath");
}
$fileCount=$fileCount+1;
}
close(FIND_OUT);
close(BATCH_SCRIPT);
# display file count so user:
# -knows how long to wait
# -knows if filtering should be improved
print "Comparing " . $fileCount . " files\n";
# copy from the other view to the rendezvous directory using cleartool
system("chmod +x $batchScript");
$cleartoolCmd='cleartool setview -exec "'.$batchScript.'" '.$args[2]."\n";
system($cleartoolCmd);
# diff current view with files from the other view. Replace xxdiff by meld
# if desired
$cmd='xxdiff '.$opts.'\''.$args[1].'\' '.$rendezvousDir.'/'.$args[1]."\n";
system($cmd);
}
There are two required arguments to vvdiff. The first required argument is the file or directory that you want to compare. The second required argument is a ClearCase view. The file(s) in the current view will be compared to the same file(s) in the other view.
For example, in the following example the xxdiff-3.0.1 directory in the current view is compared with the same directory in the Release view:
vvdiff xxdiff-3.0.1 Release
This produces the following picture. Double clicking on any file will bring up a new window with the diff output for that file. Double clicking on any directory will bring up a new window with the diff output for that directory.
Optional command line arguments can be listed by specifying the "-h" option.