キャッシュ化タスク
このページではキャッシュ化タスクの詳細を説明する。概要の解説はキャッシュ化を参照。
自動キャッシュ
val someKey = taskKey[String]("something")
someKey := name.value + version.value + "!"
sbt 2.x では、タスク結果は name と version の 2 つのセッティングに基づいて自動的にキャッシュされる。初回実行時はオンサイトで実行されるが、2 回目以降はディスクキャッシュが使用される:
sbt:demo> show someKey
[info] demo0.1.0-SNAPSHOT!
[success] elapsed time: 0 s, cache 0%, 1 onsite task
sbt:demo> show someKey
[info] demo0.1.0-SNAPSHOT!
[success] elapsed time: 0 s, cache 100%, 1 disk cache hit
キャッシュ化はシリアライズ困難である
自動キャッシュに参加するには、入力キー(例: name と version)が sjsonnew.HashWriter 型クラス用の given インスタンスを提供し、戻り値の型が sjsonnew.JsonFormat 用の given インスタンスを提供する必要がある。
[error] -- Error: /Users/xxx/caching/project/FooPlugin.scala:17:4 -
[error] 17 | foo := {
[error] | ^
[error] |given evidence sjsonnew.JsonFormat[sbt.HashedVirtualFileRef] is not found; opt out of caching by annotating the key with @transient, or as foo := Def.uncached(...), or provide a given value
[error] |
[error] 18 | val b = baseDirectory.value
HashedVirtualFileRef のような組み込み型のコーデックは CacheImplicits.given にて提供される:
import CacheImplicits.given
....
override lazy val projectSettings: Seq[Setting[?]] = Seq(
foo := {
val b = baseDirectory.value
val conv = fileConverter.value
conv.toVirtualFile((b / "build.sbt").toPath)
},
bar := foo.value,
)
Contraband で sjson-new のコーデックを生成することもできる。
エフェクトの追跡
ファイル作成のエフェクト
ファイル名を返すだけでなく、ファイル作成のエフェクトをキャッシュするには、Def.declareOutput(vf) を使ってファイル作成のエフェクトを追跡する必要がある。
someKey := {
val conv = fileConverter.value
val out: java.nio.file.Path = createFile(...)
val vf: xsbti.VirtualFile = conv.toVirtualFile(out)
Def.declareOutput(vf)
vf: xsbti.HashedVirtualFileRef
}
システム・プロパティーのエフェクト
キャッシュ化タスクからシステム・プロパティーや環境変数の捕獲するとキャッシュの安定性を破壊することがある。以下に具体例を用いて説明する:
lazy val someInt = taskKey[Int]("")
// BAD
someInt := {
sys.props("release").toInt + 1
}
まずは -Drelease=0 とともに実行したとする:
$ sbt --server -Drelease=0
....
sbt:caching> show someInt
[info] 1
[success] elapsed time: 0 s, cache 0%, 1 onsite task
しかし、次に -Drelease=1 とともに実行したとしても、値は変化しない:
$ sbt --server -Drelease=1
....
sbt:caching> show someInt
[info] 1
[success] elapsed time: 0 s, cache 100%, 1 disk cache hit
これは、someInt がタスク定義のコードの形と入力となるセッティングとタスクのみをキャッシュ・キーとして見ているためだ。someInt を正しくキャッシュ化するには、システム・プロパティーをセッティングで包む必要がある:
lazy val someInt = taskKey[Int]("")
lazy val releaseVer = settingKey[Int]("")
releaseVer := sys.props("release").toInt
someInt := releaseVer.value + 1
これでビルドが読み込まれるたびにシステム・プロパティーが再評価されるようになった:
$ sbt --server -Drelease=1
sbt:caching> show someInt
[info] 2
[success] elapsed time: 0 s, cache 0%, 1 onsite tas
キャッシュからのオプトアウト
タスクキー単位でのオプトアウト
次に、一部のタスクキーをキャッシュからオプトアウトしたい場合は、以下のようにキャッシュレベルを設定する:
@transient
val someKey = taskKey[String]("something")
または
@cacheLevel(include = Array.empty)
val someKey = taskKey[String]("something")
タスク単位でのオプトアウト
キャッシュを個別にオプトアウトするには、以下のように Def.uncached(...) を使用する:
val someKey = taskKey[String]("something")
someKey := Def.uncached {
name.value + somethingUncachable.value + "!"
}
ビルド全体でのオプトアウト
デフォルトのカスタムタスクキャッシュをオプトアウトするには、project/plugins.sbt に以下を追加する:
Compile / scalacOptions += "-Xmacro-settings:sbt:no-default-task-cache"
リモート・キャッシュ
sbt 2.x は Bazel 互換の gRPC インターフェースを実装しており、オープンソースおよび商用の多数のバックエンドと連携する。詳細はリモート・キャッシュの設定を参照。