aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/bash
diff options
context:
space:
mode:
authorGravatar Laszlo Csomor <laszlocsomor@google.com>2018-04-16 03:06:20 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-04-16 03:07:39 -0700
commit0c17f0c79d3c1fdcfb9312b5b06486a45a75c002 (patch)
tree06560a59b7075b50479d7ffe34ed9d57059537e9 /tools/bash
parent27e0c0e5406f1b480367332b0fcc9fb1e04bdc98 (diff)
Bash,runfiles: add runfiles library
See https://github.com/bazelbuild/bazel/issues/4460 Change-Id: I35a0b12ac17fe8bfdce3c7ba8c0dfddb35df7e28 Closes #5014. Change-Id: I35a0b12ac17fe8bfdce3c7ba8c0dfddb35df7e28 PiperOrigin-RevId: 193010997
Diffstat (limited to 'tools/bash')
-rw-r--r--tools/bash/runfiles/BUILD13
-rw-r--r--tools/bash/runfiles/runfiles.bash113
-rw-r--r--tools/bash/runfiles/runfiles_test.bash181
3 files changed, 307 insertions, 0 deletions
diff --git a/tools/bash/runfiles/BUILD b/tools/bash/runfiles/BUILD
index 964802ce9b..adec4cef86 100644
--- a/tools/bash/runfiles/BUILD
+++ b/tools/bash/runfiles/BUILD
@@ -16,10 +16,23 @@ filegroup(
name = "embedded_tools",
srcs = [
"BUILD.tools",
+ "runfiles.bash",
],
visibility = ["//tools/bash:__pkg__"],
)
+sh_library(
+ name = "runfiles_lib",
+ testonly = 1,
+ srcs = ["runfiles.bash"],
+)
+
+sh_test(
+ name = "runfiles_test",
+ srcs = ["runfiles_test.bash"],
+ deps = [":runfiles_lib"],
+)
+
test_suite(
name = "windows_tests",
tags = [
diff --git a/tools/bash/runfiles/runfiles.bash b/tools/bash/runfiles/runfiles.bash
new file mode 100644
index 0000000000..d56a835bfa
--- /dev/null
+++ b/tools/bash/runfiles/runfiles.bash
@@ -0,0 +1,113 @@
+#!/bin/bash
+#
+# Copyright 2018 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 Bash script defines functions to handle sh_binary/sh_test runfiles.
+#
+# REQUIREMENTS:
+# - The RUNFILES_MANIFEST_FILE and/or the RUNFILES_DIR environment variable must
+# be set to the absolute path of the runfiles manifest or the
+# <rulename>.runfiles directory, respectively.
+# - If RUNFILES_MANIFEST_ONLY=1 is set, then RUNFILES_MANIFEST_FILE must be set
+# to the absolute path of the runfiles manifest. RUNFILES_DIR may be unset in
+# this case.
+# - If RUNFILES_LIB_DEBUG=1 is set, the script will print errors to stderr.
+
+case "$(uname -s | tr [:upper:] [:lower:])" in
+msys*|mingw*|cygwin*)
+ # matches an absolute Windows path
+ _rlocation_isabs_pattern="^[a-zA-Z]:[/\\]"
+ ;;
+*)
+ # matches an absolute Unix path
+ _rlocation_isabs_pattern="^/.*"
+ ;;
+esac
+
+# Prints to stdout the runtime location of a data-dependency.
+function rlocation() {
+ if [[ "$1" =~ $_rlocation_isabs_pattern ]]; then
+ # If the path is absolute, print it as-is.
+ echo $1
+ elif [[ "$1" =~ \.\. ]]; then
+ if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then
+ echo >&2 "ERROR[runfiles.bash]: rlocation($1): contains uplevel reference"
+ fi
+ return 1
+ elif [[ "$1" == \\* ]]; then
+ if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then
+ echo >&2 "ERROR[runfiles.bash]: rlocation($1): absolute path without" \
+ "drive name"
+ fi
+ return 1
+ else
+ if [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 ]]; then
+ if [[ -n "${RUNFILES_MANIFEST_FILE:-}" \
+ && -f "${RUNFILES_MANIFEST_FILE}" ]]; then
+ grep -m1 "^$1 " "${RUNFILES_MANIFEST_FILE}" | cut -d ' ' -f 2- \
+ || return 1
+ else
+ if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then
+ echo >&2 "ERROR[runfiles.bash]: trying to use manifest-based" \
+ "runfiles but RUNFILES_MANIFEST_FILE is unset or" \
+ "non-existent" \
+ "(RUNFILES_MANIFEST_ONLY=\"${RUNFILES_MANIFEST_ONLY:-}\"," \
+ "RUNFILES_DIR=\"${RUNFILES_DIR:-}\")"
+ fi
+ return 1
+ fi
+ elif [[ -n "${RUNFILES_DIR:-}" && -d "${RUNFILES_DIR}" ]]; then
+ echo "${RUNFILES_DIR}/$1"
+ else
+ if [[ "${RUNFILES_LIB_DEBUG:-}" == 1 ]]; then
+ echo >&2 "ERROR[runfiles.bash]: trying to use directory-based" \
+ "runfiles but RUNFILES_DIR is unset or non-existent" \
+ "(RUNFILES_MANIFEST_ONLY=\"${RUNFILES_MANIFEST_ONLY:-}\"," \
+ "RUNFILES_MANIFEST_FILE=\"${RUNFILES_MANIFEST_FILE:-}\")"
+ fi
+ return 1
+ fi
+ fi
+}
+export -f rlocation
+
+# Exports the environment variables that subprocesses may need to use runfiles.
+# If a subprocess is a Bazel-built binary rule that also uses the runfiles
+# libraries under @bazel_tools//tools/bash/runfiles, then that binary needs
+# these envvars in order to initialize its own runfiles library.
+function runfiles_export_envvars() {
+ if [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 ]]; then
+ if [[ -z "${RUNFILES_MANIFEST_FILE:-}" \
+ && ! -f "$RUNFILES_MANIFEST_FILE" ]]; then
+ return 1
+ fi
+ if [[ -z "${RUNFILES_DIR:-}" ]]; then
+ if [[ "$RUNFILES_MANIFEST_FILE" == */MANIFEST \
+ && -d "${RUNFILES_MANIFEST_FILE%/MANIFEST}" ]]; then
+ export RUNFILES_DIR="${RUNFILES_MANIFEST_FILE%/MANIFEST}"
+ elif [[ "$RUNFILES_MANIFEST_FILE" == *runfiles_manifest \
+ && -d "${RUNFILES_MANIFEST_FILE%_manifest}" ]]; then
+ export RUNFILES_DIR="${RUNFILES_MANIFEST_FILE%_manifest}"
+ fi
+ fi
+ fi
+ # No need to define anything if RUNFILES_MANIFEST_ONLY is not 1: it makes no
+ # difference whether RUNFILES_DIR is defined or not.
+
+ export RUNFILES_MANIFEST_FILE="${RUNFILES_MANIFEST_FILE:-}"
+ export RUNFILES_DIR="${RUNFILES_DIR:-}"
+ export JAVA_RUNFILES="${RUNFILES_DIR:-}"
+}
+export -f runfiles_export_envvars
diff --git a/tools/bash/runfiles/runfiles_test.bash b/tools/bash/runfiles/runfiles_test.bash
new file mode 100644
index 0000000000..3d6dd8885c
--- /dev/null
+++ b/tools/bash/runfiles/runfiles_test.bash
@@ -0,0 +1,181 @@
+#!/bin/bash
+#
+# Copyright 2018 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.
+set -euo pipefail
+
+function _log_base() {
+ prefix=$1
+ shift
+ echo >&2 "${prefix}[$(basename "${BASH_SOURCE[0]}"):${BASH_LINENO[1]} ($(date "+%H:%M:%S %z"))] $*"
+}
+
+function fail() {
+ _log_base "FAILED" "$@"
+ exit 1
+}
+
+function log_fail() {
+ # non-fatal version of fail()
+ _log_base "FAILED" $*
+}
+
+function log_info() {
+ _log_base "INFO" $*
+}
+
+which uname >&/dev/null || fail "cannot locate GNU coreutils"
+
+case "$(uname -s | tr [:upper:] [:lower:])" in
+msys*|mingw*|cygwin*)
+ function is_windows() { true; }
+ ;;
+*)
+ function is_windows() { false; }
+ ;;
+esac
+
+function find_runfiles_lib() {
+ # Unset existing definitions of the functions we want to test.
+ if type rlocation >&/dev/null; then
+ unset rlocation
+ unset runfiles_export_envvars
+ fi
+
+ if [[ "${RUNFILES_MANIFEST_ONLY:-}" == "1" ]]; then
+ grep -m1 "^io_bazel/tools/bash/runfiles/runfiles.bash" \
+ "${RUNFILES_MANIFEST_FILE}" | cut -d ' ' -f 2-
+ elif [[ -n "${RUNFILES_DIR:-}" && -d "$RUNFILES_DIR" ]]; then
+ echo "${RUNFILES_DIR}/io_bazel/tools/bash/runfiles/runfiles.bash"
+ else
+ echo >&2 "ERROR: cannot find //tools/bash/runfiles:runfiles.bash"
+ return 1
+ fi
+}
+
+function test_rlocation_call_requires_no_envvars() {
+ export RUNFILES_DIR=mock/runfiles
+ export RUNFILES_MANIFEST_FILE=
+ export RUNFILES_MANIFEST_ONLY=
+ source "$runfiles_lib_path" || fail
+}
+
+function test_rlocation_argument_validation() {
+ export RUNFILES_DIR=
+ export RUNFILES_MANIFEST_FILE=
+ export RUNFILES_MANIFEST_ONLY=
+ source "$runfiles_lib_path"
+
+ # Test invalid inputs to make sure rlocation catches these.
+ if (rlocation "foo/.." >&/dev/null); then
+ fail
+ fi
+ if (rlocation "\\foo" >&/dev/null); then
+ fail
+ fi
+}
+
+function test_rlocation_abs_path() {
+ export RUNFILES_DIR=
+ export RUNFILES_MANIFEST_FILE=
+ export RUNFILES_MANIFEST_ONLY=
+ source "$runfiles_lib_path"
+
+ if is_windows; then
+ [[ "$(rlocation "c:/Foo")" == "c:/Foo" ]] || fail
+ [[ "$(rlocation "c:\\Foo")" == "c:\\Foo" ]] || fail
+ else
+ [[ "$(rlocation "/Foo")" == "/Foo" ]] || fail
+ fi
+}
+
+function test_init_manifest_based_runfiles() {
+ local tmpdir="$(mktemp -d $TEST_TMPDIR/tmp.XXXXXXXX)"
+ cat > $tmpdir/foo.runfiles_manifest << 'EOF'
+a/b c/d
+e/f g h
+EOF
+
+ export RUNFILES_DIR=
+ export RUNFILES_MANIFEST_FILE=$tmpdir/foo.runfiles_manifest
+ export RUNFILES_MANIFEST_ONLY=1
+ source "$runfiles_lib_path"
+
+ [[ -z "$(rlocation a)" ]] || fail
+ [[ "$(rlocation a/b)" == "c/d" ]] || fail
+ [[ "$(rlocation e/f)" == "g h" ]] || fail
+ [[ -z "$(rlocation c/d)" ]] || fail
+}
+
+function test_manifest_based_envvars() {
+ local tmpdir="$(mktemp -d $TEST_TMPDIR/tmp.XXXXXXXX)"
+ echo "a b" > $tmpdir/foo.runfiles_manifest
+
+ export RUNFILES_DIR=
+ export RUNFILES_MANIFEST_FILE=$tmpdir/foo.runfiles_manifest
+ export RUNFILES_MANIFEST_ONLY=1
+ mkdir -p $tmpdir/foo.runfiles
+ source "$runfiles_lib_path"
+
+ runfiles_export_envvars
+ [[ "${RUNFILES_DIR:-}" == "$tmpdir/foo.runfiles" ]] || fail
+ [[ "${RUNFILES_MANIFEST_FILE:-}" == "$tmpdir/foo.runfiles_manifest" ]] || fail
+ [[ "${RUNFILES_MANIFEST_ONLY:-}" == 1 ]] || fail
+}
+
+function test_init_directory_based_runfiles() {
+ local tmpdir="$(mktemp -d $TEST_TMPDIR/tmp.XXXXXXXX)"
+
+ export RUNFILES_DIR=${tmpdir}/mock/runfiles
+ export RUNFILES_MANIFEST_FILE=
+ export RUNFILES_MANIFEST_ONLY=
+ source "$runfiles_lib_path"
+
+ mkdir -p "$RUNFILES_DIR"
+ [[ "$(rlocation a)" == */mock/runfiles/a ]] || fail
+ [[ "$(rlocation a/b)" == *mock/runfiles/a/b ]] || fail
+}
+
+function test_directory_based_envvars() {
+ export RUNFILES_DIR=mock/runfiles
+ export RUNFILES_MANIFEST_FILE=
+ export RUNFILES_MANIFEST_ONLY=
+ source "$runfiles_lib_path"
+
+ runfiles_export_envvars
+ [[ "${RUNFILES_DIR:-}" == "mock/runfiles" ]] || fail
+ [[ -z "${RUNFILES_MANIFEST_FILE:-}" ]] || fail
+ [[ -z "${RUNFILES_MANIFEST_ONLY:-}" ]] || fail
+}
+
+function main() {
+ local -r manifest_only="${RUNFILES_MANIFEST_ONLY:-}"
+ local -r manifest_file="${RUNFILES_MANIFEST_FILE:-}"
+ local -r dir="${RUNFILES_DIR:-}"
+ local -r runfiles_lib_path=$(find_runfiles_lib)
+
+ local -r tests=$(declare -F | grep " -f test" | awk '{print $3}')
+ local failure=0
+ for t in $tests; do
+ export RUNFILES_MANIFEST_ONLY="$manifest_only"
+ export RUNFILES_MANIFEST_FILE="$manifest_file"
+ export RUNFILES_DIR="$dir"
+ if ! ($t); then
+ failure=1
+ fi
+ done
+ return $failure
+}
+
+main