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

Port bazelbuild/bazel#8196 : improve java_stub_template MANIFEST.MF construction speed #736

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions java_stub_template/file/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
filegroup(
name = "file",
srcs = ["file.txt"],
visibility = ["//visibility:public"],
)
371 changes: 371 additions & 0 deletions java_stub_template/file/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,371 @@
#!/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

# 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

if is_macos || [[ ${OSTYPE} == "freebsd" ]]; then
function md5func() { md5 -q $@ ; }
else
function md5func() { md5sum $@ | awk '{print $1}' ; }
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%
%set_java_coverage_new_implementation%

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
IFS=';'
URI_PREFIX="file:/" # e.g. "file:/C:/temp/foo.jar"
else
IFS=':'
URI_PREFIX="file:$(pwd)/" # e.g. "file:/usr/local/foo.jar"
fi
for x in $CLASSPATH; do
# Add file:/ prefix and escaped space characters, it should be a URI.
x="${URI_PREFIX}${x// /%20}"
MANIFEST_CLASSPATH="$MANIFEST_CLASSPATH $x"
done
unset IFS

# Create manifest file
MANIFEST_FILE="$(mktemp -t XXXXXXXX.jar_manifest)"

(
echo "Manifest-Version: 1.0"
CLASSPATH_LINE="Class-Path:$MANIFEST_CLASSPATH"
# No line in the MANIFEST.MF file may be longer than 72 bytes.
# A space prefix indicates the line is still the content of the last attribute.
IFS=$'\n'
WRAPPED_LINES=($(echo "$CLASSPATH_LINE" | fold -w 71))
for ((i = 0; i < "${#WRAPPED_LINES[*]}"; i += 1)); do
PREFIX=" "
if ((i == 0)); then
PREFIX=""
fi
echo "$PREFIX${WRAPPED_LINES[$i]}"
done
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

#Difference from https://github.com/bazelbuild/bazel/blob/68c7e5a3c679be51f750d44aae146007f0f04b4d/src/main/java/com/google/devtools/build/lib/bazel/rules/java/java_stub_template.txt
JARBIN="%jarbin%"
PERCENTAGE_LITERAL="%"
JARBIN_LITERAL="${PERCENTAGE_LITERAL}jarbin${PERCENTAGE_LITERAL}"
# if jarbin is evaluated to empty string or not substituted fallback to previous behavior
# for backwards compatibility
if [ -z "$JARBIN" ] || [ "$JARBIN" == "$JARBIN_LITERAL" ] ; then
JARBIN="local_jdk/bin/jar"
fi
#Difference ends

if is_windows && (("${#CLASSPATH}" > ${CLASSPATH_LIMIT} )); then
create_and_run_classpath_jar "${JARBIN}.exe"
elif (("${#CLASSPATH}" > ${CLASSPATH_LIMIT})); then
create_and_run_classpath_jar "$JARBIN"
else
exec $JAVABIN -classpath $CLASSPATH "${ARGS[@]}"
fi
Loading