The Simple Build Tool (sbt) is the standard build technology for Scala and Lift applications. However, if you are new to Scala and Lift, trying to learn sbt at the same time can be a little confusing. The aim of this article is to give you enough knowledge about both sbt and Lift to be able to build and debug a simple Lift application using sbt 0.7. We’ll start with a “blank” Lift app and do the following:
- Run some sample sbt commands to become familiar with sbt.
- Examine the sbt directory structure.
- Look at the sbt LiftProject.scala configuration file that is used to build the blank Lift app.
- Examine Lift’s Boot.scala, web.xml and default.html that are used for all Lift apps.
- Add in the Lift chat server classes from David Pollack’s example and rebuild and retest the project.
No prior knowledge of Lift, sbt, or even Scala is assumed. This tutorial uses sbt 0.7 because that is what Lift currently uses. However, sbt is evolving fast and version 0.10 has a number of key differences. I’ll try and point these out in the tutorial so that you don’t get caught out if you decide to play around with a later version of sbt.
You can download Lift from:
The version I’m using for this tutorial is 2.4-M4. If you open up the Lift directory, you’ll see it has two subdirectories, one called “scala_28″ and one called “scala_29″. Each of these directories contains four templates:
We’ll use the Scala 2.8 lift_blank template, so take a copy of the directory and rename it. On my system it is c:\lift-chat-tutorial.
Basic sbt commands
To get familiar with sbt, you can try a few a simple commands. Change to the directory you have just created and start up an interactive command prompt by typing “sbt”. sbt is self-bootstrapping, so what you are actually doing is running a small piece of launch code which will download the main sbt code using Apache Ivy. You should be able to see the main parts of sbt being downloaded:
C:\lift-chat-tutorial>sbt C:\lift-chat-tutorial>set SCRIPT_DIR=C:\lift-chat-tutorial\ C:\lift-chat-tutorial>java -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -Xmx512M -Xss2M -jar "C:\lift-chat-tutorial\\sbt-launcher.jar" Getting Scala 2.7.7 ... :: retrieving :: org.scala-tools.sbt#boot-scala confs: [default] 2 artifacts copied, 0 already retrieved (9911kB/264ms) Getting org.scala-tools.sbt sbt_2.7.7 0.7.5 ... :: retrieving :: org.scala-tools.sbt#boot-app confs: [default] 16 artifacts copied, 0 already retrieved (4271kB/594ms) [info] Recompiling project definition... [info] Source analysis: 1 new/modified, 0 indirectly invalidated, 0 removed. Getting Scala 2.8.1 ... :: retrieving :: org.scala-tools.sbt#boot-scala confs: [default] 2 artifacts copied, 0 already retrieved (15118kB/302ms) [info] Building project Lift SBT Template 0.1 against Scala 2.8.1 [info] using LiftProject with sbt 0.7.5 and Scala 2.7.7
sbt uses Apache Ivy to manage dependencies, so downloaded files are put in a local Ivy cache. By default this will be in a directory called .ivy2 in your home directory, so on my Windows 7 machine, they are in:
You should be able to browse to this directory on your system and see the jar files that sbt has downloaded.
Type “help” to see the list of available sbt commands. At first glance it may look like a short list. This is because in sbt 0.7, most sbt commands are called “actions”, so to see the available actions, type “actions”:
>actions -empty clean: Deletes all generated files (the target directory). clean-cache: Deletes the cache of artifacts downloaded for automatically... clean-lib: Deletes the managed library directory. clean-plugins compile: Compiles main sources. console: Starts the Scala interpreter with the project classes on the classpath. console-quick: Starts the Scala interpreter with the project classes on the... copy-resources: Copies resources to the target directory where they... copy-test-resources: Copies test resources to the target directory...
From version 0.10 of sbt, the nomenclature has changed, so that everything is a “task”. Hence to see in the commands in sbt 0.10 you would type “tasks”.
The “current” command will print the details of the current project:
>current Current project is Lift SBT Template 0.1 Current Scala version is 2.8.1 Current log level is info Stack traces are enabled
From sbt 0.10, you use the “project” command to see the current project information. Let’s build this blank app and check it works. The first thing to do is ask sbt to check the dependencies of the project and use Apache Ivy to download any that are missing. You can do this using the “update” command:
> update [info] [info] == update == [info] :: retrieving :: Lift#lift-sbt-template_2.8.1 [sync] [info] confs: [compile, runtime, test, provided, system, optional, sources, javadoc] [info] 21 artifacts copied, 0 already retrieved (14247kB/835ms) [info] == update == [success] Successful. [info] [info] Total time: 11 s, completed 13-Oct-2011 21:00:45
Now you can start the application with “~jetty-run”. Although you haven’t explicitly told sbt to compile the Scala code, jetty-run is dependent on the compile, so it will invoke it automatically. The ~ character tells sbt to recompile and republish the code if it changes, so by starting the command with ~, you can leave jetty running as you update the files.
>jetty-run [info] [info] == copy-resources == [info] == copy-resources == [info] [info] == compile == [info] Source analysis: 3 new/modified, 0 indirectly invalidated, 0 removed. [info] Compiling main sources... [info] Compilation successful. [info] Post-analysis: 11 classes. [info] == compile == [info] [info] == prepare-webapp == [info] == prepare-webapp == [info] [info] == jetty-run == 2011-10-13 21:07:08.197:INFO::Logging to STDERR via org.mortbay.log.StdErrLog [info] jetty-6.1.26 [info] NO JSP Support for /, did not find org.apache.jasper.servlet.JspServlet [info] Started SelectChannelConnector@0.0.0.0:8080 [info] == jetty-run == [success] Successful. [info] [info] Total time: 8 s, completed 13-Oct-2011 21:07:09
You should now be able to go to your blank Lift app at:
After you’ve experimented with the blank app, let’s take a look at how it is created.
sbt directory structure
sbt follows the Maven conventions for directory structure. In addition, Lift has some conventions of its own, so the structure of a Lift app is:
project/ src/ main/ resources/ scala/ bootstrap/ code/ comet/ lib/ model/ snippet/ view/ java/ webapp/ test/ resources scala/ java/ target/
The standard directories are:
- project directory – contains the sbt configuration files to build the project
- src/main – your application source
- src/main/webapp – contains files to be copied directly into your web application, such as html templates and the web.xml
- src/test – your test code
- target – where your compiled application will be created and packaged
sbt configuration files
sbt has two methods of configuration – “light” and “full”. “light” configuration is done using files ending in .sbt that contain lists of settings. “full” configuration uses .scala files. Light configuration is a fairly new way of configuring an sbt project, so at the moment Lift uses full configuration. If you expand the project/build directory you can open the LiftProject.scala file that defines the build for this project. Since this is a simple project, all it really does is define some dependencies:
override def libraryDependencies = Set( "net.liftweb" %% "lift-webkit" % liftVersion.value.toString % "compile", "org.mortbay.jetty" % "jetty" % "6.1.26" % "test", "junit" % "junit" % "4.7" % "test", "ch.qos.logback" % "logback-classic" % "0.9.26", "org.scala-tools.testing" %% "specs" % "1.6.6" % "test" ) ++ super.libraryDependencies
Now let’s look at the basic Lift files.
Basic Lift files
Lift always has a Boot.scala file in src/main/scala/bootstrap/liftweb which defines the global setup for the application. Open this file and take a look at it. The main things it does are:
- Defines the packages for Lift code
- Creates the sitemap – a menu and security access for the site
If you open webapp/WEB-INF/web.xml you can see the servlet filter that runs a Lift app:
<filter> <filter-name>LiftFilter</filter-name> <display-name>Lift Filter</display-name> <description>The Filter that intercepts lift calls</description> <filter-class>net.liftweb.http.LiftFilter</filter-class> </filter> <filter-mapping> <filter-name>LiftFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
You might also want to take a quick look at the default Lift html template, which is in webapp/templates-hidden/default.html.
Updating the application
We’re now ready to update the application to include David Pollack’s chat server code. The chat server example is given in chapter two of Simply Lift. There are four files:
- View – should go in your webapp/index.html.
- Chat.scala – should go in src/main/scala/code/comet.
- ChatServer.scala – also in the code.comet package.
- ChatIn.scala – this is the snippet that takes the input form data and submits it to the chatserver, so it goes in src/main/scala/code/snippets.
If you started jetty with ~jetty-run, sbt should detect the change in your source files and automatically recompile and republish the code, so you can return to your Lift app and type in messages which should appear on the web page.
In this tutorial you’ve learnt the following:
- Basic sbt commands such as update, compile and jetty-run.
- How sbt uses Maven conventions for directory structure.
- That sbt projects can be defined using .sbt or .scala files which, at a minimum, will define the dependencies of the project.
- How Lift uses a startup file called Boot.scala, a servlet filter called LiftFilter and a default.html template.
Lift controllers example – a slightly larger example which shows you how to create forms, submit them using ajax and use session variables.
http://simply.liftweb.net – David Pollack’s book which covers the sitemap, snippets, forms, wiring, CSS transforms, RESTful web services and JSON.
https://github.com/harrah/xsbt/wiki – the sbt wiki has plenty of information, but remember that sbt has changed a lot between 0.7 and 0.10. Its useful to start reading up on current sbt usage, but if you do want information specifically for sbt 0.7, you are probably better off looking at the old Google project.