diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/postinst-sysvinit-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postinst-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/postinst-sysvinit-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postinst-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/postrm-sysvinit-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postrm-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/postrm-sysvinit-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/postrm-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/prerem-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/prerm-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/prerem-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/prerm-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/sysvinit-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/systemv/start-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/postinst-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/postinst-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/postinst-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/postinst-template diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template new file mode 100644 index 000000000..52a993a8e --- /dev/null +++ b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/prerm-template @@ -0,0 +1 @@ +service ${{app_name}} stop || echo "${{app_name}} wasn't even running!" \ No newline at end of file diff --git a/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart-template b/src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-template similarity index 100% rename from src/main/resources/com/typesafe/sbt/packager/archetypes/upstart-template rename to src/main/resources/com/typesafe/sbt/packager/archetypes/upstart/start-template 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 dfd917959..a4475de19 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppUpstartScript.scala @@ -10,46 +10,67 @@ import java.net.URL object JavaAppStartScript { import ServerLoader._ + import com.typesafe.sbt.packager.debian.DebianPlugin.Names._ + val startScript = "start" - 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 postrmSysvinitTemplateSource: URL = getClass.getResource("postrm-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 - } + private val upstartScripts = Seq(startScript, Postinst, Prerm) + private val systemvScripts = Seq(startScript, Postinst, Prerm, Postrm) + /** + * Generating the URL to the startScript template. + * 1. Looking in defaultLocation + * 2. Using default fallback + * + * @param loader - used, when no file in the defaultLocation + * @param defaultLocation - use if exists + */ + def defaultStartScriptTemplate(loader: ServerLoader, defaultLocation: File): URL = + if (defaultLocation.exists) defaultLocation.toURI.toURL + else templateUrl(startScript, loader) getOrElse sys.error("Default startscript not available for loader: " + loader) - def generatePrerm(appName: String, template: java.net.URL = preremTemplateSource): String = - TemplateWriter.generateScript(template, Seq("app_name" -> appName)) - + /** + * Generating the start script depending on the serverLoader. + * + * @param loader - which startup system + * @param replacements - default replacements + * @param template - if specified, it will override the default one + */ + def generateStartScript( + loader: ServerLoader, + replacements: Seq[(String, String)], + template: Option[URL] = None): Option[String] = generateTemplate(startScript, loader, replacements, template) - def generatePostrm(appName: String, loader: ServerLoader, template: Option[java.net.URL] = None): Option[String] = - (template, loader) match { - case (Some(template), _) => Option(TemplateWriter.generateScript(template, Seq("app_name" -> appName))) - case (_, SystemV) => - Option(TemplateWriter.generateScript(postrmSysvinitTemplateSource, Seq("app_name" -> appName))) - case (_, _) => None - } + /** + * + * @param templateName - DebianPlugin.Names for maintainer scripts and "start" + * @param loader - which startup system + * @param replacements - default replacements + * @param template - if specified, it will override the default one + */ + def generateTemplate( + templateName: String, + loader: ServerLoader, + replacements: Seq[(String, String)], + template: Option[URL] = None): Option[String] = { + // use template orElse search for a default + val url = templateUrl(templateName, loader, template) - 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) => - TemplateWriter.generateScript(postinstSysvinitTemplateSource, Seq("app_name" -> appName)) + // if an url was found, create the script + url map { template => + TemplateWriter generateScript (template, replacements) } + } + def templateUrl(templateName: String, loader: ServerLoader, template: Option[URL] = None): Option[URL] = template orElse { + Option(loader match { + case Upstart if (upstartScripts contains templateName) => + getClass getResource ("upstart/" + templateName + "-template") + case SystemV if (systemvScripts contains templateName) => + getClass getResource ("systemv/" + templateName + "-template") + case _ => null + }) + } /** * @@ -82,11 +103,9 @@ object JavaAppStartScript { "app_name" -> appName, "app_main_class" -> appMainClass, "app_classpath" -> appClasspath, - "daemon_user" -> daemonUser - ) + "daemon_user" -> daemonUser) } - 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 a21ceeb9b..6ebf4e822 100644 --- a/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala +++ b/src/main/scala/com/typesafe/sbt/packager/archetypes/JavaServerApplication.scala @@ -7,6 +7,7 @@ import sbt._ import sbt.Keys.{ target, mainClass, normalizedName, sourceDirectory } import SbtNativePackager._ import com.typesafe.sbt.packager.linux.{ LinuxFileMetaData, LinuxPackageMapping, LinuxSymlink, LinuxPlugin } +import com.typesafe.sbt.packager.debian.DebianPlugin /** * This class contains the default settings for creating and deploying an archetypical Java application. @@ -20,6 +21,7 @@ import com.typesafe.sbt.packager.linux.{ LinuxFileMetaData, LinuxPackageMapping, object JavaServerAppPackaging { import ServerLoader._ import LinuxPlugin.Users + import DebianPlugin.Names.{ Preinst, Postinst, Prerm, Postrm } def settings: Seq[Setting[_]] = JavaAppPackaging.settings ++ debianSettings protected def etcDefaultTemplateSource: java.net.URL = getClass.getResource("etc-default-template") @@ -29,7 +31,7 @@ object JavaServerAppPackaging { serverLoading := Upstart, daemonUser := Users.Root, // This one is begging for sbt 0.13 syntax... - debianStartScriptReplacements <<= ( + debianScriptReplacements <<= ( maintainer in Debian, packageSummary in Debian, serverLoading in Debian, daemonUser in Debian, normalizedName, sbt.Keys.version, defaultLinuxInstallLocation, mainClass in Compile, scriptClasspath) map { (author, descr, loader, daemonUser, name, version, installLocation, mainClass, cp) => @@ -47,21 +49,15 @@ object JavaServerAppPackaging { daemonUser = daemonUser) }, // TODO - Default locations shouldn't be so hacky. + + // === Startscript creation === linuxStartScriptTemplate in Debian <<= (serverLoading in Debian, sourceDirectory) map { (loader, dir) => JavaAppStartScript.defaultStartScriptTemplate(loader, dir / "templates" / "start") }, - debianMakeStartScript <<= (debianStartScriptReplacements, normalizedName, target in Universal, linuxStartScriptTemplate in Debian) - map makeDebianStartScript, - linuxEtcDefaultTemplate in Debian <<= sourceDirectory 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 - }, + debianMakeStartScript <<= (target in Universal, serverLoading in Debian, debianScriptReplacements, linuxStartScriptTemplate in Debian) + map { (tmpDir, loader, replacements, template) => + makeDebianMaintainerScript(JavaAppStartScript.startScript, Some(template))(tmpDir, loader, replacements) + }, linuxPackageMappings in Debian <++= (debianMakeStartScript, normalizedName, serverLoading in Debian) map { (script, name, loader) => val (path, permissions) = loader match { @@ -72,7 +68,21 @@ object JavaServerAppPackaging { s <- script.toSeq } yield LinuxPackageMapping(Seq(s -> path)).withPerms(permissions).withConfig() }, + + // === etc config mapping === + linuxEtcDefaultTemplate in Debian <<= sourceDirectory 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 + }, // TODO should we specify daemonGroup in configs? + + // === logging directory mapping === linuxPackageMappings in Debian <+= (normalizedName, defaultLinuxLogsLocation, target in Debian, daemonUser in Debian) map { (name, logsDir, target, user) => // create empty var/log directory @@ -83,45 +93,22 @@ object JavaServerAppPackaging { linuxPackageSymlinks in Debian <+= (normalizedName, defaultLinuxInstallLocation) map { (name, install) => LinuxSymlink(install + "/" + name + "/logs", "/var/log/" + name) }, - // TODO - only make these if the upstart config exists... - debianMakePrermScript <<= (normalizedName, target in Universal) map makeDebianPrermScript, - debianMakePostrmScript <<= (normalizedName, target in Universal, serverLoading in Debian) map makeDebianPostrmScript, - debianMakePostinstScript <<= (normalizedName, target in Universal, serverLoading in Debian) map makeDebianPostinstScript) - private def makeDebianStartScript( - replacements: Seq[(String, String)], name: String, tmpDir: File, template: URL): Option[File] = - if (replacements.isEmpty) None - else { - val scriptBits = TemplateWriter.generateScript(template, replacements) - val script = tmpDir / "tmp" / "init" / name - IO.write(script, scriptBits) - Some(script) - } + // === Maintainer scripts === + debianMakePreinstScript <<= (target in Universal, serverLoading in Debian, debianScriptReplacements) map makeDebianMaintainerScript(Preinst), + debianMakePostinstScript <<= (target in Universal, serverLoading in Debian, debianScriptReplacements) map makeDebianMaintainerScript(Postinst), + debianMakePrermScript <<= (target in Universal, serverLoading in Debian, debianScriptReplacements) map makeDebianMaintainerScript(Prerm), + debianMakePostrmScript <<= (target in Universal, serverLoading in Debian, debianScriptReplacements) map makeDebianMaintainerScript(Postrm)) - protected def makeDebianPrermScript(name: String, tmpDir: File): Option[File] = { - val scriptBits = JavaAppStartScript.generatePrerm(name) - val script = tmpDir / "tmp" / "bin" / "debian-prerm" - IO.write(script, scriptBits) - Some(script) - } - - protected def makeDebianPostrmScript(name: String, tmpDir: File, loader: ServerLoader): Option[File] = { - JavaAppStartScript.generatePostrm(name, loader) match { - case Some(scriptBits) => - val script = tmpDir / "tmp" / "bin" / "debian-postrm" - IO.write(script, scriptBits) - Some(script) - case None => None + protected def makeDebianMaintainerScript(scriptName: String, template: Option[URL] = None)( + tmpDir: File, loader: ServerLoader, replacements: Seq[(String, String)]): Option[File] = { + JavaAppStartScript.generateTemplate(scriptName, loader, replacements, template) map { scriptBits => + val script = tmpDir / "tmp" / "bin" / ("debian-" + scriptName) + IO.write(script, scriptBits) + script } } - protected def makeDebianPostinstScript(name: String, tmpDir: File, loader: ServerLoader): Option[File] = { - val scriptBits = JavaAppStartScript.generatePostinst(name, loader) - val script = tmpDir / "tmp" / "bin" / "debian-postinst" - IO.write(script, scriptBits) - Some(script) - } - protected def makeEtcDefaultScript(name: String, tmpDir: File, loader: ServerLoader, source: java.net.URL): Option[File] = { loader match { case Upstart => None 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 63fefdfdb..ba50c99bf 100644 --- a/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala +++ b/src/main/scala/com/typesafe/sbt/packager/debian/Keys.scala @@ -47,7 +47,7 @@ trait DebianKeys { """.stripMargin) val debianMakeStartScript = TaskKey[Option[File]]("makeStartScript", "Creates or discovers the start script used by this project") - val debianStartScriptReplacements = TaskKey[Seq[(String, String)]]("upstartScriptReplacements", + val debianScriptReplacements = 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