GitLab & LaTeX Builds
I like to write letters. I do not, however, enjoy wrangling Microsoft Word to ensure the same results each time; I use LaTex, where I can be guaranteed of consistent output.
As my library of past correspondence increases, I was looking for a way to implement version control as I drafted correspondence. Git was the obvious solution, and quite straightforward to set up. As I run a GitLab server on my Synology, I was happy storing a big backup of all of the history on a RAID device elsewhere in the house. But, I realised, it wasn’t good practice to store the generated PDFs — the binary outputs — alongside their .tex files. At the same time, I had recently put together a fairly unique build server using GitLab CI for work. I was sure that I could make something that would be useful to me in this instance too.
GitLab CI
GitLab — a server for giving a git repository a nice user interface, as well as tracking ‘issues’ and ‘merges’, has bundled with it a continuous integration server, which means that building, testing and deploying code can all be automated for each commit that’s pushed to the server.
GitLab CI Runner
This is the application that needs to be set up on an OS X/Linux machine, to compile your LaTex files for you. Download here.
Configuration
There are a few files here. .gitlab-ci.yml
and compile.sh
both go in the root directory of your repository, as they are for telling GitLab what to run. The make files go in each folder, sitting alongside your .tex files.
.gitlab-ci.yml
stages:
- build
build:
stage: build
script:
- compile.sh
artifacts:
paths:
- "*.pdf"
- "*/*.pdf"
- "*/*/*.pdf"
- "*/*/*/*.pdf"
This file runs the file compile.sh
on the runner computer, and stores all of the generated files that end with *.pdf
compile.sh
#!/bin/bash
directories=$(git diff --name-only @{1} HEAD | grep -e '\.tex$' | while read line; do echo "./$line"; done | sed 's/\(.*\)\/.*/\1/')
if [ -n "$directories" ]
then
echo "Directories for compilation:"
echo "$directories"
for d in "$directories";
do
cd "$d"
if [ -e makefile ]
then
make
else
pwd
pdflatex *.tex
fi
done
fi
This file searches for all newly modified *.tex
files, and runs make on them.
Make files
Makefile
all:
./make_script.sh
clean:
./make_clean.sh
make_script.sh
#!/bin/bash
for file in *.tex;
do
bn=`basename $file .tex`
find . -type f -name "$bn*" -not -name "*.tex" -exec rm -rf {} \;
pdflatex -shell-escape $bn
bibtex $bn
makeglossaries $bn
makeindexes $bn
pdflatex -shell-escape $bn
makeglossaries $bn
pdflatex -shell-escape $bn
makeglossaries $bn
pdflatex -shell-escape $bn
pdflatex -shell-escape $bn
done;
make_clean.sh
#!/bin/bash
for file in *.tex;
do
bn=`basename $file .tex`
find . -type f -name "$bn*" -not -name "*.tex" -not -name "*.pdf" -exec rm -rf {} \;
done
So?
This is superior to most other setups for a couple of reasons.
Firstly, previous development in LaTeX assumed that your editing devices had the rather large LaTeX packages installed; if you’re on an iPad, this can be a difficult thing to manage. My solution obviates the coupling of a LaTeX compiler to a LaTeX editor.
Secondly, the PDFs are available under ‘builds’, ready to be downloaded immediately. Because the PDFs generated are now linked to a particular build, and therefore a particular commit, a complete revision is available for them, along with their associated files. However, the PDFs — binary outputs of what you’ve written — aren’t there to clutter up your git repository (nor are the associated .aux
files, etc).