これは、新しい設定システムの機能の一部を示す高度な例です。ビルドで定義されている場所に関係なく、ビルドで宣言されたすべての依存関係を一時的に変更する方法を示します。ビルドに関与するすべての設定から生成された最終的な Seq[Setting[_]]
を直接操作します。
変更は *canonicalize* を実行することによって適用されます。 *reload* または *set* を使用すると変更が元に戻り、 *canonicalize* を再度実行する必要があります。
この特定の例では、ScalaCheck のすべての宣言された依存関係をバージョン 1.8 を使用するように変換する方法を示します。演習として、他の依存関係、使用されるリポジトリ、または使用される scalac オプションを変換してみてください。設定を追加または削除することも可能です。
この種の変換は Project の設定で直接行うことができますが、プラグインや build.sbt ファイルから自動的に追加された設定は含まれません。この例で示しているのは、外部ビルドを含むすべてのビルド内のすべてのプロジェクトのすべての設定に対して無条件にそれを行うことです。
import sbt._
import Keys._
object Canon extends AutoPlugin {
// Registers the canonicalize command in every project
override def trigger = allRequirements
override def projectSettings = Seq(commands += canonicalize)
// Define the command. This takes the existing settings (including any session settings)
// and applies 'f' to each Setting[_]
def canonicalize = Command.command("canonicalize") { (state: State) =>
val extracted = Project.extract(state)
import extracted._
val transformed = session.mergeSettings map ( s => f(s) )
appendWithSession(transformed, state)
}
// Transforms a Setting[_].
def f(s: Setting[_]): Setting[_] = s.key.key match {
// transform all settings that modify libraryDependencies
case Keys.libraryDependencies.key =>
// hey scalac. T == Seq[ModuleID]
s.asInstanceOf[Setting[Seq[ModuleID]]].mapInit(mapLibraryDependencies)
// preserve other settings
case _ => s
}
// This must be idempotent because it gets applied after every transformation.
// That is, if the user does:
// libraryDependencies += a
// libraryDependencies += b
// then this method will be called for Seq(a) and Seq(a,b)
def mapLibraryDependencies(key: ScopedKey[Seq[ModuleID]], value: Seq[ModuleID]): Seq[ModuleID] =
value map mapSingle
// This is the fundamental transformation.
// Here we map all declared ScalaCheck dependencies to be version 1.8
def mapSingle(module: ModuleID): ModuleID =
if(module.name == "scalacheck") module.withRevision(revision = "1.8")
else module
}