dockerを用いてローカル環境で実行できるコマンドを作ります。 ここで作成するコマンドは、pandocです。

問題の所在

pandocとは、あるマークアップ形式で書かれた文書を別の形式へ変換するコマンドラインツールです。 pandocはhaskellパッケージとして提供されており、cabalでpandocプラグインをインストールします。

ところが、cabalはパッケージ間の依存性をうまく解決できないことがあります。 特にローカル環境にすでにhaskellパッケージがインストールされていると、それまでにインストールしたパッケージのバージョンが障碍となってプラグインのインストールに失敗することがあります。

こうした状況で有用なのが、dockerです。 dockerでpandocだけに特化したイメージを生成し、そこで必要なパッケージをインストールすることでローカル環境の影響を排除できるからです。 今回は依存関係の問題でプラグインのインストールが失敗することが多いpandocを、dockerで構築します。

Dockerfileを準備する

pandocをインストールするためのDockerfileを準備します。 ここではHaskellの公式イメージをもとにしています。

FROM haskell:8.0
LABEL maintainer="Akimichi Tatsukawa <akimichi.tatsukawa@gmail.com>" \
description="pandocコマンドを実行するためのdockerイメージ"
# インストールするpandocのバージョンを設定する
ENV PANDOC_VERSION "1.19.2.1"
# latexパッケージをインストールする
RUN apt-get update -y \
&& apt-get install -y -o Acquire::Retries=10 --no-install-recommends \
texlive-latex-base \
texlive-xetex latex-xcolor \
texlive-math-extra \
texlive-latex-extra \
texlive-fonts-extra \
texlive-bibtex-extra \
texlive-luatex \
texlive-lang-japanese \
fontconfig \
lmodern
# Rakeをインストールする
RUN apt-get install -y ruby rake
# Pythonをインストールする
RUN apt-get install -y python python-dev python-pip python-virtualenv
RUN pip install pandocfilters
# pandocをインストールする
RUN cabal update && cabal install pandoc-${PANDOC_VERSION}
RUN cabal install pandoc-csv2table pandoc-citeproc pandoc-placetable
RUN apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
VOLUME ["/workspace"]

dockerイメージを作る

一度だけ下記コマンドを実行して、Dockerfileをもとにdockerイメージを生成します。

$ docker build -t local/pandoc-command:0.1 .

-t に続くlocal/pandoc-command:0.1 の箇所は、イメージの名称です。 通常では、ユーザー名/イメージ名:バージョン という形式で指定しますが、ここではユーザー名をlocalとしています。

実際にdockerイメージが生成されたかどうかは、以下の docker images コマンドで確認できます。

$ docker images | grep pandoc
local/pandoc-command       0.1     60c2685f9dc3    39 hours ago   3.73GB

pandocを実行する

pandocを利用してMarkdownファイルからPDFファイルを生成するには、以下のようなコマンドを実行します。 ただし、{SOURCE}と{DESTINATION}にはそれぞれファイル名を指定する必要があります。

$ docker run -it -v `pwd`:/workspace local/pandoc-command:0.1 pandoc --filter pandoc-placetable  {SOURCE} -f markdown+tex_math_double_backslash -V documentclass=ltjarticle -V classoption=a4j --latex-engine=lualatex --template templates/default.latex -o {DESTINATION} 

このdockerコマンドのポイントは、以下の点です。

  • -v pwd:/workspace でカレントディレクトリをコンテナ内の/workspaceディレクトリにマウントする
  • イメージ名(local/pandoc-command:0.1 )に続く pandoc –filter … 以下で pandocコマンドを実行する

ただし、毎回このような長いコマンドを実行するのは煩雑です。 そこで次に、Rakeを利用して簡単に上記のコマンドを実行します。

Rakefileで整理する

Rakeは、rubyで書かれたmakeのようなビルドツールです。 Rakefileにファイル間の依存関係を定義することで、変更があったファイルのみを処理の対象にすることができます。

Rakefileに以下のようなコードを書きます。 ここで、SRC = FileList[‘src/*.md’] となっているので、srcディレクトリ以下のMarkdownファイルが処理の対象となる点に注意してください。

# -*- coding: utf-8 -*-

require 'rake'
require 'fileutils'
require 'rake/clean'

SRC = FileList['src/*.md']
PDF = SRC.ext('pdf')
 

task :pdf => PDF

rule ".pdf" => ".md" do |t|
  sh "docker run -it -v `pwd`:/workspace local/pandoc-command:0.1 pandoc --bibliography=./src/references.bib  --filter pandoc-placetable  #{t.source} -f markdown+tex_math_double_backslash -V documentclass=ltjarticle -V classoption=a4j --latex-engine=lualatex --toc --template templates/default.latex -o #{t.name}"
end

task :build_image do
 sh "docker build -t local/pandoc-command:0.1 ."
end

以上を前提として、あらためてrakeコマンドを利用してdockerイメージを作成してみます。

$ rake build_image

MarkdownからPDFファイルを生成するには、以下のコマンドを実行します。

$ rake pdf

すると、dockerコンテナ内のpandocを利用して、Markdownファイルが処理されます。 -v pwd:/workspace でカレントディレクトリがコンテナ内にマウントされているので、src以下のMarkdownファイルを変更後に rake pdf を実行すれば、新しくPDFファイルを生成します。