sbt 0.12.0 の変更点
ついに final がリリースされた、sbt 0.12.0 の変更点を訳しました。 バイナリバージョンという概念が導入されることで、Scala 2.9.0 で入ったけどあまり活用されていない Scala の後方バイナリ互換性がより正面に出てくるキッカケとなると思います。
互換性に影響のある新機能、バグ修正、その他の変更点
- Scala 2.10 以降の Scala 及び sbt プラグインのクロスバージョン規約の変更。 (詳細は以下の項目 )
- 直接実行された場合、強制的に
update
を実行するようにした。 #335 - sbt プラグインリポジトリがプラグインとプラグインの定義にデフォルトで加わった。 #380
- プラグイン設定ディレクトリの優先順位。 (詳細は以下の項目 )
- ソース依存性の修正。 (詳細は以下の項目 )
- 集約がより柔軟になった。 (詳細は以下の項目 )
- タスク軸の構文が
key(for task)
からtask::key
へと変更された。 (詳細は以下の項目 ) - sbt の organization が
org.scala-sbt
へと変更された。(元は、org.scala-tools.sbt) 特に、scripted プラグインのユーザはこの影響を受ける。 artifactName
の型が(ScalaVersion, ModuleID, Artifact) => String
となった。javacOptions
がタスクとなった。session save
はbuild.sbt
内の設定を(適切な時に)上書きするようにした。#369
新機能
- テストのフォークのサポート。 #415
test-quick
。 (#393)- リポジトリ設定のグローバルなオーバライドをサポートした。 #472
- 再コンパイルをせずに unchecked と deprecation の警告を表示する
print-warnings
タスクを追加した。(Scala 2.10+ のみ) - Ivy 設定ファイルを URL から読み込めるようにした。
projects add/remove
で一時的に他のビルドと作業できるようになった。- 並列実行の制御の改善。 (詳細は以下の項目 )
inspect tree
でinspect
を再帰的に呼べるようになった。#274
バグ修正
- 再帰的にディレクトリを削除するときに、シンボリックリンクが指す先のコンテンツを削除しないようにした。
- Java ソースの親の検知の修正。
update-sbt-classifiers
で用いられる resolver の修正。#304- プラグインの自動インポートの修正。#412
- 引数のクオート #396
- Ctrl+Z で停止した後 JLine を正しくリセットするようにした。(Unix のみ) #394
改善点
- ランチャーが 0.7.0 以降全ての sbt を起動できるようになった。
- スタックトレースが抑制された場合、
last
を呼ぶようにより洗練されたヒントが表示されるようになった。 - Java 7 の Redirect.INHERIT を用いて子プロセスの入力ストリームを継承するようになった。 #462, #327 これでインタラクティブなプログラムをフォークした場合に起こる問題が解決されるはず。 (@vigdorchik)
help
とtask
コマンドの様々な改善、および新たなsettings
コマンド。#315- jsch バージョンを 0.1.46 へと更新。 #403
- JLine バージョンを 1.0 へと変更。 (詳細は以下の項目 )
- その他の修正および機能改善: #368, #377, #378, #386, #387, #388, #389
実験的、もしくは開発途中
- 差分コンパイルを組み込むための API。このインターフェイスは今後変更する可能性があるが、既に scala-maven-plugin のブランチで利用されている。
- Scala コンパイラの常駐の実験的サポート。 sbt に
-Dsbt.resident.limit=n
を渡すことで設定を行う。n
は常駐させるコンパイラの最大数。 - 新サイトの howto ページを読みやすくした。
大きな変更の詳細点
## プラグインの設定ディレクトリ0.11.0 においてプラグインの設定ディレクトリは project/plugins/
からただの project/
へと移行し、project/plugins/
は非推奨となった。0.11.2 において非推奨のメッセージが表示されたが、全ての 0.11.x においては旧スタイルの project/plugins/
が新しいスタイルよりも高い優先された。0.12.0 では新しいスタイルが優先される。旧スタイルのサポートは 0.13.0 が出るまで廃止されない。
- 理想的には、プロジェクトは設定の衝突がないことを保証すべきだ。両方のスタイルがサポートされているため、設定に衝突がある場合の振る舞いのみが変更されることになる。
- 実際にこれが起こりえる状況としては、古いブランチから新しいブランチに切り替えた場合に空の
project/plugins/
が残ってしまい何も設定が無いにも関わらず旧スタイルが使われてしまうということがある。 - そのため、この変更は飽くまで新スタイルへ移行中のプロジェクトのための改善であり、他のプロジェクトには気付かれないことを意図している。
JLine 1.0 への移行。これはいくつかの顕著な修正を含む比較的新しいリリースだが、見たところ今まで使われていた 0.9.94 とバイナリ互換がある。具体的には、
- Unix 上で stty へフォークしたストリームを正しく閉じる。
- Linux での Delete キーへの対応。これが実際に動作するかは各自確認して欲しい。
- 行の折り返しが正しくなっているように思える。
セッティングやタスクのタスク軸のパーシングに関して重要な変更が行われた。 #202
- 0.12 以前の構文は
{build}project/config:key(for task)
だった。 - 提案され(採用された)0.12 からの構文は
{build}project/config:task::key
だ。 - タスク軸をキーの前に移動することで特にプラグインからの(タブ補完を用いた)キーの発見が容易にする。
- 旧構文はサポートされない予定だ。理想的は非推奨に一度すべきだが、その実装に手間がかかりすぎる。
集約がより柔軟になった。これは過去にメーリングリストで議論されたのと同様の方向だ:
- 0.12 以前は、セッティングは現行プロジェクトに基づいてパースされ、全く同様のセッティングのみが集約された。
- タブ補完は集約を考慮に入れていなかった。
- これは、セッティングもしくはタスクが現行プロジェクトに無かった場合は集約されたプロジェクトにそのセッティング/タスクがあったとしてもパーシングが失敗することになった。
- また、現行プロジェクトに compile:package があり、集約されたプロジェクトに *:package があり、ユーザが (コンフィギュレーション無しで)
package
を実行した場合 (compile:package じゃないため) *:package が集約されたプロジェクトで実行されなかった。 - 0.12 ではこのような状況において集約されたセッティングが選択されるようになった。具体的には、
1.
root
というプロジェクトが子プロジェクトのsub
を集約すると仮定する。 2.root
は:package
を定義する。 3.sub
はcompile:package
とcompile:package
を定義する。 4.root/package
を実行するとroot/:package
とsub/compile:package
が実行される。 5.root/compile
を実行するとsub/compile:compile
が実行される。 - この変更点はタスク軸のパーシングの変更に依存する。
並列実行の細かい制御がサポートされる。詳細は Parallel Execution 参照。
- デフォルトの振る舞いは、
parallelExecution
のセッティングも含め以前と同じ。 - このシステムの新しい機能は実験段階だと考えるべき。
- そのため
parallelExecution
は現段階では非推奨ではない。
#329 に対する修正が含まれた。この修正により前プロジェクトに渡ってプラグイン一つにつき唯一のバージョンのみが読み込まれることが保証されるようになった。これは、二部に分かれる。
- プラグインのバージョンは最初に読み込んだビルドに確定する。特に、(sbt が起動した) ルートのビルドで使われたプラグインのバージョンは依存性により使われるものよりも常に優先される。
- 全てのビルドのプラグインは同一のクラスローダにより読み込まれる。
さらに Sanjin のパッチにより hg と svn の URI へのサポートが追加された。
- sbt は
svn
もしくはsvn+ssh
から始まる URI を subversion を用いて取得する。省略可能なフラグメントにより特定のリビジョンを指定できる。 - Mercurial は特定のスキームを持たないため、sbt は Mercurial のリポジトリの URI に
hg:
をプレフィックスとして付けることを要求する。 .git
で終わる URI の処理が修正された。
Scala のバージョン 2.10 シリーズと sbt のバージョン 0.12 シリーズ以降に関して、クロスバージョンのサフィックスがメジャー番号とマイナー番号のみに短縮された。具体的には、普通のライブラリだと sbinary_2.10
、sbt プラグインだと sbt-plugin_2.10_0.12
のようになる。これは Scala と sbt がその中間リリースにおいて前方互換性と後方互換性を維持することを前提とする。
- これは待ちわびていた変更だが、これはオープンソースプロジェクト作者の皆が Scala 2.10 向けのものを公開する前に 0.12 に切り替えるか、ビルドのクロスバージョンのサフィックスを適宜変更することを必要とする。
- 0.12 を用いて Scala 2.10 向けのライブラリを公開するには、0.12.0 が Scala 2.10 よりも前にリリースされることが求められる。
- 同時に、sbt 0.12.0 が Scala 2.10.0 向けに公開されなければ 0.12.x シリーズに渡って Scala 2.9.x を使わなければいけないことになる。
- バイナリバージョン (binary version) という新しい概念を導入する。これはフルバージョン (full version) 文字列のサブセットで、バイナリ互換性を表す。つまり、同じバイナリバージョンはバイナリ互換性を意味する。以前の sbt の振る舞いに合わせて 2.10 以前の全ての Scala バージョンはフルバージョンをもってバイナリバージョンとする。Scala 2.10 以降はバイナリバージョンは
だ。. - 公開されるアーティファクトのクロスバージョンの振る舞いは
crossVersion
セッティングで設定される。ModuleID
に対してcross
メソッドを用いるか、今まで通りの依存性構築子である %% を用いて依存ライブラリごとに設定を変えることができる。デフォルトでは、単一の % を使った場合は依存性のクロスバージョンは無効にされ、%% を使った場合は Scala のバイナリバージョンを用いる。 artifactName
関数は第一引数としてScalaVersion
を受け取るようになった。型は(ScalaVersion, ModuleID, Artifact) => String
となった。ScalaVersion
は Scala のフルバージョン (例: 2.10.0) とバイナリバージョン (例: 2.10) を保持する。- Indrajit により追加された柔軟なバージョンのマッピングが
cross
メソッドに追加され、複数の引数を取る %% の変種は非推奨となった。以下に具体例で説明する。
以下は等価だ:
"a" % "b" % "1.0"
"a" % "b" % "1.0" cross CrossVersion.Disabled
以下は等価だ:
"a" %% "b" % "1.0"
"a" % "b" % "1.0" cross CrossVersion.binary
これは、Scala のバイナリバージョンの代わりにフルバージョンを使う:
"a" % "b" % "1.0" cross CrossVersion.full
これは Scala のバイナリバージョンを元にカスタム関数を使って Scala バージョンを決定する:
"a" % "b" % "1.0" cross CrossVersion.binaryMapped {
case "2.9.1" => "2.9.0" // 2.10 以前なのでバイナリ==フル
case x => x
}
これは Scala のフルバージョンを元にカスタム関数を使って Scala バージョンを決定する:
"a" % "b" % "1.0" cross CrossVersion.fullMapped {
case "2.9.1" => "2.9.0"
case x => x
}
全ての Scala バージョンに対して公開されていない依存ライブラリを用いてクロスビルドするときにカスタム関数を使うことができる。バイナリバージョンに移行することで、この機能の必要性が徐々に減っていくはずだ。
グローバルなリポジトリ設定
リポジトリ設定のグローバルなオーバライドをサポートした。 #472 [repositories]
項目を ~/.sbt/repositoreies
に書いて、sbt に -Dsbt.override.build.repos=true
を渡すことでリポジトリを定義する。(Launcher のページを参照) ランチャーが sbt と Scala を取得し、sbt がプロジェクトの依存性を取得するのにファイルで指定されたリポジトリが使われるようになる。
test-quick
test-quick
(#393) は引数で指定されたテスト(引数がない場合は全てのテスト)のうち以下の条件を一つでも満たすものを実行する:
- まだ実行されていない。
- 前回実行時に失敗した。
- 最後に成功した後で間接的にでも依存するコードが再コンパイルされた場合。
引数のクォート
引数のクォート #396。
> command “空白 のある 引数\n エスケープは解釈される”
> command “““空白 のある 引数\n エスケープは解釈されない””"
- 最初のリテラルは Windows のパス記号であるバックスラッシュをエスケープ (
\
) する必要があることに注意。2つ目のリテラルを使えばその必要は無い。 - バッチモードから使う場合は、ダブルクオートそのものをシェルからエスケープする必要がある。