4. Directory Structure
• “src” contains source and resource
files
• “project” directory contains build
code for this project
• “build.properties” is a key-value
properties file for sbt
• “build.sbt” also contains build
information for this project
• “target” directory (not shown)
contains build products
Image source: http://just-thor.com/2013/11/getting-started-with-a-simple-sbt-project/
5. build.sbt
——————— build.sbt —————————————————————
—————————
name := "MyProj"
version := "1.0"
scalaVersion := “2.11.6”
libraryDependencies += "com.google.guava" % "guava" % "18.0"
—————————————————————————————————
———————————————
Remember from part 1, we are setting values to keys:
KEY := VALUE <——- SETTING
KEY[T] := VALUE <——- SETTING[T] - type of value
5
6. sbt REPL
% sbt
[info] Loading project definition from my_project/project
[info] Updating {file: my_project/project/}my_project-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to MyProj (in build file:my_project/)
(Now we are in sbt REPL)
> name
[info] MyProj
> version
[info] 1.0
>
6
7. show & inspect
> show name
[info] MyProj
>
> inspect name
[info] Setting: java.lang.String = MyProj <— Type and Value
[info] Description:
[info] Project name.
[info] Provided by:
[info] {file: my_project/}my_project/*:name
[info] Defined at:
[info] my_project/build.sbt:1 <——— Key “name” that
[info] Reverse dependencies: we set in build.sbt
[info] *:projectInfo
[info] *:normalizedName
[info] *:onLoadMessage
[info] *:description
[info] Delegates: <——— Delegates (more on this later)
[info] *:name
[info] {.}/*:name
[info] */*:name
>
7
9. compile & run
% sbt
[info] Loading project definition from my_project/project
[info] Set current project to MyProj (in build file:my_project/)
> compile
[info] Updating {file:my_project/}my_project...
[info] [SUCCESSFUL ] com.google.guava#guava;18.0!guava.jar(bundle) (28ms)
[info] Done updating.
[info] Compiling 1 Scala source to my_project/target/scala-2.11/classes...
[info] 'compiler-interface' not yet compiled for Scala 2.11.6. Compiling...
[info] Compilation completed in 12.713 s
[success] Total time: 48 s, completed Apr 1, 2015 2:41:55 PM
> run
[info] Updating {file:my_project/}my_project...
[info] Resolving jline#jline;2.12.1 ...
[info] Done updating.
[info] Compiling 1 Scala source to my_project/target/scala-2.11/classes...
[info] Running example.StringSplit
hello
Part: foo
Part: bar
Part: baz
[success] Total time: 5 s, completed Apr 1, 2015 3:04:05 PM
>
9
10. package
> package
[info] Compiling 1 Scala source to my_project/target/scala-2.11/classes...
[info] Packaging my_project/target/scala-2.11/myproj_2.11-1.0.jar ...
[info] Done packaging.
[success] Total time: 1 s, completed Apr 1, 2015 3:21:59 PM
> exit
(Now we are in shell)
% ls -lh target/scala-2.11
drwxr-xr-x 3 renat renat 102B Apr 1 15:21 classes
-rw-r--r-- 1 renat renat 4.2K Apr 1 15:21 myproj_2.11-1.0.jar
10
11. List available tasks
(Now we are in sbt REPL)
> tasks
This is a list of tasks defined for the current project.
It does not list the scopes the tasks are defined in; use the 'inspect' command for that.
Tasks produce values. Use the 'show' command to run the task and print the resulting value.
clean Deletes files produced by the build, such as generated sources, comp…
compile Compiles sources.
console Starts the Scala interpreter with the project classes on the classpath.
… [truncated]
11
12. console
> console
[info] Starting scala interpreter...
[info]
Welcome to Scala version 2.11.6 (Java HotSpot(TM)
64-Bit Server VM, Java 1.7.0_60).
Type in expressions to have them evaluated.
Type :help for more information.
(Now we are in Scala console - with main classpath)
scala> import com.google.common.base.Splitter
import com.google.common.base.Splitter
scala> Splitter.on(' ').split("one two three”)
res0: Iterable[String] = [one, two, three]
scala> example.StringSplit.main(Array[String]())
hello
Part: foo
Part: bar
Part: baz
12
13. More on sbt commands…
• Can issue command directly in shell: “sbt run”
• Can combine commands: “sbt test package”
• clean, publish, publish-local, update, reload
• Plugins can add new keys
13
14. Build script
So far we have been running only with one file
build.sbt in project’s root directory.
Behind the scenes, sbt created a Project object
and appended the contents of project’s
build.sbt to its settings.
Manually creating a project by creating a Scala
file in project directory…
15. Build script
——————— project/MyBuild.scala ———————————————————————————
import sbt._
import sbt.Keys._
object MyBuild extends Build {
lazy val root = (project in file("."))
.settings(
name := "MyProj",
version := "1.0",
scalaVersion := "2.11.6",
libraryDependencies += "com.google.guava" % "guava" % "18.0"
)
}
—————————————————————————————————————————————————
—————————————
Same definition as before with build.sbt file.
Settings in build.sbt will be applied on top of this.
In fact, any .sbt files in a project, will be merged with the build definition for the entire build, but scoped to that
project.
15
16. Scopeslazy val commonSettings = Seq(
organization := "com.example",
version := "0.1.0",
scalaVersion := "2.11.4"
)
lazy val core = (project in file("core"))
.dependsOn(util)
.settings(commonSettings: _*)
.settings(
name := "projCore"
// other settings
)
lazy val util = (project in file("util"))
.settings(commonSettings: _*)
.settings(
name := "projUtil"
// other settings
)
Then in sbt:
> util/name
[info] projUtil
> core/name <— {<build-uri>}<project-id>/config:inkey::key
[info] projCore
> util/name
[info] projUtil
>
16
17. Configurations
A configuration defines a flavor of build, potentially with its own classpath, sources, generated
packages, etc.
The configuration concept comes from Ivy, which sbt uses for managed dependencies Library
Dependencies, and from MavenScopes.
Some configurations you’ll see in sbt:
Compile which defines the main build (src/main/scala).
Test which defines how to build tests (src/test/scala).
Runtime which defines the classpath for the run task.
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.
17
Source: http://www.scala-sbt.org/0.13/tutorial/Scopes.html
18. Scopes again
In build definition:
scalacOptions in Test ++= Seq(“-unchecked")
In REPL:
Test:scalacOptions
General for in REPL is {<build-uri>}<project-id>/config:intask::key
18
19. Plugins
A plugin extends the build definition, most commonly by adding new settings, possibly new tasks.
For example - if you want to create fat jars, there is a plugin for that: plugin “sbt-assembly”.
In project directory create file “assembly.sbt” with the following:
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % “0.11.2”)
This particular plugin brings in new keys, such as:
assembly, assemblyJarName, assemblyMergeStrategy, …
Now in sbt, you can run “assembly”:
> assembly
[info] Including: guava-18.0.jar
[info] Including: scala-library-2.11.6.jar
[info] Checking every *.class/*.jar file's SHA-1.
[info] Merging files...
[warn] Merging 'META-INF/MANIFEST.MF' with strategy 'discard'
[warn] Merging 'META-INF/maven/com.google.guava/guava/pom.properties' with strategy 'discard'
[warn] Merging 'META-INF/maven/com.google.guava/guava/pom.xml' with strategy 'discard'
[warn] Strategy 'discard' was applied to 3 files
[info] SHA-1: db72fdf182c7c5332a145aa4c018466840f9c554
[info] Packaging /Users/renatb/tmp/sm/my_project/target/scala-2.11/MyProj-assembly-1.0.jar ...
[info] Done packaging.
[success] Total time: 5 s, completed Apr 1, 2015 11:51:57 PM
>
19
20. Delegates
A setting has a key and a scope.
A request for a key in a scope A may be delegated to another scope if A doesn't define a
value for the key.
The delegation chain is well-defined and is displayed in the Delegates section of the inspect
command.
The Delegates section shows the order in which scopes are searched when a value is not
defined for the requested key.
> inspect console::initialCommands
...
[info] Delegates:
[info] *:console::initialCommands
[info] *:initialCommands
[info] {.}/*:console::initialCommands
[info] {.}/*:initialCommands
[info] */*:console::initialCommands
[info] */*:initialCommands
...
20
22. Upcoming Meetups
Seattle Spark Meetup
Sparkly Notebook: Interactive Analysis and Visualization with Spark
Wednesday, April 15, 2015 - Avvo - 705 5th Ave South #600, Seattle, WA
Scala at the Sea
Discuss Scala Akka and Related Technologies
Tuesday, April 14, 2015 - Whitepages - 1301 5th Avenue #1600, Seattle, WA
22
Editor's Notes
Notice how we are binding a string “MyProj” to a key “name” - we are using an operation ‘:=‘
If our key value is a list, then we can append to it with ‘+=‘. Here libraryDependencies was already defined, and we are now adding another element to it.
You will need to learn the keys - e.g. libraryDependencies
Typing the key name into REPL evaluates it: name, version
Another way of looking at the value is using “show”: evaluates the specified task and display the value returned by the task.
Another way to find out about a key is with “inspect”:
Inspect: shows where this key was defined
Starts the Scala interpreter with the project classes on the classpath.
Starts the Scala interpreter with the project classes on the classpath.
Example of a multi-project build. If core needed util on its classpath, you would define core as.
Now that we have 2 projects, our keys can be scoped to specific projects
Example of a multi-project build. If core needed util on its classpath, you would define core as.
Now that we have 2 projects, our keys can be scoped to specific projects
Example of a multi-project build. If core needed util on its classpath, you would define core as.
Now that we have 2 projects, our keys can be scoped to specific projects
Example of a multi-project build. If core needed util on its classpath, you would define core as.
Now that we have 2 projects, our keys can be scoped to specific projects