有一個入門頁面著重於使用現有的外掛,您可能需要先閱讀。
外掛是在建置定義中使用外部程式碼的方式。外掛可以是實作任務的函式庫 (您可能會使用 Knockoff 來撰寫 markdown 處理任務)。外掛可以定義一連串 sbt 設定,這些設定會自動新增到所有專案,或針對選定的專案明確宣告。例如,外掛可能會新增 proguard
任務和相關聯的 (可覆寫的) 設定。最後,外掛可以定義新的命令 (透過 commands
設定)。
sbt 0.13.5 引入了自動外掛,並改善了外掛之間的依賴管理和明確範圍的自動匯入。未來,我們的建議是遷移到自動外掛。外掛最佳實踐頁面描述了目前正在發展的撰寫 sbt 外掛指南。另請參閱一般最佳實踐。
常見的情況是使用發佈到儲存庫的二進位外掛。您可以建立 project/plugins.sbt
,其中包含所有想要的 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 外掛是一個 Scala 函式庫,它是針對 sbt 執行的 Scala 版本 (目前為 2.12.18) 或 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
)一次。這些設定讓外掛程式可以自動提供新功能或新預設值。此功能的主要用途之一是全域新增命令,例如用於 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
方法會傳回 Plugins
類型的值,這是一個用於建構相依性清單的 DSL。requires 方法通常包含以下其中一個值
empty
(沒有外掛程式)&&
運算子(用於定義多個相依性)有些外掛程式應該始終在專案上明確啟用。我們稱這些為根外掛程式,也就是外掛程式相依性圖中的「根」節點。預設情況下,自動外掛程式是根外掛程式。
自動外掛程式也提供了一種讓外掛程式在滿足其相依性時自動附加到專案的方式。我們稱這些為觸發外掛程式,它們是透過覆寫 trigger
方法建立的。
例如,我們可能想要建立一個觸發外掛程式,可以自動將命令附加到建置中。若要執行此操作,請將 requires
方法設定為傳回 empty
,並使用 allRequirements
覆寫 trigger
方法。
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 外掛程式)將 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 專案使用。
此外
$HOME/.sbt/1.0/plugins/lib/
中,並且可供目前使用者的每個建置定義使用。$HOME/.sbt/1.0/plugins/project/Build.scala
中宣告,如 .scala 建置定義中所述。$HOME/.sbt/1.0/plugins/
中的 Scala 原始碼檔案中定義,例如 $HOME/.sbt/1.0/plugins/MyPlugin.scala
。$HOME/.sbt/1.0/plugins//build.sbt
應該包含 sbtPlugin := true
。這可用於在最初開發外掛程式時更快地進行轉換reload
您要使用已修改外掛程式的專案sbt 將重建外掛程式並將其用於專案。
此外,該外掛程式也將可在機器上的其他專案中使用,而無需再次重新編譯。此方法會跳過 publishLocal
和清除使用外掛程式的專案的外掛程式目錄的開銷。
這些都是 $HOME/.sbt/1.0/plugins/
作為一個標準專案的後果,該專案的類別路徑會新增到每個 sbt 專案的建置定義中。
舉例來說,我們會將 Grizzled Scala 程式庫新增為外掛程式。雖然這不提供 sbt 特定的功能,但它示範了如何宣告外掛程式。
project/lib/
中編輯 project/plugins.sbt
以包含
libraryDependencies += "org.clapper" %% "grizzled-scala" % "1.0.4"
如果 sbt 正在執行,請執行 reload
。
我們可以使用 reload plugins
切換到 project/
中的外掛程式專案。
$ 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")
使用此方法的一個注意事項是,本機 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 佈局的儲存庫,則有一個注意事項。
如果您的成品儲存庫期望成品符合 Maven 佈局並拒絕不符合的成品,您可以: 1. (建議) 如果您和您的外掛程式的取用者使用 sbt 1.9.x 或更高版本
從 sbt 1.9 開始,它會嘗試以新的和舊有的 Maven 樣式(為了向後相容性)發佈任何外掛程式。舊有的 Maven 樣式與 Maven 佈局並不完全相容。您需要使用以下方式停用它: sbtPluginPublishLegacyMavenStyle := false
請注意,您將無法使用舊於 1.9 的 sbt 來取用此外掛程式,因為它只能解析舊有的 Maven 樣式(或者您需要使用 sbt-vspp 中所述的技巧)。3. 如果您使用 sbt < 1.9.x
您可以使用 https://github.com/esbeetee/sbt-vspp/ 5. 如果您無法使用 sbt 1.9.x 且您不能/不想使用 sbt-vspp
您的 Artifactory 設定中應該有一個類似於「抑制 POM 一致性檢查」的選項,即使成品不完全遵循 Maven 佈局,它也允許您提交成品。
您可以在以下問題中找到有關此的更多詳細資訊。
如果您是外掛程式作者,請查閱外掛程式最佳做法頁面;它包含一組準則,可協助您確保您的外掛程式具有一致性,並能與其他外掛程式良好運作。
有關跨建置 sbt 外掛程式,另請參閱 跨建置外掛程式。