这是一个高级示例,展示了新设置系统的一些强大功能。它展示了如何临时修改构建中声明的所有依赖项,无论它们在何处定义。它直接对构建中涉及的每个设置产生的最终 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
}