| #!/usr/bin/env bash |
| # Copyright 2014 The Bazel Authors. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # |
| # This script was generated from java_stub_template.txt. Please |
| # don't edit it directly. |
| # |
| # If present, these flags should either be at the beginning of the command |
| # line, or they should be wrapped in a --wrapper_script_flag=FLAG argument. |
| # |
| # --debug Launch the JVM in remote debugging mode listening |
| # --debug=<port> to the specified port or the port set in the |
| # DEFAULT_JVM_DEBUG_PORT environment variable (e.g. |
| # 'export DEFAULT_JVM_DEBUG_PORT=8000') or else the |
| # default port of 5005. The JVM starts suspended |
| # unless the DEFAULT_JVM_DEBUG_SUSPEND environment |
| # variable is set to 'n'. |
| # --main_advice=<class> Run an alternate main class with the usual main |
| # program and arguments appended as arguments. |
| # --main_advice_classpath=<classpath> |
| # Prepend additional class path entries. |
| # --jvm_flag=<flag> Pass <flag> to the "java" command itself. |
| # <flag> may contain spaces. Can be used multiple times. |
| # --jvm_flags=<flags> Pass space-separated flags to the "java" command |
| # itself. Can be used multiple times. |
| # --singlejar Start the program from the packed-up deployment |
| # jar rather than from the classpath. |
| # --print_javabin Print the location of java executable binary and exit. |
| # --classpath_limit=<length> |
| # Specify the maximum classpath length. If the classpath |
| # is shorter, this script passes it to Java as a command |
| # line flag, otherwise it creates a classpath jar. |
| # |
| # The remainder of the command line is passed to the program. |
| |
| set -o posix |
| |
| # Make it easy to insert 'set -x' or similar commands when debugging problems with this script. |
| eval "$JAVA_STUB_DEBUG" |
| |
| # Prevent problems where the caller has exported CLASSPATH, causing our |
| # computed value to be copied into the environment and double-counted |
| # against the argv limit. |
| unset CLASSPATH |
| |
| JVM_FLAGS_CMDLINE=() |
| |
| # Processes an argument for the wrapper. Returns 0 if the given argument |
| # was recognized as an argument for this wrapper, and 1 if it was not. |
| function process_wrapper_argument() { |
| case "$1" in |
| --debug) JVM_DEBUG_PORT="${DEFAULT_JVM_DEBUG_PORT:-5005}" ;; |
| --debug=*) JVM_DEBUG_PORT="${1#--debug=}" ;; |
| --main_advice=*) MAIN_ADVICE="${1#--main_advice=}" ;; |
| --main_advice_classpath=*) MAIN_ADVICE_CLASSPATH="${1#--main_advice_classpath=}" ;; |
| --jvm_flag=*) JVM_FLAGS_CMDLINE+=( "${1#--jvm_flag=}" ) ;; |
| --jvm_flags=*) JVM_FLAGS_CMDLINE+=( ${1#--jvm_flags=} ) ;; |
| --singlejar) SINGLEJAR=1 ;; |
| --print_javabin) PRINT_JAVABIN=1 ;; |
| --classpath_limit=*) |
| CLASSPATH_LIMIT="${1#--classpath_limit=}" |
| echo "$CLASSPATH_LIMIT" | grep -q '^[0-9]\+$' || \ |
| die "ERROR: $self failed, --classpath_limit is not a number" |
| ;; |
| *) |
| return 1 ;; |
| esac |
| return 0 |
| } |
| |
| die() { |
| printf "%s: $1\n" "$0" "${@:2}" >&2 |
| exit 1 |
| } |
| |
| # Windows |
| function is_windows() { |
| [[ "${OSTYPE}" =~ msys* ]] || [[ "${OSTYPE}" =~ cygwin* ]] |
| } |
| |
| # macOS |
| function is_macos() { |
| [[ "${OSTYPE}" =~ darwin* ]] |
| } |
| |
| # Parse arguments sequentially until the first unrecognized arg is encountered. |
| # Scan the remaining args for --wrapper_script_flag=X options and process them. |
| ARGS=() |
| for ARG in "$@"; do |
| if [[ "$ARG" == --wrapper_script_flag=* ]]; then |
| process_wrapper_argument "${ARG#--wrapper_script_flag=}" \ |
| || die "invalid wrapper argument '%s'" "$ARG" |
| elif [[ "${#ARGS}" -gt 0 ]] || ! process_wrapper_argument "$ARG"; then |
| ARGS+=( "$ARG" ) |
| fi |
| done |
| |
| # A file storing the test's runtime classpath, excluding the test support. |
| # The file is read by the persistent test runner. The jars inside the file are |
| # loaded dynamically for every test run into a custom classloader. |
| %test_runtime_classpath_file% |
| |
| # Find our runfiles tree. We need this to construct the classpath |
| # (unless --singlejar was passed). |
| # |
| # Call this program X. X was generated by a java_binary or java_test rule. |
| # X may be invoked in many ways: |
| # 1a) directly by a user, with $0 in the output tree |
| # 1b) via 'bazel run' (similar to case 1a) |
| # 2) directly by a user, with $0 in X's runfiles tree |
| # 3) by another program Y which has a data dependency on X, with $0 in Y's runfiles tree |
| # 4) via 'bazel test' |
| # 5) by a genrule cmd, with $0 in the output tree |
| # 6) case 3 in the context of a genrule |
| # |
| # For case 1, $0 will be a regular file, and the runfiles tree will be |
| # at $0.runfiles. |
| # For case 2, $0 will be a symlink to the file seen in case 1. |
| # For case 3, we use Y's runfiles tree, which will be a superset of X's. |
| # For case 4, $JAVA_RUNFILES and $TEST_SRCDIR should already be set. |
| # Case 5 is handled like case 1. |
| # Case 6 is handled like case 3. |
| |
| # If we are running on Windows, convert the windows style path |
| # to unix style for detecting runfiles path. |
| if is_windows; then |
| self=$(cygpath --unix "$0") |
| else |
| self="$0" |
| fi |
| |
| if [[ "$self" != /* ]]; then |
| self="$PWD/$self" |
| fi |
| |
| if [[ "$SINGLEJAR" != 1 || "%needs_runfiles%" == 1 ]]; then |
| if [[ -z "$JAVA_RUNFILES" ]]; then |
| while true; do |
| if [[ -e "$self.runfiles" ]]; then |
| JAVA_RUNFILES="$self.runfiles" |
| break |
| fi |
| if [[ $self == *.runfiles/* ]]; then |
| JAVA_RUNFILES="${self%.runfiles/*}.runfiles" |
| break |
| fi |
| if [[ ! -L "$self" ]]; then |
| break |
| fi |
| readlink="$(readlink "$self")" |
| if [[ "$readlink" = /* ]]; then |
| self="$readlink" |
| else |
| # resolve relative symlink |
| self="${self%/*}/$readlink" |
| fi |
| done |
| if [[ -n "$JAVA_RUNFILES" ]]; then |
| export TEST_SRCDIR=${TEST_SRCDIR:-$JAVA_RUNFILES} |
| elif [[ -f "${self}_deploy.jar" && "%needs_runfiles%" == 0 ]]; then |
| SINGLEJAR=1; |
| else |
| die 'Cannot locate runfiles directory. (Set $JAVA_RUNFILES to inhibit searching.)' |
| fi |
| fi |
| fi |
| |
| # If we are running on Windows, we need a windows style runfiles path for constructing CLASSPATH |
| if is_windows; then |
| JAVA_RUNFILES=$(cygpath --windows "$JAVA_RUNFILES") |
| fi |
| |
| export JAVA_RUNFILES |
| export RUNFILES_MANIFEST_FILE="${JAVA_RUNFILES}/MANIFEST" |
| export RUNFILES_MANIFEST_ONLY=%runfiles_manifest_only% |
| |
| if [ -z "$RUNFILES_MANIFEST_ONLY" ]; then |
| function rlocation() { |
| if [[ "$1" = /* ]]; then |
| echo $1 |
| else |
| echo "$(dirname $RUNFILES_MANIFEST_FILE)/$1" |
| fi |
| } |
| else |
| if ! is_macos; then |
| # Read file into my_array |
| oifs=$IFS |
| IFS=$'\n' |
| my_array=( $(sed -e 's/\r//g' "$RUNFILES_MANIFEST_FILE") ) |
| IFS=$oifs |
| |
| # Process each runfile line into a [key,value] entry in runfiles_array |
| # declare -A is not supported on macOS because an old version of bash is used. |
| declare -A runfiles_array |
| for line in "${my_array[@]}" |
| do |
| line_split=($line) |
| runfiles_array[${line_split[0]}]=${line_split[@]:1} |
| done |
| fi |
| |
| function rlocation() { |
| if [[ "$1" = /* ]]; then |
| echo $1 |
| else |
| if is_macos; then |
| # Print the rest of line after the first space |
| # First, set the first column to empty and print rest of the line |
| # Second, use a trick of awk to remove leading and trailing spaces. |
| echo $(grep "^$1 " $RUNFILES_MANIFEST_FILE | awk '{ $1=""; print }' | awk '{ $1=$1; print }') |
| else |
| echo ${runfiles_array[$1]} |
| fi |
| fi |
| } |
| fi |
| |
| # Set JAVABIN to the path to the JVM launcher. |
| %javabin% |
| |
| if [[ "$PRINT_JAVABIN" == 1 || "%java_start_class%" == "--print_javabin" ]]; then |
| echo -n "$JAVABIN" |
| exit 0 |
| fi |
| |
| if [[ "$SINGLEJAR" == 1 ]]; then |
| CLASSPATH="${self}_deploy.jar" |
| # Check for the deploy jar now. If it doesn't exist, we can print a |
| # more helpful error message than the JVM. |
| [[ -r "$CLASSPATH" ]] \ |
| || die "Option --singlejar was passed, but %s does not exist.\n (You may need to build it explicitly.)" "$CLASSPATH" |
| else |
| # Create the shortest classpath we can, by making it relative if possible. |
| RUNPATH="${JAVA_RUNFILES}/%workspace_prefix%" |
| RUNPATH="${RUNPATH#$PWD/}" |
| CLASSPATH=%classpath% |
| fi |
| |
| # Export the locations which will be used to find the location of the classes from the classpath file. |
| export SELF_LOCATION="$self" |
| export CLASSLOADER_PREFIX_PATH="${RUNPATH}" |
| |
| # If using Jacoco in offline instrumentation mode, the CLASSPATH contains instrumented files. |
| # We need to make the metadata jar with uninstrumented classes available for generating |
| # the lcov-compatible coverage report, and we don't want it on the classpath. |
| %set_jacoco_metadata% |
| %set_jacoco_main_class% |
| %set_jacoco_java_runfiles_root% |
| |
| if [[ -n "$JVM_DEBUG_PORT" ]]; then |
| JVM_DEBUG_SUSPEND=${DEFAULT_JVM_DEBUG_SUSPEND:-"y"} |
| JVM_DEBUG_FLAGS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=${JVM_DEBUG_SUSPEND},address=${JVM_DEBUG_PORT}" |
| |
| if [[ "$PERSISTENT_TEST_RUNNER" == "true" ]]; then |
| JVM_DEBUG_FLAGS+=",quiet=y" |
| fi |
| fi |
| |
| if [[ -n "$MAIN_ADVICE_CLASSPATH" ]]; then |
| CLASSPATH="${MAIN_ADVICE_CLASSPATH}:${CLASSPATH}" |
| fi |
| |
| # Check if TEST_TMPDIR is available to use for scratch. |
| if [[ -n "$TEST_TMPDIR" && -d "$TEST_TMPDIR" ]]; then |
| JVM_FLAGS+=" -Djava.io.tmpdir=$TEST_TMPDIR" |
| fi |
| |
| ARGS=( |
| ${JVM_DEBUG_FLAGS} |
| ${JVM_FLAGS} |
| %jvm_flags% |
| "${JVM_FLAGS_CMDLINE[@]}" |
| ${MAIN_ADVICE} |
| %java_start_class% |
| "${ARGS[@]}") |
| |
| |
| function create_and_run_classpath_jar() { |
| # Build class path as one single string separated by spaces |
| MANIFEST_CLASSPATH="" |
| if is_windows; then |
| CLASSPATH_SEPARATOR=";" |
| URI_PREFIX="file:/" # e.g. "file:/C:/temp/foo.jar" |
| else |
| CLASSPATH_SEPARATOR=":" |
| URI_PREFIX="file:$(pwd)/" # e.g. "file:/usr/local/foo.jar" |
| fi |
| |
| URI_PREFIX=${URI_PREFIX//\//\\/} |
| MANIFEST_CLASSPATH="${CLASSPATH_SEPARATOR}${CLASSPATH}" |
| |
| MANIFEST_CLASSPATH=$(sed "s/ /%20/g" <<< "${MANIFEST_CLASSPATH}") |
| MANIFEST_CLASSPATH=$(sed "s/$CLASSPATH_SEPARATOR/ $URI_PREFIX/g" <<< "${MANIFEST_CLASSPATH}") |
| |
| # Create manifest file |
| MANIFEST_FILE="$(mktemp -t XXXXXXXX.jar_manifest)" |
| ( |
| echo "Manifest-Version: 1.0" |
| |
| CLASSPATH_LINE="Class-Path:$MANIFEST_CLASSPATH" |
| CLASSPATH_MANIFEST_LINES=$(sed -E $'s/(.{71})/\\1\\\n /g' <<< "${CLASSPATH_LINE}") |
| |
| echo "$CLASSPATH_MANIFEST_LINES" |
| echo "Created-By: Bazel" |
| ) >$MANIFEST_FILE |
| |
| # Create classpath JAR file |
| MANIFEST_JAR_FILE="$(mktemp -t XXXXXXXX-classpath.jar)" |
| if is_windows; then |
| MANIFEST_JAR_FILE="$(cygpath --windows "$MANIFEST_JAR_FILE")" |
| MANIFEST_FILE="$(cygpath --windows "$MANIFEST_FILE")" |
| fi |
| JARBIN="${JARBIN:-$(rlocation "$1")}" |
| $JARBIN cvfm "$MANIFEST_JAR_FILE" "$MANIFEST_FILE" >/dev/null || \ |
| die "ERROR: $self failed because $JARBIN failed" |
| |
| # Execute JAVA command |
| $JAVABIN -classpath "$MANIFEST_JAR_FILE" "${ARGS[@]}" |
| exit_code=$? |
| rm -f "$MANIFEST_FILE" |
| rm -f "$MANIFEST_JAR_FILE" |
| exit $exit_code |
| } |
| |
| # If the user didn't specify a --classpath_limit, use the default value. |
| if [ -z "$CLASSPATH_LIMIT" ]; then |
| # Windows per-arg limit MAX_ARG_STRLEN == 8k |
| # Linux per-arg limit MAX_ARG_STRLEN == 128k |
| is_windows && CLASSPATH_LIMIT=7000 || CLASSPATH_LIMIT=120000 |
| fi |
| |
| if is_windows && (("${#CLASSPATH}" > ${CLASSPATH_LIMIT} )); then |
| create_and_run_classpath_jar "local_jdk/bin/jar.exe" |
| elif (("${#CLASSPATH}" > ${CLASSPATH_LIMIT})); then |
| create_and_run_classpath_jar "local_jdk/bin/jar" |
| else |
| exec $JAVABIN -classpath $CLASSPATH "${ARGS[@]}" |
| fi |