【问题标题】:Intertwined dependencies between sbt plugin and projects within multi-project build that uses the plugin itselfsbt 插件和使用插件本身的多项目构建中的项目之间的相互依赖关系
【发布时间】:2016-09-22 07:30:24
【问题描述】:

我正在开发一个包含 sbt 插件的库。自然,我使用 sbt 来构建这个(多项目)库。我的(简化的)项目如下所示:

myProject/                        # Top level of library
  -> models                       # One project in the multi-project sbt build.
      -> src/main/scala/...       # Defines common models for both sbt-plugin and framework
  -> sbt-plugin                   # The sbt plugin build
      -> src/main/scala/...
  -> framework                    # The framework. Ideally, the sbt plugin is run as part of 
      -> src/main/scala/...       # compiling this directory.
  -> project/                     # Multi-project build configuration

有没有办法将 myProject/sbt-plugin 中定义的 sbt-plugin 挂接到 myProject/framework 的构建中?

注意:类似(但更简单)的问题:How to develop sbt plugin in multi-project build with projects that use it?

【问题讨论】:

    标签: scala plugins sbt


    【解决方案1】:

    有没有办法将 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)

    在此示例中,将元构建视为平行宇宙或阴影世界,具有并行多构建结构作为正确构建(rootmodelsbt-plugin)。

    要在正确的构建中重用来自modelsbt-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 加载时,它会先构建 metaModelmetaSbtSomething,然后使用 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.xsomething 任务。

    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

    【讨论】:

      猜你喜欢
      • 2014-02-26
      • 2014-02-25
      • 2015-06-11
      • 1970-01-01
      • 2011-12-16
      • 1970-01-01
      • 2015-11-10
      • 2012-03-24
      • 1970-01-01
      相关资源
      最近更新 更多