How to share version values between project/plugins.sbt and project/Build.scala?
I would like to share a common version variable between an sbtPlugin and the rest of the build
Here is what I am trying:
in project/Build.scala
:
object Versions {
scalaJs = "0.5.0-M3"
}
object MyBuild extends Build {
//Use version number
}
in plugins.sbt
:
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % Versions.scalaJs)
results in
plugins.sbt:15: error: not found: value Versions
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % Versions.scalaJs)
Is there a way to share the version number specification between plugins.sbt
and the rest of the build, e.g. project/Build.scala
?
sbt-buildinfo
If you need to share version
number between build.sbt
and hello.scala
, what would you normally do? I don't know about you, but I would use sbt-buildinfo that I wrote.
This can be configured using buildInfoKeys
setting to expose arbitrary key values like version
or some custom String
value. I understand this is not exactly what you're asking but bear with me.
meta-build (turtles all the way down)
As Jacek noted and stated in Getting Started Guide, the build in sbt is a project defined in the build located in project
directory one level down. To distinguish the builds, let's define the normal build as the proper build, and the build that defines the proper build as meta-build. For example, we can say that an sbt plugin is a library of the root project in the meta build.
Now let's get back to your question. How can we share info between project/Build.scala
and project/plugins.sbt
?
using sbt-buildinfo for meta-build
We can just define another level of build by creating project/project
and add sbt-buildinfo
to the (meta-)meta-build.
Here are the files.
In project/project/buildinfo.sbt
:
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.3.2")
In project/project/Dependencies.scala
:
package metabuild
object Dependencies {
def scalaJsVersion = "0.5.0-M2"
}
In project/build.properties
:
sbt.version=0.13.5
In project/buildinfo.sbt
:
import metabuild.Dependencies._
buildInfoSettings
sourceGenerators in Compile <+= buildInfo
buildInfoKeys := Seq[BuildInfoKey]("scalaJsVersion" -> scalaJsVersion)
buildInfoPackage := "metabuild"
In project/scalajs.sbt
:
import metabuild.Dependencies._
addSbtPlugin("org.scala-lang.modules.scalajs" % "scalajs-sbt-plugin" % scalaJsVersion)
In project/Build.scala
:
import sbt._
import Keys._
import metabuild.BuildInfo._
object Builds extends Build {
println(s"test: $scalaJsVersion")
}
So there's a bit of a boilerplate in project/buildinfo.sbt
, but the version info is shared across the build definition and the plugin declaration.
If you're curious where BuildInfo
is defined, peek into project/target/scala-2.10/sbt-0.13/src_managed/
.
For the project/plugins.sbt
file you'd have to have another project
under project
with the Versions.scala
file. That would make the definition of Versions.scalaJs
visible.
The reason for doing it is that *.sbt
files belong to a project build definition at the current level with *.scala
files under project
to expand on it. And it's...turtles all the way down, i.e. sbt is recursive.
I'm not sure how much the following can help, but it might be worth to try out - to share versions between projects - plugins
and the main one - you'd have to use ProjectRef
as described in the answer to RootProject and ProjectRef:
When you want to include other, separate builds directly instead of using their published binaries, you use "source dependencies". This is what
RootProject
andProjectRef
declare.ProjectRef
is the most general: you specify the location of the build (a URI) and the ID of the project in the build (a String) that you want to depend on.RootProject
is a convenience that selects the root project for the build at the URI you specify.
My proposal is to hack. For example, in build.sbt
you can add a task:
val readPluginSbt = taskKey[String]("Read plugins.sbt file.")
readPluginSbt := {
val lineIterator = scala.io.Source.fromFile(new java.io.File("project","plugins.sbt")).getLines
val linesWithValIterator = lineIterator.filter(line => line.contains("scalaxbVersion"))
val versionString = linesWithValIterator.mkString("\n").split("=")(1).trim
val version = versionString.split("\n")(0) // only val declaration
println(version)
version
}
When you call readPluginSbt
you will see the contents of plugins.sbt
. You can parse this file and extract the variable.
For example:
resolvers += Resolver.sonatypeRepo("public")
val scalaxbVersion = "1.1.2"
addSbtPlugin("org.scalaxb" % "sbt-scalaxb" % scalaxbVersion)
addSbtPlugin("org.xerial.sbt" % "sbt-pack" % "0.5.1")
You can extract scalaxbVersion
with regular expressions/split:
scala> val line = """val scalaxbVersion = "1.1.2""""
line: String = val scalaxbVersion = "1.1.2"
scala> line.split("=")(1).trim
res1: String = "1.1.2"