sbt:子项目的动态聚合

Posted

技术标签:

【中文标题】sbt:子项目的动态聚合【英文标题】:sbt: dynamic aggregation of subproject 【发布时间】:2015-09-05 16:15:30 【问题描述】:

我想发明一个系统来动态发现子项目并将它们自动聚合到我的项目中。或者至少以某种方式配置它。

为此,我计划创建一个“模块”文件夹或包含模块路径的可选配置文件。

在任何情况下,我都需要遍历子文件夹(或遍历配置文件中的路径列表),并聚合每个子项目。我不知道该怎么做。

目前我正在使用 build.sbt 文件在 Play 框架中构建。我需要像这样添加循环:

name := "mysite"
version := "1.0"
scalaVersion := "2.11.1"
lazy val root = (project in file(".")).enablePlugins(PlayJava)
//pseudocode:
foreach( folder in the 'modules' folder)  
  lazy val module = (project in file(folder)).enablePlugins(PlayJava)
  root = root.dependsOn(module).aggregate(module)

有没有办法做到这一点?

编辑 3: 这里的代码几乎可以工作了:

object MyBuild extends Build 
  name := "mysite"
  version := "1.0"
  scalaVersion := "2.11.6"

  var m = new File("modules")
  var list = Seq[ProjectReference]()
  var deps = Seq[ClasspathDependency]()
  if (m.exists) 
    val subs = m.listFiles.filter ( _.isDirectory ).foreach  folder =>
      var modulePath = new File("modules", folder.getName)
      println("Found module " + modulePath)
      lazy val module:ProjectRef = ProjectRef(modulePath,folder.getName)
      lazy val dep:ClasspathDependency = ClasspathDependency(module, None)
      list = list :+ module
      deps = deps :+ dep
    
  

  lazy val root = Project(id = "mysite", base = file(".")).enablePlugins(PlayJava).aggregate(list:_*).dependsOn(deps:_*)

编辑 4:

请参阅下面 Dale Wijnand 的解决方案。

关于错误:RuntimeException: No project 'myModule' in 'file:/Users/me/mysite/modules/myModule'。我使用https://***.com/a/28820578的解决方案解决了这个问题

【问题讨论】:

println("Found module " + folder.getName) 的输出是什么? 它是“找到模块 foo”(我的模块文件夹名为“foo”)。似乎 r.depends(module) 失败了。它可能不是 Project 对象。出于某种原因。 【参考方案1】:

这里:

project/Build.scala

import sbt._
import sbt.Keys._

import play.sbt._
import play.sbt.Play.autoImport._

object Build extends Build 
  val commonSettings: Seq[Setting[_]] = Seq(
    scalaVersion := "2.11.7"
  )

  lazy val modules = (file("modules") * DirectoryFilter).get.map  dir =>
    Project(dir.getName, dir).enablePlugins(PlayJava).settings(commonSettings: _*)
  

  lazy val root = (project in file("."))
    .enablePlugins(PlayJava)
    .settings(
      name := "mysite",
      version := "1.0"
    )
    .settings(commonSettings: _*)
    .dependsOn(modules map (m => m: ClasspathDependency): _*)
    .aggregate(modules map (m => m: ProjectReference): _*)

  override lazy val projects = root +: modules

注意,请确保模块目录不包含将它们定义为项目的build.sbt 文件,因为这会导致混淆RuntimeException: No project 'x' in 'file:/x' 类型异常,请参阅Can't use sbt 0.13.7 with Play subprojects

【讨论】:

这是迄今为止最完整的解决方案。但我仍然遇到同样的错误:RuntimeException: No project 'myModule' in 'file:/Users/me/mysite/modules/myModule'。知道为什么会这样吗? 注意:子项目本身可以自行编译。 我明白了!解决方案在这里:***.com/a/28820578 基本上项目根定义在主构建和子项目构建中是重复的。解决方案是为子项目删除 build.sbt 中的根项目定义。 //懒惰的val root = ... 确实,我正在输入有关此内容并询问您是否可以检查的问题。我会将其作为 NB 添加到答案中。那么这对你来说是一个完整的解决方案吗? 一个相关的问题,如果你有兴趣:***.com/questions/31120440/…【参考方案2】:

你可以试试这样的:

import sbt._
import sbt.Keys._

import play.sbt._
import play.sbt.Play.autoImport._

object Build extends Build 

  lazy val modules = (file("modules") * DirectoryFilter).get.map  dir =>
    Project(dir.getName, dir).enablePlugins(PlayJava)
  

  lazy val root = (project in file("."))
    .enablePlugins(PlayJava)
    .settings(
      name := "mysite",
      version := "1.0"
    )
    .dependsOn(modules map (m => m: ClasspathDependency): _*)
    .aggregate(modules map (m => m: ProjectReference): _*)

  override lazy val projects = root +: modules

注意:受 Dale 回答的启发,但我必须删除“commonSettings”,否则它对我不起作用。

【讨论】:

我尝试了类似的方法。但是 root=root.dependsOn() 不起作用;那个 val 是不可变的。我收到“重新分配给 val”错误。我是 Scala 的新手,所以请握住我的手。 解决办法是把根设为“var”而不是“val”。现在我有一些几乎可以工作的东西,但我遇到了一个不同的问题。请参阅上面的更新代码。 对不起;我迷失在这段代码中。我不知道“t”和“r”是什么。 我有一个适用于 Windows 但不适用于 Mac 的解决方案。在这一点上,这都是关于文件夹的。我会尽快解决的。 好的,我已经更新了我的解决方案(见上文),并将问题缩小到 file() 返回错误的文件夹。它返回项目的根文件夹,而不是模块文件夹。 getCanonicalPath 返回 /Users/me/mysite/ 而不是 /Users/me/mysite/modules/myModule。这很奇怪。

以上是关于sbt:子项目的动态聚合的主要内容,如果未能解决你的问题,请参考以下文章

SBT将项目ID添加到多项目构建中的日志中

sbt 子项目的项目目录

如何在 sbt 子项目 build.sbt 文件中获取对当前项目的引用

SBT 多项目构建:针对不同子项目的 2 个不同版本的 sbt play 插件

如何让 SBT 跳过给定子项目的交叉编译?

SBT:多构建依赖/聚合项目中的覆盖设置