sbt笔记五 做用域

关于keys的完整故事

以前咱们假设,一个key(就像name)至关于sbt的键值对映射的一个条目。实际上是简化的。
事实上,每个key在多个上下文中分别有一个关联的值,称做“scope”(做用域)。
这是具体的例子:
  • 若是构建定义中包含多个项目,key在每一个项目中能够有不一样的值。
  • 针对main源码和测试源码,若是想用不一样的方式编译他们,compile键能够有不一样的值。
  • 打包class文件(package-bin)或打包源码(package-src),package-options键(包含建立jar包的选项)能够有不一样的值。
对于给定的键名不会有惟一的值,由于值会根据做用域而改变。
然而,对于给定的scoped键,值是惟一的。
若是考虑sbt处理setting列表来生成键值映射来描述这个项目,如先前所述,这些在键值映射中的键就是scoped键。在构建定义(如在build.sbt中)中定义的setting也适用于scoped键。
一般做用域是隐含的或有一个默认值,但若是默认值有误,你须要在build.sbt中说明但愿的做用域。

Scope axes

scope axis是一种类型,这种类型的每个实例均可以定义自身的做用域(就是说,对于keys,每一个实例都拥有本身的惟一值)
有三个scope axes:
  • Projects
  • Configurations
  • Tasks

project axis范围界定

若是把多个项目放到一个build中,每一个项目要有本身的settings。也就是说,keys能够根据项目划分做用域。
project axis也能够设为"entire build",这样setting应用于entire build而非单一项目。当一个项目没有定义特定项目setting,构建级别settings一般用做后备。

configuration axis范围界定

一个configuration定义了一个构建的味道,可能用它自身的classpath,sources,生成的包,或其余。configuration概念来自于ivy,sbt用来管理依赖(从MavenScopes)。
sbt中能够看到的一些configuration:
  • Compile 定义了main构建(src/main/scala)
  • Test 定义了如何构建测试(src/test/scala)
  • Runtime 定义了run任务的classpath
默认状况下,全部与编译,打包,和运行相关联的key,都是局限于configuration的,所以在每一个configuration中能够作不一样的工做。最明显的例子是任务键compile,package和run;但全部对这些key产生影响的其余key(好比source-directories,scalac-options或full-classpath)也局限于configuration。

task axis范围界定

setting能够影响一个任务的执行。例如package-src任务受package-options设置的影响。
为了支持这个,一个任务key(好比package-src)能够做为另外一个key(好比package-options)的做用域。
各类各样的打包任务(package-src, package-bin, package-doc)能够共享与打包相关的key,好比artifact-name和package-options。这些key对于每一个打包任务能够有不一样的值。

全局范围

每一个scope axis能够被axis类型的实例填充(例如task axis能够被任务填充),或被特殊值Global填充。
Global意味着你所指望的:setting的值应用于全部axis的实例。例如若是task axis是Global,那么这个setting将应用于全部任务。

委托

若是在它的做用域内没有与之关联的值,那么一个限定了做用域的key多是未定义的。
对于每一个做用域,sbt有一个由其余做用域构成的回调搜索路径。典型的,若是一个key在更具体的做用域内没有关联的值,sbt将尝试从更通常的做用域内得到值,好比Global做用域,或完整构建做用域。
这个特性容许你为更通常的做用域设置一个值,容许许多更具体的做用域继承这个值。
你能够用inspect命令来查看一个key的回调搜索路径(fallback search path)或“delegates”,以下所述。

Referring to scoped keys when running sbt

在命令行和交互模式下,sbt这样展现(并解析)范围限定key:
{<build-uri>}<project-id>/config:intask::key
  • {<build-uri>}<project-id> 标识project axis。若是project axis有“完整构建(entire build)”做用域,<project-id>部分将丢失。
  • config 标识configuration axis。
  • intask 标识task axis。
  • key 标识key存在做用域(identifies the key being scoped)。
* 能够为每个axis显示,参考Global做用域。
若是省略部分范围限定key,它将按以下方式推断:
  • 若是省略项目,将使用当前项目
  • 若是省略configuration或task,一个依赖键configuration会被自动发现。
更多细节,请查看 Interacting with the Configuration System

