使用 sbt 在 Scala 上构建我的项目,我想要一个在实际 Scala 编译之前运行的任务,并将生成一个Version.scala
包含项目版本信息的文件。这是我想出的一个任务:
lazy val generateVersionTask = Def.task {
// Generate contents of Version.scala
val contents = s"""package io.kaitai.struct
|
|object Version {
| val name = "${name.value}"
| val version = "${version.value}"
|}
|""".stripMargin
// Update Version.scala file, if needed
val file = (sourceManaged in Compile).value / "version" / "Version.scala"
println(s"Version file generated: $file")
IO.write(file, contents)
Seq(file)
}
这个任务似乎可行,但问题是如何插入它,因为它是一个跨项目,针对 Scala/JVM、Scala/JS 等。
这是build.sbt
我开始触摸它之前的样子:
lazy val root = project.in(file(".")).
aggregate(fooJS, fooJVM).
settings(
publish := {},
publishLocal := {}
)
lazy val foo = crossProject.in(file(".")).
settings(
name := "foo",
version := sys.env.getOrElse("CI_VERSION", "0.1"),
// ...
).
jvmSettings(/* JVM-specific settings */).
jsSettings(/* JS-specific settings */)
lazy val fooJVM = foo.jvm
lazy val fooJS = foo.js
而且,在文件系统上,我有:
- shared/ — 在 JS/JVM 构建之间共享的跨平台代码
- jvm/ — JVM 特定的代码
- js/ — JS 特定的代码
到目前为止,我想出的最好的方法是将此任务添加到foo
crossProject:
lazy val foo = crossProject.in(file(".")).
settings(
name := "foo",
version := sys.env.getOrElse("CI_VERSION", "0.1"),
sourceGenerators in Compile += generateVersionTask.taskValue, // <== !
// ...
).
jvmSettings(/* JVM-specific settings */).
jsSettings(/* JS-specific settings */)
这可行,但以一种非常尴尬的方式,与“共享”代码库并不真正兼容。它为 JS 和 JVM 生成 2 个不同的 Version.scala 文件:
sbt:root> compile
Version file generated: /foo/js/target/scala-2.12/src_managed/main/version/Version.scala
Version file generated: /foo/jvm/target/scala-2.12/src_managed/main/version/Version.scala
自然,不可能从 访问这些文件的内容shared
,而这正是我想要访问的地方。
到目前为止,我提出了一个非常草率的解决方法:
var
在共享的单例对象中有一个声明- 在 JVM 和 JS 主入口点中,我做的第一件事就是分配该变量以匹配定义在
Version.scala
另外,我用sbt-buildinfo插件尝试了同样的技巧——结果完全一样,它生成 per-platform BuildInfo.scala
,我不能直接从共享源中使用它。
有没有更好的解决方案?