Locked History Actions

Diff for "sbt/Getting-Started-Scopes"

Differences between revisions 5 and 6
Deletions are marked like this. Additions are marked like this.
Line 113: Line 113:
    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.
    full-classpath(for doc): 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:full-classpath(for doc) sets all three scope axes.
 * 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.
 * full-classpath(for doc): 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:full-classpath(for doc) sets all three scope axes.

スコープ

https://github.com/harrah/xsbt/wiki/Getting-Started-Scopesの訳(2011/10/27時点)

ここではスコープを説明する。前のページ「.sbtビルド定義」を読んで理解していることを前提にするよ。

キーについてのすべて

nameのようなキーはsbtのキー・値マップの一つのエントリになるといった説明を以前にしたが、これは話を単純化したものだ。 実を言えば、それぞれのキーは複数のコンテキスト、これをスコープというのだが、に関連した値を持つことができるんだ。

例を示そう。

  • ビルド定義の中に複数のプロジェクトがあるなら、キーはそれぞれのプロジェクトについて別の値を持ちうる。
  • compileキーはメインソースについてと、テスト用ソースについては別の値を持ちうる。もし違ったやり方でコンパイルしたいのであれば。
  • package-optionsキー(jarパッケージ生成時のオプションを含んでいる)はクラスファイルのパッケージング(package-bin)時とソースコードのパッケージング(package-src)時では異なる値を持つ。

キー名称に対する唯一の値は無く、スコープによって異なるんだ。

しかし、スコープ付のキーには唯一の値がある。

以前に説明したように、sbtがプロジェクトを表現するキー・値マップを作成するためにsettingのリストを処理するのだとしたら、そのキー・値マップの中のキーはスコープ付のキーだ。 ビルド定義(例えばbuild.sbt)中のそれぞれのsettingもまたスコープ付キーに適用される。

スコープはデフォルトのあることが多いのだが、しかしそれが間違っているなら、build.sbt中で望むスコープを指定しなければならない。

スコープ軸

スコープ軸とはタイプであり、そのタイプの各インスタンスはそれ自身のスコープを定義する。(つまり、各インスタンスはキーに対するそれ自身のユニークな値を持つ)。

スコープ軸としては三つある。

  • プロジェクト
  • コンフィギュレーション
  • タスク

プロジェクト軸によるスコープ

もし一つのビルド中に複数のプロジェクトを格納するなら、各プロジェクトはそれ自身のsettingを持たなければならない。 つまり、キーはプロジェクトによってスコープされるわけだ。

プロジェクト軸は、「全体ビルド」に設定されることもある。このとき、settingは個々のプロジェクトではなく、全体ビルドに適用される。 ビルドレベルsettingは、しばしばプロジェクト特有のsettingの無いときのフォールバックとして使用される。

コンフィギュレーション軸によるスコープ

コンフィギュレーションはビルドの「フレーバー」を定義する。 多くは、それ自身のクラスパス、ソース、生成パッケージ等を持つ。 コンフィギュレーションという概念はIvyから借りてきている which sbt uses for managed dependencies, and from MavenScopes.

sbtにあるコンフィギュレーションの一部としては以下だ。

  • Compileはメインビルドを定義する(src/main/scala).
  • Testはテストノビルド方法を定義する(src/test/scala).
  • Runtimeはrun taskのためのクラスパスを定義する

コンパイル、パッケージング、実行に関連するキーは、デフォルトではコンフィギュレーションにスコープ付されており、それぞれのコンフィギュレーションで異なる働きをする。 最も明らかな例としては、compile,package,runというタスクキーだが、これらに影響を与えるキー(source-directories、scalac-options、full-classpathなど) もまたコンフィギュレーションにスコープ付されている。

タスク軸によるスコープ

settingはタスクの働きに影響を与えることがある。例えば、packag-optionsというsettingはpackage-srcタスクに影響を与える。

これを実現するため、タスクキー(package-srcのような)は別のキー(package-optionのような)のスコープになるようにしてある。

