-
Notifications
You must be signed in to change notification settings - Fork 443
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 #647 from gzoller/wip/ash
wip/ash
- Loading branch information
Showing
11 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
113 changes: 113 additions & 0 deletions
113
src/main/scala/com/typesafe/sbt/packager/archetypes/AshScriptPlugin.scala
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,113 @@ | ||
package com.typesafe.sbt | ||
package packager | ||
package archetypes | ||
|
||
import sbt._ | ||
import sbt.Keys.{ mappings, target, name, mainClass, sourceDirectory, javaOptions, streams } | ||
import packager.Keys.{ packageName, executableScriptName } | ||
import linux.{ LinuxFileMetaData, LinuxPackageMapping } | ||
import linux.LinuxPlugin.autoImport.{ linuxPackageMappings, defaultLinuxInstallLocation } | ||
import SbtNativePackager.{ Universal, Debian } | ||
|
||
/** | ||
* == Java Application == | ||
* | ||
* This class is an alternate to JavaAppPackaging designed to support the ash shell. JavaAppPackaging | ||
* generates bash-specific code that is not compatible with ash, a very stripped-down, lightweight shell | ||
* used by popular micro base Docker images like BusyBox. The AshScriptPlugin will generate simple | ||
* ash-compatible output. | ||
* | ||
* Just like with JavaAppPackaging you can override the bash-template file by creating a src/templates | ||
* directory and adding your own bash-template file. Actually this isn't a bad idea as the default | ||
* bash-template file inherited from JavaAppPackaging has a lot of stuff you probably don't want/need | ||
* in a highly-constrained environment like ash+BusyBox. Something much simpler will do, for example: | ||
* | ||
* #!/usr/bin/env sh | ||
* | ||
* realpath () { | ||
* ( | ||
* TARGET_FILE="$1" | ||
* | ||
* cd "$(dirname "$TARGET_FILE")" | ||
* TARGET_FILE=$(basename "$TARGET_FILE") | ||
* | ||
* COUNT=0 | ||
* while [ -L "$TARGET_FILE" -a $COUNT -lt 100 ] | ||
* do | ||
* TARGET_FILE=$(readlink "$TARGET_FILE") | ||
* cd "$(dirname "$TARGET_FILE")" | ||
* TARGET_FILE=$(basename "$TARGET_FILE") | ||
* COUNT=$(($COUNT + 1)) | ||
* done | ||
* | ||
* if [ "$TARGET_FILE" == "." -o "$TARGET_FILE" == ".." ]; then | ||
* cd "$TARGET_FILE" | ||
* TARGET_FILEPATH= | ||
* else | ||
* TARGET_FILEPATH=/$TARGET_FILE | ||
* fi | ||
* | ||
* echo "$(pwd -P)/$TARGET_FILE" | ||
* ) | ||
* } | ||
* | ||
* real_script_path="$(realpath "$0")" | ||
* app_home="$(realpath "$(dirname "$real_script_path")")" | ||
* lib_dir="$(realpath "${app_home}/../lib")" | ||
* | ||
* ${{template_declares}} | ||
* | ||
* java -classpath $app_classpath $app_mainclass $@ | ||
* | ||
* | ||
* == Configuration == | ||
* | ||
* This plugin adds new settings to configure your packaged application. | ||
* The keys are defined in [[com.typesafe.sbt.packager.archetypes.JavaAppKeys]] | ||
* | ||
* @example Enable this plugin in your `build.sbt` with | ||
* | ||
* {{{ | ||
* enablePlugins(AshScriptPlugin) | ||
* }}} | ||
*/ | ||
object AshScriptPlugin extends AutoPlugin { | ||
|
||
val bashTemplate = "bash-template" | ||
|
||
override def requires = JavaAppPackaging | ||
|
||
//object autoImport extends JavaAppKeys | ||
|
||
import JavaAppPackaging.autoImport._ | ||
|
||
override def projectSettings = Seq( | ||
makeBashScript <<= (bashScriptTemplateLocation, bashScriptDefines, target in Universal, executableScriptName, sourceDirectory) map makeUniversalAshScript, | ||
bashScriptDefines <<= (Keys.mainClass in (Compile, bashScriptDefines), scriptClasspath in bashScriptDefines, bashScriptExtraDefines, bashScriptConfigLocation) map { (mainClass, cp, extras, config) => | ||
val hasMain = | ||
for { | ||
cn <- mainClass | ||
} yield JavaAppAshScript.makeDefines(cn, appClasspath = cp, extras = extras, configFile = config) | ||
hasMain getOrElse Nil | ||
} | ||
) | ||
|
||
def makeUniversalAshScript(defaultTemplateLocation: File, defines: Seq[String], tmpDir: File, name: String, sourceDir: File): Option[File] = | ||
if (defines.isEmpty) None | ||
else { | ||
val template = resolveTemplate(defaultTemplateLocation) | ||
val scriptBits = JavaAppAshScript.generateScript(defines, template) | ||
val script = tmpDir / "tmp" / "bin" / name | ||
IO.write(script, scriptBits) | ||
// TODO - Better control over this! | ||
script.setExecutable(true) | ||
Some(script) | ||
} | ||
|
||
private def resolveTemplate(defaultTemplateLocation: File): URL = { | ||
if (defaultTemplateLocation.exists) | ||
defaultTemplateLocation.toURI.toURL | ||
else | ||
getClass.getResource(defaultTemplateLocation.getName) | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
src/main/scala/com/typesafe/sbt/packager/archetypes/JavaAppAshScript.scala
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,58 @@ | ||
package com.typesafe.sbt.packager.archetypes | ||
|
||
import java.net.URL | ||
|
||
/** | ||
* Constructs a bash script for running a java application. | ||
* | ||
* Makes use of the associated bash-template, with a few hooks | ||
* | ||
*/ | ||
object JavaAppAshScript { | ||
|
||
private[this] def bashTemplateSource = | ||
getClass.getResource("bash-template") | ||
|
||
/** | ||
* Creates the block of defines for a script. | ||
* | ||
* @param mainClass The required "main" method class we use to run the program. | ||
* @param appClasspath A sequence of relative-locations (to the lib/ folder) of jars | ||
* to include on the classpath. | ||
* @param configFile An (optional) filename from which the script will read arguments. | ||
* @param extras Any additional defines/commands that should be run in this script. | ||
*/ | ||
def makeDefines( | ||
mainClass: String, | ||
appClasspath: Seq[String] = Seq("*"), | ||
configFile: Option[String] = None, | ||
extras: Seq[String] = Nil): Seq[String] = | ||
Seq(mainClassDefine(mainClass)) ++ | ||
(configFile map configFileDefine).toSeq ++ | ||
Seq(makeClasspathDefine(appClasspath)) ++ | ||
extras | ||
|
||
private def makeClasspathDefine(cp: Seq[String]): String = { | ||
val fullString = cp map (n => "$lib_dir/" + n) mkString ":" | ||
"app_classpath=\"" + fullString + "\"\n" | ||
} | ||
def generateScript(defines: Seq[String], template: URL = bashTemplateSource): String = { | ||
val defineString = defines mkString "\n" | ||
val replacements = Seq("template_declares" -> defineString) | ||
TemplateWriter.generateScript(template, replacements) | ||
} | ||
|
||
def configFileDefine(configFile: String) = | ||
"script_conf_file=\"%s\"" format (configFile) | ||
|
||
def mainClassDefine(mainClass: String) = { | ||
val jarPrefixed = """^\-jar (.*)""".r | ||
val args = mainClass match { | ||
case jarPrefixed(jarName) => Seq("-jar", jarName) | ||
case className => Seq(className) | ||
} | ||
val quotedArgsSpaceSeparated = args.map(s => "\"" + s + "\"").mkString(" ") | ||
"app_mainclass=%s\n" format (quotedArgsSpaceSeparated) | ||
} | ||
|
||
} |
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,18 @@ | ||
import scala.io.Source | ||
|
||
enablePlugins(AshScriptPlugin) | ||
|
||
name := "override-templates" | ||
|
||
version := "0.1.0" | ||
|
||
bashScriptTemplateLocation := baseDirectory.value / "custom-templates" / "custom-ash-template" | ||
|
||
TaskKey[Unit]("run-check-ash") := { | ||
val cwd = (stagingDirectory in Universal).value | ||
val source = scala.io.Source.fromFile((cwd / "bin" / packageName.value).getAbsolutePath) | ||
val contents = try source.getLines mkString "\n" finally source.close() | ||
assert(contents contains "this is the custom bash template", "Bash template didn't contain the right text: \n" + contents) | ||
assert(contents contains "app_mainclass=","Template didn't contain the right text: \n"+contents) | ||
assert( !(contents contains "declare"),"Template didn't contain the right text: \n"+contents) | ||
} |
5 changes: 5 additions & 0 deletions
5
src/sbt-test/ash/override-templates/custom-templates/custom-ash-template
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,5 @@ | ||
#!/usr/bin/env sh | ||
|
||
# this is the custom bash template | ||
|
||
${{template_declares}} |
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 @@ | ||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) |
3 changes: 3 additions & 0 deletions
3
src/sbt-test/ash/override-templates/src/main/scala/MainApp.scala
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,3 @@ | ||
object MainApp extends App { | ||
println("SUCCESS!") | ||
} |
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,3 @@ | ||
# Run the staging and check the script. | ||
> stage | ||
> run-check-ash |
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,12 @@ | ||
enablePlugins(AshScriptPlugin) | ||
|
||
name := "simple-app" | ||
|
||
version := "0.1.0" | ||
|
||
TaskKey[Unit]("run-check") := { | ||
val cwd = (stagingDirectory in Universal).value | ||
val cmd = Seq((cwd / "bin" / packageName.value).getAbsolutePath) | ||
val output = Process(cmd, cwd).!! | ||
assert(output contains "SUCCESS!", "Output didn't contain success: " + output) | ||
} |
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 @@ | ||
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version")) |
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,3 @@ | ||
object MainApp extends App { | ||
println("SUCCESS!") | ||
} |
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,3 @@ | ||
# Run the staging and check the script. | ||
> stage | ||
> run-check |