-
Notifications
You must be signed in to change notification settings - Fork 444
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #208 from sbt/wip/getting-started-guide
First cut at a getting started guide which is more useful than what we had
- Loading branch information
Showing
21 changed files
with
716 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
Advanced Topics | ||
############### | ||
|
||
|
||
|
||
.. toctree:: | ||
:maxdepth: 2 | ||
|
||
archetypes.rst | ||
universal.rst | ||
linux.rst | ||
redhat.rst | ||
debian.rst | ||
windows.rst |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
134 changes: 134 additions & 0 deletions
134
src/sphinx/GettingStartedApplications/AddingConfiguration.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
Adding configuration | ||
#################### | ||
|
||
After :doc:`creating a package <MyFirstProject>`, the very next thing needed, usually, is the ability for users/ops to customize the application once it's deployed. Let's add some configuration to the newly deployed application. | ||
|
||
There are generally two types of configurations: | ||
|
||
* Configuring the JVM and the process | ||
* Configuring the Application itself. | ||
|
||
The native packager provides a direct hook into the generated scripts for JVM configuration. Let's make use of this. First, add the following to the ``src/universal/conf/jvmopts`` file in the project :: | ||
|
||
-DsomeProperty=true | ||
|
||
Now, if we run the ``stage`` task, we'll see this file show up in the distribution :: | ||
|
||
$ sbt stage | ||
$ ls target/universal/stage | ||
bin/ | ||
conf/ | ||
lib/ | ||
$ ls target/unviersal/stage/conf | ||
jvmopts | ||
|
||
By default, any file in the ``src/universal`` directory is packaged. This is a convenient way to include things like licenses, and readmes. | ||
|
||
Now, we need to modify the script templates to load this configuration. To do so, add the following | ||
to ``build.sbt`` :: | ||
|
||
bashScriptConfigLocation := Some("${app_home}/../conf/jvmopts") | ||
|
||
Here, we define the configuration location for the BASH script too look for the ``conf/jvmopts`` file. Now, let's run ``sbt stage`` and then execute the script in debug mode to see what command line it executes :: | ||
|
||
./target/universal/stage/bin/example-cli -d | ||
# Executing command line: | ||
java | ||
-Xms1024m | ||
-Xmx1024m | ||
-XX:MaxPermSize=256m | ||
-XX:ReservedCodeCacheSize=128m | ||
-DsomeProperty=true | ||
-cp | ||
/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/example-cli.example-cli-1.0.jar:/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/org.scala-lang.scala-library-2.10.3.jar:/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/stage/lib/com.typesafe.config-1.2.0.jar | ||
TestApp | ||
|
||
|
||
The configuration file for bash scripts takes arguments for the BASH file on each line, and allows comments which start with the ``#`` character. Essentially, this provides a set of default arguments when calling the script. | ||
|
||
Now that we have ability to configure the JVM, let's add in a more robust method of customizing the applciation. We'll be using the `Typesafe Config <https://github.com/typesafehub/config>`_ library for this purpose. | ||
|
||
First, let's add it as a dependency in ``build.sbt`` :: | ||
|
||
libraryDependencies += "com.typesafe" % "config" % "1.2.0" | ||
|
||
Next, let's create the configuration file itself. Add the following to ``src/universal/conf/app.config`` :: | ||
|
||
example { | ||
greeting = "Hello, World!" | ||
} | ||
|
||
Now, we need a means of telling the typesafe config library where to find our configuration. The library supports | ||
a JVM property "``config.file``" which it will use to look for configuration. Let's expose this file | ||
in the startup BASH script. To do so, add the following to ``build.sbt`` :: | ||
|
||
bashScriptExtraDefines += """addJava "-Dconfig.file=${app_home}/../conf/app.config"""" | ||
|
||
This line modifies the generated BASH script to add the JVM options the location of the application configuration on disk. Now, let's modify the application (``src/main/scala/TestApp.scala``) to read this configuration :: | ||
|
||
import com.typesafe.config.ConfigFactory | ||
object TestApp extends App { | ||
val config = ConfigFactory.load() | ||
println(config.getString("example.greeting")) | ||
} | ||
|
||
Now, let's try it out on the command line :: | ||
|
||
$ sbt stage | ||
$ ./target/universal/stage/bin/example-cli | ||
Hello, World! | ||
|
||
|
||
Finally, let's see what this configuration looks like in a linux distribution. Let's run the debian packaging again :: | ||
|
||
$ sbt debian:packageBin | ||
|
||
The resulting structure is the following :: | ||
|
||
/usr/ | ||
share/example-cli/ | ||
conf/ | ||
app.config | ||
jvmopts | ||
bin/ | ||
example-cli | ||
lib/ | ||
example-cli.example-cli-1.0.jar | ||
org.scala-lang.scala-library-2.10.3.jar | ||
bin/ | ||
example-cli -> ../share/example-cli/bin/example-cli | ||
/etc/ | ||
example-cli -> /usr/share/example-cli/conf | ||
|
||
Here, we can see that the entire ``conf`` directory for the application is exposed on ``/etc`` as is standard for other linux applications. By convention, all files in the universal ``conf`` directory are marked as configuration files when packaged, allowing users to modify them. | ||
|
||
Configuring for Windows | ||
~~~~~~~~~~~~~~~~~~~~~~~ | ||
While we just covered how to do configuration for linux/mac, windows offers some subtle differences. | ||
|
||
First, while the BASH file allows you to configure where to load JVM options and default arguments, in | ||
windows we can only configure JVM options. The path is hardcoded, as well to: | ||
|
||
``<install directory>/@@APP_ENV_NAME@@_config.txt`` | ||
|
||
where ``@@APP_ENV_NAME@@`` is replaced with an environment friendly name for your app. In this example, that would be: ``EXAMPLE_CLI``. | ||
|
||
We can provide a configuration for JVM options on windows by creating a ``src/universal/EXAMPLE_CLI_config.txt`` file with the following contents :: | ||
|
||
-Xmx512M | ||
-Xms128M | ||
|
||
This will add each line of the file as arguments to the JVM when running your application. | ||
|
||
|
||
Now, if we want to add the typesafe config library again, we need to write the ``config.file`` property into the JVM options again. | ||
|
||
One means of doing this is hooking the ``batScriptExtraDefines`` key. This allows us to insert various BAT settings/commands into the script. Let's use this to hook the config file location, using the other variables in the BASH script. Modify your ``build.sbt`` as follows :: | ||
|
||
batScriptExtraDefines += """set _JAVA_OPTS=%_JAVA_OPTS% -Dconfig.file=%EXAMPLE_CLI_HOME%\\conf\\app.config""" | ||
|
||
Now, the windows version will also load the configuration from the ``conf/`` directory of the package. | ||
|
||
|
||
Next, let's :doc:`add some generated files <GeneratingFiles>`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
Generating files for the package | ||
################################ | ||
|
||
Let's dynamically (in the build) construct some files that should be included in the package. | ||
|
||
|
||
For the example, let's download a license file for our application and add it to the distribution. First, | ||
let's create a task which will download a license file. Add the following to build.sbt :: | ||
|
||
val downloadLicense = taskKey[File]("Downloads the latest license file.") | ||
|
||
downloadLicense := { | ||
val location = target.value / "downloads" / "LICENSE" | ||
location.getParentFile.mkdirs() | ||
IO.download(url("http://www.schillmania.com/projects/soundmanager2/license.txt?txt"), location) | ||
location | ||
} | ||
|
||
Now, we have a taks that will download the BSD license when run. Note: We assume that the license file is | ||
something you host on your own website and keep up to date separately form the package. | ||
|
||
Next, let's wire this license into the package. The native package, by default, works with **mappings**. | ||
In sbt, a **mappings** object is a grouping of files and relative locations, e.g :: | ||
|
||
/home/jsuereth/projects/example/src/universal/conf/app.config -> conf/app.config | ||
/home/jsuereth/projects/example/src/universal/conf/jvmopts -> conf/jvmopts | ||
|
||
shows the mapping of the configuration files we set up :doc:`previously <AddingConfiguration>`. We can directly | ||
append files to the mappings rather than relying on the native packager to find things. Let's add | ||
the license in the root of the package we're creating. Add the following to the ``build.sbt`` :: | ||
|
||
mappings in Universal += downloadLicense.value -> "LICENSE" | ||
|
||
This is appending a new mapping to those used for packaging. In this case, we reference the file returned by | ||
the ``downloadLicense`` task and put it in the root directory of the package, calling it ``LICENSE``. We | ||
can verify this by checking the ``stage`` task :: | ||
|
||
$ sbt stage | ||
$ ls target/universal/stage | ||
bin conf lib LICENSE | ||
|
||
You can see the license file is now included in the distribution. | ||
|
||
|
||
TODO - Describe linuxPackageMappings | ||
|
||
With control over mappings, you can rework any aspect of the native packager defaults just be overriding | ||
which files are used. However, sometimes the defaults don't need to be completely replaced, just altered a bit. | ||
|
||
Next, let's look at :doc:`how to provide our own BASH template <OverridingTemplates>` that the native packager will use when generating | ||
the script. |
136 changes: 136 additions & 0 deletions
136
src/sphinx/GettingStartedApplications/MyFirstProject.rst
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
My First Packaged Project | ||
######################### | ||
|
||
After installing the native packager, let's set up a raw sbt project to experiment with bundling things. First, let's create a | ||
``project/build.properties`` file to save the sbt version :: | ||
|
||
sbt.version=0.13.1 | ||
|
||
sbt builds should always specify which version of sbt they are designed to use. This helps keeps builds consistent between developers, | ||
and documents to users which version of sbt you require for the build. | ||
|
||
Next, let's add the native packager to our build by created a ``project/plguins.sbt`` file with the following contents :: | ||
|
||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "0.7.0-RC1") | ||
|
||
Now, the build needs to be configured for packaging. Let's define the ``build.sbt`` file as follows | ||
|
||
.. code-block:: scala | ||
name := "example-cli" | ||
version := "1.0" | ||
packageArchetype.java_application | ||
The third line of ``build.sbt`` adds the default packaging settings for java applications. The native packager includes two | ||
"batteries included" options for packaging applications: | ||
|
||
* ``java_application`` - Defines packaging of your project with a start script and automatic PATH additions | ||
* ``java_server`` - Defines packaging of your project with automatic service start scripts (supports System V + init.d). | ||
|
||
In addition to these, you can always directly configure all packaging by hand. For now, we're using one of the built-in options | ||
as these are pretty robust and configurable. | ||
|
||
Now that the build is set up, Let's create an application that we can run on the command line. Create the following file | ||
``src/main/scala/TestApp.scala`` | ||
|
||
.. code-block:: scala | ||
object TestApp extends App { | ||
println("IT LIVES!") | ||
} | ||
Once this is created, start ``sbt`` on the console and run the ``stage`` command :: | ||
|
||
$ sbt | ||
> stage | ||
|
||
Now, in another terminal, let's look at what was generated :: | ||
|
||
target/universal/stage/ | ||
bin/ | ||
example-cli | ||
example-cli.bat | ||
lib/ | ||
example-cli.example-cli-1.0.jar | ||
org.scala-lang.scala-library-2.10.3.jar | ||
|
||
By default, the plugin has created both a windows BAT file and a linux/mac bash script for running the application. | ||
In addition, all the dependent jars are added into the ``lib/`` folder. Let's try out the script in a terminal :: | ||
|
||
$ ./target/universal/stage/bin/example-cli | ||
IT LIVES! | ||
$ | ||
|
||
Now that the package has been verified, let's work on the generic or "universal" packaging. This is when | ||
the plugin packages your application in a simple format that should be consumable from most operating systems or | ||
platforms. There are two ways to do this in the sbt console :: | ||
|
||
> universal:packageBin | ||
[info] /home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/example-cli-1.0.zip | ||
|
||
> universal:packageZipTarabell | ||
[info] /home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/universal/example-cli-1.0.tgz | ||
|
||
This task simple constructs either a tgz or zip file with the exact same contents we found in the staged directory. | ||
|
||
While this is a great first step towards deploying our application, we'd like to make it even simpler. Our target | ||
deployment platform is Ubuntu. The command line tool should be usable by all our developers with a very simple | ||
installation and update mechanism. So, let's try to make a debian out of our package. Try the ``debian:packageBin`` task in the sbt console :: | ||
|
||
> debian:packageBin | ||
[trace] Stack trace suppressed: run last debian:debianControlFile for the full output. | ||
[error] (debian:debianControlFile) packageDescription in Debian cannot be empty. Use | ||
[error] packageDescription in Debian := "My package Description" | ||
[error] Total time: 0 s, completed Apr 1, 2014 10:21:13 AM | ||
|
||
Here, the native packager is warning that we haven't fully configured all the information required to genreate a valid debian file. In particular, the packageDescription needs to be filled out for debian, in addition to a few other settings. Let's add the debian configuration to ``build.sbt`` :: | ||
|
||
name := "example-cli" | ||
|
||
version := "1.0" | ||
|
||
packageArchetype.java_application | ||
|
||
packageDescription in Debian := "Example Cli" | ||
|
||
maintainer in Debian := "Josh Suereth" | ||
|
||
Now, let's try to run the ``debian:packageBin`` command in the sbt console again :: | ||
|
||
$ sbt | ||
> debian:PacakgeBin | ||
[info] Altering postrm/postinst files to add user example-cli and group example-cli | ||
[info] dpkg-deb: building package `example-cli' in `/home/jsuereth/projects/sbt/sbt-native-packager/tutorial-example/target/example-cli-1.0.deb' | ||
|
||
This generates a debian file that will install the following owners and files :: | ||
|
||
root:root /usr/ | ||
examplecli:examplecli share/example-cli/ | ||
examplecli:examplecli bin/ | ||
examplecli:examplecli example-cli | ||
examplecli:examplecli lib/ | ||
examplecli:examplecli example-cli.example-cli-1.0.jar | ||
examplecli:examplecli org.scala-lang.scala-library-2.10.3.jar | ||
root:root bin/ | ||
root:root example-cli -> ../share/example-cli/bin/example-cli | ||
|
||
So, the default packaing takes the "universal" distribution and places it inside a ``/usr/share`` directory, owned by a user for the application. In addition, there is a a symlink in ``/usr/bin`` to the distributed bin script. This allows users on the platform to run the ``example-cli`` as a native install. | ||
|
||
We can generate other packages via the following tasks. Here's a complete list of current options. | ||
|
||
* ``universal:packageBin`` - Generates a universal zip file | ||
* ``universal:packageZipTarball`` - Generates a universal tgz file | ||
* ``debian:packageBin`` - Generates a deb | ||
* ``rpm:packageBin`` - Generates an rpm | ||
* ``universal::packageOsxDmg`` - Generates a DMG file with the same contents as the universal zip/tgz. | ||
* ``windows:packageBin`` - Generates an MSI | ||
|
||
While we only covered the necessary configuration for ``debian``, each package type beyond ``universal`` requires some additonal | ||
configuration relative to that packager. For example, windows MSIs require UUIDs for all packages which are used to uniquely | ||
identifiy two packages that may have the same name. | ||
|
||
Next, let's look at how to :doc:`Add configuration files <AddingConfiguration>` to use with our script. | ||
|
||
|
Oops, something went wrong.