Getting the scala version running SBT

583 views
Skip to first unread message

Paolo Giarrusso

unread,
Jul 19, 2012, 8:21:31 PM7/19/12
to simple-b...@googlegroups.com
How do I learn programmatically, within build.sbt, the scalaVersion used for running SBT? For instance, 2.9.2 for SBT 0.12, 2.9.1 for SBT 0.11.3, etc.

I guess this is the value of scalaVersion within project/*.sbt, but that doesn't seem to help. I need the Scala version to find the Scala library at code generation time: I generate code using Scalate, which generates, compiles and load Scala code, but due to a Scalate bug I need to inform it of the path to the Scala library by hand. As you can see, the workaround hardcodes the Scala version (http://groups.google.com/group/scalate/browse_frm/thread/b17acb9a345badbc/3a9cbc742edf6cda?#3a9cbc742edf6cda)

My build.sbt attempted to find the right version and pass it to Generator(String) ** like this:

sourceGenerators in Compile <+= (sourceManaged in Compile, baseDirectory, scalaVersion) map { (dir, baseDir, scalaVer) =>

  val gen = new Generator(scalaVer)

  ...

}


But when I switched to scalaVersion := "2.10.0-M5" with SBT 0.12, I've found the hard way that the right Scala version there is "2.9.2", the one used to run SBT.

So, any suggestion?


** FYI, Generator.scala uses the version to implement the hack from the above link. Below is a reduced snippet.


import java.io.{File, PrintStream, FileOutputStream}

import org.fusesource.scalate._

import util.ClassPathBuilder

import sbt._


class Generator(scalaVersion: String) {

  val engine = new TemplateEngine()

  // XXX: workaround to big bug, as discussed here:

  // http://groups.google.com/group/scalate/browse_frm/thread/b17acb9a345badbc/3a9cbc742edf6cda?#3a9cbc742edf6cda

  //In practice, this is quite robust wrt. non-invasive changes to SBT; as long

  //as the scala library is managed using Ivy and named according to this

  //scheme, everything works.

  

  engine.combinedClassPath = true

  val cpBuilder = new ClassPathBuilder

  cpBuilder.addEntry((new File(System.getProperty("user.home")) / 

    ".ivy2" / "cache" / "org.scala-lang" / "scala-library" / "jars" /

    ("scala-library-" + scalaVersion + ".jar")).absolutePath)

  engine.classpath = cpBuilder.classPath

Jason Zaugg

unread,
Jul 20, 2012, 2:11:02 AM7/20/12
to simple-b...@googlegroups.com
On Friday, July 20, 2012 2:21:31 AM UTC+2, Paolo Giarrusso wrote:
How do I learn programmatically, within build.sbt, the scalaVersion used for running SBT? For instance, 2.9.2 for SBT 0.12, 2.9.1 for SBT 0.11.3, etc.

But when I switched to scalaVersion := "2.10.0-M5" with SBT 0.12, I've found the hard way that the right Scala version there is "2.9.2", the one used to run SBT.

So, any suggestion?


How did you switch? To do this interactively in the console, use "++ 2.10.0-M5". 

-jason

Paolo Giarrusso

unread,
Jul 31, 2012, 4:22:09 PM7/31/12
to simple-b...@googlegroups.com
Ah thanks - but I had to change both scalaVersion and the version of
ScalaTest I use, and then use reload.
But I tried to ask a different question: how do I learn the version of
Scala which runs SBT (which is different from what you talk about)
within build.sbt?
Or maybe, the right question is: can a Scala program learn the version
of the Scala library it's running on? If yes, how?
Best regards
--
Paolo Giarrusso - Ph.D. Student, Philipps-University Marburg
http://www.informatik.uni-marburg.de/~pgiarrusso/

Mark Harrah

unread,
Aug 2, 2012, 3:41:44 PM8/2/12
to simple-b...@googlegroups.com
On Tue, 31 Jul 2012 22:22:09 +0200
Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:

> On Fri, Jul 20, 2012 at 8:11 AM, Jason Zaugg <jza...@gmail.com> wrote:
> > On Friday, July 20, 2012 2:21:31 AM UTC+2, Paolo Giarrusso wrote:
> >>
> >> How do I learn programmatically, within build.sbt, the scalaVersion used
> >> for running SBT? For instance, 2.9.2 for SBT 0.12, 2.9.1 for SBT 0.11.3,
> >> etc.
> >>
> >> But when I switched to scalaVersion := "2.10.0-M5" with SBT 0.12, I've
> >> found the hard way that the right Scala version there is "2.9.2", the one
> >> used to run SBT.
> >>
> >> So, any suggestion?
> >
> >
> > How did you switch? To do this interactively in the console, use "++
> > 2.10.0-M5".
>
> Ah thanks - but I had to change both scalaVersion and the version of
> ScalaTest I use, and then use reload.
> But I tried to ask a different question: how do I learn the version of
> Scala which runs SBT (which is different from what you talk about)
> within build.sbt?

There isn't a specific setting, but you can process the launched application's AppConfiguration (that is, sbt's AppConfiguration) as is done to obtain the default Scala version:

scalaVersion in GlobalScope <<= appConfiguration(_.provider.scalaProvider.version)

I could see needing the Scala version in a project/plugins.sbt, but why do you need it in build.sbt?

> Or maybe, the right question is: can a Scala program learn the version
> of the Scala library it's running on? If yes, how?

You probably want scala.util.Properties and one of the version methods.

-Mark

> Best regards
> --
> Paolo Giarrusso - Ph.D. Student, Philipps-University Marburg
> http://www.informatik.uni-marburg.de/~pgiarrusso/
>
> --
> You received this message because you are subscribed to the Google Groups "simple-build-tool" group.
> To post to this group, send email to simple-b...@googlegroups.com.
> To unsubscribe from this group, send email to simple-build-t...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/simple-build-tool?hl=en.
>

Paolo Giarrusso

unread,
Aug 2, 2012, 7:05:24 PM8/2/12
to simple-b...@googlegroups.com
On Thu, Aug 2, 2012 at 9:41 PM, Mark Harrah <dmha...@gmail.com> wrote:
> On Tue, 31 Jul 2012 22:22:09 +0200
> Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
>
>> On Fri, Jul 20, 2012 at 8:11 AM, Jason Zaugg <jza...@gmail.com> wrote:
>> > On Friday, July 20, 2012 2:21:31 AM UTC+2, Paolo Giarrusso wrote:
>> >>
>> >> How do I learn programmatically, within build.sbt, the scalaVersion used
>> >> for running SBT? For instance, 2.9.2 for SBT 0.12, 2.9.1 for SBT 0.11.3,
>> >> etc.
>> >>
>> >> But when I switched to scalaVersion := "2.10.0-M5" with SBT 0.12, I've
>> >> found the hard way that the right Scala version there is "2.9.2", the one
>> >> used to run SBT.
>> >>
>> >> So, any suggestion?
>> >
>> >
>> > How did you switch? To do this interactively in the console, use "++
>> > 2.10.0-M5".
>>
>> Ah thanks - but I had to change both scalaVersion and the version of
>> ScalaTest I use, and then use reload.
>> But I tried to ask a different question: how do I learn the version of
>> Scala which runs SBT (which is different from what you talk about)
>> within build.sbt?
>
> There isn't a specific setting, but you can process the launched application's AppConfiguration (that is, sbt's AppConfiguration) as is done to obtain the default Scala version:
>
> scalaVersion in GlobalScope <<= appConfiguration(_.provider.scalaProvider.version)

> I could see needing the Scala version in a project/plugins.sbt, but why do you need it in build.sbt?

To configure a library (Scalate) used by source code generators, I
need to pass it its own Scala version, so that it can configure the
classpath to run the generated code. In fact, it's a Scalate bug and
this solution is a hack, but no good solution is yet known.

The first message of this thread includes a more detailed answer; I
guess that the high-level information was obscured by all the details
I gave.

# The final answer I used.
For the question I asked, the answer is using `scalaVersion in
GlobalScope` directly (since it's already initialized):

sourceGenerators in Compile <+= (sourceManaged in Compile,
baseDirectory, scalaVersion in GlobalScope) map { (dir, baseDir,
sbtScalaVersion ) =>
scala.Console.err.printf("sbtScalaVersion %s\n", sbtScalaVersion)
val gen = new Generator(sbtScalaVersion)
//use gen for code generation...
}

However, what I would in fact need would be scalaBinaryVersion in
GlobalScope, which is not available; luckily,
appConfiguration(_.provider.scalaProvider.libraryJar) is in fact
exactly what I need for Scalate.

Calling map on `appConfiguration(_.provider.scalaProvider.libraryJar)`
fails, since map returns not `SettingKey` but `Initialize` - the trick
I learned is to call map on appConfiguration before any other
processing:

sourceGenerators in Compile <+= (sourceManaged in Compile,
baseDirectory, appConfiguration) map { (dir, baseDir, appConfig ) =>
val libraryJar = appConfig.provider.scalaProvider.libraryJar
val gen = new Generator(libraryJar) //I changed the type of the constructor.
//use gen for code generation...
}

>> Or maybe, the right question is: can a Scala program learn the version
>> of the Scala library it's running on? If yes, how?

> You probably want scala.util.Properties and one of the version methods.
That's close enough; but since I need the binary version as normalized
by SBT, I'll use the SBT-specific solution.

Thanks for the help and best regards

Mark Harrah

unread,
Aug 3, 2012, 10:18:37 AM8/3/12
to simple-b...@googlegroups.com
On Fri, 3 Aug 2012 01:05:24 +0200
It was probably fine. I just came into the thread after that context was removed.

> # The final answer I used.
> For the question I asked, the answer is using `scalaVersion in
> GlobalScope` directly (since it's already initialized):
>
> sourceGenerators in Compile <+= (sourceManaged in Compile,
> baseDirectory, scalaVersion in GlobalScope) map { (dir, baseDir,
> sbtScalaVersion ) =>
> scala.Console.err.printf("sbtScalaVersion %s\n", sbtScalaVersion)
> val gen = new Generator(sbtScalaVersion)
> //use gen for code generation...
> }
>
> However, what I would in fact need would be scalaBinaryVersion in
> GlobalScope, which is not available; luckily,
> appConfiguration(_.provider.scalaProvider.libraryJar) is in fact
> exactly what I need for Scalate.

I asked because I thought the classpath was more likely to be of use than the Scala version and it looks like that is the case here. It is quite reasonable for a library like scalate that uses the compiler to require the classpath be passed explicitly. This proposal was integrated into both sbt and scalac, but sbt only sets up the required resources for 'test' and 'run':

https://gist.github.com/404272

Setting it up for sbt itself would be trickier.

> Calling map on `appConfiguration(_.provider.scalaProvider.libraryJar)`
> fails, since map returns not `SettingKey` but `Initialize` -

Yes, this is a known limitation of the task DSL. The experimental task-syntax branch[1] lifts this restriction.

> the trick
> I learned is to call map on appConfiguration before any other
> processing:
>
> sourceGenerators in Compile <+= (sourceManaged in Compile,
> baseDirectory, appConfiguration) map { (dir, baseDir, appConfig ) =>
> val libraryJar = appConfig.provider.scalaProvider.libraryJar
> val gen = new Generator(libraryJar) //I changed the type of the constructor.
> //use gen for code generation...
> }
>
> >> Or maybe, the right question is: can a Scala program learn the version
> >> of the Scala library it's running on? If yes, how?
>
> > You probably want scala.util.Properties and one of the version methods.
> That's close enough; but since I need the binary version as normalized
> by SBT, I'll use the SBT-specific solution.

You can use the binaryScalaVersion method on sbt.CrossVersion [2].

-Mark

[1] https://github.com/harrah/xsbt/tree/task-syntax
[2] http://harrah.github.com/xsbt/latest/api/index.html#sbt.CrossVersion$

> Thanks for the help and best regards
> --
> Paolo Giarrusso - Ph.D. Student, Philipps-University Marburg
> http://www.informatik.uni-marburg.de/~pgiarrusso/
>

Paolo Giarrusso

unread,
Aug 3, 2012, 12:02:25 PM8/3/12
to simple-b...@googlegroups.com
On Fri, Aug 3, 2012 at 4:18 PM, Mark Harrah <dmha...@gmail.com> wrote:
> On Fri, 3 Aug 2012 01:05:24 +0200
> Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
>
>> On Thu, Aug 2, 2012 at 9:41 PM, Mark Harrah <dmha...@gmail.com> wrote:
>> > On Tue, 31 Jul 2012 22:22:09 +0200
>> > Paolo Giarrusso <pgiar...@mathematik.uni-marburg.de> wrote:
>> >

>> However, what I would in fact need would be scalaBinaryVersion in
>> GlobalScope, which is not available; luckily,
>> appConfiguration(_.provider.scalaProvider.libraryJar) is in fact
>> exactly what I need for Scalate.

> I asked because I thought the classpath was more likely to be of use than the Scala version and it looks like that is the case here. It is quite reasonable for a library like scalate that uses the compiler to require the classpath be passed explicitly.

> This proposal was integrated into both sbt and scalac, but sbt only sets up the required resources for 'test' and 'run':
>
> https://gist.github.com/404272
>
> Setting it up for sbt itself would be trickier.

>> Calling map on `appConfiguration(_.provider.scalaProvider.libraryJar)`
>> fails, since map returns not `SettingKey` but `Initialize` -

> Yes, this is a known limitation of the task DSL. The experimental task-syntax branch[1] lifts this restriction.

>> >> Or maybe, the right question is: can a Scala program learn the version
>> >> of the Scala library it's running on? If yes, how?

>> > You probably want scala.util.Properties and one of the version methods.
>> That's close enough; but since I need the binary version as normalized
>> by SBT, I'll use the SBT-specific solution.

> You can use the binaryScalaVersion method on sbt.CrossVersion [2].

I see. There's not much ScalaDoc, but I don't have time to add any for
now. (I assume you would accept a pull request about that, if it had
reasonable content).

Here's an example (mostly for external readers):

> reload plugins
> console
[...]
scala> import sbt._
scala> Seq(CrossVersion binaryScalaVersion "2.8.1", CrossVersion
binaryScalaVersion "2.9.2", CrossVersion binaryScalaVersion "2.10.1")
mkString ", "
res11: String = 2.8.1, 2.9.2, 2.10

Btw, I'm happy that "reload plugins" finally works for me (on SBT
0.11, it always gave errors on the .scala build definition - it could
not resolve imports).

Best regards

Mark Harrah

unread,
Aug 3, 2012, 11:02:18 PM8/3/12
to simple-b...@googlegroups.com
On Fri, 3 Aug 2012 18:02:25 +0200
Yes, certainly.

> Here's an example (mostly for external readers):
>
> > reload plugins
> > console
> [...]
> scala> import sbt._
> scala> Seq(CrossVersion binaryScalaVersion "2.8.1", CrossVersion
> binaryScalaVersion "2.9.2", CrossVersion binaryScalaVersion "2.10.1")
> mkString ", "
> res11: String = 2.8.1, 2.9.2, 2.10
>
> Btw, I'm happy that "reload plugins" finally works for me (on SBT
> 0.11, it always gave errors on the .scala build definition - it could
> not resolve imports).

Yes, there are a few settings on the meta-project that are set automatically, such as `sbtPlugin := true`, and 'reload plugins' didn't handle that.

-Mark

> Best regards
> --
> Paolo Giarrusso - Ph.D. Student, Philipps-University Marburg
> http://www.informatik.uni-marburg.de/~pgiarrusso/
>
Reply all
Reply to author
Forward
0 new messages