1. 与配置系统交互

与配置系统交互 

sbt 的核心是新的配置系统,该系统旨在实现广泛的自定义。本页面的目的是解释配置系统背后的通用模型以及如何使用它。入门指南(参见 .sbt 文件)描述了如何定义设置;本页面描述了如何与设置交互并在命令行中探索它们。

选择命令、任务和设置 

对设置或任务的完全限定引用看起来像这样

{<build-uri>}<project-id>/config:intask::key

此“作用域键”引用被诸如 lastinspect 之类的命令以及在选择要运行的任务时使用。解析器通常只需要 key;其余可选部分选择作用域。这些可选部分分别称为作用域轴。在上面的描述中,{<build-uri>}<project-id>/ 指定了项目轴,config: 是配置轴,intask 是特定于任务的轴。未指定的组件被视为当前项目(项目轴)或自动检测(配置和任务轴)。星号(*)用于明确引用 Global 上下文,如 */*:key 中所示。

选择配置 

在未指定配置的情况下(即省略 config: 部分时),如果键在 Global 中定义,则选择该键。否则,将选择第一个定义键的配置,其中顺序由项目定义的 configurations 成员确定。默认情况下,此排序为 compile, test, ...

例如,以下内容在构建中的 /home/user/sample/ 中的 root 项目中运行时是等效的

> compile
> Compile/compile
> root/compile
> root/Compile/compile
> {file:/home/user/sample/}root/Compile/compile

再举一个例子,run 本身指的是 Compile/run,因为没有全局 run 任务,并且第一个搜索的配置 compile 定义了 run。因此,要引用 Test 配置的 run 任务,必须指定配置轴,如 Test/run。以下是一些需要显式 Test/ 轴的其他示例

> Test/consoleQuick
> Test/console
> Test/doc
> Test/package

特定于任务的设置 

一些设置是针对每个任务定义的。当在一个配置(如 compiletest)中有多个相关任务时,例如 packagepackageSrcpackageDoc,就会用到这种情况。对于打包任务,它们的设置是打包的文件、要使用的选项以及要生成的输出文件。每个打包任务都可以为这些设置具有不同的值。

这是通过任务轴完成的,任务轴选择要应用设置的任务。例如,以下内容打印了不同打包任务的输出 jar。

> package::artifactPath
[info] /home/user/sample/target/scala-2.8.1.final/demo_2.8.1-0.1.jar

> packageSrc::artifactPath
[info] /home/user/sample/target/scala-2.8.1.final/demo_2.8.1-0.1-src.jar

> packageDoc::artifactPath
[info] /home/user/sample/target/scala-2.8.1.final/demo_2.8.1-0.1-doc.jar

> test:package::artifactPath
[info] /home/user/sample/target/scala-2.8.1.final/root_2.8.1-0.1-test.jar

请注意,单个冒号 : 位于配置轴之后,双冒号 :: 位于任务轴之后。

发现设置和任务 

本节讨论 inspect 命令,该命令对于探索设置之间的关系很有用。例如,它可用于确定应修改哪个设置以影响另一个设置。

值和提供者 

inspect 提供的第一个信息是任务的类型或设置的值和类型。以下部分输出标记为“提供者”。这显示了定义设置的实际作用域。例如,

> inspect libraryDependencies
[info] Setting: scala.collection.Seq[sbt.ModuleID] = List(org.scalaz:scalaz-core:6.0-SNAPSHOT, org.scala-tools.testing:scalacheck:1.8:test)
[info] Provided by:
[info]  {file:/home/user/sample/}root/*:libraryDependencies
...

这表明 libraryDependencies 已在当前项目({file:/home/user/sample/}root)的全局配置(*:)中定义。对于像 update 这样的任务,输出看起来像这样

> inspect update
[info] Task: sbt.UpdateReport
[info] Provided by:
[info]  {file:/home/user/sample/}root/*:update
...

相关设置 

inspect 输出的“相关”部分列出了一个键的所有定义。例如,

> inspect compile
...
[info] Related:
[info]  test:compile

这表明除了请求的 Compile/compile 任务之外,还有一个 Test/compile 任务。

依赖项 

正向依赖项显示用于定义设置(或任务)的其他设置(或任务)。反向依赖项则相反,显示哪些内容使用给定设置。inspect 基于请求的依赖项或实际依赖项提供此信息。请求的依赖项是设置直接指定的依赖项。实际设置是指这些依赖项解析到的内容。以下部分将更详细地解释这种区别。

请求的依赖项 

作为示例,我们将查看 console

> inspect console
...
[info] Dependencies:
[info]  Compile / console / initialCommands
[info]  Compile / console / streams
[info]  Compile / console / compilers
[info]  Compile / console / cleanupCommands
[info]  Compile / console / taskTemporaryDirectory
[info]  Compile / console / scalaInstance
[info]  Compile / console / scalacOptions
[info]  Compile / console / fullClasspath

...

这显示了 console 任务的输入。我们可以看到,它从 Compile / console / fullClasspathCompile / console / scalacOptions 获取其类路径和选项。因此,inspect 命令提供的信息可以帮助找到要更改的正确设置。键(如 consolefullClasspath)的约定是,Scala 标识符为驼峰式,而字符串表示为小写并用连字符分隔。配置的 Scala 标识符为大写,以区分它和 compiletest 之类的任务。例如,我们可以从前面的示例中推断如何添加在 Scala 解释器启动时运行的代码

> set Compile / console / initialCommands := "import mypackage._"
> console
...
import mypackage._
...

inspect 显示 console 使用了设置 Compile / console / initialCommands。将 initialCommands 字符串转换为 Scala 标识符会得到 initialCommandscompile 表示这是针对主源代码的。console / 表示该设置特定于 console。因此,我们可以在 console 任务上设置初始命令,而不会影响 consoleQuick 任务,例如。

实际依赖项 

inspect actual <scoped-key> 显示了实际使用的依赖项。这很有用,因为委托意味着依赖项可以来自与请求作用域不同的作用域。使用 inspect actual,我们确切地看到了哪个作用域为设置提供值。将 inspect actual 与普通的 inspect 结合使用,我们可以看到会影响设置的作用域范围。回到请求的依赖项中的示例,

> inspect actual console
...
[info] Dependencies:
[info]  Compile / console / streams
[info]  Global / taskTemporaryDirectory
[info]  scalaInstance
[info]  Compile / scalacOptions
[info]  Global / initialCommands
[info]  Global / cleanupCommands
[info]  Compile / fullClasspath
[info]  console / compilers
...

对于 initialCommands,我们看到它来自全局作用域 (Global)。将此与 inspect console 的相关输出结合起来

Compile / console / initialCommands

我们知道,我们可以像全局作用域一样普遍地设置 initialCommands,像当前项目的 console 任务作用域一样具体地设置,或者介于两者之间。这意味着我们可以,例如,为整个项目设置 initialCommands,并且会影响 console

> set initialCommands := "import mypackage._"
...

我们可能希望在这里设置它的原因是,其他控制台任务现在将使用此值。我们可以通过查看 inspect actual 的反向依赖项输出,看看哪些任务使用了我们的新设置

> inspect actual initialCommands
...
[info] Reverse dependencies:
[info]  Compile / console
[info]  Test / console
[info]  consoleProject
[info]  Test / consoleQuick
[info]  Compile / consoleQuick
...

我们现在知道,通过在整个项目上设置 initialCommands,我们影响了该项目中所有配置中的所有控制台任务。如果我们不希望初始命令适用于 consoleProject(该项目没有我们项目的类路径可用),我们可以使用更具体的任务轴

> set console / initialCommands := "import mypackage._"
> set consoleQuick / initialCommands := "import mypackage._"`

或配置轴

> set Compile/ initialCommands := "import mypackage._"
> set Test / initialCommands := "import mypackage._"

下一部分描述了委托部分,它显示了范围的委托链。

委托 

一个设置有一个键和一个范围。如果 A 没有为键定义值,则对范围 A 中键的请求可能会被委托给另一个范围。委托链是明确定义的,并在inspect命令的委托部分显示。委托部分显示了当未为请求的键定义值时搜索范围的顺序。

例如,再次考虑console的初始命令

> inspect console/initialCommands
...
[info] Delegates:
[info]  console / initialCommands
[info]  initialCommands
[info]  ThisBuild / console / initialCommands
[info]  ThisBuild / initialCommands
[info]  Zero / console / initialCommands
[info]  Global / initialCommands
...

这意味着如果console/initialCommands没有具体的值,那么将在委托下列出的范围中按顺序搜索,直到找到定义的值。