Appendix C. Advanced setting/task API

 

Although this book covers the core of sbt, one thing we didn’t get to touch on as much as we desired was the advanced features of the task/setting system. These features aren’t widely used, but they still come in handy when needed. Here we’ll lay out a few use cases and how to achieve them in sbt.

C.1. Optional settings

It’s possible to define a SettingKey[Option[String]] to represent a setting that may not be set, but sometimes the user may experience having to write this:

optionalSetting := Some("value")

Instead, sbt provides a mechanism to find out if a particular key has a value. If you want to allow the optionalSetting key to not exist in your build, you can use the ? method to assess its value:

myTask := {
   val theValue = optionalSetting.?.value.getOrElse("default")
   println(theValue)
 }

Here the ? on a given key creates a new Intialize[Option[String]], which you can call the .value on to grab the optional String value. The big benefit here is that if a user never sets the optionalSetting key with a value, it won’t break the build.

C.2. Failing tasks

Sometimes it’s desirable to allow tasks to fail. You’d like to catch whether or not a task you depend on fails and to then perform different actions. You can achieve this by converting a TaskKey into its TaskResult, like this:

myTask := {
    otherTask.result.value match {
         case Inc(failure) =>  handleFailure(failure)
         case Value(result) => result
   }
}

C.3. Dynamic tasks

C.4. Composing InputTasks