ちょっと前に version 1.6.1 がリリースされたので、その中の目玉機能でもある カスタムスナップショット を紹介したいと思います。

NEWS

すでに多くの方がご存知かと思いますが、stack 界隈で大きな出来事が3つありました。

  • stack 1.6.1 のリリース
  • lts-10.0 のリリース
  • stack new で生成されるテンプレートのデフォルトが hpack になった

以下の記事は hpack についての記述があるため、stack 初心者におすすめです!

ただ、古い記事が全部だめかというとそうでもありません。

細部を自分で補完できれば有用な記事も多くあります。

Custom Snapshots (カスタムスナップショット) について

カスタムスナップショットは名前から想像できるように、スナップショットを好きにカスタマイズできる新機能です!

公式のスナップショットは resolver に指定する ltsnightly で始まるものです。

カスタムスナップショットとは関係ないですが、lts, nightly とバージョンを省略すると最新版のスナップショットを指定できるという小技もあります。(Feature request: stack init –latest-nightly #3641)

$ stack new sample --resolver=nightly
$ stack new sample --resolver=lts

カスタムスナップショットを作ってみよう!

通常であれば stack new で生成されるプロジェクトの stack.yamlpackage.yaml を使いますが、今回は全部ゼロから作って行こうと思います。

カスタムスナップショットの作成

まずは my-snapshot.yaml という名前で空のファイルを作ります。

$ touch my-snapshot.yaml
$ tree
.
└── my-snapshot.yaml

カスタムスナップショットを定義するためには、まずはベースとなるスナップショットを決める必要があります。

そのため、 my-snapshot.yamlresolver を追記しましょう。今回は新しくリリースされた lts-10.0 を指定します。

また name フィールドで自分のスナップショットに名前をつけます。

この2つが必須のフィールドになります。

これで lts-10.0 と全く同じカスタムスナップショットを定義することができました。

name フィールドは ~/.stack/snapshots/ 以下に保存されるスナップショットのディレクトリ名の一部として利用されたりします。

stack.yaml の作成

実際に使ってみましょう。まずは stack.yaml を用意します。

$ touch stack.yaml

$ tree
.
├── my-snapshot.yaml
└── stack.yaml

stack.yamlresolver に先に作ったカスタムスナップショットを指定します。

このままでは cabal ファイルが無いため、まだビルドできません。

package.yaml の作成

package.yaml もゼロから作っていきましょう。

$ touch package.yaml

$ tree
.
├── my-snapshot.yaml
├── package.yaml
└── stack.yaml

最小の package.yaml はこんな感じです。

ではビルドしてみましょう。

$ stack build
...

$ tree
.
├── my-snapshot.yaml
├── package.yaml
├── stack.yaml
└── test-custom-snapshot.cabal

無事に cabal ファイルが生成されていますね。

パッケージの追加

現時点の依存関係を確認してみます。

$ stack list-dependencies
base 4.10.1.0
ghc-prim 0.5.1.1
integer-gmp 1.0.1.0
rts 1.0
test-custom-snapshot 0.0.0

まずは、いつも通り何かパッケージを追加してみましょう。

今回は hakyll-shakespeare を追加することにします。hamlet 記法が好きなので hakyll でサイト作る時は個人的にお世話になっているパッケージです。

現時点で lts-10.0hakyll-shakespeare は含まれていません。

$ cat my-snapshot.yaml
resolver: lts-10.0
name: waddlaw-1.0

packages:
  - hakyll-shakespeare-0.1.0.0.2

こんな感じでカスタムスナップショットに hakyll-shakespeare を指定します。

packages フィールドには extra-deps と同じ構文が利用できます。そのため hackage などにアップロードしていないパッケージでも同様に指定可能です。

それでは、ちゃんと追加されるか確認してみます。

$ stack build
$ stack list-dependencies | grep hakyll-shakespeare
hakyll-shakespeare 0.1.0.0.2

大丈夫そうですね!

カスタムスナップショットを共有する

ここまでで基本的なカスタムスナップショットの作り方はマスターできたと思います。

しかし、複数のプロジェクトでカスタムスナップショットが利用できなければ、うれしさ半減です。なので、カスタムスナップショットには、そういった仕組みも用意されています。

どこかにカスタムスナップショットをアップロードし、単純に resolverURL を指定するだけです。

$ cat stack.yaml
resolver: https://raw.githubusercontent.com/waddlaw/example-custom-snapshot/master/my-snapshot.yaml

注意点

1つ注意しなければならない点として、ローカルに用意するカスタムスナップショットファイルと違い、リモートのファイルについてはイミュータブル (変更されないもの) として処理されるという点です。つまり、 URL にアクセスするのは一度だけということです。

そのため、リモートのファイルを上書き更新したとしても、その内容は既存のプロジェクトには反映されません。

$ tree ~/.stack/custom-plan/
/home/bm12/.stack/custom-plan/
└── yaml
    └── tCj-vP1QL-9k.yaml

$ cat ~/.stack/custom-plan/yaml/tCj-vP1QL-9k.yaml
resolver: lts-10.0
name: waddlaw-1.0

packages:
  - hakyll-shakespeare-0.1.0.0.2

なので Stackage 同様にカスタムスナップショットの内容を変更する場合は、その都度新しいスナップショットを作る必要があります。

カスタマイズ可能な設定

スナップショットをカスタマイズできる項目は以下の4つです。

  • コンパイラの上書き
  • 除外パッケージの指定
  • ghc-options の指定
  • flags の指定

具体的な使い方についてはドキュメントをご確認ください。

まとめ

この機能は Hakyll などの静的サイトジェネレータを良く使う人にとっては、便利なのではないでしょうか。

個人的には、lts-9 系で最新の pandochakyll を使おうとしたとき、数多くの extra-deps を追加する必要があり、そういう場面で便利かなと少し感じました。