Create a wrapper script which looks for an executable in the workspace

This executable in the workspace can be another Bazel binary whose
version will change with the code it's next to, or a shell script which
downloads a fixed version from some location.

RELNOTES: A tools/bazel script in the workspace will be executed
as an opportunity to use a fixed version of Bazel (not implemented for
the homebrew recipe yet).

Fixes #521

--
Change-Id: Id06177d9c2b259cd9d6fd62edb5abe541342dd05
Reviewed-on: https://bazel-review.googlesource.com/2620
MOS_MIGRATED_REVID=112477232
diff --git a/scripts/packages/BUILD b/scripts/packages/BUILD
index d9f32b1..86a3a1f 100644
--- a/scripts/packages/BUILD
+++ b/scripts/packages/BUILD
@@ -25,13 +25,28 @@
         """,
 )
 
+genrule(
+    name = "rename-bazel-bin",
+    srcs = ["//src:bazel"],
+    outs = ["bazel-real"],
+    cmd = "cp $< $@",
+)
+
+genrule(
+    name = "rename-bazel-sh",
+    srcs = ["bazel.sh"],
+    outs = ["bazel"],
+    cmd = "cp $< $@",
+)
+
 load("self_extract_binary", "self_extract_binary")
 
 self_extract_binary(
     name = "install.sh",
     empty_files = ["tools/defaults/BUILD"],
     flatten_resources = [
-        "//src:bazel",
+        ":bazel-real",
+        ":bazel",
         "//scripts:bash_completion",
     ],
     launcher = ":launcher_bin.sh",
@@ -46,10 +61,13 @@
 
 pkg_tar(
     name = "bazel-bin",
-    files = ["//src:bazel"],
+    files = [
+        ":bazel",
+        ":bazel-real",
+    ],
     mode = "0755",
     package_dir = "/usr/bin",
-    strip_prefix = "/src",
+    strip_prefix = ".",
 )
 
 pkg_tar(
diff --git a/scripts/packages/bazel.sh b/scripts/packages/bazel.sh
new file mode 100755
index 0000000..69ebdb5
--- /dev/null
+++ b/scripts/packages/bazel.sh
@@ -0,0 +1,86 @@
+#!/bin/bash -eu
+
+# Copyright 2015 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 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.
+
+WORKSPACE_DIR="${PWD}"
+while [[ "${WORKSPACE_DIR}" != / ]]; do
+    if [[ -e "${WORKSPACE_DIR}/WORKSPACE" ]]; then
+      break;
+    fi
+    WORKSPACE_DIR="$(dirname "${WORKSPACE_DIR}")"
+done
+readonly WORKSPACE_DIR
+
+if [[ -e "${WORKSPACE_DIR}/WORKSPACE" ]]; then
+  readonly WRAPPER="${WORKSPACE_DIR}/tools/bazel"
+
+  if [[ -x "${WRAPPER}" ]]; then
+    exec -a "$0" "${WRAPPER}" "$@"
+  fi
+fi
+
+# `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
+}
+
+BAZEL_REAL="$(dirname "$(get_realpath "${BASH_SOURCE[0]}")")/bazel-real"
+
+if [[ ! -x "${BAZEL_REAL}" ]]; then
+    echo "Failed to find underlying Bazel executable at ${BAZEL_REAL}" >&2
+    exit 1
+fi
+
+exec -a "$0" "${BAZEL_REAL}" "$@"
diff --git a/scripts/packages/template_bin.sh b/scripts/packages/template_bin.sh
index 75b96e8..d3f7d3b 100755
--- a/scripts/packages/template_bin.sh
+++ b/scripts/packages/template_bin.sh
@@ -142,10 +142,10 @@
 mkdir -p ${bin} ${base} ${base}/bin ${base}/etc ${base}/base_workspace
 echo -n .
 
-unzip -q "${BASH_SOURCE[0]}" bazel bazel-complete.bash -d "${base}/bin"
+unzip -q "${BASH_SOURCE[0]}" bazel bazel-real bazel-complete.bash -d "${base}/bin"
 echo -n .
-chmod 0755 "${base}/bin/bazel"
-unzip -q "${BASH_SOURCE[0]}" -x bazel bazel-complete.bash -d "${base}/base_workspace"
+chmod 0755 "${base}/bin/bazel" "${base}/bin/bazel-real"
+unzip -q "${BASH_SOURCE[0]}" -x bazel bazel-real bazel-complete.bash -d "${base}/base_workspace"
 echo -n .
 cat >"${base}/etc/bazel.bazelrc" <<EO
 build --package_path %workspace%:${base}/base_workspace