Skip to content

Commit c65b367

Browse files
committed
Modernize Java launch code
1 parent 631b31c commit c65b367

File tree

1 file changed

+108
-61
lines changed

1 file changed

+108
-61
lines changed

components/scripts/lib/java.sh

Lines changed: 108 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,148 @@
11
#!/usr/bin/env bash
22

3+
# The code within this method is based off of the Gradle application plugin's
4+
# generated start up script. The template for the start up script can be found
5+
# here:
6+
7+
# https://github.com/gradle/gradle/blob/3200a204ba96f503f1171b3584258a53ecd91bd2/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
8+
#
9+
# shellcheck disable=SC2128,SC2178
310
invoke_java() {
411
local classpath="$1"
512
shift
6-
local args=( "$@" )
713

814
# OS specific support (must be 'true' or 'false').
915
cygwin=false
1016
msys=false
17+
darwin=false
18+
nonstop=false
1119
case "$(uname)" in
12-
CYGWIN*)
13-
cygwin=true
14-
;;
15-
MINGW*)
16-
msys=true
17-
;;
20+
CYGWIN*) cygwin=true ;;
21+
Darwin*) darwin=true ;;
22+
MSYS* | MINGW*) msys=true ;;
23+
NONSTOP*) nonstop=true ;;
1824
esac
1925

2026
# Determine the Java command to use to start the JVM.
2127
if [ -n "$JAVA_HOME" ]; then
2228
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
2329
# IBM's JDK on AIX uses strange locations for the executables
24-
JAVACMD="$JAVA_HOME/jre/sh/java"
30+
JAVACMD=$JAVA_HOME/jre/sh/java
2531
else
26-
JAVACMD="$JAVA_HOME/bin/java"
32+
JAVACMD=$JAVA_HOME/bin/java
2733
fi
2834
if [ ! -x "$JAVACMD" ]; then
2935
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
3036
31-
Please set the JAVA_HOME variable in your environment to match the
32-
location of your Java installation."
37+
Please set the JAVA_HOME variable in your environment to match the
38+
location of your Java installation."
3339
fi
3440
else
35-
JAVACMD="java"
41+
JAVACMD=java
3642
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
3743
38-
Please set the JAVA_HOME variable in your environment to match the
39-
location of your Java installation."
44+
Please set the JAVA_HOME variable in your environment to match the
45+
location of your Java installation."
46+
fi
47+
48+
# Increase the maximum file descriptors if we can.
49+
if ! "$cygwin" && ! "$darwin" && ! "$nonstop"; then
50+
case $MAX_FD in
51+
max*)
52+
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
53+
MAX_FD=$(ulimit -H -n) ||
54+
warn "Could not query maximum file descriptor limit"
55+
;;
56+
esac
57+
case $MAX_FD in
58+
'' | soft) : ;;
59+
*)
60+
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
61+
ulimit -n "$MAX_FD" ||
62+
warn "Could not set maximum file descriptor limit to $MAX_FD"
63+
;;
64+
esac
4065
fi
4166

67+
# Collect all arguments for the java command, stacking in reverse order:
68+
# * args from the command line
69+
# * the main class name
70+
# * -classpath
71+
# * -D...appname settings
72+
# * --module-path (only if needed)
73+
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and APP_OPTS environment variables.
74+
4275
# For Cygwin or MSYS, switch paths to Windows format before running java
43-
if [ "$cygwin" = "true" ] || [ "$msys" = "true" ]; then
76+
if "$cygwin" || "$msys"; then
4477
APP_HOME=$(cygpath --path --mixed "$APP_HOME")
45-
CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
78+
classpath=$(cygpath --path --mixed "$classpath")
79+
4680
JAVACMD=$(cygpath --unix "$JAVACMD")
4781

