14 Oct 2015

SBT Tricks

Dear Richard: these are the SBT tricks you should have known about. They are the ones you wish you could remember just when you need them, but you don’t. So here they are written down.

Changing JVM Options

Mid-session you sometimes want to change JVM flags. The javaOptions setting is good for that. For example..

Trace Typesafe Config Files

project foo
set javaOptions := Seq("-Dconfig.trace=loads")
run

Cheap and Cheerful Profiling

Nothing like as good as Mission Control or JProfiler, but still…

project foo
set fork in run := true
set javaOptions in run += "-agentlib:hprof=cpu=samples"
runMain code.MyMain

…and then look in foo/java.hprof.txt.

Triggered Execution

You usually prefer ~test:compile over ~compile when writing code.

You always want the console cleaned at the the start of each run:

triggeredMessage in ThisBuild := Watched.clearWhenTriggered

You sometimes need test:run or test:runMain when that important application is in src/test/scala.

Stopping

When you run an application and CTRL-C it, it’s annoying if that exits sbt. Prevent that with:

cancelable in Global := true

Latest Dependencies

Ivy dependencies allow you to select “latest.integration” as the revision number:

addSbtPlugin("org.ensime" % "ensime-sbt" % "latest.integration")

This will give you the latest and greatest version. Use it for global plugins (see below) for you development environment. Avoid it for core build dependencies because you want a reproducible build at all times.

The Place for Everything

  • ~/.sbt/0.13/plugins/ folder for the plugins you use everywhere, such as ensime-sbt.

  • ~/.sbt/0.13/global.sbt for settings relating to those plugins.

  • ~/.sbtrc for commands you expect to run.

  • /usr/local/etc/sbtopts exists, and you hope to never have to touch it.

For example:

$ cat ~/.sbt/0.13/plugins/build.sbt
addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "latest.integration")
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")
addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "latest.integration")
addSbtPlugin("org.ensime" % "ensime-sbt" % "latest.integration")

$ cat ~/.sbt/0.13/global.sbt
net.virtualvoid.sbt.graph.Plugin.graphSettings
triggeredMessage in ThisBuild := Watched.clearWhenTriggered
cancelable in Global := true

$ cat ~/.sbtrc
alias cd = project

Although you typically shovel everything into build.sbt, sbt will read all the .sbt files in those folders.

Defining Commands

E.g.,

$ cat ~/.sbt/0.13/clear.sbt
// Handy `clear` command:
def clearConsoleCommand = Command.command("clear") { state =>
  val cr = new jline.console.ConsoleReader()
  cr.clearScreen
  state
}

commands += clearConsoleCommand

Problem Solving

It’s always something to do with scopes.

You can find the value of a setting in a particular scope using inspect:

inspect project1/libraryDependencies
inspect project2/libraryDependencies

So sometimes you want to make a setting the same for all projects in a build:

scalaVersion in ThisBuild := "2.11.7"

You should regularly re-read the scoping rules.

Other Ideas

A version of this post appears over at Underscore.io. It includes comments and other tips submitted by the community.