1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
#!/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 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" ]]; 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}" "$@"
|