--- /dev/null
+#!/bin/bash
+# Well-behaved repeating TeX builder -- Matt McCutchen
+# usage: retex <cmd> <input-file-minus-.tex>
+
+set -e
+
+cmd="$1"
+in="$2"
+shift 2
+
+function run {
+ echo "[$iter] Running $2..."
+ yes X | "$cmd" -file-line-error-style "$in"
+}
+
+function compare {
+ echo "Comparing files..."
+ for f in "$in"*; do
+ # ignore pdfs because they have a nonreproducible "ID" at the end
+ # and logs because they aren't read
+ if ! [ "$f" != "${f%.keep*}" ] && ! [ "$f" != "${f%.pdf}" ] \
+ && ! [ "$f" != "${f%.log}" ]; then
+ suf="${f#$in}"
+ cmp "$in$suf" "$in.keep$suf" || return $?
+ fi
+ done
+ echo "Reached a fixed point."
+}
+
+function keep {
+ echo "Keeping files..."
+ for f in "$in"*; do
+ if ! [ "$f" != "${f%.keep*}" ]; then
+ suf="${f#$in}"
+ \cp -p "$in$suf" "$in.keep$suf"
+ fi
+ done
+}
+
+function clean {
+ echo "Cleaning up kept files..."
+ rm -f "$in.keep"*
+}
+
+function fail {
+ echo "Compiler exited with code $1."
+ # Remove output files here, a la .DELETE_ON_ERROR?
+ exit $1
+}
+
+iter=0
+keep
+run || fail $?
+limit=10
+while ! compare; do
+ iter=$(($iter + 1))
+ if [ $iter -ge $limit ]; then
+ echo "Did not reach a fixed point in $limit tries."
+ exit 2
+ fi
+ keep
+ run || fail $?
+done
+clean
+echo "Successful."