[Tex/LaTex] texdiff for multi-file documents in subversion

highlightinglatexdiffrevision controlscriptssubversion

I've been looking for a convenient way to highlight changes between subversion revisions of my Latex document in the generated PDF. I am working on a reasonably complex document that pulls together various .tex files. By virtue of using multiple \input{}s, latexdiff-svn doesn't seem to offer a solution. texdiff, despite being more amenable to multi-file documents, unfortunately doesn't have the necessary magic in place to handle SVN diffs.

I have hacked together a solution which works for me, but I'm wondering if there's something more coherent that I've missed.

My solution is a fairly short script which does the following:

  1. Given a revision number, ask SVN for all the files that have changed between then and HEAD.
  2. Export only those files to a temporary location, and run texdiff between the exported copy and the working copy.
  3. Build another temporary directory, which stores either the output from texdiff or, if no changes were made, a copy of the working copy. The directory contains all the .tex files I need to build my document. A little sed ensures all \input{} commands point to the correct (i.e., temporary) location.

This does the trick! But, a solution that hooks directly into svn diff would be much neater. I played around earlier with svn wdiff and tried to hook it directly into texdiff, but I gave up on it when I realised I was breaking all the nice bracket matching that texdiff does. My searches have otherwise proved fruitless. Although I'm happy with my solution, does anyone know a neater way to achieve what I want?

Best Answer

I know coded the following Perl script which calls svn diff in summary mode to get the changed files. It extracts these using svn cat into two different directories and calls latexdiff on each modified file. It modifies the TEXINPUTS variable to load files first from the diff directory instead of the current one. This avoids the copying of all unchanged files. Finally the main file is compile using latexmk.

The usage is perl <scriptfile> <mainfile> <rev a> <rev b>.

It is absolutely not fool-proof so far, but is more general as the shell script linked to in the comments. Please test it and provide some feedback.

#!/usr/bin/env perl
use strict;
use warnings;

my @FILES;

my $rpath = '.r';

my ($mainfile,$REVA,$REVB) = @ARGV;
my $dpath = ".diff-${REVA}-${REVB}";

open(my $pipe, '-|', "svn diff --summarize -r${REVA}:${REVB}") or die;
while (<$pipe>) {
    next if not /^M.{7}(.*\.tex)$/;
    push @FILES, $1;
}
close ($pipe);

exit (1) if not @FILES;

mkdir $rpath . $REVA;
mkdir $rpath . $REVB;
mkdir $dpath;

foreach my $file (@FILES) {
    print $file, "\n";
    $file =~ /^(.*)\//;
    my $dir  = $1 || "";
    my $dira = $rpath . $REVA . '/' . $dir;
    my $dirb = $rpath . $REVB . '/' . $dir;
    my $ddir = $dpath         . '/' . $dir;
    mkdir $dira if not -e $dira;
    mkdir $dirb if not -e $dirb;
    mkdir $ddir if not -e $ddir;
    system("svn cat -r${REVA} '$file' > '${rpath}${REVA}/$file'");
    system("svn cat -r${REVB} '$file' > '${rpath}${REVB}/$file'");
    system("latexdiff '${rpath}${REVA}/$file' '${rpath}${REVB}/$file' > '${dpath}/$file'");
}

if (not exists $ENV{"TEXINPUTS"} || $ENV{"TEXINPUTS"} eq '') {
    $ENV{"TEXINPUTS"} = "$dpath:.:";
}
else {
    $ENV{"TEXINPUTS"} = "$dpath:" . $ENV{"TEXINPUTS"};
}

system("latexmk -pdf $mainfile")