やった事をまとめると、以下の通り。

  • StackでHaskellのパッケージ(Hakyll)を管理する。
  • markdownでブログを書き、Hakyllでhtmlファイルに変換する。
  • 実際には、TravisがHakyllを使ってコンパイルしhtmlファイルに変換する。
  • ソースファイルはGithubの公開リポジトリで管理し、Github Pagesで公開する。

できたのが本ブログ

Stack

Stackは、 Haskellのパッケージをビルドしたりインストールしたりするツールです。 tanakhさんによる 紹介記事をきっかけに知りました。 Haskell力のない自分にはcabal hellを乗り越えられる自信が無かったという理由と、 タイムリーなので使ってみたいという理由から選択してみました。

Hakyll

Hakyllは、 Haskellによる静的htmlページ生成ツールです。 RubyによるJekyllにインスパイアされた作られたとか。

hakyll-init "site"

とすることでsiteというディレクトリ内に必要なファイル一式が生成されます。 あとは、

ghc --make site.hs
./site build

と実行すれば_siteディレクトリ内にhtml及びcss等の必要ファイル一式が生成されます。 具体的にはsite.hsを見ながらチュートリアルを読んでみてください。 シンプルな構成になっているのでなんとなくであればすぐに理解できると思います。(自分もまだ理解不足ですが)

Travis

Travis CIはCIを行うためのサービスです。 Stackを用いるための設定方法が公開されています。

Github Pages

Github Pagesはユーザやリポジトリ毎に提供されるWebページ公開サービスです。 ソースはGithubのリポジトリで管理します。注意が必要なのは最上階層にindex.htmlが必要ということでしょうか。 Hakyllでは_siteにhtmlが生成されるからです。

記事作成 〜 公開 の流れ

Hakyllでは_siteディレクトリにコードを生成するが、最上階層にindex.htmlが必要という問題を git submoduleで吸収します。また、ついでにTravisにコード生成もやってもらいます。

  • あらかじめ_siteディレクトリをsubmoduleに追加しておく
  • sourceブランチ: markdownで記事を書く
  • sourceブランチ: hakyllでコンパイルし正しく表示されるか確認する (省略可)
  • sourceブランチ: githubにpushする
  • masterブランチ: Travisがコンパイルしhtmlファイルを生成する(_siteディレクトリに)
  • masterブランチ: Travisがgithubにpushする
  • Github Pagesに公開される

つまり、記事生成をsourceブランチで行ってgithubにpushすれば、 masterブランチに必要なファイルが作成され記事が公開されるという流れです。

stackをインストール

releasesから最新版をダウンロード。 パスが通っているディレクトリに配置します。

ビルドする

cabal init

まず.cabalファイルを作っておきます。 注意するところとしては、ライセンスをきちんと設定しておかないと (ディレクトリにLILCENSEが無いと?)後のstack build部でこけてしまいます。

次に、生成された.cabalファイルにhakyll依存を明記します。

build-depends: hakyll >=4.5

Stackageで管理されている安定verが4.6.9.0でしたので、 それが満たせるような表記になっていれば良さそうです。

stack init

これでstack.yamlが生成されます。

まずはstack.yamlをいじらずにstack buildをしてみます。すると現時点のバージョンでは、 hfsevents: needed (>=0.1.3)と怒られてしまいます。ログの下の方に

Recommended action: try adding the following to your extra-deps in .../stack.yaml
- hfsevents-0.1.5

とあるので、stack.yamlextra-depsの項に追記します。

flags: {}
packages:
- '.'
extra-deps:
- hfsevents-0.1.5
resolver: lts-2.21

以上で

stack build

とすると必要なパッケージのインストールが始まります。(初回はちょっと長め)

これまでsyntax highlightが必要な場合はcabal install --reinstall -fhighlighting pandocとか してたと思います。おそらくstack.yamlflagsを設定してやればうまくいくかと思うのですが、 私はそれに気づかずにインストールしてしまいました。今現在再インストールするような仕組みは無く、 何を消去すれば再インストールできるのかわからなかったため、 とりあえずhighlight.jsを使っています。

