eclass: pulled Bazel eclass from upstream.

In future, there will be more / more complex Bazel projects in
Chrome OS. We pull Gentoo's Bazel eclass to make ebuilds
simpler for those projects.

BUG=chromium:955950
TEST=None
CQ-DEPEND=CL:1580568

Change-Id: I8550ac3168c5cecbe1f0d3e3c0af23d82c87bfa8
Reviewed-on: https://chromium-review.googlesource.com/1580569
Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com>
Tested-by: Michael Martis <martis@chromium.org>
Reviewed-by: Andrew Moylan <amoylan@chromium.org>
diff --git a/eclass/bazel.eclass b/eclass/bazel.eclass
new file mode 100644
index 0000000..ce80ea1
--- /dev/null
+++ b/eclass/bazel.eclass
@@ -0,0 +1,220 @@
+# Copyright 1999-2018 Jason Zaman
+# Distributed under the terms of the GNU General Public License v2
+
+# @ECLASS: bazel.eclass
+# @MAINTAINER:
+# Jason Zaman <perfinion@gentoo.org>
+# @AUTHOR:
+# Jason Zaman <perfinion@gentoo.org>
+# @BLURB: Utility functions for packages using Bazel Build
+# @DESCRIPTION:
+# A utility eclass providing functions to run the Bazel Build system.
+#
+# This eclass does not export any phase functions.
+
+case "${EAPI:-0}" in
+	0|1|2|3|4|5|6)
+		die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}"
+		;;
+	7)
+		;;
+	*)
+		die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
+		;;
+esac
+
+if [[ ! ${_BAZEL_ECLASS} ]]; then
+
+inherit multiprocessing toolchain-funcs
+
+BDEPEND=">=dev-util/bazel-0.20"
+
+# @FUNCTION: bazel_get_flags
+# @DESCRIPTION:
+# Obtain and print the bazel flags for target and host *FLAGS.
+#
+# To add more flags to this, append the flags to the
+# appropriate variable before calling this function
+bazel_get_flags() {
+	local i fs=()
+	for i in ${CFLAGS}; do
+		fs+=( "--conlyopt=${i}" )
+	done
+	for i in ${BUILD_CFLAGS}; do
+		fs+=( "--host_conlyopt=${i}" )
+	done
+	for i in ${CXXFLAGS}; do
+		fs+=( "--cxxopt=${i}" )
+	done
+	for i in ${BUILD_CXXFLAGS}; do
+		fs+=( "--host_cxxopt=${i}" )
+	done
+	for i in ${CPPFLAGS}; do
+		fs+=( "--conlyopt=${i}" "--cxxopt=${i}" )
+	done
+	for i in ${BUILD_CPPFLAGS}; do
+		fs+=( "--host_conlyopt=${i}" "--host_cxxopt=${i}" )
+	done
+	for i in ${LDFLAGS}; do
+		fs+=( "--linkopt=${i}" )
+	done
+	for i in ${BUILD_LDFLAGS}; do
+		fs+=( "--host_linkopt=${i}" )
+	done
+	echo "${fs[*]}"
+}
+
+# @FUNCTION: bazel_setup_bazelrc
+# @DESCRIPTION:
+# Creates the bazelrc with common options that will be passed
+# to bazel. This will be called by ebazel automatically so
+# does not need to be called from the ebuild.
+bazel_setup_bazelrc() {
+	if [[ -f "${T}/bazelrc" ]]; then
+		return
+	fi
+
+	# F: fopen_wr
+	# P: /proc/self/setgroups
+	# Even with standalone enabled, the Bazel sandbox binary is run for feature test:
+	# https://github.com/bazelbuild/bazel/blob/7b091c1397a82258e26ab5336df6c8dae1d97384/src/main/java/com/google/devtools/build/lib/sandbox/LinuxSandboxedSpawnRunner.java#L61
+	# https://github.com/bazelbuild/bazel/blob/76555482873ffcf1d32fb40106f89231b37f850a/src/main/tools/linux-sandbox-pid1.cc#L113
+	addpredict /proc
+
+	mkdir -p "${T}/bazel-cache" || die
+	mkdir -p "${T}/bazel-distdir" || die
+
+	cat > "${T}/bazelrc" <<-EOF || die
+		startup --batch
+
+		# dont strip HOME, portage sets a temp per-package dir
+		build --action_env HOME
+
+		# make bazel respect MAKEOPTS
+		build --jobs=$(makeopts_jobs)
+		build --compilation_mode=opt --host_compilation_mode=opt
+
+		# FLAGS
+		build $(bazel_get_flags)
+
+		# Use standalone strategy to deactivate the bazel sandbox, since it
+		# conflicts with FEATURES=sandbox.
+		build --spawn_strategy=standalone --genrule_strategy=standalone
+		test --spawn_strategy=standalone --genrule_strategy=standalone
+
+		build --strip=never
+		build --verbose_failures --noshow_loading_progress
+		test --verbose_test_summary --verbose_failures --noshow_loading_progress
+
+		# make bazel only fetch distfiles from the cache
+		fetch --repository_cache="${T}/bazel-cache/" --distdir="${T}/bazel-distdir/"
+		build --repository_cache="${T}/bazel-cache/" --distdir="${T}/bazel-distdir/"
+
+		build --define=PREFIX=${EPREFIX%/}/usr
+		build --define=LIBDIR=\$(PREFIX)/$(get_libdir)
+		EOF
+
+	if tc-is-cross-compiler; then
+		echo "build --nodistinct_host_configuration" >> "${T}/bazelrc" || die
+	fi
+}
+
+# @FUNCTION: ebazel
+# @USAGE: [<args>...]
+# @DESCRIPTION:
+# Run bazel with the bazelrc and output_base.
+#
+# output_base will be specific to $BUILD_DIR (if unset, $S).
+# bazel_setup_bazelrc will be called and the created bazelrc
+# will be passed to bazel.
+#
+# Will automatically die if bazel does not exit cleanly.
+ebazel() {
+	bazel_setup_bazelrc
+
+	# Use different build folders for each multibuild variant.
+	local output_base="${BUILD_DIR:-${S}}"
+	output_base="${output_base%/}-bazel-base"
+	mkdir -p "${output_base}" || die
+
+	set -- bazel --bazelrc="${T}/bazelrc" --output_base="${output_base}" ${@}
+	echo "${*}" >&2
+	"${@}" || die "ebazel failed"
+}
+
+# @FUNCTION: bazel_load_distfiles
+# @USAGE: <distfiles>...
+# @DESCRIPTION:
+# Populate the bazel distdir to fetch from since it cannot use
+# the network. Bazel looks in distdir but will only look for the
+# original filename, not the possibly renamed one that portage
+# downloaded. If the line has -> we to rename it back. This also
+# handles use-conditionals that SRC_URI does.
+#
+# Example:
+# @CODE
+# bazel_external_uris="http://a/file-2.0.tgz
+#     python? ( http://b/1.0.tgz -> foo-1.0.tgz )"
+# SRC_URI="http://c/${PV}.tgz
+#     ${bazel_external_uris}"
+#
+# src_unpack() {
+#     unpack ${PV}.tgz
+#     bazel_load_distfiles "${bazel_external_uris}"
+# }
+# @CODE
+bazel_load_distfiles() {
+	local file=""
+	local rename=0
+
+	[[ "${@}" ]] || die "Missing args"
+	mkdir -p "${T}/bazel-distdir" || die
+
+	for word in ${@}
+	do
+		if [[ "${word}" == "->" ]]; then
+			# next word is a dest filename
+			rename=1
+		elif [[ "${word}" == ")" ]]; then
+			# close conditional block
+			continue
+		elif [[ "${word}" == "(" ]]; then
+			# open conditional block
+			continue
+		elif [[ "${word}" == ?(\!)[A-Za-z0-9]*([A-Za-z0-9+_@-])\? ]]; then
+			# use-conditional block
+			# USE-flags can contain [A-Za-z0-9+_@-], and start with alphanum
+			# https://dev.gentoo.org/~ulm/pms/head/pms.html#x1-200003.1.4
+			# ?(\!) matches zero-or-one !'s
+			# *(...) zero-or-more characters
+			# ends with a ?
+			continue
+		elif [[ ${rename} -eq 1 ]]; then
+			# Make sure the distfile is used
+			if [[ "${A}" == *"${word}"* ]]; then
+				echo "Copying ${file} to bazel distdir as ${word}"
+				ln -s "${DISTDIR}/${word}" "${T}/bazel-distdir/${file}" || die
+			fi
+			rename=0
+			file=""
+		else
+			# another URL, current one may or may not be a rename
+			# if there was a previous one, its not renamed so copy it now
+			if [[ -n "${file}" && "${A}" == *"${file}"* ]]; then
+				echo "Copying ${file} to bazel distdir"
+				ln -s "${DISTDIR}/${file}" "${T}/bazel-distdir/${file}" || die
+			fi
+			# save the current URL, later we will find out if its a rename or not.
+			file="${word##*/}"
+		fi
+	done
+
+	# handle last file
+	if [[ -n "${file}" ]]; then
+		echo "Copying ${file} to bazel distdir"
+		ln -s "${DISTDIR}/${file}" "${T}/bazel-distdir/${file}" || die
+	fi
+}
+
+_BAZEL_ECLASS=1
+fi