Examples of scoped key notation

  • full-classpath: just a key, so the default scopes are used: current project, a key-dependent configuration, and global task scope.
  • test:full-classpath: specifies the configuration, so this is full-classpath in the test configuration, with defaults for the other two scope axes.
  • *:full-classpath: specifies Global for the configuration, rather than the default configuration.
  • doc::full-classpath: specifies the full-classpath key scoped to the doc task, with the defaults for the project and configuration axes.
  • {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath specifies a project, {file:/home/hp/checkout/hello/}default-aea33a, where the project is identified with the build {file:/home/hp/checkout/hello/} and then a project id inside that build default-aea33a. Also specifies configuration test, but leaves the default task axis.
  • {file:/home/hp/checkout/hello/}/test:full-classpath sets the project axis to "entire build" where the build is {file:/home/hp/checkout/hello/}
  • {.}/test:full-classpath sets the project axis to "entire build" where the build is {.}. {.} can be written ThisBuild in Scala code.
  • {file:/home/hp/checkout/hello/}/compile:doc::full-classpath sets all three scope axes.

Inspecting scopes

In sbt's interactive mode, you can use the inspect command to understand keys and their scopes. Try inspect test:full-classpath:
$ sbt
> inspect test:full-classpath
[info] Task: scala.collection.Seq[sbt.Attributed[java.io.File]]
[info] Description:
[info]  The exported classpath, consisting of build products and unmanaged and managed, internal and external dependencies.
[info] Provided by:
[info]  {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath
[info] Dependencies:
[info]  test:exported-products
[info]  test:dependency-classpath
[info] Reverse dependencies:
[info]  test:run-main
[info]  test:run
[info]  test:test-loader
[info]  test:console
[info] Delegates:
[info]  test:full-classpath
[info]  runtime:full-classpath
[info]  compile:full-classpath
[info]  *:full-classpath
[info]  {.}/test:full-classpath
[info]  {.}/runtime:full-classpath
[info]  {.}/compile:full-classpath
[info]  {.}/*:full-classpath
[info]  */test:full-classpath
[info]  */runtime:full-classpath
[info]  */compile:full-classpath
[info]  */*:full-classpath
[info] Related:
[info]  compile:full-classpath
[info]  compile:full-classpath(for doc)
[info]  test:full-classpath(for doc)
[info]  runtime:full-classpath

On the first line, you can see this is a task (as opposed to a setting, as explained in .sbt build definition). The value resulting from the task will have type scala.collection.Seq[sbt.Attributed[java.io.File]].

"Provided by" points you to the scoped key that defines the value, in this case {file:/home/hp/checkout/hello/}default-aea33a/test:full-classpath (which is the full-classpath key scoped to the test configuration and the {file:/home/hp/checkout/hello/}default-aea33a project).

"Dependencies" may not make sense yet; stay tuned for the next page.

You can also see the delegates; if the value were not defined, sbt would search through:
  • two other configurations (runtime:full-classpath, compile:full-classpath). In these scoped keys, the project is unspecified meaning "current project" and the task is unspecified meaning Global
  • configuration set to Global (*:full-classpath), since project is still unspecified it's "current project" and task is still unspecified so Global
  • project set to {.} or ThisBuild (meaning the entire build, no specific project)
  • project axis set to Global (*/test:full-classpath) (remember, an unspecified project means current, so searching Global here is new; i.e. * and "no project shown" are different for the project axis; i.e. */test:full-classpath is not the same as test:full-classpath)
  • both project and configuration set to Global (*/*:full-classpath) (remember that unspecified task means Global already, so */*:full-classpath uses Global for all three axes)
Try inspect full-classpath (as opposed to the above example, inspect test:full-classpath) to get a sense of the difference. Because the configuration is omitted, it is autodetected as compile. inspect compile:full-classpath should therefore look the same as inspect full-classpath.

Try inspect *:full-classpath for another contrast. full-classpath is not defined in the Global configuration by default.

Again, for more details, see Interacting with the Configuration System.

Referring to scopes in a build definition

若是你在build.sbt中用一个空键(a bare key)建立一个setting,他将适用于当前项目,Global配置(configuration Global)和Global任务(task Global):
build.sbt经常为单一项目定义setting,因此“当前项目”就是特定build.sbt中定义的那个项目。(对于多项目构建,每一个项目有本身的build.sbt。)
key有一个重载的方法in用于设置做用域。in的参数能够是任何一个scope axes的实例。例如,虽然你没有真正理由这么作,你能够设置Compile配置范围限定的name:
name in Compile := "hello"
或者你能够设置package-bin任务范围限定的name(没有意义,只是一个例子)
name in packageBin := "hello"
或者你可使用多个scope axes设置name,例如在packageBin任务和Compile配置中。
name in (Compile, packageBin) := "hello"
或者你能够用Global(对全部axes):
name in Global := "hello"
(name in Global implicitly converts the scope axis Global to a scope with all axes set to Global; the task and configuration are already Global by default, so here the effect is to make the project Global, that is, define */*:name rather than {file:/home/hp/checkout/hello/}default-aea33a/*:name)

若是你不用Scala,一个提醒:理解in和:=仅仅是个方法是很重要的,这不是魔法。Scala容许你用更好的方式来写它们,可是你也能够用Java风格:
name.in(Compile).:=("hello")
没有理由用这种丑陋的语法,但它说明了它们实际上就是方法。

何时须要指定做用域

若是正在讨论的key一般被范围限定,那么你须要指定一个范围。例如,compile任务默认状况下限定于Compile和Test配置,而且不存在于这些做用域以外。
要改变compile键关联的值,你须要写compile in Compile或compile in Test。用普通的compile将定义一个新的compile任务,并范围限定于当前项目,而不是覆盖标准compile任务(范围限定于一个configuration的)。
若是你获得一个像“ Reference to undefined setting”这样的错误,一般是你指定做用域失败,或指定一个错误的做用域。你正在使用的key可能定义在其余做用域,sbt将尝试给出建议,做为错误消息的一部分(sbt will try to suggest what you meant as part of the error message);寻找“Did you mean compile:compile?”

一种记住它的方式是,name仅仅是一个键的一部分。实际上,全部的key既包含name,也有做用域(做用域有3个axes)。换句话说,完整的表达式packageOptions in (Compile, packageBin)是一个键名。简单的packageOptions也是一个键名,但却不是同一个(对于没有in的key,做用域隐式假定为:当前项目,全局配置,全局任务)。 html


2013-1-28
这篇怎么全是字啊,没几句代码,没咋看懂都,凑合这样吧。等啥时候我把这块理解了,再回头好好看看这些翻译。中间一大段懒得翻译,由于不知道它在说啥... java

相关文章
相关标签/搜索