インストール終了後に

stack exec hakyll-init weblog

とすることで、weblogフォルダに必要ファイル一式が生成されます。 ここまででビルドできるようになるのですが、まずはgit submoduleやTravisの設定を行ってしまいます。

git submodule & Travisの設定をする

weblog/_siteをサブモジュールに追加します。 そのためまずは、Githubのレポジトリ(masterブランチ)に空の状態でpushします。

git init
git commit --allow-empty -m 'first commit'
git remote add origin git@github.com:<account>/<account>.github.io.git
git push origin master

git checkout -b source
git submodule add git@github.com:<account>/<account>.github.io.git weblog/_site

作成された.gitmoduleTravisから読めるようにするため、 urlを修正します。

https://github.com/<account name>/<account name>.github.io.git

必要無いファイルは管理しないように.gitignoreを作成します。

weblog/_site
weblog/_cache
weblog/site*
!weblog/site.hs
.stack-work

Travisの管理画面で、 <account>/<account>.github.ioのスイッチをonにすることでレポジトリをアクティブにします。

また、歯車アイコンから設定画面へ行き、 Build only if .travis.yml is presentのスイッチをonにしておきます。

次に.travis.ymlを作ります。 環境変数にGH_TOKENGH_EMAILをセキュアな状態で入力する必要があるため、 travisコマンドを使います。

travis encrypt -r <account>/<account>.github.io.git GH_EMAIL=<email address>
travis encrypt -r <account>/<account>.github.io.git GH_TOKEN=<github token>

ここで使う<github token>はGithubで生成したものを使います。 また、travisコマンドはgemを使ってあらかじめインストールしておきます。

sudo gem install travis

.travis.ymlはこんな感じにしました。


language: haskell

sudo: false
cache:
  directories:
    - $HOME/.stack/

branches:
  only:
    - source

env:
  global:
    - GH_NAME="335g.travis"
    - secure: "*******" # token
    - secure: "*******" # email

before_install:
  - mkdir -p ~/.local/bin
  - export PATH=~/.local/bin:$PATH
  - travis_retry curl -L https://github.com/commercialhaskell/stack/releases/download/v0.1.2.0/stack-0.1.2.0-x86_64-linux.gz | gunzip > ~/.local/bin/stack
  - chmod a+x ~/.local/bin/stack
  - export PATH=~/opt/ghc/7.8.4/bin:$PATH
  - git submodule foreach --recursive 'git checkout master; git ls-files | grep -v README | grep -v CNAME | xargs -r git rm'

addons:
  apt:
    sources:
      - hvr-ghc
    packages:
      - ghc-7.8.4

install:
  - stack setup --no-terminal
  - stack build --only-snapshot --no-terminal

before_script:
  - git config --global user.name "$GH_NAME"
  - git config --global user.email "$GH_EMAIL"

script:
  - stack build --no-terminal
  - cd weblog
  - stack ghc site.hs
  - ./site build

after_success:
  - cd _site
  - export REMOTE=$(git config remote.origin.url | sed 's/.*:\/\///')
  - git remote add github https://${GH_TOKEN}@${REMOTE}
  - git add ./*
  - git status
  - git commit -m "Built by Travis (build $TRAVIS_BUILD_NUMBER)"
  - git push --quiet github master:master

notifications:
  email: false

具体的には、 script:内でビルドしhakyllでhtmlファイルを生成しています。 また、after_success:内でgithubにpushしています。

Travis内でstack buildするため初回は時間がかかります。 2回目以降はキャッシュされたものを使うため時間が短縮されます。

公開

ここまで設定しておけばpushすることで公開されます。

git push origin source

まとめ(感想)

stackもTravisも初めてで、Haskell久しぶりな状態だったため時間がかかりましたが、 作業量はそれほどではありませんでした。心配していたcabal hellも起きませんでしたし、 チャンスがあればまたstack使ってみたいと思います。

  • Stack便利
  • Hakyll便利
  • Travis便利
  • Github Pages便利
  • ブログ書くモチベーションが続けば良いな

参考