search term:

フィールドテスト: conscript, giter8, sbt-dirty-money

Scala のツールを使った、日常のコーディングでのテクニックを紹介したい。 例えば、ツールとかライブラリを開発してるとして、バグ報告を受けるとする。まず原因の分析に入る前に僕が集中することは、ユーザが使っているのと同じデータで問題を再現することだ。問題が再現できれば、次に問題を単純化して失敗する spec や機能テストに落としこむことに移行する。バグが修正されれた後で、同じセットアップを使って実際のデータでもバグが直っているかを確認することができる。

conscript を使ったコマンドラインアプリ

最初に考えるシナリオはコマンドラインアプリだ。再現の部分はあまり面白く無い。普通のプロジェクトとは別に再現用のディレクトリを作って、そこにさらにサブディレクトリを作って、データを使ってアプリを実行するだけだ。 シェルスクリプトを用意すれば、色々パラメータを渡しながら実行するのには便利かもしれない。

僕が狙っているのは、ユーザと同じ環境下での、編集-デプロイ-テストのサイクルを短くすることだ。n8han の conscript 登場。conscript は、sbt の依存性の管理をバックエンドに使ったコマンドラインアプリをセットアップする簡単なユーティリティだ。 xsbti.AppMain を拡張するクラスを含んだ jar を公開して、launchconfig を github にプッシュするだけでいい。

ユーザが cs you/project とアプリをインストールすると、conscript は、launchconfig をダウンロードして、sbt-launch.jarlaunchconfig と一緒に呼び出すシェルスクリプトを作る。つまり、この時点では、ユーザのマシンにはアプリの jar は存在していない。そこで、conscript は --version という引数付きでシェルスクリプトを呼び出す。残りは、sbt のランチャーが適当にやってくれる。公開されている launchconfig には、現行の安定バージョンを書くのが普通だけど、これをオーバーライドして任意のバージョンをダウンロードさせることもできる。これは、メインのエントリーポイントその他の設定が変わっていないことが前提だ。

準備ステップ:

  1. プロジェクトのバージョンを x.y.z-SNAPSHOT に変更する。

  2. アプリ foo をバージョン x.y.z-SNAPSHOT でインストールする:

    $ cs you/foo/x.y.z-SNAPSHOT

編集-デプロイ-テスト:

  1. sbt から > publish-local
  2. 別のタブでシェルから、$ cs --clean-boot
  3. これも、シェルから $ foo data.txt

便利なのは、このまま snapshot の jar を公開してしまえば、直ちにユーザが使えることだ。

giter8 を使った sbt プラグインのセットアップ

次にのシナリオは sbt プラグインだ。プラグインは便利だけど、使い捨てのプロジェクトのために設定するには面倒だ。n8han の giter8 登場。

Giter8 は github 上に公開されたテンプレートからアプリケーションのひな形を作成するコマンドラインツールだ。

you/foo.g8 をセットアップすれば、以下を実行すると:

$ g8 you/foo

src/main/g8 以下の全ファイルをダウンロードして、もし必要なら文字列置換を実行してくれる。 これを使って、プラグインをインストール済みの sbt プロジェクトを作っておくことができる。

編集-デプロイ-テスト:

  1. sbt から > publish-local
  2. 別のタブでシェルから、$ sbt run

これも、snapshot を公開してしまえば、修正は直ちに利用可能となる。

sbt-dirty-money を使った Ivy キャッシュの掃除

publish-local にも問題はある。Ivy のキャッシュは、最後にどこから jar を取ってきたか覚えていて、それを使い続ける。これにより、「僕の環境では動く(他では動かない)」という状況を作り出してしまうことがある。~/.ivy2 を全部削除するというのは理想的ではない。sbt-dirty-money 登場。

このプラグインは、~/.ivy2 をもう少し選択的に削除するコマンドをいくつか追加する:

((dir / "cache") ** ("*" + organization + "*") ** ("*" + name + "*")).get

例えば、unfiltered/unfiltered からこれを実行すると unfiltered-xyz などにもマッチするので、明らかにこれは、完全ではない。

> show clean-cache-files
> clean-cache

上記は、~/.ivy2/cache を組織名とプロジェクト名を使って削除する。

> show clean-local-files
> clean-local

上記は、~/.ivy2/local を組織名とプロジェクト名を使って削除する。