How to limit changes to `sbt run` and `sbt test` tasks? - sbt

I'm puzzled by sbt tool. I would like to define two Java options, one for sbt run target and another for sbt test target. These options require forking the VM, which I would not like to happen for other commands (such as compile, update).
How to define this in the build.sbt elegantly?
what's the role of the Compile thing? What about Test?
how to declare fork only once, so that it would apply to both sbt run and sbt test?
I've been using sbt for a few years, now. Read the documents. Something like this still escapes me. sigh
fork in run := true
javaOptions in (Compile,run) ++= Seq(
"-Dconfig.file=conf/debug.conf"
)
fork in test := true
javaOptions in (Test,test) ++= Seq(
"-Dconfig.file=conf/debug-test.conf"
)
Using sbt 0.13.8

Say you want to specify that you only want to fork() on sbt run and not on other executions of run (e.g., on sbt test:run) then you need to use the Configuration scope together with the task. That is:
fork in (Compile,run) := true
If you had the following:
fork in run := true
It will fork all run tasks, including test:run etc.
Now, if you had this:
fork := true
It will fork() all the fork-able task in all scopes.
Coming back to your questions, you can think of the (Compile, run) and (Test, run) etc. as instances of (Configuration,task) scope. You should use this construct when you want to narrow down the scope of a particular setting down to the task of a specific configuration: Compile, Run, Test, or any custom one you may have.
In your .sbt file I think the right thing to do is:
fork in (Compile,run) := true
javaOptions in (Compile,run) ++= Seq(
"-Dconfig.file=conf/debug.conf"
)
fork in (Test,test) := true
javaOptions in (Test,test) ++= Seq(
"-Dconfig.file=conf/debug-test.conf"
)

Related

Forking "sbt run &"

I cannot fork my sbt process using sbt run &. When I do so, I return to bash console, and I get a PID, but soon, the process stops.
In my build.sbt I have added the line Keys.fork in run := true but that doesn't do anything.
What is that?
I don't believe you need to restrict to run. Try just
fork := true

How do I set Java options in SBT for the test configuration only?

I currently have a command line sbt -Dsome.configuration.option test doing what I want, but I would like it to apply that configuration option automatically for sbt test (and no other sbt phase). If my terminology is correct, then I want to set a Java Option for the Test Configuration. How do I do this?
Searching on these terms has led me to http://www.scala-sbt.org/release/docs/Testing.html but I have not yet been able to understand it.
This question looks similar to mine: Define custom test configurations in sbt
Try this:
testOptions in Test +=
Tests.Setup(() => sys.props += "some.configuration.option" -> "true")
Caveat:
Because you're not forking this mutates the state of the system property in the JVM running sbt itself.
Which means that after running test the first time it that system property will also be set if you, for instance, run your main from within sbt (run/runMain).

How to have SBT skip cross compile for a given sub-project?

I've run into a couple related cases with SBT that have me stumped. Is there a way to tell SBT to skip a sub project entirely for certain scala versions when you're cross compiling?
Here are two examples where this would be useful.
1) A build with three projects A, B, and C. Both A and B are scala projects, and have 'scalaVersions ++= Seq("2.11.2", "2.10.4") in their settings. Project C is a pure-Java artifact, and thus I've excluded the Scala libraries from it's dependencies. I'd like A and B to depend on C, but ideally I'd only like to build C just once. If I use the default behavior and do "+publish" from the root aggregator project, I get two copies of C-1.0.0.jar produced, and SBT attempts to publish it twice, which is of course a no-no for a maven repository.
2) A build with multiple scala projects, but where one project should only build against a single Scala version. I've tried defining 'scalaVersions' in the settings for this project to hold only one version where the other projects have two, but again "+publish" from a root aggregator seems to ignore this and still compiles it twice, with the second time failing because it's dependencies aren't available for that Scala version. This project is a leaf node in the dependency graph, so it's a perfectly fine thing to want to do logically.
For case #2, I've thought of setting the source dirs for the 'bad' scala version to /dev/null or something similar, but that still actually runs the build and produces an empty artifact. I know I could probably go in and find all of the relevant keys and do something like
publishArtifact := if(scalaBinaryVersion.value == "2.10") false else publishArtifact.value
and then hunt down all of the other related settings/tasks (compile, compile in Test, test in Test, packageBin, etc) but that seems pretty hack-ish. Is there a 'skip' setting somewhere?
I wrote sbt-doge to address task aggregation across subprojects respecting their crossScalaVersions. For Java projects you might need a dummy crossScalaVersion entry.
The plugin sbt-doge can be used to specify a crossScalaVersion setting in each subproject.
First, add the line addSbtPlugin("com.eed3si9n" % "sbt-doge" % "0.1.5") to your projects/plugins.sbt.
To avoid the ridiculous doge syntax ("such compile", really?) you need to enablePlugins(CrossPerProjectPlugin) in your root project. With this, you can add a plus sign before your sbt commands, and they will honor the cross build settings. Just like this: + compile.

How to increase available PermGen space for forked tests?

This is for sbt 0.13.5.
I keep getting Out of PermGen space errors upon running my tests. I created the following in my .bashrc:
export SBT_OPTS="-Xmx2536M -XX:MaxPermSize=4000M"
but it makes no difference.
I'm using
fork in Test := true
Is there a different setting for the fork? How do I figure out how much I'm actually using?
As described in the official documentation of sbt in Forked JVM options:
To specify options to be provided to the forked JVM, set javaOptions.
Use javaOptions scoped to Test configuration to have your tests be running with non-default settings as follows:
javaOptions in Test += "-Xmx8G"
To learn about the current values use inspect:
> show test:javaOptions
[info] List(-Xmx8G)
I don't know how to know the default values when javaOptions is not set explicitly.

Combine sbt tasks from different scopes

I use sbt with the native packager plugin, in order to build Debian packages for our Play 2.2 applications. We use the debian:publish in order to upload the packages to our Artifactory server, and the publish command to publish the regular Java jars.
I'd like to be able to use the regular publish command to published both the jar files and the Debian packages. I think I need to somehow combine the publish task in the Debian scope with the regular one in the Compile scope, but I can't really find any documentation on how to do that.
I came up with the following code, which works, but seems to me to be the 'wrong' way to do it:
publish := { // Also publish deb files
val value = publish.value
(publish in Debian).value
}
Especially the second line seems wrong, since it's ignoring the value. The val is there to quiet a warning, which is another smell.
Is there a better way to do this?
You can use triggeredBy. In your build.sbt add following line:
publish in Debian <<= (publish in Debian).triggeredBy(publish in Compile)
PS. I think the way you did it is also fine. If you're worried about the warning you can assign the result to some val.
Here, the dependsOn task is appropriate, if you don't care about the return value:
publish := publish.dependsOn(publish in Debian).value

Resources