Create a binary packager for Bazel

This packager can be called by the release scripts to generate
a self-extractable bash installer for Bazel. This script was
tested by hand as extra arguments can be specified to change
the default install of Bazel (default is system-wide and
with the argument you can make a user install).

This will be the only packager for now since GitHub is offering
the possibility to download the source tree as a ZIP. Hopefully,
before the end of the year we could build some more package kind.

--
Change-Id: I1a2d0cd39b9e4adcaf6c984ec4c855a04213b61a
Reviewed-on: https://bazel-review.googlesource.com/1581
MOS_MIGRATED_REVID=99258828
diff --git a/scripts/packages/BUILD b/scripts/packages/BUILD
new file mode 100644
index 0000000..0364718
--- /dev/null
+++ b/scripts/packages/BUILD
@@ -0,0 +1,39 @@
+sh_binary(
+    name = "package-info-generator",
+    srcs = ["package_info_generator.sh"],
+)
+
+genrule(
+    name = "generate-package-info",
+    outs = ["README.md"],
+    cmd = "$(location :package-info-generator) $$(find . -name '*status*.txt') >$@",
+    stamp = 1,
+    tools = [":package-info-generator"],
+)
+
+genrule(
+    name = "generate-launcher",
+    srcs = [
+        "template_bin.sh",
+        ":README.md",
+    ],
+    outs = ["launcher_bin.sh"],
+    cmd = """
+        release_info="$$(cat $(location :README.md))"
+        template="$$(cat $(location template_bin.sh))"
+        echo "$${template//%release_info%/$${release_info}}" >$@
+        """,
+)
+
+load("self_extract_binary", "self_extract_binary")
+
+self_extract_binary(
+    name = "install.sh",
+    flatten_resources = ["//src:bazel"],
+    launcher = ":launcher_bin.sh",
+    resources = [
+        "//third_party:srcs",
+        "//third_party/java/jdk/langtools:srcs",
+        "//tools:package-srcs",
+    ],
+)
diff --git a/scripts/packages/package_info_generator.sh b/scripts/packages/package_info_generator.sh
new file mode 100755
index 0000000..6480dab
--- /dev/null
+++ b/scripts/packages/package_info_generator.sh
@@ -0,0 +1,76 @@
+#!/bin/bash -eu
+
+# Copyright 2015 Google Inc. 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.
+
+# Generate a README.md for the package from the information provided
+# by the build status command.
+
+# Store the build status information we care about
+release_name=
+git_hash=
+url=
+built_by=
+build_log=
+commit_msg=
+
+for i in "${@}"; do
+  while read line; do
+    key=$(echo "$line" | cut -d " " -f 1)
+    value="$(echo "$line" | cut -d " " -f 2- | tr '\f' '\n')"
+    case $key in
+      RELEASE_NAME)
+        release_name="$value"
+        ;;
+      RELEASE_GIT_HASH)
+        git_hash="$value"
+        ;;
+      RELEASE_BUILT_BY)
+        built_by="$value"
+        ;;
+      RELEASE_BUILD_LOG)
+        build_log="$value"
+        ;;
+      RELEASE_COMMIT_MSG)
+        commit_msg="$value"
+        ;;
+      RELEASE_COMMIT_URL)
+        commit_url="$value"
+        ;;
+   esac
+  done <<<"$(cat $i)"
+done
+
+url="${url:-https://github.com/google/bazel/commit/${git_hash}}"
+
+if [ -z "${release_name}" ]; then
+  # Not a release
+  echo "# Binary package at HEAD (@$git_hash)"
+else
+  echo "# $commit_msg"  # Make the first line the header
+  # Subsection for environment
+  echo
+  echo "## Build informations"
+fi
+if [ -n "${built_by-}" ]; then
+  if [ -n "${build_log}" ]; then
+    echo "   - [Built by ${built_by}](${build_log})"
+  else
+    echo "   - Built by ${built_by}"
+  fi
+elif [ -n "${build_log-}" ]; then
+  echo "   - [Build log](${build_log})"
+fi
+
+echo "   - [Commit](${url})"
diff --git a/scripts/packages/self_extract_binary.bzl b/scripts/packages/self_extract_binary.bzl
new file mode 100644
index 0000000..60928f6
--- /dev/null
+++ b/scripts/packages/self_extract_binary.bzl
@@ -0,0 +1,87 @@
+# Copyright 2015 Google Inc. 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.
+"""Self-extracting binary.
+
+Generate a binary suitable for self-extraction:
+
+self_extract_binary(
+  name = "install.sh",
+  launcher = "launcher.sh",
+  resources = ["path1/file1", "path2/file2"],
+  flatten_ressources = ["path3/file3"],
+)
+
+will generate a file 'install.sh' with a header (launcher.sh)
+and a ZIP footer with the following entries:
+  path1/
+  path1/file1
+  path2/
+  path2/file2
+  file3
+
+"""
+
+def _self_extract_binary(ctx):
+  """Implementation for the self_extract_binary rule."""
+  # This is a bit complex for stripping out timestamps
+  zip_artifact = ctx.new_file(ctx.label.name + ".zip")
+  cp_resources = [
+      ("mkdir -p $(dirname ${tmpdir}/%s)\n" % r.short_path +
+       "cp %s ${tmpdir}/%s" % (r.path, r.short_path))
+      for r in ctx.files.resources
+      ]
+  cp_flatten_resources = [
+      "cp %s ${tmpdir}/%s" % (r.path, r.basename)
+      for r in ctx.files.flatten_resources
+      ]
+  ctx.action(
+      inputs = ctx.files.resources + ctx.files.flatten_resources,
+      outputs = [zip_artifact],
+      command = "\n".join([
+          "tmpdir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXX)",
+          "trap \"rm -fr ${tmpdir}\" EXIT"
+          ] + cp_resources + cp_flatten_resources + [
+              "find ${tmpdir} -exec touch -t 198001010000.00 '{}' ';'",
+              "(d=${PWD}; cd ${tmpdir}; zip -rq ${d}/%s *)" % zip_artifact.path,
+              ]),
+      mnemonic = "ZipBin",
+  )
+  ctx.action(
+      inputs = [ctx.file.launcher, zip_artifact],
+      outputs = [ctx.outputs.executable],
+      command = "\n".join([
+          "cat %s %s > %s" % (ctx.file.launcher.path,
+                              zip_artifact.path,
+                              ctx.outputs.executable.path),
+          "zip -qA %s" % ctx.outputs.executable.path
+      ]),
+      mnemonic = "BuildSelfExtractable",
+  )
+
+self_extract_binary = rule(
+    _self_extract_binary,
+    executable = True,
+    attrs = {
+        "launcher": attr.label(
+            mandatory=True,
+            allow_files=True,
+            single_file=True),
+        "resources": attr.label_list(
+            default=[],
+            allow_files=True),
+        "flatten_resources": attr.label_list(
+            default=[],
+            allow_files=True),
+        },
+    )
diff --git a/scripts/packages/template_bin.sh b/scripts/packages/template_bin.sh
new file mode 100755
index 0000000..ea20044
--- /dev/null
+++ b/scripts/packages/template_bin.sh
@@ -0,0 +1,130 @@
+#!/bin/bash -e
+
+# Copyright 2015 Google Inc. 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.
+
+# Bazel self-extractable installer
+
+# Installation and etc prefix can be overriden from command line
+install_prefix=${1:-"/usr/local"}
+bazelrc=${2:-"/etc/bazel.bazelrc"}
+
+progname="$0"
+
+echo "Bazel installer"
+echo "---------------"
+echo
+cat <<'EOF'
+%release_info%
+EOF
+
+function usage() {
+  echo "Usage: $progname [options]" >&2
+  echo "Options are:" >&2
+  echo "  --prefix=/some/path set the prefix path (default=/usr/local)." >&2
+  echo "  --bazelrc= set the bazelrc path (default=/etc/bazel.bazelrc)." >&2
+  echo "  --bin= set the binary folder path (default=%prefix%/bin)." >&2
+  echo "  --base= set the base install path (default=%prefix%/lib/bazel)." >&2
+  echo "  --user configure for user install, expands to" >&2
+  echo '           `--bin=$HOME/bin --base=$HOME/.bazel --bazelrc=$HOME/.bazelrc`.' >&2
+  exit 1
+}
+
+prefix="/usr/local"
+bin="%prefix%/bin"
+base="%prefix%/lib/bazel"
+bazelrc="/etc/bazel.bazelrc"
+
+for opt in "${@}"; do
+  case $opt in
+    --prefix=*)
+      prefix="$(echo "$opt" | cut -d '=' -f 2-)"
+      ;;
+    --bazelrc=*)
+      bazelrc="$(echo "$opt" | cut -d '=' -f 2-)"
+      ;;
+    --bin=*)
+      bin="$(echo "$opt" | cut -d '=' -f 2-)"
+      ;;
+    --base=*)
+      base="$(echo "$opt" | cut -d '=' -f 2-)"
+      ;;
+    --user)
+      bin="$HOME/bin"
+      base="$HOME/.bazel"
+      bazelrc="$HOME/.bazelrc"
+      ;;
+    *)
+      usage
+      ;;
+  esac
+done
+
+bin="${bin//%prefix%/${prefix}}"
+base="${base//%prefix%/${prefix}}"
+bazelrc="${bazelrc//%prefix%/${prefix}}"
+
+function test_write() {
+  local file="$1"
+  while [ "$file" != "/" ] && [ -n "${file}" ] && [ ! -e "$file" ]; do
+    file="$(dirname "${file}")"
+  done
+  [ -w "${file}" ] || {
+    echo >&2
+    echo "The Bazel installer must have write access to $1!" >&2
+    echo >&2
+    usage
+  }
+}
+
+test_write "${bin}"
+test_write "${base}"
+test_write "${bazelrc}"
+
+echo -n "Uncompressing."
+rm -fr "${bin}" "${base}" "${bazelrc}"
+
+mkdir -p ${bin} ${base} ${base}/bin ${base}/etc ${base}/base_workspace
+echo -n .
+
+unzip -q "${BASH_SOURCE[0]}" bazel -d "${base}/bin"
+echo -n .
+chmod 0755 "${base}/bin/bazel"
+unzip -q "${BASH_SOURCE[0]}" -x bazel -d "${base}/base_workspace"
+echo -n .
+cat >"${base}/etc/bazel.bazelrc" <<EO
+build --package_path %workspace%:${base}/base_workspace"
+fetch --package_path %workspace%:${base}/base_workspace"
+query --package_path %workspace%:${base}/base_workspace"
+EO
+echo -n .
+chmod -R og-w "${base}"
+chmod -R og+rX "${base}"
+chmod -R u+rwX "${base}"
+echo -n .
+
+ln -s "${base}/bin/bazel" "${bin}/bazel"
+echo -n .
+
+if [ -f "${bazelrc}" ]; then
+  echo
+  echo "${bazelrc} already exists, ignoring. It is either a link to"
+  echo "${base}/etc/bazel.bazelrc or that it's importing that file with:"
+  echo "  import ${base}/etc/bazel.bazelrc"
+else
+  ln -s "${base}/etc/bazel.bazelrc" "${bazelrc}"
+  echo .
+fi
+
+exit 0