Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Win exit code fix #421

Closed
wants to merge 14 commits into from
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,8 @@ Any help on testing and improving this feature is appreciated so feel free to re

Native packager now provides experimental `Docker` images.
To enable this feature follow [My First Packaged Server Project guide](http://www.scala-sbt.org/sbt-native-packager/GettingStartedServers/MyFirstProject.html) and use one of the provided Docker tasks for generating images.
The only essential extra setting for creating a local image for testing is:

maintainer in Docker := "John Smith <john.smith@example.com>"

To publish the image, ``dockerRepository`` should also be set.
To publish the image, ``dockerRepository`` should be set.

As with the `systemd` support, help with testing and improvements is appreciated.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
@setlocal enabledelayedexpansion

@echo off

if "%@@APP_ENV_NAME@@_HOME%"=="" set "@@APP_ENV_NAME@@_HOME=%~dp0\\.."
set ERROR_CODE=0

set "APP_LIB_DIR=%@@APP_ENV_NAME@@_HOME%\lib\"

rem Detect if we were double clicked, although theoretically A user could
rem manually run cmd /c
for %%x in (%cmdcmdline%) do if %%~x==/c set DOUBLECLICKED=1
for %%x in (!cmdcmdline!) do if %%~x==/c set DOUBLECLICKED=1

rem FIRST we load the config file of extra options.
set "CFG_FILE=%@@APP_ENV_NAME@@_HOME%\@@APP_ENV_NAME@@_config.txt"
Expand Down Expand Up @@ -72,86 +73,63 @@ if "%JAVAOK%"=="false" (

rem We use the value of the JAVA_OPTS environment variable if defined, rather than the config.
set _JAVA_OPTS=%JAVA_OPTS%
if "%_JAVA_OPTS%"=="" set _JAVA_OPTS=%CFG_OPTS%
if "!_JAVA_OPTS!"=="" set _JAVA_OPTS=!CFG_OPTS!

rem We keep in _JAVA_PARAMS all -J-prefixed and -D-prefixed arguments
rem "-J" is stripped, "-D" is left as is, and everything is appended to JAVA_OPTS
set _JAVA_PARAMS=

:param_beforeloop
if [%1]==[] goto param_afterloop
set _TEST_PARAM=%~1

rem ignore arguments that do not start with '-'
if not "%_TEST_PARAM:~0,1%"=="-" (
shift
goto param_beforeloop
)

set _TEST_PARAM=%~1
if "%_TEST_PARAM:~0,2%"=="-J" (
rem strip -J prefix
set _TEST_PARAM=%_TEST_PARAM:~2%
)

if "%_TEST_PARAM:~0,2%"=="-D" (
rem test if this was double-quoted property "-Dprop=42"
for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO (
if not "%%G" == "%_TEST_PARAM%" (
rem double quoted: "-Dprop=42" -> -Dprop="42"
set _JAVA_PARAMS=%%G="%%H"
) else if [%2] neq [] (
rem it was a normal property: -Dprop=42 or -Drop="42"
set _JAVA_PARAMS=%_TEST_PARAM%=%2
shift
)
)
) else (
rem a JVM property, we just append it
set _JAVA_PARAMS=%_TEST_PARAM%
)
set _APP_ARGS=

:param_loop
shift
call set _PARAM1=%%1
set "_TEST_PARAM=%~1"

if ["!_PARAM1!"]==[""] goto param_afterloop

if [%1]==[] goto param_afterloop
set _TEST_PARAM=%~1

rem ignore arguments that do not start with '-'
if not "%_TEST_PARAM:~0,1%"=="-" goto param_loop
if "%_TEST_PARAM:~0,1%"=="-" goto param_java_check
set _APP_ARGS=!_APP_ARGS! !_PARAM1!
shift
goto param_loop

set _TEST_PARAM=%~1
if "%_TEST_PARAM:~0,2%"=="-J" (
:param_java_check
if "!_TEST_PARAM:~0,2!"=="-J" (
rem strip -J prefix
set _TEST_PARAM=%_TEST_PARAM:~2%
set _JAVA_PARAMS=!_JAVA_PARAMS! !_TEST_PARAM:~2!
shift
goto param_loop
)

if "%_TEST_PARAM:~0,2%"=="-D" (
if "!_TEST_PARAM:~0,2!"=="-D" (
rem test if this was double-quoted property "-Dprop=42"
for /F "delims== tokens=1-2" %%G in ("%_TEST_PARAM%") DO (
if not "%%G" == "%_TEST_PARAM%" (
rem double quoted: "-Dprop=42" -> -Dprop="42"
set _JAVA_PARAMS=%_JAVA_PARAMS% %%G="%%H"
for /F "delims== tokens=1,*" %%G in ("!_TEST_PARAM!") DO (
if not ["%%H"] == [""] (
set _JAVA_PARAMS=!_JAVA_PARAMS! !_PARAM1!
) else if [%2] neq [] (
rem it was a normal property: -Dprop=42 or -Drop="42"
set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM%=%2
call set _PARAM1=%%1=%%2
set _JAVA_PARAMS=!_JAVA_PARAMS! !_PARAM1!
shift
)
)
) else (
rem a JVM property, we just append it
set _JAVA_PARAMS=%_JAVA_PARAMS% %_TEST_PARAM%
set _APP_ARGS=!_APP_ARGS! !_PARAM1!
)
shift
goto param_loop
:param_afterloop

set _JAVA_OPTS=%_JAVA_OPTS% %_JAVA_PARAMS%
set _JAVA_OPTS=!_JAVA_OPTS! !_JAVA_PARAMS!
:run

@@APP_DEFINES@@

rem Call the application and pass all arguments unchanged.
"%_JAVACMD%" %_JAVA_OPTS% %@@APP_ENV_NAME@@_OPTS% -cp "%APP_CLASSPATH%" %APP_MAIN_CLASS% %*
"%_JAVACMD%" !_JAVA_OPTS! !@@APP_ENV_NAME@@_OPTS! -cp "%APP_CLASSPATH%" %APP_MAIN_CLASS% !_APP_ARGS!

@endlocal

if ERRORLEVEL 1 goto error
goto end

Expand All @@ -160,6 +138,4 @@ set ERROR_CODE=1

:end

@endlocal

exit /B %ERROR_CODE%
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,17 @@ if [ -z "$DAEMON_USER" ]; then
DAEMON_USER=${{daemon_user}}
fi

if [ -z "$DAEMON_GROUP" ]; then
DAEMON_GROUP=${{daemon_group}}
fi


RUN_CMD="${{chdir}}/bin/${{exec}}"


start_daemon() {
log_daemon_msg "Starting" "${{app_name}}"
[ -d "/var/run/${{app_name}}" ] || install -d -o "$DAEMON_USER" -m750 "/var/run/${{app_name}}"
[ -d "/var/run/${{app_name}}" ] || install -d -o "$DAEMON_USER" -g "$DAEMON_GROUP" -m755 "/var/run/${{app_name}}"
start-stop-daemon --background --chdir ${{chdir}} --chuid "$DAEMON_USER" --make-pidfile --pidfile "$PIDFILE" --exec "$RUN_CMD" --start -- $RUN_OPTS
log_end_msg $?
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ if [ -z "$DAEMON_USER" ]; then
DAEMON_USER=${{daemon_user}}
fi

if [ -z "$DAEMON_GROUP" ]; then
DAEMON_GROUP=${{daemon_group}}
fi


# smb could define some additional options in $RUN_OPTS
RUN_CMD="${{chdir}}/bin/${{app_name}}"
Expand All @@ -64,7 +68,7 @@ start() {
[ $retval -eq 0 ] && touch ${lockfile} && success || failure

# Insert pid into pid file for CentOS killproc function
[ -d "/var/run/${{app_name}}" ] || install -d -o "$DAEMON_USER" -m750 "/var/run/${{app_name}}"
[ -d "/var/run/${{app_name}}" ] || install -d -o "$DAEMON_USER" -g "$DAEMON_GROUP" -m755 "/var/run/${{app_name}}"
echo
echo $PID > ${PIDFILE}
return $retval
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,10 @@ object JavaServerAppPackaging {
},
makeEtcDefault <<= (packageName in Linux, target in Universal, linuxEtcDefaultTemplate, linuxScriptReplacements)
map makeEtcDefaultScript,
linuxPackageMappings <++= (makeEtcDefault, packageName in Linux) map { (conf, name) =>
conf.map(c => LinuxPackageMapping(Seq(c -> ("/etc/default/" + name)),
LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig()).toSeq
linuxPackageMappings <++= (makeEtcDefault, bashScriptConfigLocation) map { (conf, configLocation) =>
configLocation.flatMap { path =>
conf.map(c => LinuxPackageMapping(Seq(c -> path), LinuxFileMetaData(Users.Root, Users.Root, "644")).withConfig())
}.toSeq
},

// === /var/run/app pid folder ===
Expand Down
17 changes: 12 additions & 5 deletions src/main/scala/com/typesafe/sbt/packager/docker/DockerPlugin.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,14 @@ trait DockerPlugin extends Plugin with UniversalPlugin {
val Docker = config("docker") extend Universal

private[this] final def makeDockerContent(dockerBaseImage: String, dockerBaseDirectory: String, maintainer: String, daemonUser: String, execScript: String, exposedPorts: Seq[Int], exposedVolumes: Seq[String]) = {
val headerCommands = Seq(
Cmd("FROM", dockerBaseImage),
Cmd("MAINTAINER", maintainer)
)
val fromCommand = Cmd("FROM", dockerBaseImage)

val maintainerCommand: Option[Cmd] = {
if (maintainer.isEmpty)
None
else
Some(Cmd("MAINTAINER", maintainer))
}

val dockerCommands = Seq(
Cmd("ADD", "files /"),
Expand Down Expand Up @@ -45,7 +49,10 @@ trait DockerPlugin extends Plugin with UniversalPlugin {
)
}

Dockerfile(headerCommands ++ volumeCommands ++ exposeCommand ++ dockerCommands: _*).makeContent
val commands =
Seq(fromCommand) ++ maintainerCommand ++ volumeCommands ++ exposeCommand ++ dockerCommands

Dockerfile(commands: _*).makeContent
}

private[this] final def generateDockerConfig(
Expand Down
103 changes: 103 additions & 0 deletions src/sbt-test/windows/test-bat-template/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import NativePackagerKeys._

packageArchetype.java_application

name := "windows-test"

version := "0.1.0"

maintainer := "Josh Suereth <joshua.suereth@typesafe.com>"

packageSummary := "test-windows"

packageDescription := """Test Windows Batch."""

// debug out
val debugOutFile = file(".") / "debug_out.txt"

batScriptExtraDefines += "call :print_args %%* > "+ debugOutFile.getAbsolutePath

batScriptExtraDefines += "goto print_args_end"

batScriptExtraDefines += ":print_args"

batScriptExtraDefines += "echo cmdcmdline=!cmdcmdline!"

batScriptExtraDefines += "echo *=%*"

batScriptExtraDefines += 1.to(9).map(i => "echo %%"+i+"=%"+i).mkString("\n")

batScriptExtraDefines += "echo _JAVA_OPTS=!_JAVA_OPTS!"

batScriptExtraDefines += "echo _APP_ARGS=!_APP_ARGS!"

batScriptExtraDefines += "exit /B"

batScriptExtraDefines += ":print_args_end"


TaskKey[Unit]("check-script") <<= (stagingDirectory in Universal, name, streams) map { (dir, name, streams) =>
import scala.sys.process._
val fails = new StringBuilder()
val script = dir / "bin" / (name+".bat")
val detailScript:File = {
val d = dir / "bin" / "detail.bat"
val out = new java.io.PrintWriter( d , "UTF-8")
out.print( scala.io.Source.fromFile(script).mkString.replaceAll("@echo off","@echo on & prompt \\$g ") )
out.close
d
}
def crlf2cr(txt:String) = txt.trim.replaceAll("\\\r\\\n", "\n")
def checkOutputEnv(env:Map[String,String], expectedRC: Int, expected:String, args:String*) = {
val pr = new StringBuilder()
val logger = ProcessLogger((o: String) => pr.append(o+"\n"),(e: String) => pr.append("error < " + e+"\n"))
val cmd = Seq("cmd", "/c", script.getAbsolutePath) ++ args
val result = Process(cmd, None, env.toSeq:_*) ! logger
if ( result != expectedRC ) {
pr.append("error code: " + result+"\n")
}
val output = crlf2cr(pr.toString)
if(result != expectedRC || output != expected.trim){
fails.append("\n---------------------------------\n")
fails.append("Failed to correctly run the main script!.\n")
fails.append("\""+cmd.mkString("\" \"")+"\"\n")
if(debugOutFile.exists){
fails.append(crlf2cr(scala.io.Source.fromFile(debugOutFile).mkString))
}
fails.append("\n--return code---------------------------\n")
fails.append("\ngot: " + result+", expected: "+expectedRC+"\n")
fails.append("\n--expected----------------------------\n")
fails.append(expected.trim+"\n")
fails.append("\n--found-------------------------------\n")
fails.append(crlf2cr(pr.toString)+"\n")
fails.append("\n--detail-------------------------------\n")
pr.clear
Process(Seq("cmd", "/c", detailScript.getAbsolutePath) ++ args, None, env.toSeq:_*) ! logger
fails.append(crlf2cr(pr.toString)+"\n")
}
if(debugOutFile.exists){
debugOutFile.delete()
}
}
def checkOutput(expectedRC: Int, expected:String, args:String*) = checkOutputEnv(Map.empty, expectedRC, expected, args:_*)
checkOutput(0, "arg #0 is [OK]\nSUCCESS!", "OK")
checkOutput(0, "arg #0 is [OK]\nproperty(test.hoge) is [huga]\nSUCCESS!", "-Dtest.hoge=\"huga\"", "OK")
checkOutputEnv(Map("show-vmargs"->"true"), 0, "arg #0 is [OK]\nvmarg #0 is [-Xms6m]\nSUCCESS!","-J-Xms6m", "OK")
checkOutputEnv(Map("show-vmargs"->"true"), 0, "arg #0 is [first]\narg #1 is [-XX]\narg #2 is [last]\nproperty(test.hoge) is [huga]\nvmarg #0 is [-Dtest.hoge=huga]\nvmarg #1 is [-Xms6m]\nSUCCESS!",
"first", "-Dtest.hoge=\"huga\"", "-J-Xms6m", "-XX", "last")
// include space
checkOutput(0, "arg #0 is [C:\\Program Files\\Java]\nproperty(test.hoge) is [C:\\Program Files\\Java]\nSUCCESS!",
"-Dtest.hoge=C:\\Program Files\\Java", "C:\\Program Files\\Java")
// split "include symbols"
checkOutput(0, "property(test.hoge) is [\\[]!< >%]\nSUCCESS!", "\"-Dtest.hoge=\\[]!< >%\"")
checkOutput(0, "arg #0 is [\\[]!< >%]\nSUCCESS!", "\\[]!< >%")
checkOutput(0, "property(test.huga) is [\\[]!<>%]\nSUCCESS!", "-Dtest.huga=\"\\[]!<>%\"")
// include symbols
checkOutput(0, "arg #0 is [\\[]!< >%]\nproperty(test.hoge) is [\\[]!< >%]\nproperty(test.huga) is [\\[]!<>%]\nSUCCESS!",
"\"-Dtest.hoge=\\[]!< >%\"", "\\[]!< >%", "-Dtest.huga=\"\\[]!<>%\"")
// include space and double-quote is failed...
// can't success include double-quote. arguments pass from Process(Seq("-Da=xx\"yy", "aa\"bb")) is parsed (%1="-Da", %2="xx\"yy aa\"bb") by cmd.exe ...
//checkOutput(0, "arg #0 is [xx\"yy]\nproperty(test.hoge) is [aa\"bb]\nvmarg #0 is [-Dtest.hoge=aa\"bb]\nSUCCESS!", "-Dtest.hoge=aa\"bb", "xx\"yy")
checkOutputEnv(Map("return-code-1"->"true"), 1, "arg #0 is [RC1]\nSUCCESS!", "RC1")
assert(fails.toString == "", fails.toString)
}
1 change: 1 addition & 0 deletions src/sbt-test/windows/test-bat-template/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % sys.props("project.version"))
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package test

import scala.collection.JavaConversions._

object Test extends App {
override def main(args: Array[String]): Unit = {
for((x,i) <- args.zipWithIndex) println("arg #" + i + " is [" + x + "]")
for((k,v) <- System.getProperties if k.startsWith("test.")) println("property(" + k + ") is [" + v + "]")
if(System.getenv("show-vmargs") == "true"){
for((x,i) <- java.lang.management.ManagementFactory.getRuntimeMXBean().getInputArguments().zipWithIndex){
println("vmarg #" + i + " is [" + x + "]")
}
}
println("SUCCESS!")
if(System.getenv("return-code-1") == "true"){
System.exit(1)
} else {
System.exit(0)
}
}
}
4 changes: 4 additions & 0 deletions src/sbt-test/windows/test-bat-template/test
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Run the windows batch.
> stage
$ exists target/universal/stage/bin/windows-test.bat
> check-script
2 changes: 1 addition & 1 deletion src/sphinx/DetailedTopics/redhat.rst
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ Example Settings


rpmChangelogFile
----------
----------------
The rpmChangelogFile property allows you to set a source that will be imported and used on the RPM generation. So if you use rpm commands to see the changelog it brings that information. You have to create the content on that file following the RPM conventions that are available here http://fedoraproject.org/wiki/Packaging:Guidelines#Changelogs.

Example Settings
Expand Down
13 changes: 13 additions & 0 deletions src/sphinx/GettingStartedApplications/AddingConfiguration.rst
Original file line number Diff line number Diff line change
Expand Up @@ -130,5 +130,18 @@ One means of doing this is hooking the ``batScriptExtraDefines`` key. This allo

Now, the windows version will also load the configuration from the ``conf/`` directory of the package.

More Complex Scripts
--------------------

As you read earlier the ``bashScriptExtraDefines`` sequence allows you to add new lines to the default bash script used to start the application.
This is useful when you need a setting which isn't mean for the command-line parameter list passed to the java process. The lines added to
``bashScriptExtraDefines`` are placed near the end of the script and have access to a number of utility bash functions (e.g. ``addJava``,
``addApp``, ``addResidual``, ``addDebugger``). You can add lines to this script as we did for the Typesage config file above. For more complex
scripts you can also inject a seperate file managed in your source tree or resource directory: ::

bashScriptExtraDefines ++= IO.readLines(baseDirectory.value / "scripts" / "extra.sh")

This will add the contents of ``/scripts/extra.sh`` in the resource directory to the bash script. Note you should always concatenate lines
to ``bashScriptExtraDefines`` as other stages in the pipeline may be include linex to the start-script.

Next, let's :doc:`add some generated files <GeneratingFiles>`.
Loading