Writing a Simple SBT Task

In a project I'm working on, I wanted to copy a fat jar to a remote machine for testing.

The sbt-assembly plugin is handy for making a fat jar, but I didn't find any convenient plugins for just copying the jar somewhere. (SBT's built-in publish mechanism is overkill for what I need.)

It turns out that this is an almost trivial task to write. Unfortunately, figuring out exactly how to tie the pieces together isn't exactly straightforward.

I found this set of slides, while not comprehensive, to be about 100x more enlightening than the official sbt documentation. Starting with this slide especially, I "got" how the task could fall together.

The main sticking point for me was trying to figure out how to get the jar filename in my task. As the slides point out, operators that begin with < create a dependency on other values. Specifically, <<=:

declares a dependency and passes the right-hand value or method result to the setting represented by the left-hand key

I started from scratch, not worrying about the jar filename yet, just creating a stub task. The canonical "hello world" task is easily accomplished by adding two lines to build.sbt:

val helloTask = TaskKey[Unit]("hello", "Print hello")

helloTask := println("hello world")

(Note that I'm using SBT 0.13.)

Take note that := in the definition of helloTask means that it's not dependent on any other settings. If we redefine it as follows, it will depend on the assembly task, and the assembly task's value (a java.io.File) will be available in the hello task:

val helloTask = TaskKey[Unit]("hello", "Print hello")

helloTask <<= assembly map { (asm) => println(s"hello ${asm.getName}") }

Now when you run hello at the sbt prompt, it will run all the tasks required to generate the assembly jar, and then print the name of the jar in the hello message.

Armed with this (still shallow!) knowledge, and cribbing from this (obsolete) recipe to accomplish the same goal with an older SBT, let's get dangerous and add this task to build.sbt:

val deployTask = TaskKey[Unit]("deploy", "Copies assembly jar to remote location")

deployTask <<= assembly map { (asm) =>
  val account = "user@example.com" // FIXME!
  val local = asm.getPath
  val remote = account + ":" + "/tmp/" + asm.getName
  println(s"Copying: $local -> $account:$remote")
  Seq("scp", local, remote) !!
}
Posted on 2013-12-17 by brian in scala .
Comments on this post are closed. If you have something to share, please send me email.