#!/c/Perl/bin/perl
#
# svndiff.pl: Wrapper for WinMerge around 'svn diff' to display the
#             differences between two revisions of a file.
#
# James Goodall : jgoodall@dmetrix.com
# Dec 1, 2003
#
use strict;
use Getopt::Std;
use File::Temp qw/ :mktemp /;

# tweak these path values to accomodate your environment
my $winmerge_cmd = '"C:\\Program Files\\WinMerge\\WinMerge.exe"';
my $svn_cmd = 'svn';

my @tmp_files;	# keep global for 'die' cleanups

local $SIG{__DIE__} = \&cleanup_tmp_files;

main();

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

sub usage
{
	{
		print <<EOUSAGE
svndiff.pl: Wrapper for WinMerge around 'svn diff' to display the
            differences between two revisions of a file.

usage: 1. svndiff.pl [-r N[:M]]] PATH
       2. svndiff.pl -r N:M URL

  1. Displays the differences between revisions N and M of the file
     specified by PATH.  If M is not specified, the results show the
     differences between the working copy and revision N (default 
     for N is rBASE).

  2. Displays the differences between revisions N and M of the file
     specified by URL.
EOUSAGE
	}
	exit 1;
}

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

sub cleanup_tmp_files
{
	foreach (@tmp_files)
	{
		unlink $_
	}
}

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

sub diff_revs
{
	my ($target, $rev1, $rev2) = @_;

	# make the default action be to compare working copy and rBASE
	$rev1 = 'BASE' unless $rev1;

	# check for illegal trailing / or \
	die "Cannot difference directories.\n" if $target =~ m![/\\]$!;

	# get the name of the file from the path for a template
	$target =~ m!^(.*[/\\])*(.*)$!;
	
	# make temp files into which we can 'svn cat'
	push @tmp_files, mktemp("$2.r$rev1.XXXXXX");
	push @tmp_files, mktemp("$2.r$rev2.XXXXXX") if $rev2;

	# 'svn cat' the requested revisions
	my $cmd = "$svn_cmd cat -r $rev1 $target > $tmp_files[0]";
	`$cmd`;
	die "Subversion command failed: $cmd\n" if $?;
	$cmd = "$svn_cmd cat -r $rev2 $target > $tmp_files[1]";
	`$cmd` if $rev2;
	die "Subversion command failed: $cmd\n" if $?;
	
	# call winmerge
	$cmd = "$winmerge_cmd /e /ub " . ($rev2 ? $tmp_files[0] : $target) . 
		   " " . ($rev2 ? $tmp_files[1] : $tmp_files[0]);
	`$cmd`;
	die "WinMerge command failed: $cmd\n" if $?;
}

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

sub main
{
	# get the revisions we want to diff
	our($opt_r, $opt_h);
	getopts('hr:');
	my @rev = split /:/, $opt_r;
	
	# determine if the target is specified with a path or URL
	my $isURL = 0;
	if (int(@ARGV) == 1)
	{
		$isURL = $ARGV[0] =~ m!^http://!		||
				 $ARGV[0] =~ m!^https://!		||
				 $ARGV[0] =~ m!^file:///!		||
				 $ARGV[0] =~ m!^file\|///!		||
				 $ARGV[0] =~ m!^svn://!			||
				 $ARGV[0] =~ m!^svn\+ssh://!
	}
	
	# show usage on parameter error
	if (int(@ARGV) != 1				||
		$isURL && int(@rev) != 2	||
		int(@rev) > 2				||
		$opt_h)
	{
		usage()
	}

	# do the diffing
	diff_revs($ARGV[0], @rev);

	# make sure to clean up any temp files lying around
	cleanup_tmp_files();
}

#-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-



