Some(SBT)





By



Sam Smoot
.NET
Ruby
Other Things

Scala is the closest I've ever been to being a Rocket Scientist :-p

http://substantiality.net
(When I bother to make sure it's online.)
ssmoot@gmail.com
@srsmoot



Chris Gibson
.NET
Perl
Ruby
Rails
Beer
Hates Musicals

"I think Scala... TBD"

@chrislgibson

¡Inspirado!



Introduction

What is SBT?




Simple Build Tool

(Scala Build Tool?)

Features

  • Scala REPL
  • Framework for Writing Tasks
  • Continuous Testing
  • Incremental Compilation
  • Documentation Generation
  • Manages Packaged Dependencies (JARs)
  • Manages Source Dependencies (File, or Git)
  • Packaging
  • Deployment
  • Builds Mixed Scala/Java Projects
  • Aggregate Multiple Projects
  • Manage Dependencies Between Projects

Installation


(Official Docs)


OSX

brew install sbt

Commands


  • help
  • clean
  • compile
  • console
  • exit
  • project
  • reload
  • run
  • session
  • set
  • show
  • test
  • test-only
  • update

Structure of a SBT Project


  • Sources in the base directory
  • Sources in src/main/scala or  src/main/java
  • Tests in src/test/scala or  src/test/java
  • Data files in src/main/resources or  src/test/resources
  • jars in lib

Basic Maven layout.

If you're working at a Java shop you might be able to replace Maven with SBT today.

SBT Files


build.sbt


Recursive (in multi-project structures)

project/Build.scala


For arbitrary Scala code like writing Tasks, or to define intra-project dependencies in a multi-project build definition.

project/build.properties






sbt.version=0.12.2

project/plugins.sbt






addSbtPlugin("play" % "sbt-plugin" % "2.1.0")

build.sbt Vs Build.scala


Don't Worry, Be Happy




My First SBT Project


Giter8


https://github.com/wiecklabs/wieck-scala.g8

Create a template project using your favorite SBT settings, then use it to quickly generate new projects.

g8 wiecklabs/wieck-scala 

Interactive


Minimal

$ mkdir example$ cd example$ sbt> set name := "bob"> session save> exit

Baseline
> set name := "bob"> set version := "1.0-SNAPSHOT"> set scalaVersion := "2.10.1"

None At All


$ cat <<EOS | tee Hi.scala > /dev/null
object Hi {
  def main(args: Array[String]) = println("Hi!")
}
EOS

$ sbt run[info] Loading global plugins from /Users/sam/.sbt/plugins
[info] Set current project to default-3da5a3 (in build file:/Users/sam/src/example/)
[info] Updating {file:/Users/sam/src/example/}default-3da5a3...
[info] Resolving org.scala-lang#scala-library;2.9.2 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/sam/src/example/target/scala-2.9.2/classes...
[info] Running Hi 
Hi!
[success] Total time: 2 s, completed May 22, 2013 3:17:06 PM

Pro-Tip


Use the right Scala

$ sbt ++2.10.1 run[info] Loading global plugins from /Users/sam/.sbt/plugins
[info] Set current project to default-3da5a3 (in build file:/Users/sam/src/example/)
Setting version to 2.10.1
[info] Set current project to default-3da5a3 (in build file:/Users/sam/src/example/)
[info] Updating {file:/Users/sam/src/example/}default-3da5a3...
[info] Resolving org.scala-lang#scala-library;2.10.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to /Users/sam/src/example/target/scala-2.10/classes...
[info] Running Hi 
Hi!

There Can Be Only One?

$ cd example$ lsHi.scala$ cat <<EOS | tee Hello.scala > /dev/null
object Hello {
  def main(args: Array[String]) = println("Hello!")
}
EOS
$ lsHi.scala Hello.scala$ sbt ++2.10.1 run [info] Loading global plugins from /Users/sam/.sbt/plugins [info] Set current project to default-3da5a3 (in build file:/Users/sam/src/example/) Setting version to 2.10.1 [info] Set current project to default-3da5a3 (in build file:/Users/sam/src/example/) Multiple main classes detected, select one to run: [1] Hi [2] Hello Enter number: 2 [info] Running Hello Hello! [success] Total time: 2 s, completed May 22, 2013 3:54:42 PM

From Scratch


$ mkdir example$ cd example$ mkdir project$ echo "sbt.version=0.12.2" | tee project/build.properties$ vim build.sbt

build.sbt Syntax


  • Blank line between expressions
  • %% means "Current Scala Version"
  • := is for binding, not assignment
  • Dependencies are scoped
  • Build commands are scoped

InAction

name := "scube"

version := "1.0-SNAPSHOT"

scalaVersion := "2.10.1"

scalacOptions in ThisBuild ++= Seq(
    "-language:_",
    "-feature",
    "-unchecked",
    "-deprecation")

resolvers ++= Seq(
    "Maven Central" at "http://repo1.maven.org/maven2",
    "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/")

testOptions in Test := Nil

parallelExecution in Test := false

libraryDependencies ++= Seq(
  "joda-time" % "joda-time" % "2.2" % "test",
  "org.joda" % "joda-convert" % "1.2" % "test",
  "com.typesafe" %% "scalalogging-slf4j" % "1.0.1",
  "org.codehaus.janino" % "janino" % "2.6.1",
  "ch.qos.logback" % "logback-classic" % "1.0.13",
  "org.scalatest" %% "scalatest" % "2.0.M5b" % "test",
  "net.databinder.dispatch" %% "dispatch-core" % "0.10.0",
  "com.typesafe" % "config" % "1.0.0")

The POWTJW


How would you get the classpath for an SBT project?

 → sbt
> show classpath
[error] Not a valid key: classpath (similar: full-classpath, classpath-types, classpath-filter)
> show full-classpath
[info] Compiling 14 Scala sources to /Users/sam/src/scube/target/scala-2.10/classes...
[info] List(Attributed(/Users/sam/src/scube/target/scala-2.10/classes), Attributed(/Users/sam/.sbt/boot/scala-2.10.1/lib/scala-library.jar), Attributed(/Users/sam/.ivy2/cache/com.typesafe/scalalogging-slf4j_2.10/jars/scalalogging-slf4j_2.10-1.0.1.jar), Attributed(/Users/sam/.ivy2/cache/org.scala-lang/scala-reflect/jars/scala-reflect-2.10.0.jar), Attributed(/Users/sam/.ivy2/cache/net.databinder.dispatch/dispatch-core_2.10/jars/dispatch-core_2.10-0.10.0.jar), Attributed(/Users/sam/.ivy2/cache/com.ning/async-http-client/jars/async-http-client-1.7.11.jar), Attributed(/Users/sam/.ivy2/cache/io.netty/netty/bundles/netty-3.6.3.Final.jar), Attributed(/Users/sam/.ivy2/cache/com.typesafe/config/bundles/config-1.0.0.jar))
[success] Total time: 7 s, completed May 23, 2013 2:01:28 PM
The Principle of Wow That Just Wokred!

Grumpy Cat



Task Mastery


Hello World




import sbt._import Keys._
object HelloBuild extends Build {
val hello = TaskKey[Unit]("hello", "Prints 'Hello World!'") val helloTask = hello := println("Hello World!")
lazy val main = Project("HelloWorld", file(".")) settings helloTask
}

Discovering Tasks





$ sbt> tasks             # Displays the main tasks
> tasks -v          # Displays additional tasks
> help tasks -V     # Displays all tasks

Having Arguments






$ sbt> my-task -- --some-option=foo -Z

Pro-Tip

(Use the Tilde Luke!)


$ sbt
> ~test
> ~test-only
> ~compile
> ~run
~clean

Working With Multiple Projects



Project

Where you define project names, paths, settings.


RootProject

A Reference to an external Project (like a github repository).

Running Commands in Sub-Projects




$ sbt> ming/test> flash/test> test> play/run> project play> run^D> test> project /

Aggregating Projects


import sbt._
import Keys._
import play.Project._

object ApplicationBuild extends Build {
  lazy val root = Project(id = "farm", base = file(".")).
    aggregate(util, io, data, web, migrations)

  lazy val util = Project("farm-util", file("farm-util")).dependsOn(hasher)
  lazy val utilWithTest = util % "test->test;compile->compile"

  lazy val io = Project("farm-io", file("farm-io"))

  lazy val data = Project("farm-data", file("farm-data")).dependsOn(utilWithTest)

  lazy val web = play.Project("farm-web", path = file("farm-web")).
    settings(libraryDependencies += "io.spray" %%  "spray-json" % "1.2.3").
    dependsOn(utilWithTest, io, data, hasher)

  lazy val hasher = RootProject(uri("git://github.com/Nycto/Hasher.git"))
}

build.sbt for Aggregate Project


name := "Farm"

version := "1.0-SNAPSHOT"

scalaVersion in ThisBuild := "2.10.1"

scalacOptions in ThisBuild ++= Seq(
    "-language:_",
    "-feature",
    "-unchecked",
    "-deprecation")

testOptions in Test := Nil

parallelExecution in Test := false

resolvers ++= Seq(
    "Maven Central" at "http://repo1.maven.org/maven2",
    "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/")

libraryDependencies += "org.scalatest" %% "scalatest" % "2.0.M5b" % "test"

in ThisBuild







Applies to all projects/contexts in the Build.

build.sbt for Child Project


name := "farm-data"
version := "1.0-SNAPSHOT"

parallelExecution in Test := false

libraryDependencies ++= Seq(
    "net.databinder.dispatch" %% "dispatch-core" % "0.10.0",
    "com.typesafe.akka" %% "akka-actor" % "2.1.0",
    "com.typesafe.akka" %% "akka-testkit" % "2.1.0",
    "com.typesafe" %% "scalalogging-slf4j" % "1.0.1",
    "joda-time" % "joda-time" % "2.2",
    "org.joda" % "joda-convert" % "1.2" % "compile",
    "com.typesafe.akka" %% "akka-slf4j" % "2.1.0",
    "ch.qos.logback" % "logback-classic" % "1.0.1" % "runtime")

That Feeling?

It's The Feel of Winning.


Global Configuration


Resolving PermGen Errors
$ cat ~/.sbtconfig
SBT_OPTS="-XX:+UseConcMarkSweepGC -XX:+CMSClassUnloadingEnabled -XX:PermSize=256M -XX:MaxPermSize=512M"
Plugins
$ cat ~/.sbt/plugins/build.sbt
logLevel := Level.Warn

resolvers += "Maven Central" at "http://repo1.maven.org/maven2/"

resolvers += "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/"

addSbtPlugin("com.github.mpeltonen" % "sbt-idea" % "1.4.0")

addSbtPlugin("org.ensime" % "ensime-sbt-cmd" % "0.1.1")

IntelliJ IDEA Plugin



$ sbt
> gen-idea

Sharing Your Code



Nexus
(If you can figure it out)


Ivy
(Just scp the files up somewhere)


Source
(Stick it in a public git repository)

Documentation


History


SBT < 0.10.0


Problems


  • Starting a Play app in a multi-project Build
  • PermGen
  • Typesafe Repository
  • Debugger Integration (I am not a smart man)
  • Actor Systems (making a clean exit)


Ctrl-C


Further Reading




Josh Suereth's "SBT in Action" MEAP Book
(covers SBT version 0.13.0)

Summary



"At the very root of the Scala eco-system, lies SBT."

-Sam Smoot © 2013

SBT is to Scala, as RVM, RDoc, Rubygems, Bundler, Rake, Rackup
and Continuous Testing is to Ruby. Ruby wouldn't be Ruby without those, and Scala wouldn't be the Scala you know without SBT.

Thank You



Mark Harrah

For writing the best build/test/run/compile/packaging tool ever written.




Some(SBT)

By Sam Smoot