Created
December 19, 2018 04:22
-
-
Save markehammons/42d75709e060625f1a663b442842b461 to your computer and use it in GitHub Desktop.
Packaging your application with a minimized runtime courtesy of jlink
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
import java.io.{ByteArrayOutputStream, PrintWriter} | |
import java.util.spi.ToolProvider | |
enablePlugins(JavaAppPackaging) | |
//this allows us to run tools like jdeps and jlink from within the JVM | |
def runTool(name: String, arguments: Seq[String]): Either[String,String] = { | |
val maybeTool: Option[ToolProvider] = { | |
val _tool = ToolProvider.findFirst(name) | |
if(_tool.isPresent) { | |
Some(_tool.get()) | |
} else { | |
None | |
} | |
} | |
val result = for(tool <- maybeTool) yield { | |
val stdOut = new ByteArrayOutputStream() | |
val errOut = new ByteArrayOutputStream() | |
tool.run(new PrintWriter(stdOut), new PrintWriter(errOut), arguments: _*) | |
(new String(stdOut.toByteArray), new String(errOut.toByteArray)) | |
} | |
result | |
.toRight(s"Could not find tool $name in your java development environment") | |
.flatMap{ case (ret,err) => | |
if(ret.contains("Error:") || err.nonEmpty) { | |
Left(ret + err) | |
} else { | |
Right(ret -> "") | |
} | |
} | |
.map(_._1) | |
} | |
//get the jvm module dependencies (such as java.base) from our application and imported libraries | |
val moduleDependencies = taskKey[Array[String]]("outputs the jdk module dependency information of our classpath") | |
moduleDependencies := { | |
val logger = streams.value | |
logger.log.info("getting module dependencies from jdeps...") | |
val classPathValue = (dependencyClasspath in Runtime) | |
.value | |
.map(_.data.getAbsolutePath) | |
val command = Seq("-recursive", "--list-deps") ++ classPathValue | |
logger.log.info(s"jdeps ${command.mkString(" ")}") | |
runTool("jdeps", command) | |
.map(_ | |
.split('\n') | |
.filter(!_.isEmpty) | |
.map(_ | |
.filter(!_.isWhitespace) | |
.split('/') | |
.head | |
) | |
.distinct | |
.filter(_ != "JDKremovedinternalAPI") | |
) | |
.fold(sys.error, mods => { | |
logger.log.info("done generating module dependencies...") | |
mods | |
}) | |
} | |
//this generates the minimized JRE for our application courtesy of jlink | |
val jlink = taskKey[File]("generates a java runtime for the project") | |
jlink := { | |
val logger = streams.value | |
logger.log.info("generating runtime with jlink...") | |
val outputFile = target.value / s"${name.value}-runtime" | |
if(outputFile.exists()) { | |
logger.log.info("deleting already generated runtime") | |
IO.delete(outputFile) | |
} | |
val modulesToAdd = Seq("--add-modules", moduleDependencies.value.mkString(",")) | |
val outputArgument = Seq("--output", outputFile.absolutePath) | |
val command = Seq("--no-header-files","--no-man-pages","--compress=2","--strip-debug") ++ modulesToAdd ++ outputArgument | |
logger.log.debug(s"command: jlink ${command.mkString(" ")}") | |
runTool("jlink", command).map(_ => outputFile).fold(sys.error, identity) | |
} | |
//this tells sbt-native-packager to bundle our minimized JRE with our application | |
mappings in Universal ++= { | |
val dir = jlink.value | |
(dir.**(AllPassFilter) --- dir).pair(file => IO.relativize(dir.getParentFile, file)) | |
} | |
//sbt-native-packager launch script modifications necessary for using the internal JRE to run the application | |
bashScriptExtraDefines ++= Seq(s"JAVA_HOME=$$app_home/../${jlink.value.getName}") | |
//call sbt universal:packageBin to create a nice packed up .zip of your application with launch script | |
// and all the dependencies needed to run it! Windows users will need to add a change to the batch script | |
// to get the batch script launcher to use the built-in jre. |
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
//needed for packaging. remember to put in project/plugins.sbt | |
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.3.15") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment