Skip to content

Commit

Permalink
Add $USE_BAZEL_VERSION and .bazelversion support to Bazel's wrapper s…
Browse files Browse the repository at this point in the history
…cript.

Also simplify the installation instructions for Ubuntu and how to

RELNOTES: Bazel's Debian package and the binary installer now include an improved wrapper that understands `<WORKSPACE>/.bazelversion` files and the `$USE_BAZEL_VERSION` environment variable. This is similar to what Bazelisk offers (https://github.com/bazelbuild/bazelisk#how-does-bazelisk-know-which-bazel-version-to-run-and-where-to-get-it-from), except that it works offline and integrates with apt-get.
PiperOrigin-RevId: 283031899
  • Loading branch information
philwo authored and copybara-github committed Nov 29, 2019
1 parent 40f464c commit d3f8efc
Show file tree
Hide file tree
Showing 5 changed files with 422 additions and 78 deletions.
8 changes: 8 additions & 0 deletions scripts/packages/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ filegroup(
}),
)

filegroup(
name = "wrapper",
srcs = ["bazel.sh"],
visibility = [
"//src/test/shell/bazel:__subpackages__",
],
)

sh_binary(
name = "package-info-generator",
srcs = ["package_info_generator.sh"],
Expand Down
139 changes: 118 additions & 21 deletions scripts/packages/bazel.sh
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/bin/bash

# Copyright 2015 The Bazel Authors. All rights reserved.
# 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.
Expand All @@ -16,10 +16,37 @@

set -eu

# This is a script which is installed instead of the real Bazel binary.
# It looks for a tools/bazel executable next to the containing WORKSPACE
# file and runs that. If that's not found, it runs the real Bazel binary which
# is installed next to this script as bazel-real.
# 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() {
Expand Down Expand Up @@ -61,29 +88,99 @@ function get_realpath() {
fi
}

BAZEL_REAL="$(dirname "$(get_realpath "${BASH_SOURCE[0]}")")/bazel-real"
export BAZEL_REAL
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

WORKSPACE_DIR="${PWD}"
while [[ "${WORKSPACE_DIR}" != / ]]; do
if [[ -e "${WORKSPACE_DIR}/WORKSPACE" ]]; then
break;
readonly wrapper_dir="$(dirname "$(get_realpath "${BASH_SOURCE[0]}")")"
readonly os_arch_suffix="$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m)"

function get_bazel_version() {
if [[ -n ${USE_BAZEL_VERSION:-} ]]; then
readonly reason="specified in \$USE_BAZEL_VERSION"
readonly bazel_version="${USE_BAZEL_VERSION}"
elif [[ -e "${workspace_dir}/.bazelversion" ]]; then
readonly reason="specified in ${workspace_dir}/.bazelversion"
read -r bazel_version < "${workspace_dir}/.bazelversion"
readonly bazel_version="${bazel_version}"
elif [[ -x "${wrapper_dir}/bazel-real" ]]; then
readonly reason="automatically selected bazel-real"
readonly bazel_version="real"
else
# Find the latest Bazel version installed on the system.
readonly 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
WORKSPACE_DIR="$(dirname "${WORKSPACE_DIR}")"
done
readonly WORKSPACE_DIR
# Remove the "bazel-" prefix from the file name.
bazel_version="${bazel_version#"bazel-"}"
readonly bazel_version
fi
}

get_bazel_version

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

BAZEL_REAL="${wrapper_dir}/bazel-${bazel_version}-${os_arch_suffix}"
if [[ ! -x ${BAZEL_REAL} ]]; then
BAZEL_REAL="${wrapper_dir}/bazel-${bazel_version}"
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 [[ -e "${WORKSPACE_DIR}/WORKSPACE" ]]; then
readonly WRAPPER="${WORKSPACE_DIR}/tools/bazel"
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 releaeses can be downloaded from here:"
echo " https://github.com/bazelbuild/bazel/releases") 2>&1

if [[ -x "${WRAPPER}" && ! -d "${WRAPPER}" ]]; then
exec -a "$0" "${WRAPPER}" "$@"
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 -LO 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

