sbt 1.0.0 

互換性に影響のある新機能、バグ修正、その他の変更点 

移植に関しては Migrating from sbt 0.13.x も参照。

以前より廃止勧告が出ていて、今回撤廃されたもの:

新機能 

改善点 

内部 

大きな変更の詳細点 

Zinc 1: クラスベースの name hashing 

(Lightbend の委託で) Grzegorz Kossakowski が Zinc 1 にもたらした大きな改善として、クラスベースの name hashing がある。これは、大規模な Scala プロジェクトにおいて差分コンパイルが高速化することが見込まれる。

Zinc 1 の name hashing は、コード間の依存性をファイルではなく、クラスのレベルで追跡する。GitHub issue sbt/sbt#1104 に有名なプロジェクトの既存のクラスにメソッドを追加した場合の比較データがある:

ScalaTest   AndHaveWord class:          Before 49s, After 4s (12x)
Specs2      OptionResultMatcher class:  Before 48s, After 1s (48x)
scala/scala Platform class:             Before 59s, After 15s (3.9x)
scala/scala MatchCodeGen class:         Before 48s, After 17s (2.8x)

これは、クラスがどのようにまとめられているかといった様々な要素に依存するが、3x ~ 40x の向上が見られるのが分かる。高速化の理由は、クラスをソースファイルという「くくり」から分けたことで少ない数のソースファイルをコンパイルしているからだ。scala/scala の Platform クラスにメソッドを追加した例だと、sbt 0.13 の name hashing は 72 のソースをコンパイルしていたのに対し、新しい Zinc は 6 のソースをコンパイルしている。

Zinc API の変更 

sbt サーバ: ツーリング統合のための JSON API 

sbt 1.0 はサーバ機能を含み、IDE や他のツールは JSON API を用いてビルドのセッティングをクエリしたり、コマンドを呼び出すことができる。sbt 0.13 においてインタラクティブ・シェルが shell コマンドによって実装されていたのと同様に、「サーバ」も shell コマンドによって実装されていて、人間とネットワークの両方の入力を受け取るようになっている。ユーザ視点で見ると、サーバが加わったことによる影響はほとんど無いはずだ。

2016年3月に「サーバ」機能が最小限になるようにリブートが行われた。JetBrain社で IntelliJ の sbt インターフェイスを担当する @jastice とコラボして機能のリストを絞っていった。sbt 1.0 の段階では当初欲しかった機能の全ては入っていないが、長期的に IDE と sbt エコシステムの連携が向上する布石になることを目指している。例えば、IDE 側から compile タスクを命令して、コンパイラ警告を JSON イベントして受け取るといったことができる:

{"type":"xsbti.Problem","message":{"category":"","severity":"Warn","message":"a pure expression does nothing in statement position; you may be omitting necessary parentheses","position":{"line":2,"lineContent":"  1","offset":29,"pointer":2,"pointerSpace":"  ","sourcePath":"/tmp/hello/Hello.scala","sourceFile":"file:/tmp/hello/Hello.scala"}},"level":"warn"}

関連して追加された機能として、テスト中にバックグラウンドで web サーバなどを実行するのに使える bgRun タスクがある。

イベント・ロギング 

sbt 1.0 は、Log4J 2 と sjson-new を用いて実装したイベント・ロギングを導入する。 普通の String ベースのログの他に、logger に対して case clase や Contraband によって生成された疑似 case class を渡すことができる:

def registerStringCodec[A: ShowLines: TypeTag]: Unit = ...
final def debugEvent[A: JsonFormat: TypeTag](event: => A): Unit = logEvent(Level.Debug, event)
final def infoEvent[A: JsonFormat: TypeTag](event: => A): Unit = logEvent(Level.Info, event)
final def warnEvent[A: JsonFormat: TypeTag](event: => A): Unit = logEvent(Level.Warn, event)
final def errorEvent[A: JsonFormat: TypeTag](event: => A): Unit = logEvent(Level.Error, event)

[success] メッセージといった様々なイベントは、内部でイベント・ロギングを用いて送信されている。 この機構をサーバと併用することで、プラグインやコンパイラから JSON イベントを発行することができる。

また、Log4J 2 を内部に採用したことで SLF4J のバインディングを提供するようになった。

build.sbt の静的バリデーション 

sbt 1.0 は、タスク内において if 式の本文や匿名関数内からの .value の呼び出しを禁止する。@sbtUnchecked アノテーションを使ってこのチェックを無効化できる。

