From 9d0fa60d0e77f533b7ac0f17f9b8721187f11641 Mon Sep 17 00:00:00 2001 From: Alexey Kardapoltsev Date: Thu, 21 Nov 2013 19:38:36 +0600 Subject: [PATCH 1/4] Sysvinit script added --- project/build.properties | 2 +- .../sbt/packager/archetypes/sysvinit-template | 49 ++++++++++++ .../com/typesafe/sbt/PackagerPlugin.scala | 2 + .../archetypes/JavaAppUpstartScript.scala | 50 ++++++++++-- .../archetypes/JavaServerApplication.scala | 78 +++++++++++++++---- .../typesafe/sbt/packager/debian/Keys.scala | 14 ++++ src/sbt-test/debian/sysvinit-deb/build.sbt | 15 ++++ .../debian/sysvinit-deb/project/plugins.sbt | 1 + src/sbt-test/debian/sysvinit-deb/test | 6 ++ 9 files changed, 197 insertions(+), 20 deletions(-) create mode 100644 src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template create mode 100644 src/sbt-test/debian/sysvinit-deb/build.sbt create mode 100644 src/sbt-test/debian/sysvinit-deb/project/plugins.sbt create mode 100644 src/sbt-test/debian/sysvinit-deb/test diff --git a/project/build.properties b/project/build.properties index 5e96e9672..0974fce44 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.12.4 +sbt.version=0.13.0 diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template new file mode 100644 index 000000000..e215060e9 --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template @@ -0,0 +1,49 @@ +#! /bin/sh + +### BEGIN INIT INFO +# Provides: ${{app_name}} +# Required-Start: $syslog +# Required-Stop: $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: +# Short-Description: ${{descr}} +### END INIT INFO + +PIDFILE=/var/run/${{app_name}}.pid + +. /lib/init/vars.sh +. /lib/lsb/init-functions + +#TODO: fix this +get_java_cmd() { + if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then + echo "$JAVA_HOME/bin/java" + else + echo "java" + fi +} + +JAVA_CMD=$(get_java_cmd) + +RUN_CMD=$JAVA_CMD -cp ${{app_classpath}} ${{app_main_class}} + +case "$1" in + +start) log_daemon_msg "Starting ${{app_name}}" + + start-stop-daemon --background --start --make-pidfile --pidfile $PIDFILE --exec $RUN_CMD + + ;; +stop) log_daemon_msg "Stopping ${{app_name}}" + + start-stop-daemon --stop --pidfile $PIDFILE --chuid $DAEMONUSER + + RETVAL=$? + [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE + exit 2 + ;; +*) log_daemon_msg "Usage: /etc/init.d/${{app_name}} {start|stop}" + exit 2 + ;; +esac +exit 0 \ No newline at end of file diff --git a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala index bebe1e2a6..a62692a77 100644 --- a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala @@ -46,6 +46,8 @@ object SbtNativePackager extends Plugin genericMappingSettings ++ archetypes.JavaAppPackaging.settings def java_server: Seq[Setting[_]] = genericMappingSettings ++ archetypes.JavaServerAppPackaging.settings + def java_server_sysvinit: Seq[Setting[_]] = + genericMappingSettings ++ archetypes.JavaServerAppSysVinitPackaging.settings } // TODO - Add a few targets that detect the current OS and build a package for that OS. diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala index 071405dbc..b75bb7205 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala @@ -6,12 +6,10 @@ package com.typesafe.sbt.packager.archetypes * Makes use of the associated upstart-template, with a few hooks * */ -object JavaAppUpstartScript { +object JavaAppUpstartScript extends JavaAppScript { - private[this] def upstartTemplateSource: java.net.URL = getClass.getResource("upstart-template") + protected def templateSource: java.net.URL = getClass.getResource("upstart-template") - private[this] def postinstTemplateSource: java.net.URL = getClass.getResource("postinst-template") - private[this] def preremTemplateSource: java.net.URL = getClass.getResource("prerem-template") /** * * @param author - @@ -36,11 +34,51 @@ object JavaAppUpstartScript { "retries" -> retries.toString, "retryTimeout" -> retryTimeout.toString) +} + +object JavaAppSysVinitScript extends JavaAppScript { + protected def templateSource: java.net.URL = getClass.getResource("sysvinit-template") + + + /** + * + * @param author - + * @param description - short description + * @return Seq of key,replacement pairs + */ + def makeReplacements( + author: String, + description: String, + appDir: String, + appName: String, + appMainClass: String, + appClasspath: String + + ): Seq[(String, String)] = + Seq( + "author" -> author, + "descr" -> description, + "app_name" -> appName, + "app_dir" -> appDir, + "app_main_class" -> appMainClass, + "app_classpath" -> appClasspath + ) +} + + +trait JavaAppScript { + + protected def templateSource: java.net.URL + + protected def postinstTemplateSource: java.net.URL = getClass.getResource("postinst-template") + protected def preremTemplateSource: java.net.URL = getClass.getResource("prerem-template") + + def generateScript(replacements: Seq[(String, String)]): String = - TemplateWriter.generateScript(upstartTemplateSource, replacements) + TemplateWriter.generateScript(templateSource, replacements) def generatePrerm(appName: String): String = TemplateWriter.generateScript(preremTemplateSource, Seq("app_name" -> appName)) def generatePostinst(appName: String): String = TemplateWriter.generateScript(postinstTemplateSource, Seq("app_name" -> appName)) -} +} \ No newline at end of file diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala index 30b0934cc..3c5383a68 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -19,7 +19,7 @@ import com.typesafe.sbt.packager.linux.LinuxPackageMapping * * **NOTE: EXPERIMENTAL** This currently only supports debian upstart scripts. */ -object JavaServerAppPackaging { +object JavaServerAppPackaging extends JavaServerAppPackaging { def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ @@ -42,26 +42,78 @@ object JavaServerAppPackaging { debianMakePrermScript <<= (normalizedName, target in Universal) map makeDebianPrermScript, debianMakePostinstScript <<= (normalizedName, target in Universal) map makeDebianPostinstScript) - private[this] final def makeDebianPrermScript(name: String, tmpDir: File): Option[File] = { + + protected final def makeDebianUpstartScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = + if (replacements.isEmpty) None + else { + val scriptBits = JavaAppUpstartScript.generateScript(replacements) + val script = tmpDir / "tmp" / "bin" / (name + ".conf") + IO.write(script, scriptBits) + Some(script) + } +} + + +object JavaServerAppSysVinitPackaging extends JavaServerAppPackaging { + + def settings: Seq[Setting[_]] = + JavaAppPackaging.settings ++ debianSysVinitSettings + + def debianSysVinitSettings: Seq[Setting[_]] = { + Seq( + debianSysVinitScriptReplacements <<= (maintainer in Debian, packageSummary in Debian, + normalizedName, name, sbt.Keys.version, defaultLinuxInstallLocation, sbt.Keys.mainClass in Compile, scriptClasspath) + map { (author, descr, normalizedName, name, version, installLocation, mainClass, cp) => + // TODO name-version is copied from UniversalPlugin. This should be consolidated into a setting (install location...) + val appDir = installLocation + "/" + normalizedName + val appClasspath = cp.map(appDir + "/lib/" + _).mkString(":") + + JavaAppSysVinitScript.makeReplacements( + author = author, description = descr, + appDir = appDir, + appName = name, + appClasspath = appClasspath, + appMainClass = mainClass.getOrElse("") //TODO: is it possible + ) + }, + debianMakeSysVinitScript <<= (debianSysVinitScriptReplacements, normalizedName, target in Universal) map makeDebianSysVinitScript, + linuxPackageMappings in Debian <++= (debianMakeSysVinitScript, normalizedName) map { (script, name) => + for { + s <- script.toSeq + } yield LinuxPackageMapping(Seq(s -> ("/etc/init.d/" + name))).withPerms("0755") + }, + // TODO - only make these if the upstart config exists... + debianMakePrermScript <<= (normalizedName, target in Universal) map makeDebianPrermScript, + debianMakePostinstScript <<= (normalizedName, target in Universal) map makeDebianPostinstScript) + } + + + protected final def makeDebianSysVinitScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = + if (replacements.isEmpty) None + else { + val scriptBits = JavaAppSysVinitScript.generateScript(replacements) + val script = tmpDir / "tmp" / "bin" / (name + ".conf") + IO.write(script, scriptBits) + Some(script) + } +} + + +trait JavaServerAppPackaging { + + def settings: Seq[Setting[_]] + + protected def makeDebianPrermScript(name: String, tmpDir: File): Option[File] = { val scriptBits = JavaAppUpstartScript.generatePrerm(name) val script = tmpDir / "tmp" / "bin" / "debian-prerm" IO.write(script, scriptBits) Some(script) } - private[this] final def makeDebianPostinstScript(name: String, tmpDir: File): Option[File] = { + protected def makeDebianPostinstScript(name: String, tmpDir: File): Option[File] = { val scriptBits = JavaAppUpstartScript.generatePostinst(name) val script = tmpDir / "tmp" / "bin" / "debian-postinst" IO.write(script, scriptBits) Some(script) } - - private[this] final def makeDebianUpstartScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = - if (replacements.isEmpty) None - else { - val scriptBits = JavaAppUpstartScript.generateScript(replacements) - val script = tmpDir / "tmp" / "bin" / (name + ".conf") - IO.write(script, scriptBits) - Some(script) - } -} \ No newline at end of file +} diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala index 66da9378b..fcb255756 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -57,6 +57,20 @@ trait DebianKeys { | retries - on fail, how often should a restart be tried | retryTimeout - pause between retries """.stripMargin) + + // Debian sysVinit scripts + val debianMakeSysVinitScript = TaskKey[Option[File]]("makeSysVinitScript", "Creates or discovers the sysVinit script used by this project") + val debianSysVinitScriptReplacements = TaskKey[Seq[(String, String)]]("sysVinitScriptReplacements", + """|Replacements of template parameters used in the sysVinit script. + | Default supported templates: + | execScript - name of the script in /usr/bin + | daemonUser - daemon user + | author - author of this project + | descr - short description + | retries - on fail, how often should a restart be tried + | retryTimeout - pause between retries + """.stripMargin) + } /** Keys used for Debian specific settings. */ diff --git a/src/sbt-test/debian/sysvinit-deb/build.sbt b/src/sbt-test/debian/sysvinit-deb/build.sbt new file mode 100644 index 000000000..59966950f --- /dev/null +++ b/src/sbt-test/debian/sysvinit-deb/build.sbt @@ -0,0 +1,15 @@ +import NativePackagerKeys._ + +packageArchetype.java_server_sysvinit + +name := "debian-test" + +version := "0.1.0" + +maintainer := "Josh Suereth " + +packageSummary := "Test debian package" + +packageDescription := """A fun package description of our software, + with multiple lines.""" + diff --git a/src/sbt-test/debian/sysvinit-deb/project/plugins.sbt b/src/sbt-test/debian/sysvinit-deb/project/plugins.sbt new file mode 100644 index 000000000..b53de154c --- /dev/null +++ b/src/sbt-test/debian/sysvinit-deb/project/plugins.sbt @@ -0,0 +1 @@ +addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) diff --git a/src/sbt-test/debian/sysvinit-deb/test b/src/sbt-test/debian/sysvinit-deb/test new file mode 100644 index 000000000..b7ae637c9 --- /dev/null +++ b/src/sbt-test/debian/sysvinit-deb/test @@ -0,0 +1,6 @@ +# Run the debian packaging. +> debian:package-bin +$ exists target/debian-test-0.1.0.deb + +$ exists target/debian-test-0.1.0/etc +$ exists target/debian-test-0.1.0/etc/init.d/debian-test From c1a927ffbb6f02a5caadc44120e63066373e856b Mon Sep 17 00:00:00 2001 From: Alexey Kardapoltsev Date: Fri, 22 Nov 2013 13:54:15 +0600 Subject: [PATCH 2/4] Some config options added to sysvinit template. Small code refactor --- .../sbt/packager/archetypes/sysvinit-template | 6 +++--- .../packager/archetypes/JavaAppUpstartScript.scala | 8 +++++--- .../packager/archetypes/JavaServerApplication.scala | 11 ++++++----- .../scala/com/typesafe/sbt/packager/debian/Keys.scala | 3 +++ .../scala/com/typesafe/sbt/packager/linux/Keys.scala | 1 + 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template index e215060e9..544a7e85f 100644 --- a/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template @@ -10,11 +10,11 @@ ### END INIT INFO PIDFILE=/var/run/${{app_name}}.pid +DAEMON_USER=${{daemon_user}} . /lib/init/vars.sh . /lib/lsb/init-functions -#TODO: fix this get_java_cmd() { if [[ -n "$JAVA_HOME" ]] && [[ -x "$JAVA_HOME/bin/java" ]]; then echo "$JAVA_HOME/bin/java" @@ -31,12 +31,12 @@ case "$1" in start) log_daemon_msg "Starting ${{app_name}}" - start-stop-daemon --background --start --make-pidfile --pidfile $PIDFILE --exec $RUN_CMD + start-stop-daemon --background --start --chuid $DAEMON_USER --make-pidfile --pidfile $PIDFILE --exec $RUN_CMD ;; stop) log_daemon_msg "Stopping ${{app_name}}" - start-stop-daemon --stop --pidfile $PIDFILE --chuid $DAEMONUSER + start-stop-daemon --stop --pidfile $PIDFILE --chuid $DAEMON_USER RETVAL=$? [ $RETVAL -eq 0 ] && [ -e "$PIDFILE" ] && rm -f $PIDFILE diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala index b75bb7205..82212b894 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala @@ -13,7 +13,7 @@ object JavaAppUpstartScript extends JavaAppScript { /** * * @param author - - * @param description - short description + * @param descr - short description * @param execScript - name of the script in /usr/bin * @param chdir - execution path of the script * @param retries - on fail, how often should a restart be tried @@ -52,7 +52,8 @@ object JavaAppSysVinitScript extends JavaAppScript { appDir: String, appName: String, appMainClass: String, - appClasspath: String + appClasspath: String, + daemonUser: String ): Seq[(String, String)] = Seq( @@ -61,7 +62,8 @@ object JavaAppSysVinitScript extends JavaAppScript { "app_name" -> appName, "app_dir" -> appDir, "app_main_class" -> appMainClass, - "app_classpath" -> appClasspath + "app_classpath" -> appClasspath, + "daemon_user" -> daemonUser ) } diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala index 3c5383a68..ea9d141d7 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -43,7 +43,7 @@ object JavaServerAppPackaging extends JavaServerAppPackaging { debianMakePostinstScript <<= (normalizedName, target in Universal) map makeDebianPostinstScript) - protected final def makeDebianUpstartScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = + private def makeDebianUpstartScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = if (replacements.isEmpty) None else { val scriptBits = JavaAppUpstartScript.generateScript(replacements) @@ -61,9 +61,9 @@ object JavaServerAppSysVinitPackaging extends JavaServerAppPackaging { def debianSysVinitSettings: Seq[Setting[_]] = { Seq( - debianSysVinitScriptReplacements <<= (maintainer in Debian, packageSummary in Debian, + debianSysVinitScriptReplacements <<= (maintainer in Debian, packageSummary in Debian, daemonUser in Debian, normalizedName, name, sbt.Keys.version, defaultLinuxInstallLocation, sbt.Keys.mainClass in Compile, scriptClasspath) - map { (author, descr, normalizedName, name, version, installLocation, mainClass, cp) => + map { (author, descr, daemonUser, normalizedName, name, version, installLocation, mainClass, cp) => // TODO name-version is copied from UniversalPlugin. This should be consolidated into a setting (install location...) val appDir = installLocation + "/" + normalizedName val appClasspath = cp.map(appDir + "/lib/" + _).mkString(":") @@ -73,7 +73,8 @@ object JavaServerAppSysVinitPackaging extends JavaServerAppPackaging { appDir = appDir, appName = name, appClasspath = appClasspath, - appMainClass = mainClass.getOrElse("") //TODO: is it possible + appMainClass = mainClass.get, + daemonUser = daemonUser ) }, debianMakeSysVinitScript <<= (debianSysVinitScriptReplacements, normalizedName, target in Universal) map makeDebianSysVinitScript, @@ -88,7 +89,7 @@ object JavaServerAppSysVinitPackaging extends JavaServerAppPackaging { } - protected final def makeDebianSysVinitScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = + private def makeDebianSysVinitScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = if (replacements.isEmpty) None else { val scriptBits = JavaAppSysVinitScript.generateScript(replacements) diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala index fcb255756..c76e51cdc 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -91,5 +91,8 @@ object Keys extends DebianKeys { def target = sbt.Keys.target def streams = sbt.Keys.streams + //init script parameters + def daemonUser = linux.Keys.daemonUser + val debianPackageInstallSize = TaskKey[Long]("debian-installed-size") } diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala index fc6d6fce7..522d9c768 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala @@ -10,6 +10,7 @@ trait Keys { val packageSummary = SettingKey[String]("package-summary", "Summary of the contents of a linux package.") val packageDescription = SettingKey[String]("package-description", "The description of the package. Used when searching.") val maintainer = SettingKey[String]("maintainer", "The name/email address of a maintainer for the native package.") + val daemonUser = SettingKey[String]("daemon-user", "User to start application daemon") 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") From 3e512067b5684db212ecfb5c955da2e555027352 Mon Sep 17 00:00:00 2001 From: Alexey Kardapoltsev Date: Fri, 22 Nov 2013 20:26:33 +0600 Subject: [PATCH 3/4] Start script system added to settings in Debian --- .../com/typesafe/sbt/PackagerPlugin.scala | 2 - .../archetypes/JavaAppUpstartScript.scala | 92 ++++++++----------- .../archetypes/JavaServerApplication.scala | 89 ++++++------------ .../typesafe/sbt/packager/debian/Keys.scala | 24 ++--- .../typesafe/sbt/packager/linux/Keys.scala | 2 + 5 files changed, 79 insertions(+), 130 deletions(-) diff --git a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala index a62692a77..bebe1e2a6 100644 --- a/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala +++ b/src/main/scala/com/typesafe/sbt/PackagerPlugin.scala @@ -46,8 +46,6 @@ object SbtNativePackager extends Plugin genericMappingSettings ++ archetypes.JavaAppPackaging.settings def java_server: Seq[Setting[_]] = genericMappingSettings ++ archetypes.JavaServerAppPackaging.settings - def java_server_sysvinit: Seq[Setting[_]] = - genericMappingSettings ++ archetypes.JavaServerAppSysVinitPackaging.settings } // TODO - Add a few targets that detect the current OS and build a package for that OS. diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala index 82212b894..bfbdff0fc 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala @@ -1,66 +1,66 @@ package com.typesafe.sbt.packager.archetypes /** - * Constructs an upstart script for running a java application. - * - * Makes use of the associated upstart-template, with a few hooks + * Constructs an start script for running a java application. * */ -object JavaAppUpstartScript extends JavaAppScript { +object JavaAppStartScript { - protected def templateSource: java.net.URL = getClass.getResource("upstart-template") + import ServerLoader._ - /** - * - * @param author - - * @param descr - short description - * @param execScript - name of the script in /usr/bin - * @param chdir - execution path of the script - * @param retries - on fail, how often should a restart be tried - * @param retryTimeout - pause between retries - * @return Seq of key,replacement pairs - */ - def makeReplacements( - author: String, - descr: String, - execScript: String, - chdir: String, - retries: Int = 0, - retryTimeout: Int = 60): Seq[(String, String)] = Seq( - "exec" -> execScript, - "author" -> author, - "descr" -> descr, - "chdir" -> chdir, - "retries" -> retries.toString, - "retryTimeout" -> retryTimeout.toString) + 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 preremTemplateSource: java.net.URL = getClass.getResource("prerem-template") -object JavaAppSysVinitScript extends JavaAppScript { - protected def templateSource: java.net.URL = getClass.getResource("sysvinit-template") + + def generateScript(replacements: Seq[(String, String)], loader: ServerLoader): String = + loader match { + case Upstart => + TemplateWriter.generateScript(upstartTemplateSource, replacements) + case SystemV => + TemplateWriter.generateScript(sysvinitTemplateSource, replacements) + } + + + def generatePrerm(appName: String): String = + TemplateWriter.generateScript(preremTemplateSource, Seq("app_name" -> appName)) + + + def generatePostinst(appName: String): String = + TemplateWriter.generateScript(postinstTemplateSource, Seq("app_name" -> appName)) /** * * @param author - * @param description - short description + * @param execScript - name of the script in /usr/bin + * @param chdir - execution path of the script + * @param retries - on fail, how often should a restart be tried + * @param retryTimeout - pause between retries * @return Seq of key,replacement pairs */ def makeReplacements( author: String, description: String, - appDir: String, + execScript: String, + chdir: String, appName: String, appMainClass: String, appClasspath: String, - daemonUser: String - - ): Seq[(String, String)] = + daemonUser: String, + retries: Int = 0, + retryTimeout: Int = 60): Seq[(String, String)] = Seq( "author" -> author, "descr" -> description, + "exec" -> execScript, + "chdir" -> chdir, + "retries" -> retries.toString, + "retryTimeout" -> retryTimeout.toString, "app_name" -> appName, - "app_dir" -> appDir, "app_main_class" -> appMainClass, "app_classpath" -> appClasspath, "daemon_user" -> daemonUser @@ -68,19 +68,7 @@ object JavaAppSysVinitScript extends JavaAppScript { } -trait JavaAppScript { - - protected def templateSource: java.net.URL - - protected def postinstTemplateSource: java.net.URL = getClass.getResource("postinst-template") - protected def preremTemplateSource: java.net.URL = getClass.getResource("prerem-template") - - - def generateScript(replacements: Seq[(String, String)]): String = - TemplateWriter.generateScript(templateSource, replacements) - - def generatePrerm(appName: String): String = - TemplateWriter.generateScript(preremTemplateSource, Seq("app_name" -> appName)) - def generatePostinst(appName: String): String = - TemplateWriter.generateScript(postinstTemplateSource, Seq("app_name" -> appName)) -} \ No newline at end of file +object ServerLoader extends Enumeration { + type ServerLoader = Value + val Upstart, SystemV = Value +} diff --git a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala index ea9d141d7..5ef9f5b42 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -19,100 +19,69 @@ import com.typesafe.sbt.packager.linux.LinuxPackageMapping * * **NOTE: EXPERIMENTAL** This currently only supports debian upstart scripts. */ -object JavaServerAppPackaging extends JavaServerAppPackaging { +object JavaServerAppPackaging { + import ServerLoader._ - def settings: Seq[Setting[_]] = - JavaAppPackaging.settings ++ - debianUpstartSettings + def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ debianSettings - def debianUpstartSettings: Seq[Setting[_]] = + def debianSettings: Seq[Setting[_]] = Seq( - debianUpstartScriptReplacements <<= (maintainer in Debian, packageSummary in Debian, normalizedName, sbt.Keys.version, defaultLinuxInstallLocation) map { (author, descr, name, version, installLocation) => + debianStartScriptReplacements <<= ( + maintainer in Debian, packageSummary in Debian, serverLoading in Debian, daemonUser in Debian, normalizedName, sbt.Keys.version, defaultLinuxInstallLocation, sbt.Keys.mainClass in Compile, scriptClasspath) + map { (author, descr, loader, daemonUser, name, version, installLocation, mainClass, cp) => // TODO name-version is copied from UniversalPlugin. This should be consolidated into a setting (install location...) - val chdir = installLocation + "/" + name + "/bin" - JavaAppUpstartScript.makeReplacements(author = author, descr = descr, execScript = name, chdir = chdir) - }, - debianMakeUpstartScript <<= (debianUpstartScriptReplacements, normalizedName, target in Universal) map makeDebianUpstartScript, - linuxPackageMappings in Debian <++= (debianMakeUpstartScript, normalizedName) map { (script, name) => - for { - s <- script.toSeq - } yield LinuxPackageMapping(Seq(s -> ("/etc/init/" + name + ".conf"))).withPerms("0644") - }, - // TODO - only make these if the upstart config exists... - debianMakePrermScript <<= (normalizedName, target in Universal) map makeDebianPrermScript, - debianMakePostinstScript <<= (normalizedName, target in Universal) map makeDebianPostinstScript) - - - private def makeDebianUpstartScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = - if (replacements.isEmpty) None - else { - val scriptBits = JavaAppUpstartScript.generateScript(replacements) - val script = tmpDir / "tmp" / "bin" / (name + ".conf") - IO.write(script, scriptBits) - Some(script) - } -} - - -object JavaServerAppSysVinitPackaging extends JavaServerAppPackaging { - - def settings: Seq[Setting[_]] = - JavaAppPackaging.settings ++ debianSysVinitSettings - - def debianSysVinitSettings: Seq[Setting[_]] = { - Seq( - debianSysVinitScriptReplacements <<= (maintainer in Debian, packageSummary in Debian, daemonUser in Debian, - normalizedName, name, sbt.Keys.version, defaultLinuxInstallLocation, sbt.Keys.mainClass in Compile, scriptClasspath) - map { (author, descr, daemonUser, normalizedName, name, version, installLocation, mainClass, cp) => - // TODO name-version is copied from UniversalPlugin. This should be consolidated into a setting (install location...) - val appDir = installLocation + "/" + normalizedName + val appDir = installLocation + "/" + name + val chdir = appDir + "/bin" val appClasspath = cp.map(appDir + "/lib/" + _).mkString(":") - JavaAppSysVinitScript.makeReplacements( - author = author, description = descr, - appDir = appDir, + JavaAppStartScript.makeReplacements( + author = author, + description = descr, + execScript = name, + chdir = chdir, appName = name, appClasspath = appClasspath, appMainClass = mainClass.get, daemonUser = daemonUser ) }, - debianMakeSysVinitScript <<= (debianSysVinitScriptReplacements, normalizedName, target in Universal) map makeDebianSysVinitScript, - linuxPackageMappings in Debian <++= (debianMakeSysVinitScript, normalizedName) map { (script, name) => + debianMakeStartScript <<= (debianStartScriptReplacements, normalizedName, target in Universal, serverLoading in Debian) map makeDebianStartScript, + linuxPackageMappings in Debian <++= (debianMakeStartScript, normalizedName, serverLoading in Debian) map { (script, name, loader) => + val (path, permissions) = loader match { + case Upstart => ("/etc/init/" + name + ".conf", "0644") + case SystemV => ("/etc/init.d/" + name, "0755") + } + for { s <- script.toSeq - } yield LinuxPackageMapping(Seq(s -> ("/etc/init.d/" + name))).withPerms("0755") + } yield LinuxPackageMapping(Seq(s -> path)).withPerms(permissions) }, // TODO - only make these if the upstart config exists... debianMakePrermScript <<= (normalizedName, target in Universal) map makeDebianPrermScript, debianMakePostinstScript <<= (normalizedName, target in Universal) map makeDebianPostinstScript) - } - private def makeDebianSysVinitScript(replacements: Seq[(String, String)], name: String, tmpDir: File): Option[File] = + private def makeDebianStartScript( + replacements: Seq[(String, String)], name: String, tmpDir: File, loader: ServerLoader): Option[File] = if (replacements.isEmpty) None else { - val scriptBits = JavaAppSysVinitScript.generateScript(replacements) - val script = tmpDir / "tmp" / "bin" / (name + ".conf") + val scriptBits = JavaAppStartScript.generateScript(replacements, loader) + val script = tmpDir / "tmp" / "bin" / name IO.write(script, scriptBits) Some(script) } -} -trait JavaServerAppPackaging { - - def settings: Seq[Setting[_]] - protected def makeDebianPrermScript(name: String, tmpDir: File): Option[File] = { - val scriptBits = JavaAppUpstartScript.generatePrerm(name) + val scriptBits = JavaAppStartScript.generatePrerm(name) val script = tmpDir / "tmp" / "bin" / "debian-prerm" IO.write(script, scriptBits) Some(script) } + protected def makeDebianPostinstScript(name: String, tmpDir: File): Option[File] = { - val scriptBits = JavaAppUpstartScript.generatePostinst(name) + val scriptBits = JavaAppStartScript.generatePostinst(name) val script = tmpDir / "tmp" / "bin" / "debian-postinst" IO.write(script, scriptBits) Some(script) diff --git a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala index c76e51cdc..166e4d540 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -46,8 +46,8 @@ trait DebianKeys { | version - app version """.stripMargin) - val debianMakeUpstartScript = TaskKey[Option[File]]("makeUpstartScript", "Creates or discovers the upstart script used by this project") - val debianUpstartScriptReplacements = TaskKey[Seq[(String, String)]]("upstartScriptReplacements", + val debianMakeStartScript = TaskKey[Option[File]]("makeStartScript", "Creates or discovers the start script used by this project") + val debianStartScriptReplacements = TaskKey[Seq[(String, String)]]("upstartScriptReplacements", """|Replacements of template parameters used in the upstart script. | Default supported templates: | execScript - name of the script in /usr/bin @@ -56,23 +56,14 @@ trait DebianKeys { | chdir - execution path of the script | retries - on fail, how often should a restart be tried | retryTimeout - pause between retries + | appName - name of application + | appClasspath - application classpath + | appMainClass - main class to start + | daemonUser - daemon user """.stripMargin) - - // Debian sysVinit scripts - val debianMakeSysVinitScript = TaskKey[Option[File]]("makeSysVinitScript", "Creates or discovers the sysVinit script used by this project") - val debianSysVinitScriptReplacements = TaskKey[Seq[(String, String)]]("sysVinitScriptReplacements", - """|Replacements of template parameters used in the sysVinit script. - | Default supported templates: - | execScript - name of the script in /usr/bin - | daemonUser - daemon user - | author - author of this project - | descr - short description - | retries - on fail, how often should a restart be tried - | retryTimeout - pause between retries - """.stripMargin) - } + /** Keys used for Debian specific settings. */ object Keys extends DebianKeys { // Metadata keys @@ -93,6 +84,7 @@ object Keys extends DebianKeys { //init script parameters def daemonUser = linux.Keys.daemonUser + def serverLoading = linux.Keys.serverLoading val debianPackageInstallSize = TaskKey[Long]("debian-installed-size") } diff --git a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala index 522d9c768..a91868cbe 100644 --- a/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/linux/Keys.scala @@ -3,6 +3,7 @@ package packager package linux import sbt._ +import com.typesafe.sbt.packager.archetypes.ServerLoader.ServerLoader /** Linux packaging generic build targets. */ trait Keys { @@ -11,6 +12,7 @@ trait Keys { val packageDescription = SettingKey[String]("package-description", "The description of the package. Used when searching.") val maintainer = SettingKey[String]("maintainer", "The name/email address of a maintainer for the native package.") val daemonUser = SettingKey[String]("daemon-user", "User to start application daemon") + val serverLoading = SettingKey[ServerLoader]("server-loader", "Loading system to be used for application start script") 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") From 96a0043e62d1958b26eb33341911dc25ca6f2309 Mon Sep 17 00:00:00 2001 From: Alexey Kardapoltsev Date: Sat, 23 Nov 2013 12:13:12 +0600 Subject: [PATCH 4/4] sbt downgraded to 0.12.4, test for sysvinit-deb fixed --- project/build.properties | 2 +- src/sbt-test/debian/sysvinit-deb/build.sbt | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/project/build.properties b/project/build.properties index 0974fce44..5e96e9672 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=0.13.0 +sbt.version=0.12.4 diff --git a/src/sbt-test/debian/sysvinit-deb/build.sbt b/src/sbt-test/debian/sysvinit-deb/build.sbt index 59966950f..aae500ea3 100644 --- a/src/sbt-test/debian/sysvinit-deb/build.sbt +++ b/src/sbt-test/debian/sysvinit-deb/build.sbt @@ -1,6 +1,13 @@ import NativePackagerKeys._ +import com.typesafe.sbt.packager.archetypes.ServerLoader -packageArchetype.java_server_sysvinit +packageArchetype.java_server + +serverLoading in Debian := ServerLoader.SystemV + +daemonUser in Debian := "root" + +mainClass in Compile := Some("empty") name := "debian-test"