論文執筆を支える継続的インテグレーション: Git から Amazon S3 まで

この記事は CAMPHOR- Advent Calendar 2017 8日目の記事です.

学位論文を書く季節になってきました.論文を書く際にはきちんとバックアップを取っておかなければならないなど,実際の執筆以外でも気を遣わなければならないことが多くあります.この記事では,ソフトウェア開発における継続的インテグレーション (CI) や継続的デリバリー (CD) の考え方を取り入れ,様々なツールを活用することで,論文の執筆に集中できる環境を整備する方法を紹介します.

対象読者

基本的に TeX を使って論文を書く人を想定しています.(Word などで論文を書かざるを得ない環境にいる方には申し訳ない)

目標

この記事では以下のようなものを作っていく方法について説明します.

  • Git と GitHub でバージョン管理
  • CircleCI でコンパイルやスペルチェックを実行
  • 生成された PDF ファイルを Amazon S3 にアップロード
  • GitHub や CircleCI からの通知を Slack に送信

Git

TeX はテキストファイルなので大抵のバージョン管理システムと相性が良いです.今回の記事ではバージョン管理システム (VCS)として Git を使います.Git を使うメリットはいくつかあります:

  • 最近よく使われている VCS で,操作に慣れている人が多い
  • 分散型の VCS なので,データが失われる可能性を減らせる
  • GitHub などの Git を利用した様々な便利なサービスが使える

Git を導入するデメリットはほぼないと思いますが,共著者が Git の操作に慣れていない場合,執筆中に conflict などが発生し事故が起こる可能性があります.たいていの場合は知識がある人が操作することで復旧できるので問題ないと思われます.

実験データが巨大なバイナリになるような研究を行っている場合は,Git で実験データを管理するのはあまりおすすめできません.このような場合は,実験データには Git LFS やファイルサーバーを使うなど柔軟な対応が必要です.

GitHub

Git のリポジトリを置く場所として GitHub を利用します.GitHub を使うメリットは以下のようなものがあります.

  • 自分でリポジトリをメンテナンスする必要がない
  • メジャーなサービスなので使い慣れている人が多い
  • Web ブラウザで差分を見たり,issue や PR の機能も利用できる
  • 他のツールと組み合わせやすい
  • (多くの場合) プライベートリポジトリが無料で使える (詳細は後述します)

デメリットには以下のようなものがあります.

  • GitHub が落ちると作業が停滞する恐れがある
    • 分散型の VCS なので,ローカルにリポジトリの完全なコピーがあるためそれほど大きな影響はないと考えられます
    • ただし issue や PR を多用している場合は影響があります
  • 原稿のデータを外部のサービスに置くことになる
    • セキュリティ上の理由があるなどの場合は利用できない

プライベートリポジトリを無料で利用する

GitHub でプライベートリポジトリを利用するには,一般的には課金する必要があります.ただ,学校の教員・研究者・学生の個人のアカウントや,研究室等の organization のアカウントでは education.github.com から申請することで,無料でプライベートリポジトリを利用することが出来ます.

申請するためには .ac.jp で終わるような学校が発行したメールアドレスがあれば OK です.GitHub は複数のメールアドレスを登録できるので,申請前に学校のアドレスもアカウントに登録しておくとスムーズに行えます.極めて簡単な手順でプライベートリポジトリを使えるようになるので,ぜひ利用しましょう.

Slack

Slack は無料で使い始めることが出来るチャットサービスです.主に以下のような目的で使用しています

  • 著者間のちょっとした相談や議論
  • GitHub からの通知
    • 複数人で同時に編集することがよくあるため,他の人が push したことに気づけます
  • CircleCI からの通知
    • コンパイルが通らないものが push されたら CI が落ちるためすぐに分かります

Slack は GitHub や CircleCI といった,外部のサービスとの連携が簡単にできるのでおすすめですが,他のチャットサービスを使っても良いですし,もちろんチャットサービスを導入せずにメールで通知を受ける形でも構いません.

