在 Scala 和 sbt 上构建我的项目时,我想要一个任务,在实际编译 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生成了两个不同的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
访问这些文件的内容,这就是我想要访问它的地方。
到目前为止,我想到了一个非常笨拙的解决方法:
- 在 singleton 对象中声明了一个
var
,在共享代码中使用 - 在 JVM 和 JS 的主入口点中,我做的第一件事就是将该变量分配给与
Version.scala
中定义的常量相匹配
此外,我还尝试过使用sbt-buildinfo插件进行相同的操作 - 结果完全相同,它生成了针对每个平台的BuildInfo.scala
,但我无法直接从共享源中使用。
是否有更好的解决方案可用?
shared
无法访问这些文件的内容”是什么意思?从共享代码中调用特定于平台的代码是完全可能的。 - Travis Brownshared
被单独编译,而jvm
和js
不在其类路径中。此外,当前使用两个Version.scala
文件的解决方案实际上证实了这一点:如果Version.scala
可用,那么拥有相同名称的2个文件将会产生冲突。 - GreyCat