forked from bazelbuild/bazel
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
shell,runfiles: add runfiles library
Create sourceable runfiles.sh that implements rlocation and a couple other helper functions for shell scripts. Change-Id: Ifcf9ee86ed63afe2ce655be596ac781494660398 RELNOTES[NEW]: runfiles, sh: Shell scripts may now depend on //src/tools/runfiles:runfiles_sh_lib and source runfiles.sh. The script defines the `rlocation` function which returns runfile paths on every platform. PiperOrigin-RevId: 171816037
- Loading branch information
1 parent
52f32bf
commit 0cb8d40
Showing
5 changed files
with
351 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
package(default_visibility = ["//visibility:private"]) | ||
|
||
exports_files( | ||
["runfiles.sh"], | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
filegroup( | ||
name = "srcs", | ||
srcs = glob(["**"]), | ||
visibility = ["//src:__pkg__"], | ||
) | ||
|
||
sh_library( | ||
name = "runfiles_sh_lib", | ||
srcs = ["runfiles.sh"], | ||
visibility = ["//visibility:public"], | ||
) | ||
|
||
sh_test( | ||
name = "runfiles_sh_test", | ||
srcs = select({ | ||
"//src:windows": ["runfiles_windows_test.sh"], | ||
"//src:windows_msys": ["runfiles_windows_test.sh"], | ||
"//src:windows_msvc": ["runfiles_windows_test.sh"], | ||
"//conditions:default": ["runfiles_posix_test.sh"], | ||
}), | ||
deps = [":runfiles_sh_lib"], | ||
) | ||
|
||
test_suite( | ||
name = "windows_tests", | ||
tags = [ | ||
"-no_windows", | ||
"-slow", | ||
], | ||
visibility = ["//visibility:private"], | ||
) | ||
|
||
test_suite( | ||
name = "all_windows_tests", | ||
tests = [ | ||
":windows_tests", | ||
], | ||
visibility = ["//src:__pkg__"], | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
#!/bin/bash | ||
# | ||
# Copyright 2017 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 defines utility functions to handle sh_binary runfiles. | ||
# | ||
# On Windows, this script needs $RUNFILES_MANIFEST_FILE to point to the absolute | ||
# path of the runfiles manifest file. If the envvar is undefined or empty, this | ||
# script calls "exit 1". | ||
# | ||
# On Linux/macOS, this script needs $RUNFILES_DIR to point to the absolute path | ||
# of the runfiles directory. If the envvar is undefined or empty, this script | ||
# tries to determine the value by looking for the nearest "*.runfiles" parent | ||
# directory of "$0", and if not found, this script calls "exit 1". | ||
|
||
set -eu | ||
|
||
# Check that we can find the bintools, otherwise we would see confusing errors. | ||
stat "$0" >&/dev/null || { | ||
echo >&2 "ERROR[runfiles.sh]: cannot locate GNU coreutils; check your PATH." | ||
echo >&2 " You may need to run 'export PATH=/bin:/usr/bin:\$PATH' (on Linux/macOS)" | ||
echo >&2 " or 'set PATH=c:\\tools\\msys64\\usr\\bin;%PATH%' (on Windows)." | ||
exit 1 | ||
} | ||
|
||
# Now that we have bintools on PATH, determine the current platform and define | ||
# `is_windows` accordingly. | ||
case "$(uname -s | tr [:upper:] [:lower:])" in | ||
msys*|mingw*|cygwin*) | ||
function is_windows() { | ||
true | ||
} | ||
;; | ||
*) | ||
function is_windows() { | ||
false | ||
} | ||
;; | ||
esac | ||
export -f is_windows | ||
|
||
# Define `is_absolute` unless already defined. | ||
if ! type is_absolute &>/dev/null; then | ||
function is_absolute() { | ||
if is_windows; then | ||
echo "$1" | grep -q "^[a-zA-Z]:[/\\]" | ||
else | ||
[[ "$1" = /* ]] | ||
fi | ||
} | ||
export -f is_absolute | ||
fi | ||
|
||
# Define `rlocation` unless already defined. | ||
if ! type rlocation &>/dev/null; then | ||
if is_windows; then | ||
# If RUNFILES_MANIFEST_FILE is empty/undefined, bail out. | ||
# On Windows there's no runfiles tree with symlinks like on Linux/macOS, so | ||
# we cannot locate the runfiles root and the manifest by walking the path | ||
# of $0. | ||
if [[ -z "${RUNFILES_MANIFEST_FILE:-}" ]]; then | ||
echo >&2 "ERROR[runfiles.sh]: RUNFILES_MANIFEST_FILE is empty/undefined" | ||
exit 1 | ||
fi | ||
|
||
# Read the runfiles manifest to memory, to quicken runfiles lookups. | ||
# First, read each line of the manifest into `runfiles_lines`. We need to do | ||
# this while IFS is still the newline character. In the subsequent loop, | ||
# after we reset IFS, we can construct the `line_split` arrays. | ||
old_ifs="${IFS:-}" | ||
IFS=$'\n' | ||
runfiles_lines=( $(sed -e 's/\r//g' "$RUNFILES_MANIFEST_FILE") ) | ||
IFS="$old_ifs" | ||
# Now create a dictionary from `runfiles_lines`. Creating `line_split` uses | ||
# $IFS so we could not have done this without a helper array. | ||
declare -A runfiles_dict | ||
for line in "${runfiles_lines[@]}"; do | ||
line_split=($line) | ||
runfiles_dict[${line_split[0]}]="${line_split[@]:1}" | ||
done | ||
else | ||
# If RUNFILES_DIR is empty/undefined, try locating the runfiles directory. | ||
# When the user runs a sh_binary's output directly, it's just a symlink to | ||
# the main script. There's no launcher like on Windows which would set this | ||
# environment variable. | ||
# Walk up the path of $0 looking for a runfiles directory. | ||
if [[ -z "${RUNFILES_DIR:-}" ]]; then | ||
RUNFILES_DIR="$(dirname "$0")" | ||
while [[ "$RUNFILES_DIR" != "/" ]]; do | ||
if [[ "$RUNFILES_DIR" = *.runfiles ]]; then | ||
break | ||
else | ||
RUNFILES_DIR="$(dirname "$RUNFILES_DIR")" | ||
fi | ||
done | ||
if [[ "$RUNFILES_DIR" = "/" ]]; then | ||
echo >&2 "ERROR[runfiles.sh]: RUNFILES_DIR is empty/undefined, and cannot find a" | ||
echo >&2 " runfiles directory on the path of this script" | ||
exit 1 | ||
fi | ||
fi | ||
fi | ||
|
||
function rlocation() { | ||
if is_absolute "$1"; then | ||
echo "$1" | ||
else | ||
if is_windows; then | ||
echo "${runfiles_dict[$1]}" | ||
else | ||
echo "${RUNFILES_DIR}/$1" | ||
fi | ||
fi | ||
} | ||
export -f rlocation | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#!/bin/bash | ||
# | ||
# Copyright 2017 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 -eu | ||
|
||
function _log_base() { | ||
prefix=$1 | ||
shift | ||
echo >&2 "${prefix}[$(basename "$0") $(date "+%H:%M:%S.%N (%z)")] $@" | ||
} | ||
|
||
function log_fatal() { | ||
_log_base "ERROR" "$@" | ||
exit 1 | ||
} | ||
|
||
function fail() { | ||
_log_base "FAILED" "$@" | ||
exit 1 | ||
} | ||
|
||
stat "$0" >&/dev/null || log_fatal "cannot locate GNU coreutils" | ||
|
||
# Unset existing definitions of the functions we want to test. | ||
if type rlocation >&/dev/null; then | ||
unset is_absolute | ||
unset is_windows | ||
unset rlocation | ||
fi | ||
if rlocation >&/dev/null; then | ||
fail "rlocation is still defined" | ||
fi | ||
|
||
# Find runfiles.sh | ||
runfiles_sh=$(dirname $0)/runfiles.sh | ||
[[ -e "$runfiles_sh" ]] || fail "cannot find '$runfiles_sh'" | ||
|
||
# Assert that runfiles.sh attempts to look up the runfiles directory. | ||
# It will find the actual runfiles directory of this test. | ||
unset RUNFILES_DIR | ||
source "$runfiles_sh" || fail "cannot source '$runfiles_sh'" | ||
[[ "$RUNFILES_DIR" = *.runfiles ]] \ | ||
|| fail "'$runfiles_sh' cannot find the runfiles directory" | ||
|
||
# Set a mock $RUNFILES_DIR. | ||
# Unset `rlocation` so runfiles.sh will define it again. | ||
export RUNFILES_DIR="/path/to runfiles" | ||
unset is_absolute | ||
source "$runfiles_sh" || fail "cannot source '$runfiles_sh'" | ||
|
||
# Exercise the functions in runfiles.sh. | ||
if is_windows; then | ||
fail "expected is_windows() to be false" | ||
fi | ||
|
||
if is_absolute "d:/foo"; then | ||
fail "expected d:/foo not to be absolute" | ||
fi | ||
if is_absolute "D:\\foo"; then | ||
fail "expected D:\\foo not to be absolute" | ||
fi | ||
is_absolute "/foo" || fail "expected /foo to be absolute" | ||
|
||
[[ "$(rlocation "some/runfile")" = "/path/to runfiles/some/runfile" ]] \ | ||
|| fail "rlocation 1 failed" | ||
[[ "$(rlocation "/some absolute/runfile")" = "/some absolute/runfile" ]] \ | ||
|| fail "rlocation 2 failed" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
#!/bin/bash | ||
# | ||
# Copyright 2017 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 -eu | ||
|
||
if ! stat "$0" >&/dev/null; then | ||
echo >&2 "ERROR[runfiles_windows_test.sh] cannot locate GNU coreutils" | ||
exit 1 | ||
fi | ||
|
||
function _log_base() { | ||
prefix=$1 | ||
shift | ||
echo >&2 "${prefix}[$(basename "$0") $(date "+%H:%M:%S.%N (%z)")] $@" | ||
} | ||
|
||
function log_fatal() { | ||
_log_base "ERROR" "$@" | ||
exit 1 | ||
} | ||
|
||
function fail() { | ||
_log_base "FAILED" "$@" | ||
exit 1 | ||
} | ||
|
||
# Look up runfiles.sh manually, do not rely on rlocation being already defined. | ||
# If all is working well, then rlocation should already be defined, because the | ||
# native launcher of the sh_test already sourced runfiles.sh from @bazel_tools, | ||
# but this test exercises runfiles.sh itself (from HEAD). | ||
[ -n "${RUNFILES_MANIFEST_FILE:-}" ] \ | ||
|| log_fatal "RUNFILES_MANIFEST_FILE is undefined or empty" | ||
runfiles_sh="$(cat "$RUNFILES_MANIFEST_FILE" \ | ||
| fgrep "io_bazel/src/tools/runfiles/runfiles.sh" \ | ||
| cut -d' ' -f2-)" | ||
[ -n "$runfiles_sh" ] || fail "cannot find runfiles.sh" | ||
|
||
# Unset existing definitions of the functions we want to test. | ||
if type rlocation >&/dev/null; then | ||
unset is_absolute | ||
unset is_windows | ||
unset rlocation | ||
fi | ||
if type rlocation >&/dev/null; then | ||
fail "rlocation is still defined" | ||
fi | ||
|
||
# Assert that runfiles.sh needs $RUNFILES_MANIFEST_FILE. | ||
unset RUNFILES_MANIFEST_FILE | ||
if (source "$runfiles_sh" >&/dev/null) then | ||
fail "should fail to source '$runfiles_sh'" | ||
fi | ||
|
||
# Set a mock $RUNFILES_MANIFEST_FILE. | ||
export RUNFILES_MANIFEST_FILE="$TEST_TMPDIR/mock-runfiles.txt" | ||
cat >"$RUNFILES_MANIFEST_FILE" <<'end_of_manifest' | ||
runfile/without/absolute/path | ||
runfile/spaceless c:\path\to\runfile1 | ||
runfile/spaceful c:\path\to\runfile with spaces | ||
end_of_manifest | ||
|
||
# Source runfiles.sh and exercise its functions. | ||
source "$runfiles_sh" || fail "cannot source '${runfiles_sh}'" | ||
|
||
# Exercise the functions in runfiles.sh. | ||
is_windows || fail "expected is_windows() to be true" | ||
|
||
is_absolute "d:/foo" || fail "expected d:/foo to be absolute" | ||
is_absolute "D:\\foo" || fail "expected D:\\foo to be absolute" | ||
if is_absolute "/foo"; then | ||
fail "expected /foo not to be absolute" | ||
fi | ||
|
||
[[ -z "$(rlocation runfile/without/absolute/path)" ]] \ | ||
|| fail "rlocation 1 failed" | ||
[[ "$(rlocation runfile/spaceless)" = "c:\\path\\to\\runfile1" ]] \ | ||
|| fail "rlocation 2 failed" | ||
[[ "$(rlocation runfile/spaceful)" = "c:\\path\\to\\runfile with spaces" ]] \ | ||
|| fail "rlocation 3 failed" | ||
[[ "$(rlocation "c:\\some absolute/path")" = "c:\\some absolute/path" ]] \ | ||
|| fail "rlocation 4 failed" |