How to publish webjar assets with publish/publishLocal in Play 2.3? - sbt

Since Play Framework 2.3 assets are packaged into one jar archive file. I would like to publish this jar automatically with the project, i.e. upon publish or publishLocal I want the assets jar to be published as well.
How to achieve that?

After inspect tree dist I managed to find the task playPackageAssets that generates the assets file:
[play-publish-webjar] $ inspect playPackageAssets
[info] Task: java.io.File
[info] Description:
[info]
[info] Provided by:
[info] {file:/Users/jacek/sandbox/play-publish-webjar/}root/*:playPackageAssets
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:641
[info] Dependencies:
[info] *:playPackageAssets::packageConfiguration
[info] *:playPackageAssets::streams
[info] Reverse dependencies:
[info] *:scriptClasspath
[info] universal:mappings
[info] Delegates:
[info] *:playPackageAssets
[info] {.}/*:playPackageAssets
[info] */*:playPackageAssets
A naive solution might be to attach the assets webjar as is generated by playPackageAssets to publishLocal task's artifacts. Add the following to build.sbt (the types are to show what you work with):
import play.PlayImport.PlayKeys._
packagedArtifacts in publishLocal := {
val artifacts: Map[sbt.Artifact, java.io.File] = (packagedArtifacts in publishLocal).value
val assets: java.io.File = (playPackageAssets in Compile).value
artifacts + (Artifact(moduleName.value, "asset", "jar", "assets") -> assets)
}
Repeat it for the other tasks you want to exhibit similar behaviour.
I'm however quite doubtful it's the best solution.

Related

SBT Autoplugin and task modification with "dependsOn"

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.

SBT Config extend vs DefaultSettings

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.

Different compile options for tests and release in SBT?

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.

"publish" to local maven repo creates only scaladoc jars?

I'm using sbt 0.13.0 and Scala 2.10.3
I wanted to publish an artifact to my local maven repo so I added the following to build.sbt:
publishMavenStyle := true
publishTo := Some(Resolver.file("file", new File(Path.userHome.absolutePath+"/.m2/repository")))
artifactName := {
(sv: ScalaVersion, module: ModuleID, artifact: Artifact) =>
artifact.name + "-" + module.revision + "." + artifact.extension
}
When I use publish cmd jars are created in my home .m2 directory but there are of the same content meaning they only contain scaladocs - only html, css and js files.
This is my second time I'm publishing my artifact in this project. Last time it worked perfectly. Most of the classes changed their packages, can this be the reason, and how to fix this?
Remove artifactName and it should work fine again.
Why do you redefine it (as it now breaks publish)? What's the initial goal?
[sbt-0-13-1]> about
[info] This is sbt 0.13.1
[info] The current project is {file:/Users/jacek/sandbox/so/sbt-0.13.1/}sbt-0-13-1 0.1-SNAPSHOT
[info] The current project is built against Scala 2.10.3
[info] Available Plugins: com.typesafe.sbt.SbtGit, com.typesafe.sbt.SbtProguard, growl.GrowlingTests, np.Plugin, com.timushev.sbt.updates.UpdatesPlugin
[info] sbt, sbt plugins, and build definitions are using Scala 2.10.3
[sbt-0-13-1]> help artifactName
Function that produces the artifact name from its definition.
[sbt-0-13-1]> inspect artifactName
[info] Setting: scala.Function3[sbt.ScalaVersion, sbt.ModuleID, sbt.Artifact, java.lang.String] = <function3>
[info] Description:
[info] Function that produces the artifact name from its definition.
[info] Provided by:
[info] */*:artifactName
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:533
[info] Reverse dependencies:
[info] *:makePom::artifactPath
[info] Delegates:
[info] *:artifactName
[info] {.}/*:artifactName
[info] */*:artifactName
[info] Related:
[info] */*:artifactName
See how the default implementation is defined in sbt.Artifact.

Accessing managedClasspath of sbt subprojects

I'm converting an sbt 0.7.x build script to sbt 0.11.2. I'm writing a task to collect various JARs together from subprojects. In the old build, part of the task does the following:
deployedProjects.foreach {
p: BasicScalaProject =>
p.managedClasspath(config("compile")) --- p.managedClasspath(config("provided"))
// etc
}
How can I do the equivalent in sbt 0.11?
Updated to add:
In particular:
How can I write a task that depends on a list of settings/tasks? For example, how would I write a task that depends on all the managedClasspaths from a List of subprojects (without bundling it all into a tuple).
Is there a particular scope for getting the managed jars that are or are not marked as "provided"?
In sbt 0.11.x there is the task managedClasspath:
> inspect managed-classpath
[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/heiko/tmp/test/}default-f3fb6c/compile:managed-classpath
[info] Dependencies:
[info] compile:classpath-configuration
[info] compile:classpath-types
[info] compile:update
[info] Reverse dependencies:
[info] compile:external-dependency-classpath
[info] Delegates:
[info] compile:managed-classpath
[info] *:managed-classpath
[info] {.}/compile:managed-classpath
[info] {.}/*:managed-classpath
[info] */compile:managed-classpath
[info] */*:managed-classpath
[info] Related:
[info] test:managed-classpath
[info] runtime:managed-classpath
Looking at the delegates you see that you can scope this task to various configurations, e.g. compile:
> show compile:managed-classpath
[info] Updating {file:/Users/heiko/tmp/test/}default-f3fb6c...
[info] Resolving org.scala-lang#scala-library;2.9.1 ...
[info] Done updating.
[info] ArraySeq(Attributed(/Users/heiko/.sbt/boot/scala-2.9.1/lib/scala-library.jar))

Resources