| #!/bin/bash | 
 |  | 
 | # Copyright 2019 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 | 
 |  | 
 | # This is a script which can be installed as your "bazel" binary instead of the | 
 | # real Bazel binary. When called, it tries to determine and run the correct | 
 | # Bazel version for a given project and forwards all arguments to it. | 
 | # | 
 | # You can specify which Bazel version to use using these methods: | 
 | # 1. Set $USE_BAZEL_VERSION to a version number | 
 | #    (e.g. export USE_BAZEL_VERSION=1.0.0). | 
 | # 2. Add a .bazelversion file that contains a version number next to your | 
 | #    WORKSPACE[.bazel] file. | 
 | # 3. Otherwise, the latest Bazel version will be used. | 
 | # | 
 | # This wrapper only recognizes Bazel versions installed next to itself, thus | 
 | # if you install this wrapper as /usr/bin/bazel, you'll have to install binaries | 
 | # for individual Bazel binaries as e.g. /usr/bin/bazel-1.0.0. | 
 | # | 
 | # In addition, if an executable called "tools/bazel" is found in the current | 
 | # workspace, this script will not directly execute Bazel, but instead store | 
 | # the path to the real Bazel executable in the environment variable BAZEL_REAL | 
 | # and then execute the "tools/bazel" wrapper script. | 
 | # | 
 | # In contrast to Bazelisk, this script does not download anything from the | 
 | # internet and instead relies on the local system to provide Bazel binaries. | 
 |  | 
 | function color() { | 
 |       # Usage: color "31;5" "string" | 
 |       # Some valid values for color: | 
 |       # - 5 blink, 1 strong, 4 underlined | 
 |       # - fg: 31 red,  32 green, 33 yellow, 34 blue, 35 purple, 36 cyan, 37 white | 
 |       # - bg: 40 black, 41 red, 44 blue, 45 purple | 
 |       printf '\033[%sm%s\033[0m\n' "$@" | 
 | } | 
 |  | 
 | # `readlink -f` that works on OSX too. | 
 | function get_realpath() { | 
 |     if [ "$(uname -s)" == "Darwin" ]; then | 
 |         local queue="$1" | 
 |         if [[ "${queue}" != /* ]] ; then | 
 |             # Make sure we start with an absolute path. | 
 |             queue="${PWD}/${queue}" | 
 |         fi | 
 |         local current="" | 
 |         while [ -n "${queue}" ]; do | 
 |             # Removing a trailing /. | 
 |             queue="${queue#/}" | 
 |             # Pull the first path segment off of queue. | 
 |             local segment="${queue%%/*}" | 
 |             # If this is the last segment. | 
 |             if [[ "${queue}" != */* ]] ; then | 
 |                 segment="${queue}" | 
 |                 queue="" | 
 |             else | 
 |                 # Remove that first segment. | 
 |                 queue="${queue#*/}" | 
 |             fi | 
 |             local link="${current}/${segment}" | 
 |             if [ -h "${link}" ] ; then | 
 |                 link="$(readlink "${link}")" | 
 |                 queue="${link}/${queue}" | 
 |                 if [[ "${link}" == /* ]] ; then | 
 |                     current="" | 
 |                 fi | 
 |             else | 
 |                 current="${link}" | 
 |             fi | 
 |         done | 
 |  | 
 |         echo "${current}" | 
 |     else | 
 |         readlink -f "$1" | 
 |     fi | 
 | } | 
 |  | 
 | function get_workspace_root() { | 
 |   workspace_dir="${PWD}" | 
 |   while [[ "${workspace_dir}" != / ]]; do | 
 |     if [[ -e "${workspace_dir}/WORKSPACE" || -e "${workspace_dir}/WORKSPACE.bazel" ]]; then | 
 |       readonly workspace_dir | 
 |       return | 
 |     fi | 
 |     workspace_dir="$(dirname "${workspace_dir}")" | 
 |   done | 
 |   readonly workspace_dir="" | 
 | } | 
 |  | 
 | get_workspace_root | 
 |  | 
 | readonly wrapper_dir="$(dirname "$(get_realpath "${BASH_SOURCE[0]}")")" | 
 | readonly os_arch_suffix="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)" | 
 |  | 
 | function get_bazel_version() { | 
 |   bazel_version="" | 
 |  | 
 |   if [[ -n ${USE_BAZEL_VERSION:-} ]]; then | 
 |     reason="specified in \$USE_BAZEL_VERSION" | 
 |     bazel_version="${USE_BAZEL_VERSION}" | 
 |   elif [[ -e "${workspace_dir}/.bazelversion" ]]; then | 
 |     reason="specified in ${workspace_dir}/.bazelversion" | 
 |     # The "read" can fail if the .bazelversion file does not contain a final | 
 |     # newline character. It will still correctly assign the read data to the | 
 |     # variable. Of course it can also fail due to real I/O errors. Because we do | 
 |     # validation of the read data later, we can just ignore the error here. | 
 |     # Alternatives like 'bazel_version=$(head -1 ...)' are not better either, | 
 |     # because bash does not care about the exit code of processes used in | 
 |     # command substitution. | 
 |     read -r bazel_version < "${workspace_dir}/.bazelversion" || true | 
 |   fi | 
 |  | 
 |   # If we read an empty string or the magic word "latest" from .bazelversion or | 
 |   # $USE_BAZEL_VERSION, then we should use the latest available stable version. | 
 |   # This mimics the behavior of Bazelisk. | 
 |   if [[ -z $bazel_version || $bazel_version == "latest" ]]; then | 
 |     if [[ -x "${wrapper_dir}/bazel-real" ]]; then | 
 |       reason="${reason:-"automatically selected bazel-real"}" | 
 |       bazel_version="real" | 
 |     else | 
 |       # Find the latest Bazel version installed on the system. | 
 |       reason="${reason:-"automatically selected latest available version"}" | 
 |       bazel_version="$(basename "$(find -H "${wrapper_dir}" -maxdepth 1 -name 'bazel-[0-9]*-${os_arch_suffix}' -type f | sort -V | tail -n 1)")" | 
 |       if [[ -z $bazel_version ]]; then | 
 |         bazel_version="$(basename "$(find -H "${wrapper_dir}" -maxdepth 1 -name 'bazel-[0-9]*' -type f | sort -V | tail -n 1)")" | 
 |       fi | 
 |       # Remove the "bazel-" prefix from the file name. | 
 |       bazel_version="${bazel_version#"bazel-"}" | 
 |     fi | 
 |   fi | 
 |  | 
 |   readonly reason | 
 |   readonly bazel_version | 
 | } | 
 |  | 
 | get_bazel_version | 
 |  | 
 | BAZEL_REAL="${wrapper_dir}/bazel-${bazel_version}-${os_arch_suffix}" | 
 |  | 
 | # Try without the architecture suffix. | 
 | if [[ ! -x ${BAZEL_REAL} ]]; then | 
 |   BAZEL_REAL="${wrapper_dir}/bazel-${bazel_version}" | 
 | fi | 
 |  | 
 | # Last try: Maybe `bazel-real` is actually the requested correct version? | 
 | readonly bazel_real_path="${wrapper_dir}/bazel-real" | 
 | if [[ ! -x ${BAZEL_REAL} && -x ${bazel_real_path} ]]; then | 
 |   # Note that "bazel --version" is very fast and doesn't start the Bazel server, | 
 |   # as opposed to "bazel version". | 
 |   readonly bazel_real_version="$("${bazel_real_path}" --version | grep '^bazel ' | cut -d' ' -f2)" | 
 |   if [[ $bazel_real_version == $bazel_version ]]; then | 
 |     BAZEL_REAL="${bazel_real_path}" | 
 |   fi | 
 | fi | 
 |  | 
 | # If the repository contains a checked-in executable called tools/bazel, we | 
 | # assume that they know what they're doing and have their own way of versioning | 
 | # Bazel. Thus, we don't have to print our helpful messages or error out in case | 
 | # we couldn't find a binary. | 
 | readonly wrapper="${workspace_dir}/tools/bazel" | 
 | if [[ -x "$wrapper" && -f "$wrapper" ]]; then | 
 |   export BAZEL_REAL | 
 |   exec -a "$0" "${wrapper}" "$@" | 
 | fi | 
 |  | 
 | if [[ -z $bazel_version ]]; then | 
 |   color "31" "ERROR: No installed Bazel version found, cannot continue." | 
 |   (echo "" | 
 |   echo "Bazel binaries have to be installed in ${wrapper_dir}, but none were found.") 2>&1 | 
 |   exit 1 | 
 | fi | 
 |  | 
 | if [[ ! -x $BAZEL_REAL ]]; then | 
 |   color "31" "ERROR: The project you're trying to build requires Bazel ${bazel_version} (${reason}), but it wasn't found in ${wrapper_dir}." | 
 |  | 
 |   long_binary_name="bazel-${bazel_version}-${os_arch_suffix}" | 
 |  | 
 |   if [[ -x $(command -v apt-get) && $wrapper_dir == "/usr/bin" ]]; then | 
 |     (echo "" | 
 |     echo "You can install the required Bazel version via apt:" | 
 |     echo "  sudo apt update && sudo apt install bazel-${bazel_version}" | 
 |     echo "" | 
 |     echo "If this doesn't work, check Bazel's installation instructions for help:" | 
 |     echo "  https://docs.bazel.build/versions/master/install-ubuntu.html") 2>&1 | 
 |   else | 
 |     (echo "" | 
 |     echo "Bazel binaries for all official releases can be downloaded from here:" | 
 |     echo "  https://github.com/bazelbuild/bazel/releases") 2>&1 | 
 |  | 
 |     if [[ -x $(command -v curl) && -w $wrapper_dir ]]; then | 
 |       (echo "" | 
 |       echo "You can download the required version directly using this command:" | 
 |       echo "  (cd \"${wrapper_dir}\" && curl -fLO https://releases.bazel.build/${bazel_version}/release/${long_binary_name} && chmod +x ${long_binary_name})") 2>&1 | 
 |     elif [[ -x $(command -v wget) && -w $wrapper_dir ]]; then | 
 |       (echo "" | 
 |       echo "You can download the required version directly using this command:" | 
 |       echo "  (cd \"${wrapper_dir}\" && wget https://releases.bazel.build/${bazel_version}/release/${long_binary_name} && chmod +x ${long_binary_name})") 2>&1 | 
 |     else | 
 |       (echo "" | 
 |       echo "Please put the downloaded Bazel binary into this location:" | 
 |       echo "  ${wrapper_dir}/${long_binary_name}") 2>&1 | 
 |     fi | 
 |   fi | 
 |   exit 1 | 
 | fi | 
 |  | 
 | exec -a "$0" "${BAZEL_REAL}" "$@" |