Accessing managedClasspath of sbt subprojects - sbt

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))

Related

Why does setting (test in assembly) give type error?

I'm using sbt 0.13.8 and sbt-assembly 0.13.0 in a multi-module project. Everything works great until I try to turn off tests during assembly.
As instructed in the docs I add the line
test in assembly := {}
in the settings of one of my modules and get the following error
/Users/lanny/work/IdeaProjects/Search/build.sbt:61: error: type mismatch;
found : sbt.TaskKey[sbt.File]
required: java.io.File
test in assembly := {},
^
sbt.compiler.EvalException: Type error in expression
I'd be happy to show the results of 'inspect test' but alas, I cannot run sbt without removing the line causing the error. Here's what I see with the line removed.
[info] Set current project to search-hadoop (in build file:/Users/lanny/work/IdeaProjects/Search/)
> inspect assembly::test
[info] Task: Unit
[info] Description:
[info] Executes all tests.
[info] Provided by:
[info] {file:/Users/lanny/work/IdeaProjects/Search/}hadoop/*:assembly::test
[info] Defined at:
[info] (sbtassembly.AssemblyPlugin) AssemblyPlugin.scala:32
[info] Dependencies:
[info] hadoop/test:test
[info] Reverse dependencies:
[info] hadoop/*:assemblyPackageScala::test
[info] hadoop/*:assemblyPackageDependency::test
[info] hadoop/*:assembly
[info] Delegates:
[info] hadoop/*:assembly::test
[info] hadoop/*:test
[info] {.}/*:assembly::test
[info] {.}/*:test
[info] */*:assembly::test
[info] */*:test
[info] Related:
[info] test/*:assemblyPackageDependency::test
[info] third_party/test:test
[info] third_party/*:assemblyPackageDependency::test
[info] search/*:assembly::test
[info] search/*:assemblyPackageScala::test
[info] server/*:assemblyPackageDependency::test
[info] search/*:assemblyPackageDependency::test
[info] server/test:test
[info] hadoop/test:test
[info] hadoop/*:assemblyPackageScala::test
[info] ...
sbt.Keys.test in assembly := {}
does the trick.
As stated in the documentation, for sbt 0.13.6+, add this line to your project/assembly.sbt
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.2")

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

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.

How to specify additional source directory for scaladoc?

I have a bit of a nonstandard sbt build setup due to the need to use both Eclipse and sbt.
My sources are in src/main/scala and src/com/companyname/[folder1, folder2, etc] directories.
How can I set up sbt so it also generates documentation for these additional folderX folders under src/com/companyname?
tl;dr Use the following in build.sbt:
unmanagedSourceDirectories in Compile += sourceDirectory.value
inspect is your friend.
> inspect doc
[info] Task: java.io.File
[info] Description:
[info] Generates API documentation.
[info] Provided by:
[info] {file:/Users/jacek/sandbox/scaladoc/}scaladoc/compile:doc
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:706
[info] Dependencies:
[info] compile:doc::configuration
[info] compile:doc::sources
[info] compile:doc::apiMappings
[info] compile:doc::target
[info] compile:doc::fileInputOptions
[info] compile:doc::streams
[info] compile:doc::compilers
[info] compile:doc::scalacOptions
[info] compile:doc::dependencyClasspath
[info] compile:doc::maxErrors
[info] compile:doc::javacOptions
[info] Reverse dependencies:
[info] *:copyDocAssetsTask
[info] Delegates:
[info] compile:doc
[info] *:doc
[info] {.}/compile:doc
[info] {.}/*:doc
[info] */compile:doc
[info] */*:doc
[info] Related:
[info] test:doc
Under Dependencies you'll find that doc task depends on compile:doc::sources among other things. Use inspect again with the setting.
> inspect compile:doc::sources
[info] Task: scala.collection.Seq[java.io.File]
[info] Description:
[info] All sources, both managed and unmanaged.
[info] Provided by:
[info] {file:/Users/jacek/sandbox/scaladoc/}scaladoc/compile:sources
[info] Defined at:
[info] (sbt.Defaults) Defaults.scala:187
[info] Reverse dependencies:
[info] compile:doc
[info] Delegates:
[info] compile:doc::sources
[info] compile:sources
[info] *:doc::sources
[info] *:sources
[info] {.}/compile:doc::sources
[info] {.}/compile:sources
[info] {.}/*:doc::sources
[info] {.}/*:sources
[info] */compile:doc::sources
[info] */compile:sources
[info] */*:doc::sources
[info] */*:sources
[info] Related:
[info] compile:sources
[info] test:sources
Under Dependencies you find that it depends on compile:sources and following along you find that you should change unmanagedSourceDirectories setting to have what you want.

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.

Resources