有没有办法将 myProject/sbt-plugin 中定义的 sbt-plugin 挂接到 myProject/framework 的构建中?
我在 Github eed3si9n/plugin-bootstrap 上有一个工作示例。它不是超级漂亮,但它有点工作。我们可以利用sbt is recursive这一事实。
project 目录是您的构建中的另一个构建,它知道如何构建您的构建。为了区分构建,我们有时使用术语 proper build 来指代您的构建,而 meta-build 来指代 project 中的构建。元构建中的项目可以做任何其他项目可以做的任何事情。 您的构建定义是一个 sbt 项目。
通过扩展,我们可以将 sbt 插件视为元构建根项目的库或项目间依赖项。
元构建定义 (project/plugins.sbt)
在此示例中,将元构建视为平行宇宙或阴影世界,具有并行多构建结构作为正确构建(root、model、sbt-plugin)。
要在正确的构建中重用来自model 和sbt-plugin 子项目的源代码,我们可以在元构建中重新创建多项目构建。这样我们就不需要进入循环依赖了。
addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.5")
lazy val metaroot = (project in file(".")).
dependsOn(metaSbtSomething)
lazy val metaModel = (project in file("model")).
settings(
sbtPlugin := true,
scalaVersion := "2.10.6",
unmanagedSourceDirectories in Compile :=
mirrorScalaSource((baseDirectory in ThisBuild).value.getParentFile / "model")
)
lazy val metaSbtSomething = (project in file("sbt-plugin")).
dependsOn(metaModel).
settings(
sbtPlugin := true,
scalaVersion := "2.10.6",
unmanagedSourceDirectories in Compile :=
mirrorScalaSource((baseDirectory in ThisBuild).value.getParentFile / "sbt-plugin")
)
def mirrorScalaSource(baseDirectory: File): Seq[File] = {
val scalaSourceDir = baseDirectory / "src" / "main" / "scala"
if (scalaSourceDir.exists) scalaSourceDir :: Nil
else sys.error(s"Missing source directory: $scalaSourceDir")
}
当 sbt 加载时,它会先构建 metaModel 和 metaSbtSomething,然后使用 metaSbtSomething 作为插件来正确构建。
如果您有任何其他需要的插件,您可以将其添加到project/plugins.sbt,就像我添加了sbt-doge一样。
正确构建 (build.sbt)
正确的构建看起来像一个正常的多项目构建。
如您所见,framework 子项目使用SomethingPlugin。重要的是它们共享源代码,但target 目录是完全分开的,因此一旦加载了正确的构建,并且您正在更改代码,就不会受到干扰。
import Dependencies._
lazy val root = (project in file(".")).
aggregate(model, framework, sbtSomething).
settings(inThisBuild(List(
scalaVersion := scala210,
organization := "com.example"
)),
name := "Something Root"
)
// Defines common models for both sbt-plugin and framework
lazy val model = (project in file("model")).
settings(
name := "Something Model",
crossScalaVersions := Seq(scala211, scala210)
)
// The framework. Ideally, the sbt plugin is run as part of building this.
lazy val framework = (project in file("framework")).
enablePlugins(SomethingPlugin).
dependsOn(model).
settings(
name := "Something Framework",
crossScalaVersions := Seq(scala211, scala210),
// using sbt-something
somethingX := "a"
)
lazy val sbtSomething = (project in file("sbt-plugin")).
dependsOn(model).
settings(
sbtPlugin := true,
name := "sbt-something",
crossScalaVersions := Seq(scala210)
)
演示
在SomethingPlugin 示例中,我定义了使用foo.Model.x 的something 任务。
package foo
import sbt._
object SomethingPlugin extends AutoPlugin {
def requries = sbt.plugins.JvmPlugin
object autoImport {
lazy val something = taskKey[Unit]("")
lazy val somethingX = settingKey[String]("")
}
import autoImport._
override def projectSettings = Seq(
something := { println(s"something! ${Model.x}") }
)
}
以下是我们如何从构建中调用something 任务:
Something Root> framework/something
something! 1
[success] Total time: 0 s, completed May 29, 2016 3:01:07 PM
1 来自foo.Model.x,因此这表明我们在framework 子项目中使用了sbt-something 插件,并且该插件正在使用metaModel。