if [[ ! -x "${BAZEL_REAL}" ]]; then
echo "Failed to find underlying Bazel executable at ${BAZEL_REAL}" >&2
exit 1
readonly wrapper="${workspace_dir}/tools/bazel"
if [[ -x "$wrapper" ]]; then
export BAZEL_REAL
exec -a "$0" "${wrapper}" "$@"
fi

exec -a "$0" "${BAZEL_REAL}" "$@"
133 changes: 76 additions & 57 deletions site/docs/install-ubuntu.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,80 +10,100 @@ Supported Ubuntu Linux platforms:
* 18.04 (LTS)
* 16.04 (LTS)

Bazel will probably work fine on other Ubuntu releases and Debian stretch and
above, but we currently do not test this on Bazel's CI and thus can't promise
it.

Install Bazel on Ubuntu using one of the following methods:

* [Use the binary installer (recommended)](#install-with-installer-ubuntu)
* [Use our custom APT repository](#install-on-ubuntu)
* [Use our custom APT repository (recommended)](#install-on-ubuntu)
* [Use the binary installer](#install-with-installer-ubuntu)
* [Compile Bazel from source](install-compile-source.md)

Bazel comes with two completion scripts. After installing Bazel, you can:

* Access the [bash completion script](completion.md#bash)
* Install the [zsh completion script](completion.md#zsh)

<h2 id="install-with-installer-ubuntu">Installing using binary installer</h2>
<h2 id="install-on-ubuntu"> Using Bazel's apt repository</h2>

The binary installers are on Bazel's [GitHub releases page](https://github.com/bazelbuild/bazel/releases).
### Step 1: Add Bazel distribution URI as a package source

The installer contains the Bazel binary. Some additional libraries must also be
installed for Bazel to work.
**Note:** This is a one-time setup step.

### Step 1: Install required packages
```bash
sudo apt install curl
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
```

Bazel needs a C++ compiler and unzip / zip in order to work:
The component name "jdk1.8" is kept for legacy reasons only and doesn't relate
to supported or included JDK versions anymore. In the past, when Bazel did not
yet bundle a private JRE, we had two release versions, one compatible with JDK 7
and one with JDK 8. However, since we dropped Java 7 support and started
bundling a private runtime, Bazel releases are Java version agnostic. Changing
the "jdk1.8" component name would break existing users of the repo though.

### Step 2: Install and update Bazel

```bash
sudo apt-get install g++ unzip zip
sudo apt update && sudo apt install bazel
```

If you want to build Java code using Bazel, install a JDK:
Once installed, you can upgrade to a newer version of Bazel as part of your normal system updates:

```bash
# Ubuntu 16.04 (LTS) uses OpenJDK 8 by default:
sudo apt-get install openjdk-8-jdk
sudo apt update && sudo apt full-upgrade
```

# Ubuntu 18.04 (LTS) uses OpenJDK 11 by default:
sudo apt-get install openjdk-11-jdk
The `bazel` package will always install the latest stable version of Bazel. You
can install specific, older versions of Bazel in addition to the latest one like
this:

```bash
sudo apt install bazel-1.0.0
```

### Step 2: Download Bazel
This will install Bazel 1.0.0 as `/usr/bin/bazel-1.0.0` on your system. This
can be useful if you need a specific version of Bazel to build a project, e.g.
because it uses a `.bazelversion` file to explicitly state with which Bazel
version it should be built.

Next, download the Bazel binary installer named `bazel-<version>-installer-linux-x86_64.sh`
from the [Bazel releases page on GitHub](https://github.com/bazelbuild/bazel/releases).
### Step 3: Install a JDK (optional)

### Step 3: Run the installer
Bazel includes a private, bundled JRE as its runtime and doesn't require you to
install any specific version of Java.

Run the Bazel installer as follows:
However, if you want to build Java code using Bazel, you have to install a JDK.

```bash
chmod +x bazel-<version>-installer-linux-x86_64.sh
./bazel-<version>-installer-linux-x86_64.sh --user
```
# Ubuntu 16.04 (LTS) uses OpenJDK 8 by default:
sudo apt install openjdk-8-jdk

The `--user` flag installs Bazel to the `$HOME/bin` directory on your system and
sets the `.bazelrc` path to `$HOME/.bazelrc`. Use the `--help` command to see
additional installation options.
# Ubuntu 18.04 (LTS) uses OpenJDK 11 by default:
sudo apt install openjdk-11-jdk
```

### Step 4: Set up your environment
<h2 id="install-with-installer-ubuntu">Using the binary installer</h2>

If you ran the Bazel installer with the `--user` flag as above, the Bazel
executable is installed in your `$HOME/bin` directory. It's a good idea to add
this directory to your default paths, as follows:
While we generally recommend to use the apt repository, the binary installer can
be useful in case you don't have admin permissions on your machine or can't add
custom repositories.

```bash
export PATH="$PATH:$HOME/bin"
```
The binary installers can be downloaded from Bazel's [GitHub releases page](https://github.com/bazelbuild/bazel/releases).

You can also add this command to your `~/.bashrc` file.
The installer contains the Bazel binary and extracts it into your `$HOME/bin`
folder. Some additional libraries must be installed manually for Bazel to work.

<h2 id="install-on-ubuntu"> Using Bazel's APT repository</h2>
### Step 1: Install required packages

### Step 1: Install the JDK (optional)
Bazel needs a C++ compiler and unzip / zip in order to work:

Bazel includes a private, bundled JRE as its runtime and doesn't require you to
install any specific version of Java.
```bash
sudo apt install g++ unzip zip
```

However, if you want to build Java code using Bazel, you have to install a JDK.
If you want to build Java code using Bazel, install a JDK:

```bash
# Ubuntu 16.04 (LTS) uses OpenJDK 8 by default:
Expand All @@ -93,32 +113,31 @@ sudo apt-get install openjdk-8-jdk
sudo apt-get install openjdk-11-jdk
```

### Step 2: Add Bazel distribution URI as a package source
### Step 2: Run the installer

**Note:** This is a one-time setup step.
Next, download the Bazel binary installer named `bazel-<version>-installer-linux-x86_64.sh`
from the [Bazel releases page on GitHub](https://github.com/bazelbuild/bazel/releases).

Run it as follows:

```bash
sudo apt-get install curl
curl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.list
chmod +x bazel-<version>-installer-linux-x86_64.sh
./bazel-<version>-installer-linux-x86_64.sh --user
```

Note: The component name "jdk1.8" is kept for legacy reasons only and doesn't
relate to supported or included JDK versions anymore. In the past, when Bazel
did not yet bundle a private JRE, we had two release versions, one compatible
with JDK 7 and one with JDK 8. However, since we dropped Java 7 support and
started bundling a private runtime, Bazel releases are Java version agnostic.
Changing the "jdk1.8" component name would break existing users of the repo
though.

### Step 3: Install and update Bazel
The `--user` flag installs Bazel to the `$HOME/bin` directory on your system and
sets the `.bazelrc` path to `$HOME/.bazelrc`. Use the `--help` command to see
additional installation options.

```bash
sudo apt-get update && sudo apt-get install bazel
```
### Step 3: Set up your environment

Once installed, you can upgrade to a newer version of Bazel with the following command:
If you ran the Bazel installer with the `--user` flag as above, the Bazel
executable is installed in your `$HOME/bin` directory. It's a good idea to add
this directory to your default paths, as follows:

```bash
sudo apt-get install --only-upgrade bazel
export PATH="$PATH:$HOME/bin"
```

You can also add this command to your `~/.bashrc` or `~/.zshrc` file to make it
permanent.
13 changes: 13 additions & 0 deletions src/test/shell/bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,19 @@ sh_test(
],
)

sh_test(
name = "bazel_wrapper_test",
srcs = ["bazel_wrapper_test.sh"],
data = [
":test-deps",
"//scripts/packages:wrapper",
"@bazel_tools//tools/bash/runfiles",
],
tags = [
"no_windows", # wrapper is not used on Windows
],
)

sh_test(
name = "bazel_java_test_no_windows",
size = "large",
Expand Down
Loading

0 comments on commit d3f8efc

Please sign in to comment.