Can I access my Scala app's name and version (as set in SBT) from code?
Asked Answered
H

3

69

I am building an app with SBT (0.11.0) using a Scala build definition like so:

object MyAppBuild extends Build {

  import Dependencies._

  lazy val basicSettings = Seq[Setting[_]](
    organization  := "com.my",
    version       := "0.1",
    description   := "Blah",
    scalaVersion  := "2.9.1",
    scalacOptions := Seq("-deprecation", "-encoding", "utf8"),
    resolvers     ++= Dependencies.resolutionRepos
  )

  lazy val myAppProject = Project("my-app-name", file("."))
    .settings(basicSettings: _*)
    [...]

I'm packaging a .jar at the end of the process.

My question is a simple one: is there a way of accessing the application's name ("my-app-name") and version ("0.1") programmatically from my Scala code? I don't want to repeat them in two places if I can help it.

Any guidance greatly appreciated!

Hiers answered 4/1, 2012 at 19:36 Comment(5)
Are you packaging a jar?Fizgig
Sorry yes - have clarified in my question, thanks Jean-PhilippeHiers
I think sbt saves the version in the jar's manifest, no?Fizgig
I'm not sure Jean-Philippe - I've seen code like this: val version = new BufferedReader(new InputStreamReader(getClass.getResourceAsStream("/version"))).readLine() but I haven't been able to get it working...Hiers
This is working now for me val currentVersion: String = { IO.readLines(new File("VERSION")).head }Hemihedral
N
66

sbt-buildinfo

I just wrote sbt-buildinfo. After installing the plugin:

lazy val root = (project in file(".")).
  enablePlugins(BuildInfoPlugin).
  settings(
    buildInfoKeys := Seq[BuildInfoKey](name, version, scalaVersion, sbtVersion),
    buildInfoPackage := "foo"
  )

Edit: The above snippet has been updated to reflect more recent version of sbt-buildinfo.

It generates foo.BuildInfo object with any setting you want by customizing buildInfoKeys.

Ad-hoc approach

I've been meaning to make a plugin for this, (I wrote it) but here's a quick script to generate a file:

sourceGenerators in Compile <+= (sourceManaged in Compile, version, name) map { (d, v, n) =>
  val file = d / "info.scala"
  IO.write(file, """package foo
    |object Info {
    |  val version = "%s"
    |  val name = "%s"
    |}
    |""".stripMargin.format(v, n))
  Seq(file)
}

You can get your version as foo.Info.version.

Neutron answered 5/1, 2012 at 2:0 Comment(4)
Thanks Eugene - how do I make this a part of my build process - where do I put the code?Hiers
Since you're using .scala build, stick it in a Seq and append it to basicSettings as .settings(basicSettings ++ Seq(sourceGenerators in Compile <+= (...) map {...}): _*).Neutron
Thanks Eugene - that's working really well. SBT source generation is powerful stuff!Hiers
I tried adding this to build.sbt and not sure how I can access the foo.BuildInfo from my scala class? any suggestionsConsultative
M
50

Name and version are inserted into manifest. You can access them using java reflection from Package class.

val p = getClass.getPackage
val name = p.getImplementationTitle
val version = p.getImplementationVersion
Maier answered 24/11, 2012 at 23:44 Comment(1)
I upvoted this before realizing that it won't work in test tasks.Besprent
T
0

You can also generate a dynamic config file, and read it from scala.

// generate config (to pass values from build.sbt to scala)
Compile / resourceGenerators += Def.task {
  val file = baseDirectory.value / "conf" / "generated.conf"
  val contents = "app.version=%s".format(version.value)
  IO.write(file, contents)
  Seq(file)
}.taskValue

When you run sbt universal:packageBin the file will be there.

Teachin answered 12/1, 2023 at 14:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.