如何创建 sbt 任务来生成代码,然后将这些生成的托管源包含在我的根项目中?

Jin*_*Kim 6 scala sbt

我想要一个 sbt 任务,我可以运行它来生成一些代码。我不想在每次运行时都生成这个,只是偶尔手动运行一次这个任务。我创建了一个骨架项目来解释(https://github.com/jinyk/sbtmanagedsrc)。

构建.sbt:

lazy val root = (project in file("."))
    .settings(scalaVersion := "2.11.8")
    .settings(gensomecode := genSomeCodeTask.value)
    /////////////////////////////////////////////////////////////
    // fugly way to get managed sources compiled along with main
    .settings(unmanagedSourceDirectories in Compile += baseDirectory.value / "target/scala-2.11/src_managed/")
    /////////////////////////////////////////////////////////////

lazy val gensomecode = taskKey[Seq[File]]("gen-code")
lazy val genSomeCodeTask = Def.task {
  val file = (sourceManaged in Compile).value / "SomeGenCode.scala"
  println("file: " + file)
  IO.write(file, """object SomeGenCode {
                   |  def doSomething() {
                   |    println("Hi!")
                   |  }
                   |}""".stripMargin)
  Seq(file)
}
Run Code Online (Sandbox Code Playgroud)

因此,使用上面的 build.sbt,我可以运行sbt gensomecode它创建 target/scala-2.11/src_managed/main/SomeGenCode.scalasbt 放置“托管源”的默认位置。

我想让它SomeGenCode可用于根项目。

src/main/scala/Main.scala:

object Main extends App {
  SomeGenCode.doSomething()
}
Run Code Online (Sandbox Code Playgroud)

我唯一能想到的就是sourceManaged在根项目中包含默认目录unmanagedSourceDirectories(参见注释build.sbt:line 4下方的行fugly way...)。这太丑了,看起来不像是应该如何处理托管源。

我可能不了解有关 sbt 的托管源概念或如何处理创建 sbt 任务以生成源的情况的基本知识。

我错过了什么?

the*_*met 4

有我熟悉的三个选项:

  1. 生成到非托管源目录中。

  2. 通过添加在每次运行时生成sourceGenerators in Compile <+= gensomecode

  3. 与 (2) 类似,但使用缓存,这样就不会在每次编译时生成文件。完整示例如下。

在此示例中,缓存基于 的内容build.sbt,因此每当该文件发生更改时,它都会重新生成该文件。

lazy val root = (project in file("."))
    .settings(scalaVersion := "2.11.8")
    .settings(gensomecode <<= genSomeCodeTask)

sourceGenerators in Compile <+= genSomeCodeTask

lazy val gensomecode = taskKey[Seq[File]]("gen-code")

def generateFile(sourceManaged: java.io.File) = {
  val file = sourceManaged / "main" / "SomeGenCode.scala"
  println("file: " + file)
  IO.write(file, """object SomeGenCode {
                   |  def doSomething() {
                   |    println("Hi!")
                   |  }
                   |}""".stripMargin)
  Set(file)
}

def genSomeCodeTask = (sourceManaged in Compile, streams).map {
  (sourceManaged, streams) =>

  val cachedCompile = FileFunction.cached(
      streams.cacheDirectory / "mything", 
      inStyle = FilesInfo.lastModified,
      outStyle = FilesInfo.exists) { 
        (in: Set[java.io.File]) =>
          generateFile(sourceManaged)
      }
  cachedCompile(Set(file("build.sbt"))).toSeq
}
Run Code Online (Sandbox Code Playgroud)