關於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會被自動發現。
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