48-
# We build the pattern for arguments to be converted via cygpath
49-
ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
50-
SEP=""
51-
for dir in $ROOTDIRSRAW; do
52-
ROOTDIRS="$ROOTDIRS$SEP$dir"
53-
SEP="|"
54-
done
55-
OURCYGPATTERN="(^($ROOTDIRS))"
56-
# Add a user-defined pattern to the cygpath arguments
57-
if [ "$GRADLE_CYGPATTERN" != "" ]; then
58-
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
59-
fi
6082
# Now convert the arguments - kludge to limit ourselves to /bin/sh
61-
i=0
62-
for arg in "${args[@]}"; do
63-
CHECK=$(echo "$arg" | grep -E -c "$OURCYGPATTERN" -)
64-
CHECK2=$(echo "$arg" | grep -E -c "^-") ### Determine if an option
65-
66-
# shellcheck disable=SC2046 # we actually want word splitting
67-
# shellcheck disable=SC2116 # using echo to expand globs
68-
if [ "$CHECK" -ne 0 ] && [ "$CHECK2" -eq 0 ]; then ### Added a condition
69-
eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg")
70-
else
71-
eval $(echo args$i)="\"$arg\""
83+
for arg; do
84+
if
85+
case $arg in
86+
-*) false ;; # don't mess with options
87+
/?*)
88+
t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
89+
[ -e "$t" ]
90+
;;
91+
*) false ;;
92+
esac
93+
then
94+
arg=$(cygpath --path --ignore --mixed "$arg")
7295
fi
73-
# shellcheck disable=SC2003
74-
i=$(expr $i + 1)
96+
# Roll the args list around exactly as many times as the number of
97+
# args, so each arg winds up back in the position where it started, but
98+
# possibly modified.
99+
#
100+
# NB: a `for` loop captures its iteration list before it begins, so
101+
# changing the positional parameters here affects neither the number of
102+
# iterations, nor the values presented in `arg`.
103+
shift # remove old arg
104+
set -- "$@" "$arg" # push replacement arg
75105
done
76-
# shellcheck disable=SC2154
77-
case $i in
78-
0) set -- ;;
79-
1) set -- "$args0" ;;
80-
2) set -- "$args0" "$args1" ;;
81-
3) set -- "$args0" "$args1" "$args2" ;;
82-
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
83-
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
84-
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
85-
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
86-
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
87-
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
88-
esac
89106
fi
90107

91-
# Escape application args
92-
save() {
93-
for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
94-
echo " "
95-
}
108+
# Collect all arguments for the java command;
109+
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $APP_OPTS can contain fragments of
110+
# shell script including quotes and variable substitutions, so put them in
111+
# double quotes to make sure that they get re-expanded; and
112+
# * put everything else in single quotes, so that it's not re-expanded.
113+
114+
set -- -Dpicocli.ansi=true -jar "$classpath" "$@"
115+
116+
# Stop when "xargs" is not available.
117+
if ! command -v xargs >/dev/null 2>&1; then
118+
die "xargs is not available"
119+
fi
120+
121+
# Use "xargs" to parse quoted args.
122+
#
123+
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
124+
#
125+
# In Bash we could simply go:
126+
#
127+
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
128+
# set -- "${ARGS[@]}" "$@"
129+
#
130+
# but POSIX shell has neither arrays nor command substitution, so instead we
131+
# post-process each arg (as a line of input to sed) to backslash-escape any
132+
# character that might be a shell metacharacter, then use eval to reverse
133+
# that process (while maintaining the separation between arguments), and wrap
134+
# the whole thing up as a single "set" statement.
135+
#
136+
# This will of course break if any of these variables contains a newline or
137+
# an unmatched quote.
138+
#
96139

97-
# Collect all arguments for the java command, following the shell quoting and substitution rules
98-
eval set -- -Dpicocli.ansi=true -jar "\"$classpath\"" "$(save "${args[@]}")"
140+
eval "set -- $(
141+
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $APP_OPTS" |
142+
xargs -n1 |
143+
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
144+
tr '\n' ' '
145+
)" '"$@"'
99146

100147
# shellcheck disable=SC2154
101148
if [[ "${debug_mode}" == "on" ]]; then

0 commit comments

Comments
 (0)