Latex-ing with Correct Versions and Dates

I use Latex a lot on documents that are stored in a CVS or SVN repository. The approach with Latex is that you write your document in the Latex programming language, and then you "compile" or "execute" your latex file to produce a pdf. Frequently when writing, and very frequently when writing with a coauthor, I like to compile early, incomplete versions of the paper and distribute the resulting pdf. After a few of these pdf's are floating around, however, people using them start wondering, when you talk to them, whether they have the newest version or not....

A good way to approach this is to put some kind of version-specific information on the early copies. For example, it is good to put the date of the file into the pdf. Then people can say things like, "I read the June 23 version of the paper." For best functioning, note that this date should not be the date the pdf was created, but the date of the last modification to the Latex file. That way, the file can be recompiled later (e.g., by your coauthor, on a different day) without changing the result.

A more specific piece of information is the repository's version number for the file as of the last compile. This is particularly sensible for SVN repositories, since the version number corresponds to the entire repository instead of to individual files. Then you can put on your title page something like, "compiled from version 1849", even if your Latex source code includes more than one file.

Now that this problem and solution have been stated, it is straightforward to work out a system for working this way. However, the tools do not support this version-stamping and date-stamping by default, so you have to work a little bit. This page accumulates the scripts and build-file code that I use, so that others might benefit. Maybe one day these things will become popular enough to be supported more directly.

version.tex

My general approach is to have the build system create a version.tex containing the date and version information. An example version.tex file is as follows:

%Automatically generated file.  See ./scripts/getversion.
\newcommand\svnversion{1601}
\newcommand\svndate{Mon, 30 Jan 2006}

The main Latex file can then include this file and make use of the \svnversion and \svndate commands that version.tex provides. It will probably use them in a \date command, like this:

\include{version}
\title{Coolest Stuff Ever}
\date{{\svndate}\hspace{1em}(revision \svnversion)}

Computing version.tex

The next piece of the puzzle is the script to compute the version.tex file. I only have a script for SVN right now, not for CVS.

This is a natural task for Perl. The following script is what I use:

#!/usr/bin/perl
# Retrieve version info for the list of svn-managed files listed
# in the argument vector.  Print out Latex definitions holding
# the retrieved information.

$scriptname = $0 ;

$maxversion = 0 ;
$newestdate = "" ;

for $file (@ARGV) {
    $version = 0;
    $date = "";

    open(RAWINFO, "svn info $file |");
    while() {
	if(/^Revision: ([0-9]+).*/) {
	    $version = $1;
	}

	if(/^Last Changed Date: .*\((.*)\)/) {
	    $date = $1;
	}
    }

    if($version==0 || $date eq "") {
	print("file $file, version $version, date $date\n");
	exit(2);
    }
    
    if($version > $maxversion) {
	$maxversion = $version;
	$newestdate = $date;
    }
}

print "%Automatically generated file.  See $scriptname.\n";
print "\\newcommand\\svnversion{$maxversion}\n";
print "\\newcommand\\svndate{$newestdate}\n";

This script expects to have the list of files to consider for version.tex be listed on the command line. (Typically, a single repository may well have a number of other files in it, so you don't want to version all of them.) It then issues svn commands to find the modification times and revision numbers of the files, chooses the maximum of them, and prints out the contents that should be placed in the version.tex file.

Integration with Jam

The final step is to integrate the computation of version.tex into your build process. I use Jam, but the approach should be the same with make, ant, or whatever else you use. (If it's hard, then you need a better build tool! Make your life easier!)

The basic approach is that version.tex depends on all of the files you want to version, and tell it to use the above script to build it. Here are the relevant chunks from one Jamfile I use:

rule Version {
  DEPENDS $(1) : $(2) ;
  DEPENDS $(1) : scripts/getversion ;
  Clean clean : $(1) ;
}

actions Version {
  ./scripts/getversion $(2) > $(1).tmp
  mv $(1).tmp $(1) ;
}


Version version.tex :
 phdtr.tex
 gatech-thesis-lexpatch.sty

 macros.tex 
 autoref-tweaks.tex 
 acknowledgements.tex 
 motivation.tex 
 previous.tex 
 algdevel.tex 
 semantics.tex 
 dataflow.tex 
 ddp.tex 
 correctness.tex 
 implementation.tex 
 chuck.tex 
 experiments.tex 
 langchanges.tex
 future.tex 
 sourcetags.tex 
 conclusion.tex 


 screenshots/ss-askflow.png 
 screenshots/ss-asktype.png 
 screenshots/ss-chuckresponders.png 
 screenshots/ss-chucksenders.png 
 screenshots/ss-editpolice.png 
 screenshots/ss-enquirer.png 
 screenshots/ss-flowanswer.png 
 screenshots/ss-implementors.png 
 screenshots/ss-sendersof.png 
 screenshots/ss-typeanswer.png 
 screenshots/ss-typefail.png 
 screenshots/ss-typesucceed.png 
 screenshots/ss-useduration1.png 
 screenshots/ss-useduration2.png 
 screenshots/ss-varrefs1.png 
 screenshots/ss-varrefs2.png 

 screenshots/ex-goal.png
 screenshots/ex-start.png
 screenshots/ex-firstsubgoals.png
 screenshots/ex-updatey.png
 screenshots/ex-updatexfory.png
 screenshots/ex-updatep1.png
 screenshots/ex-prune.png
 screenshots/ex-updatep1forprune.png
 screenshots/ex-updateQ.png
 screenshots/ex-updateP1trivial.png
 screenshots/ex-updateXtrivial.png

 screenshots/speed.png
 screenshots/precision.png

 screenshots/ary1resp.png
 screenshots/basic-response.png
 screenshots/dotResp.png
 screenshots/factResp1.png
 screenshots/factResp2.png  ;

Includes phdtr.tex : version.tex ;

There are better approaches imaginable than having an explicit list of files that need to be versioned. It would be nice if you could say, "have version.tex account for all files needed to build blah.dvi". This should be doable using include-file scanners: whenever you notice that A includes B, then A's version file should account for the version of B. However, I have not explored that approach. LocalWords: href CVS SVN pdf pdf's blockquote pre ing tex newcommand svndate


Lex Spoon