他に、静的バリデーションは、タスクの本文内から .value を呼び忘れるのも予防する。

#3216 and #3225 by @jvican

Eviction 警告の表示 

sbt 1.0 は eviction 警告の表示を改善する。

ビフォー:

[warn] There may be incompatibilities among your library dependencies.
[warn] Here are some of the libraries that were evicted:
[warn]  * com.google.code.findbugs:jsr305:2.0.1 -> 3.0.0
[warn] Run 'evicted' to see detailed eviction warnings

アフター:

[warn] Found version conflict(s) in library dependencies; some are suspected to be binary incompatible:
[warn]
[warn]      * com.typesafe.akka:akka-actor_2.12:2.5.0 is selected over 2.4.17
[warn]          +- de.heikoseeberger:akka-log4j_2.12:1.4.0            (depends on 2.5.0)
[warn]          +- com.typesafe.akka:akka-parsing_2.12:10.0.6         (depends on 2.4.17)
[warn]          +- com.typesafe.akka:akka-stream_2.12:2.4.17 ()       (depends on 2.4.17)
[warn]
[warn] Run 'evicted' to see detailed eviction warnings

#3202 by @eed3si9n

sbt-cross-building 

@jrudolph の sbt-cross-building はプラグイン作者のためのプラグインだ。 ^ (クロス) コマンドと ^^ (sbtVersion スイッチ) コマンドを追加して、これは +++ を sbt のメジャーバージョン間の切り替えに対応させたものだと考えることができる。 プラグインを sbt 1.0 に対応させるのに便利なので、sbt 0.13.16 においてこれらのコマンドを sbt 本体にマージした。

シェルから sbtVersion in pluginCrossBuild をスイッチするには以下を実行する:

^^ 1.0.0

これで sbt 1.0.0 (とその Scala バージョンである 2.12) を使うようになる。

sbt バージョンに特定のコードを含む必要があれば、src/main/scala-sbt-0.13src/main/scala-sbt-1.0 などバイナリ sbt バージョンを末尾に追加したディレクトリを作る。

複数の sbt バージョンをまたいでコマンドを実行するには、まず:

crossSbtVersions := Vector("0.13.16", "1.0.0")

と設定して、以下を実行する:

^ compile

#3133 by @eed3si9n (forward ported from 0.13.16-M1)

CopyOptions 

sbt IO 1.0 は IO.copyFileIO.copyDirectory のバリエーションとして sbt.io.CopyOptions() を受け取るものを追加する。 CopyOptions() は疑似 case class の一例で、ビルダーパターンに似ている。

import sbt.io.{ IO, CopyOptions }

IO.copyDirectory(source, target)

// The above is same as the following
IO.copyDirectory(source, target, CopyOptions()
  .withOverwrite(false)
  .withPreserveLastModified(true)
  .withPreserveExecutable(true))

io#53 by @dwijnand

Library management API とアーティファクトの並列ダウンロード 

sbt 1.0 は Lightbend社の Eugene Yokota (@eed3si9n) と Scala Center の Martin Duhem (@Duhemm) 共著で書かれた Library management API を追加する。 この API は Apache Ivy および cached resolution や Coursier といったその他の代替依存性解決エンジンを抽象化することを目指している。

Ivy エンジンのためのアーティファクトの並列ダウンロードは Scala Center の Jorge (@jvican) によってコントリビュートされた。 また、これは Gigahorse OkHttp を Network API として導入し、内部で Square OkHttp をアーティファクトのダウンロードにも用いる。

lm#124 by @eed3si9n/@Duhemm, lm#90 by @jvican/@jsuereth and lm#104 by @eed3si9n.

Zinc の内部構造保存のためのバイナリ形式 

Zinc の内部構造の保存方法として Google Protocol Buffer を用いたバイナリ形式が Scala Center の Jorge (@jvican) によってコントリビュートされた。この新形式は主に 3つの利点がある:

  1. フォーマットレベルでの後方および前方互換性の向上。
  2. ファイルへのシリアライズ・デシリアライズの高速化 (1.5 ~ 2x)。
  3. ファイルのマシン非依存性の向上。

zinc#351 by @jvican

ライブラリ依存性のロッキング 

ライブラリ依存性のロッキング機能はまだ実装途中だが、Scala Center の Jorge (@jvican) は関連する機能を追加して、最終的にロッキングが可能となる予定だ。

コントリビュータの皆さん 

感謝しなければいけない人が多すぎでここにおさまらなった。Credits を参照してほしい。