Skip to content

Commit

Permalink
Fixes #118
Browse files Browse the repository at this point in the history
* Add customizable sbt keys for all template sources
* Make sure current template sources are used by default.
* Start on documentation for archetypes.
  • Loading branch information
jsuereth committed Jan 5, 2014
1 parent d9b49e7 commit 699e24b
Show file tree
Hide file tree
Showing 7 changed files with 90 additions and 38 deletions.
21 changes: 14 additions & 7 deletions src/main/scala/com/typesafe/sbt/packager/archetypes/JavaApp.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ package archetypes
import Keys._
import sbt._
import sbt.Project.Initialize
import sbt.Keys.{ mappings, target, name, mainClass, normalizedName }
import sbt.Keys.{ mappings, target, name, mainClass, normalizedName, sourceDirectory }
import linux.LinuxPackageMapping
import SbtNativePackager._

Expand Down Expand Up @@ -43,15 +43,16 @@ object JavaAppPackaging {
} yield JavaAppBashScript.makeDefines(cn, appClasspath = cp, extras = extras)
hasMain getOrElse Nil
},
makeBashScript <<= (bashScriptDefines, target in Universal, normalizedName) map makeUniversalBinScript,
// TODO - Overridable bash template.
makeBashScript <<= (bashScriptDefines, target in Universal, normalizedName, sourceDirectory in Compile) map makeUniversalBinScript,
batScriptExtraDefines := Nil,
batScriptReplacements <<= (normalizedName, Keys.mainClass in Compile, scriptClasspath, batScriptExtraDefines) map { (name, mainClass, cp, extras) =>
mainClass map { mc =>
JavaAppBatScript.makeReplacements(name = name, mainClass = mc, appClasspath = cp, extras = extras)
} getOrElse Nil

},
makeBatScript <<= (batScriptReplacements, target in Universal, normalizedName) map makeUniversalBatScript,
makeBatScript <<= (batScriptReplacements, target in Universal, normalizedName, sourceDirectory in Compile) map makeUniversalBatScript,
mappings in Universal <++= (makeBashScript, normalizedName) map { (script, name) =>
for {
s <- script.toSeq
Expand All @@ -73,21 +74,27 @@ object JavaAppPackaging {
else "../" + name
}

def makeUniversalBinScript(defines: Seq[String], tmpDir: File, name: String): Option[File] =
def makeUniversalBinScript(defines: Seq[String], tmpDir: File, name: String, sourceDir: File): Option[File] =
if (defines.isEmpty) None
else {
val scriptBits = JavaAppBashScript.generateScript(defines)
val defaultTemplateLocation = sourceDir / "templates" / "bash-template"
val scriptBits =
if(defaultTemplateLocation.exists) JavaAppBashScript.generateScript(defines, defaultTemplateLocation.toURI.toURL)
else JavaAppBashScript.generateScript(defines)
val script = tmpDir / "tmp" / "bin" / name
IO.write(script, scriptBits)
// TODO - Better control over this!
script.setExecutable(true)
Some(script)
}

def makeUniversalBatScript(replacements: Seq[(String, String)], tmpDir: File, name: String): Option[File] =
def makeUniversalBatScript(replacements: Seq[(String, String)], tmpDir: File, name: String, sourceDir: File): Option[File] =
if (replacements.isEmpty) None
else {
val scriptBits = JavaAppBatScript.generateScript(replacements)
val defaultTemplateLocation = sourceDir / "templates" / "bat-template"
val scriptBits =
if(defaultTemplateLocation.exists) JavaAppBatScript.generateScript(replacements, defaultTemplateLocation.toURI.toURL)
else JavaAppBatScript.generateScript(replacements)
val script = tmpDir / "tmp" / "bin" / (name + ".bat")
IO.write(script, scriptBits)
Some(script)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.typesafe.sbt.packager.archetypes

import java.net.URL

/**
* Constructs a bash script for running a java application.
*
Expand Down Expand Up @@ -33,10 +35,10 @@ object JavaAppBashScript {
val fullString = cp map (n => "$lib_dir/"+n) mkString ":"
"declare -r app_classpath=\""+fullString+"\"\n"
}
def generateScript(defines: Seq[String]): String = {
def generateScript(defines: Seq[String], template: URL = bashTemplateSource): String = {
val defineString = defines mkString "\n"
val replacements = Seq("template_declares" -> defineString)
TemplateWriter.generateScript(bashTemplateSource, replacements)
TemplateWriter.generateScript(template, replacements)
}

def configFileDefine(configFile: String) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ object JavaAppBatScript {
}

def generateScript(
replacements: Seq[(String,String)]): String =
TemplateWriter.generateScript(bashTemplateSource, replacements, "\r\n", TemplateWriter.batFriendlyKeySurround)
replacements: Seq[(String,String)], template: java.net.URL = bashTemplateSource): String =
TemplateWriter.generateScript(template, replacements, "\r\n", TemplateWriter.batFriendlyKeySurround)

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package com.typesafe.sbt.packager.archetypes

import java.io.File
import java.net.URL

/**
* Constructs an start script for running a java application.
*
Expand All @@ -8,31 +11,32 @@ object JavaAppStartScript {

import ServerLoader._

protected def upstartTemplateSource: java.net.URL = getClass.getResource("upstart-template")
protected def sysvinitTemplateSource: java.net.URL = getClass.getResource("sysvinit-template")
protected def postinstTemplateSource: java.net.URL = getClass.getResource("postinst-template")
protected def postinstSysvinitTemplateSource: java.net.URL = getClass.getResource("postinst-sysvinit-template")
protected def preremTemplateSource: java.net.URL = getClass.getResource("prerem-template")


def generateScript(replacements: Seq[(String, String)], loader: ServerLoader): String =
loader match {
case Upstart =>
TemplateWriter.generateScript(upstartTemplateSource, replacements)
case SystemV =>
TemplateWriter.generateScript(sysvinitTemplateSource, replacements)
protected def upstartTemplateSource: URL = getClass.getResource("upstart-template")
protected def sysvinitTemplateSource: URL = getClass.getResource("sysvinit-template")
protected def postinstTemplateSource: URL = getClass.getResource("postinst-template")
protected def postinstSysvinitTemplateSource: URL = getClass.getResource("postinst-sysvinit-template")
protected def preremTemplateSource: URL = getClass.getResource("prerem-template")


def defaultStartScriptTemplate(loader: ServerLoader, defaultLocation: File): URL =
if(defaultLocation.exists) defaultLocation.toURI.toURL
else loader match {
case Upstart => upstartTemplateSource
case SystemV => sysvinitTemplateSource
}


def generatePrerm(appName: String): String =
TemplateWriter.generateScript(preremTemplateSource, Seq("app_name" -> appName))
def generatePrerm(appName: String, template: java.net.URL = preremTemplateSource): String =
TemplateWriter.generateScript(template, Seq("app_name" -> appName))


def generatePostinst(appName: String, loader: ServerLoader): String =
loader match {
case Upstart =>
def generatePostinst(appName: String, loader: ServerLoader, template: Option[java.net.URL] = None): String =
(template, loader) match {
// User has overriden the default.
case (Some(template), _) => TemplateWriter.generateScript(template, Seq("app_name" -> appName))
case (_, Upstart) =>
TemplateWriter.generateScript(postinstTemplateSource, Seq("app_name" -> appName))
case SystemV =>
case (_, SystemV) =>
TemplateWriter.generateScript(postinstSysvinitTemplateSource, Seq("app_name" -> appName))
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ package archetypes

import Keys._
import sbt._
import sbt.Keys.{ target, mainClass, normalizedName }
import sbt.Keys.{ target, mainClass, normalizedName, sourceDirectory }
import SbtNativePackager._
import com.typesafe.sbt.packager.linux.{ LinuxFileMetaData, LinuxPackageMapping, LinuxSymlink, LinuxPlugin }

Expand All @@ -28,6 +28,7 @@ object JavaServerAppPackaging {
Seq(
serverLoading := Upstart,
daemonUser := Users.Root,
// This one is begging for sbt 0.13 syntax...
debianStartScriptReplacements <<= (
maintainer in Debian, packageSummary in Debian, serverLoading in Debian, daemonUser in Debian, normalizedName,
sbt.Keys.version, defaultLinuxInstallLocation, mainClass in Compile, scriptClasspath)
Expand All @@ -45,9 +46,18 @@ object JavaServerAppPackaging {
appMainClass = mainClass.get,
daemonUser = daemonUser)
},
debianMakeStartScript <<= (debianStartScriptReplacements, normalizedName, target in Universal, serverLoading in Debian)
// TODO - Default locations shouldn't be so hacky.
linuxStartScriptTemplate in Debian <<= (serverLoading in Debian, sourceDirectory in Compile) map { (loader, dir) =>
JavaAppStartScript.defaultStartScriptTemplate(loader, dir / "templates" / "start")
},
debianMakeStartScript <<= (debianStartScriptReplacements, normalizedName, target in Universal, linuxStartScriptTemplate in Debian)
map makeDebianStartScript,
debianMakeEtcDefault <<= (normalizedName, target in Universal, serverLoading in Debian)
linuxEtcDefaultTemplate in Debian <<= sourceDirectory in Compile map { dir =>
val overrideScript = dir / "templates" / "etc-default"
if(overrideScript.exists) overrideScript.toURI.toURL
else etcDefaultTemplateSource
},
debianMakeEtcDefault <<= (normalizedName, target in Universal, serverLoading in Debian, linuxEtcDefaultTemplate in Debian)
map makeEtcDefaultScript,
linuxPackageMappings in Debian <++= (debianMakeEtcDefault, normalizedName) map { (conf, name) =>
conf.map(c => LinuxPackageMapping(Seq(c -> ("/etc/default/" + name))).withConfig()).toSeq
Expand All @@ -58,7 +68,6 @@ object JavaServerAppPackaging {
case Upstart => ("/etc/init/" + name + ".conf", "0644")
case SystemV => ("/etc/init.d/" + name, "0755")
}

for {
s <- script.toSeq
} yield LinuxPackageMapping(Seq(s -> path)).withPerms(permissions)
Expand All @@ -79,10 +88,10 @@ object JavaServerAppPackaging {
debianMakePostinstScript <<= (normalizedName, target in Universal, serverLoading in Debian) map makeDebianPostinstScript)

private def makeDebianStartScript(
replacements: Seq[(String, String)], name: String, tmpDir: File, loader: ServerLoader): Option[File] =
replacements: Seq[(String, String)], name: String, tmpDir: File, template: URL): Option[File] =
if (replacements.isEmpty) None
else {
val scriptBits = JavaAppStartScript.generateScript(replacements, loader)
val scriptBits = TemplateWriter.generateScript(template, replacements)
val script = tmpDir / "tmp" / "init" / name
IO.write(script, scriptBits)
Some(script)
Expand All @@ -102,11 +111,11 @@ object JavaServerAppPackaging {
Some(script)
}

protected def makeEtcDefaultScript(name: String, tmpDir: File, loader: ServerLoader): Option[File] = {
protected def makeEtcDefaultScript(name: String, tmpDir: File, loader: ServerLoader, source: java.net.URL): Option[File] = {
loader match {
case Upstart => None
case SystemV => {
val scriptBits = TemplateWriter.generateScript(etcDefaultTemplateSource, Seq.empty)
val scriptBits = TemplateWriter.generateScript(source, Seq.empty)
val script = tmpDir / "tmp" / "etc" / "default" / name
IO.write(script, scriptBits)
Some(script)
Expand Down
3 changes: 3 additions & 0 deletions src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ trait Keys {
val linuxPackageMappings = TaskKey[Seq[LinuxPackageMapping]]("linux-package-mappings", "File to install location mappings including owner and privileges.")
val linuxPackageSymlinks = TaskKey[Seq[LinuxSymlink]]("linux-package-symlinks", "Symlinks we should produce in the underlying package.")
val generateManPages = TaskKey[Unit]("generate-man-pages", "Shows all the man files in the current project")

val linuxStartScriptTemplate = TaskKey[URL]("linuxStartScriptTemplate", "The location of the template start script file we use for debian (upstart or init.d")
val linuxEtcDefaultTemplate = TaskKey[URL]("linuxEtcDefaultTemplate", "The location of the /etc/default/<pkg> template script.")
}

object Keys extends Keys {
Expand Down
27 changes: 27 additions & 0 deletions src/sphinx/archetypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,30 @@ produces a universal layout that looks like the following:


You can add additional files to the project by placing things in ``src/windows``, ``src/universal`` or ``src/linux`` as needed.


Java Server
-----------

This archetype is designed for Java applications that are intended to run as
servers or services. This archetype includes wiring such that the application
is started immediately upon startup.

Currently supported operating systems:

* Ubuntu 12.04 LTS - Upstart
* Ubuntu 12.04 LTS - init.d


The Java Server archetype has a similar installation layout as the java
application. The primary differneces are:

* Linux

* ``/var/log/<pkg>`` is symlinked from ``<install>/log``

* Creates a start script in ``/etc/init.d`` or ``/etc/init/``

* Creates a startup config file in ``/etc/default/<pkg>``


0 comments on commit 699e24b

Please sign in to comment.