パッケージビルドのためのタスク(package-src, package-bin, package-doc)は関連するパッケージングに関するキー、つまりartifact-namやpackag-optionsを共有できるが、これらのキーは各パッケージタスクで異なる値を持つこともできる。

グローバルスコープ

各スコープ軸は、その軸タイプのインスタンスを代入しうるが(例えば、タスク軸はタスクを代入しうる)、軸には特別な値Globalを代入することもできる。

Globalはその名の通りの働きだ。settingの値は、その軸のすべてのインスタンスについて適用される。例えば、タスク軸がGlobalの場合、settingは全タスクに適用される。

移譲

スコープ付きキーは未定義の場合がある、そのスコープに対応する値を持たなければ。

For each scope, sbt has a fallback search path made up of other scopes. Typically, if a key has no associated value in a more-specific scope, sbt will try to get a value from a more general scope, such as the Global scope or the entire-build scope.

This feature allows you to set a value once in a more general scope, allowing multiple more-specific scopes to inherit the value.

You can see the fallback search path or "delegates" for a key using the inspect command, as described below. Read on. Referring to scoped keys when running sbt

On the command line and in interactive mode, sbt displays (and parses) scoped keys like this:

{<build-uri>}<project-id>/config:key(for task-key)
  • {<build-uri>}<project-id> identifies the project axis. The <project-id> part will be missing if the project axis has "entire build" scope. config identifies the configuration axis. (for task-key) identifies the task axis. key identifies the key being scoped.

* can appear for each axis, referring to the Global scope.

If you omit part of the scoped key, it will be inferred as follows:

  • the current project will be used if you omit the project. a key-dependent configuration will be auto-detected if you omit the configuration. the Global task scope will be used if you omit the task.

For more details, see Inspecting Settings.

スコープ付キーの記述例

スコープの調査

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 Inspecting Settings. Referring to scopes in a build definition

If you create a setting in build.sbt with a bare key, it will be scoped to the current project, configuration Global and task Global:

name := "hello"

Run sbt and inspect name to see that it's provided by {file:/home/hp/checkout/hello/}default-aea33a/*:name, that is, the project is {file:/home/hp/checkout/hello/}default-aea33a, the configuration is * (meaning global), and the task is not shown (which also means global).

build.sbt always defines settings for a single project, so the "current project" is the project you're defining in that particular build.sbt. (For multi-project builds, each project has its own build.sbt.)

Keys have an overloaded method called in used to set the scope. The argument to in can be an instance of any of the scope axes. So for example, though there's no real reason to do this, you could set the name scoped to the Compile configuration:

name in Compile := "hello"

or you could set the name scoped to the package-bin task (pointless! just an example):

name in packageBin := "hello"

or you could set the name with multiple scope axes, for example in the packageBin task in the Compile configuration:

name in (Compile, packageBin) := "hello"

or you could use Global for all 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)

If you aren't used to Scala, a reminder: it's important to understand that in and := are just methods, not magic. Scala lets you write them in a nicer way, but you could also use the Java style:

name.in(Compile).:=("hello")

There's no reason to use this ugly syntax, but it illustrates that these are in fact methods.

When to specify a scope

You need to specify the scope if the key in question is normally scoped. For example, the compile task, by default, is scoped to Compile and Test configurations, and does not exist outside of those scopes.

To change the value associated with the compile key, you need to write compile in Compile or compile in Test. Using plain compile would define a new compile task scoped to the current project, rather than overriding the standard compile tasks which are scoped to a configuration.

If you get an error like "Reference to undefined setting", often you've failed to specify a scope, or you've specified the wrong scope. The key you're using may be defined in some other scope. sbt will try to suggest what you meant as part of the error message; look for "Did you mean compile:compile?"

One way to think of it is that a name is only part of a key. In reality, all keys consist of both a name, and a scope (where the scope has three axes). The entire expression packageOptions in (Compile, packageBin) is a key name, in other words. Simply packageOptions is also a key name, but a different one (for keys with no in, a scope is implicitly assumed: current project, global config, global task).