TeX ファイルのコンパイル

TeX ファイルをコンパイルして PDF ファイルを出力するために,手動で何回もコマンドを打つのは無駄が多いです.ツールを導入して,コマンド1つでコンパイルできるようにしておくことが,自分にとっても共著者にとっても重要です.

Latexmk

Latexmk は一般的な論文を書く際には最もおすすめできるツールです.TeX の処理系を設定次第で使い分けられたり,必要な回数だけきちんとコンパイルを行ってくれたり,BibTeX にも対応していたりして,とても便利です.また,ファイルの更新を検知して自動でコンパイルしてプレビューすると言ったことも簡単に行えます.使い方の詳細はこちらを参照して下さい.

Make

自分が論文を書く際には,TeX のソースのプリプロセッサのようなものを使うことがあります.このような場合は Latexmk を直接使わず,Makefile を書いてプリプロセッサを利用しています.

その他

その他にも好みのツールがあればそれを使うのが良いと思います.少なくともコマンドを一度実行できるだけで,望んでいる PDF ファイルが得られるような環境は整えておくべきです.

CircleCI

CircleCI は主にソフトウェア開発に用いられる CI ツールです.GitHub と簡単に連携して,コミットがプッシュされたタイミングで様々なタスク (ここでは TeX のコンパイルなど) をすることができます.CircleCI には次のような特徴があります:

  • GitHub と連携できる
  • GitHub のプライベートリポジトリについても無料で CI を実行できる
  • CircleCI 2.0 を使うと,Docker ベースの高速な環境を利用できる

CircleCI の基本的な使い方はこちらを,Slack などのチャットツールに結果を通知する方法はこちらを参照して下さい.

基本の設定

CircleCI の設定は .circleci/config.yml に YAML 形式で記述します.paper ディレクトリ以下にあるTeX ソースを latexmk でコンパイルするだけの最も基本的な設定は以下のようになります.

version: 2
jobs:
  build:
    docker:
      - image: ubuntu:17.10
    steps:
      - checkout
      - run:
          command: |
            apt update
            apt install -y latexmk make texlive texlive-latex-extra
      - run:
          command: latexmk
          working_directory: paper

ベースとなる Docker イメージには Ubuntu 17.10 を利用していますが,このあたりはお好みで設定して下さい.自分の場合は新しめの TeX Live を利用したいためこのような設定にしています.また,TeX Live はいくつものパッケージに分かれて提供されているため,必要なパッケージは適宜 apt で導入するようにして下さい.

応用: Docker イメージを作って高速化

毎回 CircleCI で apt install を行うと時間がかかってしまいます.この時間が気になる場合は,以下のような Dockerfile を作成し,事前に Docker イメージをビルドして,Docker Hub にイメージを置いておくと良いでしょう.

FROM ubuntu:17.10

RUN apt update && \
    apt install --no-install-recommends -y \
        latexmk lmodern make texlive texlive-latex-extra

Docker イメージをビルドしてプッシュする例:

$ docker build -t ymyzk/sgtp:latest .
$ docker push ymyzk/sgtp:latest

このイメージを使うための,CircleCI の設定は以下のようになります:

version: 2
jobs:
  build:
    docker:
      - image: ymyzk/sgtp:latest
    steps:
      - checkout
      - run:
          command: |
            apt update
            apt install -y latexmk make texlive texlive-latex-extra
      - run:
          command: latexmk
          working_directory: paper

スペルチェック

英語で論文を書いている場合は,自動でスペルチェックを行ってくれると便利です.この記事では aspell というスペルチェッカーを利用します.

インストール

macOS では brew install aspell,Linux (Debian系) では apt install aspell aspell-en などで簡単に導入できます.

基本的な使い方

# インタラクティブにスペルチェックを行う
$ aspell --lang=en --mode=tex check paper.tex

# スペルチェックを行って,スペルが誤っている単語のリストを出力する
$ cat paper.tex | aspell --lang=en --mode=tex list | sort | uniq

ユーザー定義辞書を準備する

