To be honest, this article is a bit of a rant piece, but I figured it could go to helping others. If you're wondering how you could build LaTeX documents using Travis CI and Minted, you've come to the right place.
Problem Description
In case you’re wondering how I came up with this predicament, I’m a PhD student, and I’ve just decided to start learning LaTeX because it seems useful. In the process, however, I’ve decided to tie in good software engineering principles like version control and continuous integration. As it turns out, the latter is very, very challenging.
In particular, I was looking for a way to generate LaTeX PDFs using Travis CI which is built right into GitHub. While that’s a challenge on its own, I took it upon myself to make things more interesting by adding a package, minted, which requires a few external dependencies. Namely, I needed Python access, the Pygments library, and shell access. As it turns out, this was more challenging than you’d think.
How to Build LaTeX
Normally, we can build LaTeX using any number of LaTeX tools. For me, that meant downloading MikTex and Perl on my Windows 10 machine. After that, I download the LaTeX plugin for Atom, and I got to work.
To put it more formally, I used the following steps to get my Windows environment setup for LateX building:
- Download and install MikTex
- Download and install Strawberry Perl
- Download and install Python
- Download and install Atom
- Download and install latex package
- Check box in latex plugin settings for Enable Shell Script
After that, you should be able to get up and running. Of course, I may be missing some dependencies here and there as I already had some of these installed on my system.
With all the dependencies setup, the build workflow looks something like the following:
- Write and save document changes
- Go to Packages > LaTeX > Rebuild
- Profit
To be honest, it really couldn’t be easier once everything is installed. After all, MikTex handles the installing of packages you’re missing, so LaTeX dependencies shouldn’t be an issue. Of course, let me know otherwise in the comments.
How to Automate LaTeX Build
Unfortunately, the method described above is impractical when it comes to Travis CI. After all, we’d like to be able to install all these components every build using the command line.
Luckily, there’s a community of LaTeX folks who work with continuous integration, so there are already several methods for continuous integration. That said, I had a lot of trouble getting up and running despite their efforts. If you’re looking for the world’s saddest list of commits, check out my pull request just to get the build working. In total, there were about 82 commits of which more than half were failing builds.
Of course, I don’t expect you to dig through my efforts. Instead, I want to provide you with the solution.
Travis YAML
With every Travis CI build, you need a YAML file to tell the server how to build your code. In this case, I’m using a YAML that looks like the following:
language: generic
# Dependency of the minted package
before_install:
- sudo apt-get install python-pygments
install:
- source ./texlive/texlive_install.sh
cache:
directories:
- /tmp/texlive
- $HOME/.texlive
# Change working directory so including files will work
before_script: cd $TRAVIS_BUILD_DIR/assignment01/doc/
script:
- pdflatex --shell-escape ./assignment01.tex
deploy:
provider: releases
api_key:
secure: ${GITHUB_TOKEN}
file:
- ./assignment01.pdf
skip_cleanup: true
on:
tags: true
branch: master
notifications:
email: false
Breaking this down, there are a few things to note. First, it’s important to be aware that we can’t specify a language as Travis CI doesn’t have native LaTeX build support. Instead, we have to go with a generic setup:
language: generic
With language setup out of the way, we can begin by running a before install command to pick up the Python Pygments package which aids in syntax highlighting:
before_install:
- sudo apt-get install python-pygments
After that, we run another install command on a local shell script—more on that later:
install:
- source ./texlive/texlive_install.sh
From there, we make sure to cache our install, so we don’t have to do it every build:
cache:
directories:
- /tmp/texlive
- $HOME/.texlive
After the initial setup, we move into the working directory which happens to be a folder where my LaTeX file sits. Feel free to change this line to your needs:
before_script: cd $TRAVIS_BUILD_DIR/assignment01/doc/
Now that we’re in our working directory, we can safely build our PDF. This is the real magic of the build as we require a special option, -shell-escape, which allows us to access our python packages for syntax highlighting:
script:
- pdflatex --shell-escape ./assignment01.tex
At this point, everything else is just bonus. For instance, I’ve setup my YAML to deploy all the PDFs to the latest tagged release. You’ll need to populate the GITHUB_TOKEN with your own token.
deploy:
provider: releases
api_key:
secure: ${GITHUB_TOKEN}
file:
- ./assignment01.pdf
skip_cleanup: true
on:
tags: true
branch: master
Finally, we turn off email notifications because those are annoying:
notifications:
email: false
And, there we have it! A Travis CI YAML which gets the job done for automated builds.
Additional Build Scripts
In addition to this YAML, we’ll need a set of scripts which are used to setup LaTeX and the dependencies we need. Fortunately, I didn’t have to write these scripts as they were provided for me by our friends over at the travis-ci-latex-pdf repo. For the sake of completeness, I’ve shared them below. Make sure to place all these files in the root of your repo under a directory called texlive:
texlive/texlive.profile
selected_scheme scheme-basic
TEXDIR /tmp/texlive
TEXMFCONFIG ~/.texlive/texmf-config
TEXMFHOME ~/texmf
TEXMFLOCAL /tmp/texlive/texmf-local
TEXMFSYSCONFIG /tmp/texlive/texmf-config
TEXMFSYSVAR /tmp/texlive/texmf-var
TEXMFVAR ~/.texlive/texmf-var
option_doc 0
option_src 0
texlive/texlive_packages
xcolor
fancyhdr
fancyvrb
makecmds
multirow
chngcntr
fvextra
upquote
lineno
ifplatform
xstring
framed
caption
collection-fontsrecommended
minted
oberdiek
etoolbox
float
booktabs
texlive/texlive_install.sh
#!/usr/bin/env sh
# Originally from https://github.com/latex3/latex3
# This script is used for building LaTeX files using Travis
# A minimal current TL is installed adding only the packages that are
# required
# See if there is a cached version of TL available
export PATH=/tmp/texlive/bin/x86_64-linux:$PATH
if ! command -v texlua > /dev/null; then
# Obtain TeX Live
wget http://mirror.ctan.org/systems/texlive/tlnet/install-tl-unx.tar.gz
tar -xzf install-tl-unx.tar.gz
cd install-tl-20*
# Install a minimal system
./install-tl --profile=../texlive/texlive.profile
cd ..
fi
# Just including texlua so the cache check above works
tlmgr install luatex
# Install package to install packages automatically
tlmgr install texliveonfly
# Install babel languages manually, texliveonfly does't understand the babel error message
tlmgr install collection-langeuropean
# Common fonts with hard to debug errors if not found
#tlmgr install collection-fontsrecommended
# In the case you have to install packages manually, you can use an index of packages like
# http://ctan.mirrors.hoobly.com/systems/texlive/tlnet/archive/
# Or better, check https://www.ctan.org/pkg/some-package to see in which TeX Live package it is contained.
# Then you can add one package per line in the texlive_packages file
# We need to change the working directory before including a file
cd "$(dirname "${BASH_SOURCE[0]}")"
tlmgr install $(cat texlive_packages)
# Keep no backups (not required, simply makes cache bigger)
tlmgr option -- autobackup 0
# Update the TL install but add nothing new
tlmgr update --self --all --no-auto-install
Voila
At this point, we should have everything we need to launch a successful remote LaTeX build using Travis CI and Minted. If you have any problems or questions, feel free to reach out. That said, Thomas Schouten is the real expert. I recommend visiting their repo at some point as there are several other ways to get things working.
At any rate, that’s all I have for now. Thanks again for stopping by!