| #!/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 |