既存のプラグインの使用方法に焦点を当てた入門ページがあるので、最初にそちらを読むとよいかもしれません。
プラグインは、ビルド定義で外部コードを使用する方法です。プラグインは、タスクを実装するために使用されるライブラリにすることができます (markdown 処理タスクを作成するために Knockoff を使用できます)。プラグインは、すべてのプロジェクトに自動的に追加されるか、選択したプロジェクトに明示的に宣言される sbt 設定のシーケンスを定義できます。たとえば、プラグインは proguard
タスクと関連する (オーバーライド可能な) 設定を追加するかもしれません。最後に、プラグインは新しいコマンドを定義できます (commands
設定を介して)。
sbt 0.13.5 では、プラグイン間の依存関係管理の改善と明示的にスコープされた自動インポートを備えた自動プラグインが導入されました。今後、自動プラグインに移行することをお勧めします。プラグインのベストプラクティスページでは、現在進化している sbt プラグインの作成ガイドラインについて説明しています。一般的なベストプラクティスも参照してください。
一般的な状況は、リポジトリに公開されているバイナリプラグインを使用する場合です。必要なすべての sbt プラグイン、一般的な依存関係、および必要なリポジトリを含む project/plugins.sbt
を作成できます。
addSbtPlugin("org.example" % "plugin" % "1.0")
addSbtPlugin("org.example" % "another-plugin" % "2.0")
// plain library (not an sbt plugin) for use in the build definition
libraryDependencies += "org.example" % "utilities" % "1.3"
resolvers += "Example Plugin Repository" at "https://example.org/repo/"
多くの自動プラグインはプロジェクトに設定を自動的に追加しますが、明示的な有効化が必要なものもあります。次に例を示します。
lazy val util = (project in file("util"))
.enablePlugins(FooPlugin, BarPlugin)
.disablePlugins(plugins.IvyPlugin)
.settings(
name := "hello-util"
)
プラグインの使用の詳細については、入門ガイドのプラグインの使用を参照してください。
プラグイン定義は、project/
フォルダーにあるプロジェクトです。このプロジェクトのクラスパスは、project/
内のビルド定義とプロジェクトのベースディレクトリにある .sbt
ファイルに使用されるクラスパスです。また、eval
および set
コマンドにも使用されます。
具体的には、
project/
プロジェクトで宣言された管理された依存関係は取得され、通常のプロジェクトと同様にビルド定義クラスパスで使用できます。project/lib/
内の管理されていない依存関係は、通常のプロジェクトと同様にビルド定義で使用できます。project/
プロジェクトのソースはビルド定義ファイルであり、管理対象および管理対象外の依存関係から構築されたクラスパスを使用してコンパイルされます。project/plugins.sbt
(通常のプロジェクトの build.sbt
ファイルと同様) で宣言でき、ビルド定義で使用できます。ビルド定義クラスパスは、sbt/sbt.autoplugins
記述子ファイルで検索され、sbt.AutoPlugin
実装の名前が含まれています.
reload plugins
コマンドは、現在のビルドを (ルート) プロジェクトの project/
ビルド定義に変更します。これにより、ビルド定義プロジェクトを通常のプロジェクトのように操作できます。 reload return
は元のビルドに戻ります。プラグイン定義プロジェクトの保存されていないセッション設定はすべて破棄されます。
自動プラグインは、プロジェクトに自動的に挿入する設定を定義するモジュールです。さらに、自動プラグインは次の機能を提供します。
.sbt
ファイルと eval
および set
コマンドに選択的な名前を自動的にインポートします。projectSettings
、buildSettings
、および globalSettings
を指定します。従来のプラグインが既存のプラグインからいくつかの機能を再利用したい場合、ライブラリの依存関係としてプラグインを取り込み、次のいずれかを実行します。
これは、アプリケーション内のプラグインの数が増えるにつれて複雑になり、エラーが発生しやすくなります。自動プラグインの主な目標は、この設定の依存関係の問題を軽減することです。自動プラグインは他の自動プラグインに依存でき、これらの依存関係設定が最初にロードされるようにします。
SbtLessPlugin
と SbtCoffeeScriptPlugin
があり、それが SbtJsTaskPlugin
、SbtWebPlugin
、および JvmPlugin
に依存しているとします。これらのプラグインすべてを手動でアクティブ化する代わりに、プロジェクトは次のように SbtLessPlugin
と SbtCoffeeScriptPlugin
をアクティブ化できます。
lazy val root = (project in file("."))
.enablePlugins(SbtLessPlugin, SbtCoffeeScriptPlugin)
これにより、プラグインから正しい順序で正しい設定シーケンスが取り込まれます。ここでの重要な概念は、必要なプラグインを宣言することで、sbt がギャップを埋めることができるということです。
ただし、プラグインの実装で自動プラグインを生成する必要はありません。これはプラグインコンシューマーにとって便利ですが、自動的な性質のため、常に適切とは限りません。
$HOME/.sbt/1.0/plugins/
ディレクトリは、グローバルプラグイン定義プロジェクトとして扱われます。これは通常の sbt プロジェクトであり、そのクラスパスは、プロジェクトごとのプラグインについて上記で説明したように、そのユーザーのすべての sbt プロジェクト定義で使用できます。
最小限の sbt プラグインは、sbt が実行される Scala のバージョン (現在、2.12.18) に対してビルドされた Scala ライブラリ、または Java ライブラリです。このタイプのライブラリのために特別なことは何もする必要はありません。より一般的なプラグインは、sbt タスク、コマンド、または設定を提供します。この種のプラグインは、これらの設定を自動的に提供するか、ユーザーが明示的に統合できるようにします.
自動プラグインを作成するには、プロジェクトを作成し、SbtPlugin
を有効にします。
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.example"
ThisBuild / homepage := Some(url("https://github.com/sbt/sbt-hello"))
lazy val root = (project in file("."))
.enablePlugins(SbtPlugin)
.settings(
name := "sbt-hello",
pluginCrossBuild / sbtVersion := {
scalaBinaryVersion.value match {
case "2.12" => "1.2.8" // set minimum sbt version
}
}
)
注意すべき点がいくつかあります
scalaVersion
を指定しない場合、sbt はプラグインに適した Scala バージョンをデフォルトで使用します.pluginCrossBuild / sbtVersion
は、プラグインを*古い*バージョンの sbt に対してコンパイルするためのオプションの設定であり、プラグインユーザーは sbt バージョンの範囲から選択できます。次に、プラグインコードを作成し、プロジェクトをリポジトリに公開します。プラグインは、前のセクションで説明したように使用できます。
まず、適切な名前空間で、sbt.AutoPlugin
を拡張して自動プラグインオブジェクトを定義します。
自動プラグインを使用すると、提供されるすべての設定 (例: assemblySettings
) は、projectSettings
メソッドを介してプラグインによって直接提供されます。 sbt プロジェクトに hello という名前のタスクを追加するプラグインの例を次に示します。
package sbthello
import sbt._
import Keys._
object HelloPlugin extends AutoPlugin {
override def trigger = allRequirements
object autoImport {
val helloGreeting = settingKey[String]("greeting")
val hello = taskKey[Unit]("say hello")
}
import autoImport._
override lazy val globalSettings: Seq[Setting[_]] = Seq(
helloGreeting := "hi",
)
override lazy val projectSettings: Seq[Setting[_]] = Seq(
hello := {
val s = streams.value
val g = helloGreeting.value
s.log.info(g)
}
)
}
プラグインがビルドレベル (つまり、ThisBuild
内) で設定を追加する必要がある場合、buildSettings
メソッドがあります。ここで返される設定は、この AutoPlugin をアクティブにするビルドのプロジェクト数に関係なく、特定のビルドスコープに一度だけ追加されることが保証されています。
override def buildSettings: Seq[Setting[_]] = Nil
globalSettings
は、グローバル設定 (in Global
) に一度だけ追加されます。これらにより、プラグインは新しい機能または新しいデフォルトを自動的に提供できます。この機能の主な用途の 1 つは、IDE プラグインなどのコマンドをグローバルに追加することです。
override def globalSettings: Seq[Setting[_]] = Nil
設定のデフォルト値を定義するには、globalSettings
を使用します。
次のステップは、プラグインの依存関係を定義することです。
package sbtless
import sbt._
import Keys._
object SbtLessPlugin extends AutoPlugin {
override def requires = SbtJsTaskPlugin
override lazy val projectSettings = ...
}
requires
メソッドは、依存関係リストを構築するための DSL である Plugins
型の値を返します。 requires メソッドには、通常、次の値のいずれかが含まれます。
empty
(プラグインなし)&&
演算子 (複数の依存関係を定義するため)一部のプラグインは、常にプロジェクトで明示的に有効にする必要があります。 これらをルートプラグイン、つまりプラグイン依存関係グラフの「ルート」ノードであるプラグインと呼びます。 自動プラグインは、デフォルトではルートプラグインです。
自動プラグインは、依存関係が満たされている場合にプラグインがプロジェクトに自動的にアタッチされる方法も提供します。これらをトリガープラグインと呼び、`trigger` メソッドをオーバーライドすることで作成されます。
たとえば、ビルドにコマンドを自動的に追加できるトリガープラグインを作成したい場合があります。これを行うには、`requires` メソッドが `empty` を返すように設定し、`trigger` メソッドを `allRequirements` でオーバーライドします。
package sbthello
import sbt._
import Keys._
object HelloPlugin2 extends AutoPlugin {
override def trigger = allRequirements
override lazy val buildSettings = Seq(commands += helloCommand)
lazy val helloCommand =
Command.command("hello") { (state: State) =>
println("Hi!")
state
}
}
ビルドユーザーはこのプラグインを `project/plugins.sbt` に含める必要がありますが、`build.sbt` に含める必要はもうありません。これは、要件を持つプラグインを指定する場合に、より興味深いものになります。別のプラグインに依存するように `SbtLessPlugin` を変更してみましょう。
package sbtless
import sbt._
import Keys._
object SbtLessPlugin extends AutoPlugin {
override def trigger = allRequirements
override def requires = SbtJsTaskPlugin
override lazy val projectSettings = ...
}
実際には、`PlayScala` プラグイン(ご存知ない方のために説明すると、Play フレームワークは sbt プラグインです)は、必要なプラグインの1つとして `SbtJsTaskPlugin` をリストしています。そのため、`build.sbt` を次のように定義すると
lazy val root = (project in file("."))
.enablePlugins(PlayScala)
`SbtLessPlugin` の設定シーケンスは、`PlayScala` の設定の後のどこかに自動的に追加されます。
これにより、プラグインは既存のプラグインをより多くの機能でサイレントかつ正しく拡張できます。また、ユーザーからの順序付けの負担を軽減し、プラグインの作成者がユーザーに機能を提供する際の自由度とパワーを高めることができます。
自動プラグインが `autoImport` という名前の `val` または `object` などの安定したフィールドを提供する場合、フィールドの内容は `set`、`eval`、および `.sbt` ファイルでワイルドカードインポートされます。次の例では、hello コマンドを `greeting` の値を簡単に取得するタスクに置き換えます。実際には、コマンドよりも設定またはタスクを優先することをお勧めします。
package sbthello
import sbt._
import Keys._
object HelloPlugin3 extends AutoPlugin {
object autoImport {
val greeting = settingKey[String]("greeting")
val hello = taskKey[Unit]("say hello")
}
import autoImport._
override def trigger = allRequirements
override lazy val buildSettings = Seq(
greeting := "Hi!",
hello := helloTask.value)
lazy val helloTask =
Def.task {
println(greeting.value)
}
}
通常、`autoImport` は、インポートや修飾を必要とせずに、新しいキー(`SettingKey`、`TaskKey`、または `InputKey`)またはコアメソッドを提供するために使用されます。
典型的なプラグインの例
build.sbt
:
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.example"
ThisBuild / homepage := Some(url("https://github.com/sbt/sbt-obfuscate"))
lazy val root = (project in file("."))
.enablePlugins(SbtPlugin)
.settings(
name := "sbt-obfuscate",
pluginCrossBuild / sbtVersion := {
scalaBinaryVersion.value match {
case "2.12" => "1.2.8" // set minimum sbt version
}
}
)
ObfuscatePlugin.scala
:
package sbtobfuscate
import sbt._
import sbt.Keys._
object ObfuscatePlugin extends AutoPlugin {
// by defining autoImport, the settings are automatically imported into user's `*.sbt`
object autoImport {
// configuration points, like the built-in `version`, `libraryDependencies`, or `compile`
val obfuscate = taskKey[Seq[File]]("Obfuscates files.")
val obfuscateLiterals = settingKey[Boolean]("Obfuscate literals.")
// default values for the tasks and settings
lazy val baseObfuscateSettings: Seq[Def.Setting[_]] = Seq(
obfuscate := {
Obfuscate(sources.value, (obfuscate / obfuscateLiterals).value)
},
obfuscate / obfuscateLiterals := false
)
}
import autoImport._
override def requires = sbt.plugins.JvmPlugin
// This plugin is automatically enabled for projects which are JvmPlugin.
override def trigger = allRequirements
// a group of settings that are automatically added to projects.
override val projectSettings =
inConfig(Compile)(baseObfuscateSettings) ++
inConfig(Test)(baseObfuscateSettings)
}
object Obfuscate {
def apply(sources: Seq[File], obfuscateLiterals: Boolean): Seq[File] = {
// TODO obfuscate stuff!
sources
}
}
プラグインを使用するビルド定義は次のようになります。 `obfuscate.sbt`
obfuscate / obfuscateLiterals := true
最も単純なグローバルプラグイン定義は、`$HOME/.sbt/1.0/plugins/build.sbt` でライブラリまたはプラグインを宣言することです。
libraryDependencies += "org.example" %% "example-plugin" % "0.1"
このプラグインは、現在のユーザーのすべての sbt プロジェクトで使用できます。
さらに
sbt はプラグインを再構築し、プロジェクトに使用します。
さらに、プラグインは、再コンパイルすることなく、マシン上の他のプロジェクトで使用できます。このアプローチでは、`publishLocal` のオーバーヘッドと、プラグインを使用するプロジェクトの plugins ディレクトリの `clean` をスキップします。
これらはすべて、`$HOME/.sbt/1.0/plugins/` が標準プロジェクトであり、そのクラスパスがすべての sbt プロジェクトのビルド定義に追加されることの結果です。
例として、Grizzled Scala ライブラリをプラグインとして追加します。これは sbt 固有の機能を提供するものではありませんが、プラグインを宣言する方法を示しています。
`project/plugins.sbt` を編集して、以下を含めます
libraryDependencies += "org.clapper" %% "grizzled-scala" % "1.0.4"
sbt が実行されている場合は、`reload` を実行します。
`reload plugins` を使用して、`project/` の plugins プロジェクトに変更できます。
$ sbt
> reload plugins
[info] Set current project to default (in build file:/Users/sbt/demo2/project/)
>
次に、通常どおり依存関係を追加し、`project/plugins.sbt` に保存できます。依存関係が正しいことを確認するために `update` を実行すると便利ですが、必須ではありません。
> set libraryDependencies += "org.clapper" %% "grizzled-scala" % "1.0.4"
...
> update
...
> session save
...
メインプロジェクトに戻るには、`reload return` を使用します
> reload return
[info] Set current project to root (in build file:/Users/sbt/demo2/)
このバリアントは、sbt の外部プロジェクトサポートを使用して、プラグインのソース依存関係を宣言する方法を示しています。これは、プラグインがソースからビルドされ、クラスパスで使用されることを意味します。
`project/plugins.sbt` を編集する
lazy val root = (project in file(".")).dependsOn(assemblyPlugin)
lazy val assemblyPlugin = RootProject(uri("git://github.com/sbt/sbt-assembly"))
sbt が実行されている場合は、`reload` を実行します。
このアプローチは、プラグインを開発するときに役立つことに注意してください。プラグインを使用するプロジェクトは、`reload` でプラグインを再構築します。これにより、`publishLocal` と `update` の中間ステップが節約されます。また、リポジトリからプラグインの開発バージョンを操作するためにも使用できます。
ただし、コミットまたはタグをフラグメントとしてリポジトリに追加することで、明示的に指定することをお勧めします。
lazy val assemblyPlugin = uri("git://github.com/sbt/sbt-assembly#0.9.1")
この方法を使用する際の注意点の1つは、ローカルの sbt がリモートプラグインのビルドを実行しようとすることです。多くのプラグインが複数の sbt バージョンに対してクロス公開されているため、プラグイン独自のビルドで異なる sbt バージョンが使用されている可能性があります。そのため、可能な場合はバイナリ成果物を使用することをお勧めします。
Grizzled Scala は、ビルド定義で使用できるようになりました。これには、`eval` および `set` コマンドと、`.sbt` および `project/*.scala` ファイルが含まれます。
> eval grizzled.sys.os
`build.sbt` ファイル内
import grizzled.sys._
import OperatingSystem._
libraryDependencies ++=
if(os == Windows)
Seq("org.example" % "windows-only" % "1.0")
else
Seq.empty
プラグインは、他のプロジェクトと同様に公開できます。プラグインを Maven レイアウトのリポジトリに公開する場合は、sbt 1.9.x 以降を使用してください。
ただし、Maven レイアウトに従うリポジトリにプラグインを公開しようとすると、1つの注意点があります。
アーティファクトリポジトリがアーティファクトが Maven レイアウトに準拠していることを期待し、準拠していないアーティファクトを拒否する場合、次のことができます。1.(推奨)あなたとプラグインのコンシューマーが sbt 1.9.x 以降を使用している場合
sbt 1.9 以降では、新しい Maven スタイルと従来の Maven スタイルの両方でプラグインを公開しようとします(下位互換性のため)。従来の Maven スタイルは、Maven レイアウトと完全には互換性がありません。`sbtPluginPublishLegacyMavenStyle := false` で無効にする必要があります。このプラグインは、従来の Maven スタイルのみを解決できるため、1.9 より古い sbt では使用できません(または、sbt-vspp で説明されているトリックを使用する必要があります)。3. sbt < 1.9.x を使用している場合
https://github.com/esbeetee/sbt-vspp/ を使用できます。5. sbt 1.9.x を使用できず、sbt-vspp を使用できない/したくない場合
アーティファクトリ設定に `POM 整合性チェックの抑制` のようなオプションがあり、Maven レイアウトに完全に準拠していなくてもアーティファクトを送信できるはずです。
これについての詳細は、次の issue を参照してください。
プラグインの作成者の場合は、プラグインのベストプラクティス ページを参照してください。プラグインの一貫性を確保し、他のプラグインとうまく連携するためのガイドラインが含まれています。
sbt プラグインのクロスビルドについては、プラグインのクロスビルド も参照してください。