The sbt launcher component is a self-contained jar that boots a Scala application without Scala or the application already existing on the system. The only prerequisites are the launcher jar itself, an optional configuration file, and a java runtime version 1.5 or greater.
== Configuration ==
The launcher may be configured in the following ways in increasing order of precedence:
* Specify the location of an alternate configuration on the command line. This can be done by either specifying the location as the system property 'sbt.boot.properties' or as the first argument to the launcher prefixed by '@'. The system property has lower precedence. Resolution of a relative path is first attempted against the current working directory, then against the user's home directory, and then against the directory containing the launcher jar. An error is generated if none of these attempts succeed.
The scala.version property specifies the version of Scala used to run the application. The app.org, app.name, and app.version properties specify the organization, module ID, and version of the application, respectively. These are used to resolve and retrieve the application from the repositories listed in [repositories]. If cross-versioned is true, the resolved module is {app.name+'_'+scala.version}
The app.class property specifies the name of the entry point to the application. An application entry point must be a public class with a no-argument constructor that implements xsbti.AppMain. The AppMain interface specifies the entry method signature 'run'. The run method is passed an instance of AppConfiguration, which provides access to the startup environment. AppConfiguration also provides an interface to retrieve other versions of Scala or other applications. Finally, the return type of the run method is `xsbti.MainResult`, which has two subtypes: xsbti.Reboot and xsbti.Exit. To exit with a specific code, return an instance of xsbti.Exit with the requested code. To restart the application, return an instance of Reboot. You can change some aspects of the configuration with a reboot, such as the version of Scala, the application ID, and the arguments.
On startup, the launcher searches for its configuration in the order described in the Configuration section and then parses it. If either the Scala version or the application version are implicit (specified as 'read'), the launcher determines them in the following manner. The file given by the 'boot.properties' property is read as a Java properties file to obtain the version. The property names are [app.name].version for the application version (where [app.name] is replaced with the value of the app.name property from the boot configuration file) and scala.version for the Scala version. If the file does not exist, the default value provided is used. If no default was provided, an error is generated.
Once the final configuration is resolved, the launcher proceeds to obtain the necessary jars to launch the application. The 'boot.directory' property is used as a base directory to retrieve jars to. No locking is done on the directory, so it should not be shared system-wide. The launcher retrieves the requested version of Scala to [boot.directory]/[scala.version]/lib/. If this directory already exists, the launcher takes a shortcut for performance and assumes that the jars have already been downloaded. If the directory does not exists, the launcher uses Apache Ivy to resolve and retrieve the jars. A similar process occurs for the application itself. It and its dependencies are retreived to [boot.directory]/[scala.version]/[app.org]/[app.name]/.
Once all required code is downloaded, the class loaders are set up. The launcher creates a class loader for the requested version of Scala. It then creates a child class loader containing the jars for the requested 'app.components'. An application that does not use components will have all of its jars in this class loader.
The main class for the application is then instantiated. It must be a public class with a public no-argument constructor and must conform to xsbti.AppMain. The `run` method is invoked and execution passes to the application. The argument to the 'run' method provides configuration information and a callback to obtain a class loader for any version of Scala that can be obtained from a repository in [repositories]. The return value of the run method determines what is done after the application executes. It can specify that the launcher should restart the application or that it should exit with the provided exit code.
== Creating a Launched Application ==
This section shows how to make an application that is launched by this launcher. First, declare a dependency on the launcher-interface. Do not declare a dependency on the launcher itself. The interface consists strictly of Java interfaces in order to avoid binary incompatibility between the version of Scala used to compile the launcher and the version compiling your application. Additionally, the launcher interface class will be provided by the launcher, so it is only a compile-time dependency. If you are building with sbt, your dependency definition would be:
val launchInterface = "org.scala-tools.sbt" % "launcher-interface" % "0.7" % "provided"
Make the entry point to your class implement 'xsbti.AppMain'. For example:
package xsbt.test
class Main extends xsbti.AppMain
{
def run(configuration: xsbti.AppConfiguration) =
{
// get the version of Scala used to launch the application
val scalaVersion = configuration.provider.scalaProvider.version
// Print a message and the arguments to the application
// demonstrate the ability to reboot the application into different versions of Scala
// and how to return the code to exit with
scalaVersion match
{
case "2.7.5" =>
new xsbti.Reboot {
def arguments = configuration.arguments
def baseDirectory = configuration.baseDirectory
def scalaVersion = "2.7.4"
def app = configuration.provider.id
}
case "2.7.4" => new xsbti.Exit{ def code = 1 }
case _ => new xsbti.Exit{ def code = 0 }
}
}
}
Define a configuration file for the launcher. For the above class, it might look like:
[scala]
version: 2.7.5
[app]
org: org.scala-tools.sbt
name: xsbt-test
version: 0.7
class: xsbt.test.Main
cross-versioned: true
[repositories]
local
maven-local
maven-central
scala-tools-releases
# scala-tools-snapshots
[boot]
directory: boot
Then, +publish-local the application to make it available.
As mentioned above, there are a few options to actually run the application. The first involves providing a modified jar for download. The second two require providing a configuration file for download.
1) Replace the /sbt/sbt.boot.properties file in the launcher jar and distribute the modified jar. The user would need to run 'java -jar your-launcher.jar'.
2) The user downloads the vanilla sbt launcher jar and you provide the sbt.boot.properties file. The user would need to run 'java -Dsbt.boot.properties=your.boot.properties -jar sbt-launcher.jar'
3) The user sets up the sbt launcher, including the bash script. You provide the sbt.boot.properties file and the user runs sbt @your.boot.properties <other arguments>.