I have a project where I need to disable assertions when creating the binaries. Now I could just do:
scalacOptions += "-Xdisable-assertions"
But then also the unit tests would be run without assertions. Is there a (hopefully) simple way to achieve what I need?
How do you create the binaries? What task/command do you use?
Use the task as the scope for scalacOptions to have different values for them. See Scoping by configuration axis:
By default, all the keys associated with compiling, packaging, and
running are scoped to a configuration and therefore may work
differently in each configuration. The most obvious examples are the
task keys compile, package, and run; but all the keys which affect
those keys (such as sourceDirectories or scalacOptions or
fullClasspath) are also scoped to the configuration.
Use inspect when in doubt.
> inspect scalacOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options for the Scala compiler.
[info] Provided by:
[info] {file:/C:/dev/sandbox/task-dependsOn/}task-dependson/compile:scalacOptions
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:1424
[info] Dependencies:
[info] task-dependson/compile:autoCompilerPlugins
[info] task-dependson/compile:settingsData
[info] task-dependson/compile:update
[info] task-dependson/compile:buildDependencies
[info] task-dependson/compile:thisProjectRef
[info] Delegates:
[info] task-dependson/compile:scalacOptions
[info] task-dependson/*:scalacOptions
[info] {.}/compile:scalacOptions
[info] {.}/*:scalacOptions
[info] */compile:scalacOptions
[info] */*:scalacOptions
[info] Related:
[info] b/compile:scalacOptions
[info] b/test:scalacOptions
[info] task-dependson/test:scalacOptions
[info] task-dependson/jacoco:scalacOptions
[info] a/jacoco:scalacOptions
[info] */*:scalacOptions
[info] a/test:scalacOptions
[info] a/compile:scalacOptions
[info] b/jacoco:scalacOptions
The Compile configuration scope is the default one (see show defaultConfiguration for a project) so scalacOptions += "-Xdisable-assertions" is in fact scalacOptions in Compile += "-Xdisable-assertions". Use different configuration, say Test, and you'll get different results.
There's however a hitch in SBT (I missed the very first time I responded) - settings are chained and when a setting is not defined in a scope, it gets its value from a more general scope. When I said, scalacOptions +=... is in fact scalacOptions in Compile I missed the important feature of settings - scalacOptions is global while scalacOptions in Compile is Compile-scoped.
Related
I found this in the root build.sbt
skip in test := true
What does it do? I cannot find any reference regarding this in sbt documents. I'm using sbt 1.3.8 in my Scala project.
If set to true, the test task won't run and no test will be executed.
In your context, no test of the root project will be executed.
One way to know what the task is doing and how it used by other tasks is to run inspect task.
sbt "inspect test:skip"
Produces:
[info] Task: Boolean
[info] Description:
[info] For tasks that support it (currently only 'compile', 'update', and 'publish'), setting skip to true will force the task to not to do its work. This exact semantics may vary by task.
[info] Provided by:
[info] Global / skip
[info] Defined at:
[info] (sbt.Defaults.globalSbtCore) Defaults.scala:294
[info] Delegates:
[info] Test / skip
[info] Runtime / skip
[info] Compile / skip
[info] skip
[info] ThisBuild / Test / skip
[info] ThisBuild / Runtime / skip
[info] ThisBuild / Compile / skip
[info] ThisBuild / skip
[info] Zero / Test / skip
[info] Zero / Runtime / skip
[info] Zero / Compile / skip
[info] Global / skip
[info] Related:
[info] Global / skip
With description
For tasks that support it (currently only 'compile', 'update', and 'publish'), setting skip to true will force the task to not to do its work. This exact semantics may vary by task.
I'm unable to understand the difference between the following expressions. The expressions a reduced -- the real world case has more settings distributed in seperate objects.
specified directly as sequence
Seq(libraryDependencies +=
"org.openjdk.jmh" % "jmh-core" % "1.6.2" % "compile")
wrapped in inConfig
inConfig(Compile)(libraryDependencies +=
"org.openjdk.jmh" % "jmh-core" % "1.6.2" % "compile")
In both cases show compile:libraryDependencies shows the same
[info] List(org.scala-lang:scala-library:2.10.4, org.openjdk.jmh:jmh-core:1.6.2:compile)
but for show compile:managedClasspath the dependency towards JMH is only shown in the first case. As a result the normal compiler run fails due to unresolvable classes.
Please explain or point the logical difference between both cases.
TLDR: Use % "compile" not Compile when declaring libraryDependencies
What you're seeing is a gap, possibly a bug, in how sbt tries to use Ivy's module configurations (such as compile) as one of its setting scopes.
For reference:
Official docs about Scopes
Blog post about sbt "dimensions"
The problem lies that, currently, you can declare the configuration at both the value level:
"org.openjdk.jmh" % "jmh-core" % "1.6.2" % "compile"
and the key level:
inConfig(Compile)(libraryDependencies += xyz)
or alternatively:
libraryDependencies in Compile += xyz
As you say in both examples show compile:libraryDependencies shows the same sequence, but show libraryDependencies demonstrates that you only added jmh-core in the Compile axes of libraryDependencies:
show libraryDependencies
[info] List(org.scala-lang:scala-library:2.10.4, org.openjdk.jmh:jmh-core:1.6.2:compile)
show libraryDependencies
[info] List(org.scala-lang:scala-library:2.10.4)
This then leads as to why show compile:managedClasspath is different.
Have a look at what inspect actual compile:managedClasspath outputs:
[info] Task: scala.collection.Seq[sbt.Attributed[java.io.File]]
[info] Description:
[info] The classpath consisting of external, managed library dependencies.
[info] Provided by:
[info] {file:/Users/dnw/Desktop/t-2015-04-08.0540/}t-2015-04-08-0540/compile:managedClasspath
[info] Defined at:
[info] (sbt.Classpaths) Defaults.scala:991
[info] Dependencies:
[info] *:update
[info] */*:classpathTypes
[info] compile:classpathConfiguration
[info] compile:managedClasspath::streams
[info] Reverse dependencies:
[info] compile:externalDependencyClasspath
[info] Delegates:
[info] compile:managedClasspath
[info] *:managedClasspath
[info] {.}/compile:managedClasspath
[info] {.}/*:managedClasspath
[info] */compile:managedClasspath
[info] */*:managedClasspath
[info] Related:
[info] test:managedClasspath
[info] runtime:managedClasspath
The thing to note is its dependency on *:update, which isn't scoped to compile. From there it eventually leads to *:libraryDependencies which in your second example doesn't include jmh-core.
I've created an Autoplugin for an SBT project to launch middleware inside Docker containers for integration tests (Zookeeper and Kafka).
My first version without Autoplugin was to add manually in the projects settings such as :
(test in Test) <<= (test in Test) dependsOn zkStart
That was working very well.
Now with an Autoplugin, I've the following code
override def projectSettings: Seq[Def.Setting[_]] = Seq(
(test in Test) <<= (test in Test) dependsOn ZookeeperPlugin.zkStart
)
but Zookeeper is no longer start before tests.
when I do
[core_akka_cluster] $ inspect test
[info] Task: Unit
[info] Description:
[info] Executes all tests.
[info] Provided by:
[info] {file:/Users/xx/Projects/../../}core_akka_cluster/test:test
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:394
We can see that the setting test:test is provided by the default SBT values.
When I manually add the previous settings in the build definition of my project, this works once more and we have the following analysis
[core_akka_cluster] $ inspect test
[info] Task: Unit
[info] Description:
[info] Executes all tests.
[info] Provided by:
[info] [info] {file:/Users/xx/Projects/../../}core_akka_cluster/test:test
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:394
[info] (com.ingenico.msh.sbt.KafkaPluginSettings) KafkaPlugin.scala:36
Any idea about precedence in this case?
Thanks
Are you making the auto plugin a triggered plugin?
Since test is also added by an auto plugin (JvmPlugin) by sbt, you should require JvmPlugin.
I've migrated my project to 0.13.5 and started using the xsbt-web-plugin.
I'd like to configure logback to be using a configuration file outside the classpath which is set by a system property logback.configurationFile (so I can keep the logconfig outside the war file).
Previously I would simply set:
System.setProperty("logback.configurationFile", "/some/path/logback.xml")
inside the project/build.scala and logback would pick it up.
However, after upgrading sbt to 0.13.5 and migrating to the xsbt-web-plugin system properties set in sbt don't seem to be available at runtime(jetty).
I've tried setting system properties in different ways, also by passing it along using the -D flag when starting sbt.
On the sbt console I can see the property:
eval sys.props("logback.configurationFile")
[info] ans: String = /some/path/logback.xml
But it's not available inside the webapp.
Any ideas on how to set system properties to be available inside the webapp?
I've tried both jetty() and tomcat(). Same behaviour.
Update:
I ended up with:
jetty(options = new ForkOptions(runJVMOptions = Seq("-Dlogback.configurationFile=/some/path/logback.xml")))
that works.
Use javaOptions in container += "-Dlogback.configurationFile=/some/path/logback.xml" as described in Set forked JVM options.
javaOptions alone (without in container) should work, too, as could be seen in inspect actual under Dependencies and Delegates:
[play-new-app] $ inspect actual container:javaOptions
[info] Task: scala.collection.Seq[java.lang.String]
[info] Description:
[info] Options passed to a new JVM when forking.
[info] Provided by:
[info] {file:/Users/jacek/sandbox/play-new-app/}root/container:javaOptions
[info] Defined at:
[info] /Users/jacek/sandbox/play-new-app/build.sbt:26
[info] Dependencies:
[info] */*:javaOptions
[info] Delegates:
[info] container:javaOptions
[info] *:javaOptions
[info] {.}/container:javaOptions
[info] {.}/*:javaOptions
[info] */container:javaOptions
[info] */*:javaOptions
[info] Related:
[info] */*:javaOptions
If I define an SBT config with
val MyConfig = config("my") extend Test
is that basically the same as doing
val MyConfig = config("my")
val mySettings = inConfig(MyConfig)(Defaults.testSettings)
and then importing mySettings inside a build definition ?
No, calling extend method is not the same thing as calling inConfig. extend just returns a new configuration with passed in configurations prepended extendsConfigs, and it will not introduce any new settings.
When you add MyConfig into the project, it becomes part of the scoped key resolution path:
val MyConfig = config("my") extend Test
val root = (project in file(".")).
configs(MyConfig)
Suppose you type my:test in the sbt shell. Since test task is not found under my configuration, it will traverse extendsConfigs and check if the tasks are available under them. The first one it's going to hit is Test since we prepended it. You can check this by running inspect my:test:
root> inspect my:test
[info] Task: Unit
[info] Description:
[info] Executes all tests.
[info] Provided by:
[info] {file:/Users/eugene/work/quick-test/sbt-so/}root/test:test
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:365
[info] Delegates:
[info] my:test
[info] test:test
[info] runtime:test
[info] compile:test
[info] *:test
[info] {.}/my:test
[info] {.}/test:test
[info] {.}/runtime:test
[info] {.}/compile:test
[info] {.}/*:test
[info] */my:test
[info] */test:test
[info] */runtime:test
[info] */compile:test
[info] */*:test
[info] Related:
[info] test:test
"Provided by" says it delegated to root/test:test. This mechanism allows you to share some of the settings but override others, but you still have to know the inner wiring of the settings scoped to tasks etc, so it's tricky business. You probably already know, but I'll link to Additional test configurations, which specifically discusses configurations for testing.