這是一個進階範例,展示了新設定系統的一些強大功能。它展示了如何臨時修改建置中所有宣告的相依性,無論它們定義在哪裡。它直接操作從建置中涉及的每個設定產生的最終 Seq[Setting[_]]
。
這些修改透過執行canonicalize來應用。reload 或使用 set 會還原修改,需要再次執行 canonicalize。
這個特殊的範例展示了如何轉換所有宣告的 ScalaCheck 相依性以使用 1.8 版本。作為練習,您可以嘗試轉換其他相依性、使用的儲存庫或使用的 scalac 選項。也可以新增或移除設定。
這種轉換可以直接在專案的設定上進行,但它不會包含從外掛程式或 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
}