論文のスペルチェックを行うと専門用語等が弾かれてしまうことがよくあります.このためユーザー定義辞書を準備しておく必要があります.普通はホームディレクトリにユーザー定義辞書が保存されますが,これでは他の著者や CI 上でこの辞書を利用できません.--personal オプションを使って Git リポジトリ内の aspell/aspell.en.pws にユーザー定義辞書を保存するようにしたのが以下の例です.

# インタラクティブにスペルチェックを行う
$ aspell --lang=en --mode=tex --personal=aspell/aspell.en.pws check paper.tex

# スペルチェックを行って,スペルが誤っている単語のリストを出力する
$ cat paper.tex | aspell --lang=en --mode=tex --personal=aspell/aspell.en.pws list | sort | uniq

まず,1つ目のコマンドでインタラクティブにスペルチェックを行って,足りない単語を辞書に追加して,その後2つ目のコマンドを使って検証するのが良いでしょう.

複数のファイルをスペルチェックする

aspell は複数のファイルを引数に取ってくれないようなので,複数のファイルに対してスペルチェックを行うにはちょっとした工夫が必要です.

# インタラクティブにスペルチェックを行う
$ for f in sections/*.tex; do
    aspell --lang=en --mode=tex --personal=aspell/aspell.en.pws check paper.tex
  done

# スペルチェックを行って,スペルが誤っている単語のリストを出力する
$ cat sections/*.tex | aspell --lang=en --mode=tex --personal=aspell/aspell.en.pws list | sort | uniq

CI でスペルチェックを実行する

基本的には上に上げたコマンドを使ってスペルチェックを行います.スペルチェックに失敗した場合は exit code を 0 以外の値にして欲しいのですが,aspell はエラーがあった場合も exit code が 0 になるようなので少し不便です.このため以下のようなシェルスクリプトを準備しておくと便利です.

#!/bin/bash
set -e

files="paper/paper.tex paper/sections/*.tex"
words=$(cat $files | aspell --lang=en --mode=tex --personal=aspell/aspell.en.pws list | sort | uniq)

echo "Processed files: $files"
echo

if [[ -z $words ]]; then
  echo "Succeeded!"
  exit 0
fi

echo "Misspelled words:"
for word in $words; do
  echo "- $word"
done
echo

echo "Result of git-grep:"
for word in $words; do
  git grep -n $word
done
echo

echo "Failed..."

exit 1

このシェルスクリプトは,スペルエラーが1つもないときのみ exit code が 0 になり,それ以外の場合は 1 になります.また,スペルエラーが検出された単語の一覧や,そのスペルエラーがどのファイルに存在するかも (git grep で) 調べてくれます.このシェルスクリプトを使う CircleCI の設定は以下のようになります.

version: 2
jobs:
  build:
    docker:
      - image: ubuntu:17.10
        environment:
          TERM: xterm
    steps:
      - run:
          command: |
            apt update
            apt install -y aspell aspell-en git latexmk make texlive texlive-latex-extra
      - checkout
      - run:
          command: latexmk
          working_directory: paper
      - run:
          command: ./run_aspell.sh

これで,論文を書いて GitHub に push するだけで,コンパイルが出来るかチェックし,スペルチェックを行い,結果をチャットツールに通知する仕組みが整いました!

Amazon S3

せっかく CircleCI で PDF ファイルを生成するようにしたので,このファイルを簡単に閲覧できるようにするとより便利そうです.今回は Amazon S3 にファイルをアップロードするようにしてみます.

バケットを作成する

PDF ファイルを置くためのバケットを S3 に作成します.Web から作成する場合はこちらから作業が出来ます.

IAM ユーザーを作成する

CircleCI のこのリポジトリから AWS を使うための IAM ユーザーを作成しましょう.今回は,このユーザーに先ほど作成したバケットへの s3:PutObjects3:ListBucket の権限のみを付与しました:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::my-paper/*"
        },
        {
            "Sid": "VisualEditor1",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": "arn:aws:s3:::my-paper"
        }
    ]
}

作成した IAM ユーザーの認証情報はこちらの手順に従って CircleCI に登録します.

CircleCI から Amazon S3 にアップロードする

CircleCI から Amazon S3 にファイルをアップロードするための設定例は以下のようになります:

version: 2
jobs:
  build:
    docker:
      - image: ubuntu:17.10
        environment:
          TERM: xterm
    steps:
      - run:
          command: |
            apt update
            apt install -y aspell aspell-en ca-certificates git latexmk make texlive texlive-latex-extra
      - checkout
      - run:
          command: latexmk
          working_directory: paper
      - run:
          command: ./run_aspell.sh
      - run:
          command: |
            mkdir -p /tmp/workspace
            cp ./paper.pdf /tmp/workspace/paper.pdf
          working_directory: paper
      - persist_to_workspace:
          root: /tmp/workspace
          paths:
            - paper.pdf

  deploy-s3:
    docker:
      - image: python:3.6-stretch

    steps:
      - checkout
      - attach_workspace:
          at: /tmp/workspace
      - restore_cache:
          key: config-{{ checksum ".circleci/config.yml" }}
      - run:
          command: |
            python3 -m venv venv
            . venv/bin/activate
            pip install -U awscli
      - save_cache:
          key: config-{{ checksum ".circleci/config.yml" }}
          paths:
            - venv
      - run:
          command: |
            now=$(TZ=Asia/Tokyo git show -s --date=iso-local --format=%ad $CIRCLE_SHA1 | tr -d '\n')
            short_sha1=$(git rev-parse --short $CIRCLE_SHA1)
            echo "Author Date: $now"
            echo "Short Hash: $short_sha1"
            cd /tmp/workspace
            for f in *; do mv "$f" "$now $short_sha1 $f"; done
      - run:
          command: |
            . venv/bin/activate
            aws s3 sync /tmp/workspace/ s3://my-paper/

workflows:
  version: 2
  build:
    jobs:
      - build
      - deploy-s3:
          requires:
            - build

今回は CircleCI の Workflows という機能を利用しています.build のジョブでは PDF を作成して,作成したファイルを workspace に保存しています.(workspace はジョブ間でファイルを共有するために必要です.また,これを利用するために ca-certificates をインストールしています.)

deploy-s3 のジョブは build のジョブの後に実行されるようになっており,以下のような作業を行います.

  1. pip で awscli をインストールし,いい感じにキャッシュ
  2. Workspace から PDF ファイルを取り出す
  3. PDF ファイルを分かりやすいファイル名 (今回は コミット日時 コミットのハッシュ paper.pdf という形式) に変更
  4. aws s3 sync でファイルをアップロード

ここまで設定すると,GitHub のコミットをプッシュすると CI が走り,成功すれば Amazon S3 にコンパイルされた結果の PDF ファイルが自動的にアップロードされる環境が手に入ります.アップロードされたファイルは AWS の管理画面から見ることが出来ます.

更に進める

今回の記事では紹介しきれませんでしたが,これらの仕組みを応用すると以下のようなことも可能になります:

  • 論文に関連するプログラムの実装についても同様の仕組みで
    • ビルドやテストを CircleCI で実行
    • 生成されたバイナリをアップロード
  • 生成された PDF ファイルやバイナリを活用するために
    • 研究室などの一部のネットワークのみから自由に閲覧できるように
    • BASIC 認証をかけて公開
  • textlint を使った文章のチェック

まとめ

論文執筆のための継続的インテグレーションに使える様々なツールを紹介しました.Docker Hub や CircleCI の Workflows,AWS は慣れていないと難しい部分もあるかもしれません.この記事で理解できる部分だけでも導入すれば,論文の執筆により集中しやすい環境が整うはずです.(もちろん環境整備だけしても研究自体は何も進まないので注意が必要ですが… (自戒))

CAMPHOR- Advent Calendar 2017 明日の担当は @ohmuraken です.お楽しみに!