Update build scripts to work under Kokoro+Repo

Kokoro does not support <linkfile> tags. That means two workarounds are
needed:
(a) build.sh is called as "./core/kokoro" (not "./kokoro") and therefore
must adjust ROOT_DIR location - done by checking for presence of
"../.repo_manifest" folder
(b) build.sh must first symlink files specified in <linkfile> tags of
the manifest - done by a Python script

Move init logic like this to a .inc file that can be shared between
build scripts for different projects.

Change-Id: I4d632c7200d34d08981e58d290883bd2cd9e5a04
diff --git a/build/bash/common.inc b/build/bash/common.inc
new file mode 100644
index 0000000..4d7bd73
--- /dev/null
+++ b/build/bash/common.inc
@@ -0,0 +1,130 @@
+# Copyright 2019 The Hafnium Authors.
+#
+# 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
+#
+#     https://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.
+
+# Fail on any error.
+set -e
+# Fail on any part of a pipeline failing.
+set -o pipefail
+# Treat unset variables as an error.
+set -u
+# Display commands being run.
+set -x
+
+# Returns absolute path to a file or a directory. The path must exist.
+function abs_path() {
+	local rel_path="$1"
+	if [ -d "$rel_path" ]
+	then
+		# Parameter is a directory
+		local rel_dir="$rel_path"
+		local rel_base=""
+	elif [ -f "$rel_path" ]
+	then
+		# Parameter is a regular file
+		local rel_dir="$(dirname "$rel_path")"
+		local rel_base="/$(basename "$rel_path")"
+	else
+		# File does not exist
+		echo "File not found: $rel_path" >&2
+		exit 1
+	fi
+	echo "$(cd $rel_dir && pwd)$rel_base"
+	return 0
+}
+
+# Returns true if the environment contains Kokoro build variables.
+function is_kokoro_build() {
+	[ -v KOKORO_JOB_NAME ]
+	return $?
+}
+
+# Returns true if the `.repo_manifest` folder exists. The folder should contain
+# the manifest and be present in all Repo builds. Eventually this should be
+# obsolete as we switch exclusively to Repo.
+function is_repo_build() {
+	[ -d "${ROOT_DIR}/.repo_manifest" ]
+	return $?
+}
+
+# Returns absolute path to the source file that called this function.
+function get_script_path() {
+	abs_path "${BASH_SOURCE[1]}"
+}
+
+# Returns absolute path to the directory containing the source file that called
+# this function.
+function get_script_dir() {
+	local caller_path="${BASH_SOURCE[1]}"
+	local caller_abs_path="$(abs_path $caller_path)"
+	dirname "$caller_abs_path"
+}
+
+# Assigns value (second arg) of a variable (first arg) if it is not set already.
+function default_value {
+	local var_name=$1
+	local value=$2
+	export ${var_name}=${!var_name:-${value}}
+}
+
+# Returns true if `git status` reports uncommitted changes in the source tree.
+# Runs on all projects if Repo is detected.
+function is_repo_dirty() {
+	local cmd=(git status --porcelain=v1)
+	if is_repo_build
+	then
+		# This source tree was checked out using `repo`. Check the
+		# status of all projects.
+		cmd=(${REPO} forall -c "${cmd[@]}")
+	fi
+	! (u="$(${cmd[@]})" && test -z "$u")
+	return $?
+}
+
+# Prepares the source directory for building. This includes setting global
+# variables and workaronuds for different build environments.
+function init_build() {
+	##
+	## Find Hafnium's root directory.
+	##
+	ROOT_DIR="$(abs_path $(get_script_dir)/../..)"
+	# Temporary workaround for Repo builds. Check if there is a project
+	# folder specific to Repo builds in a parent directory. If it is, the
+	# root is further one level up.
+	if [ -d "${ROOT_DIR}/../.repo_manifest" ]
+	then
+		ROOT_DIR="$(dirname ${ROOT_DIR})"
+	fi
+
+	##
+	## Paths to tools
+	##
+	CLANG="${ROOT_DIR}/prebuilts/linux-x64/clang/bin/clang"
+	REPO="${ROOT_DIR}/prebuilts/generic/repo/repo"
+
+	##
+	## Workarounds for Kokoro+Repo builds.
+	##
+	if is_kokoro_build && is_repo_build
+	then
+		# Kokoro does not correctly initialize the `.repo` folder which
+		# causes `is_repo_dirty` checks to fail. We check out the
+		# manifest as one of the projects and use it to initialize the
+		# `.repo` folder here.
+		(cd "${ROOT_DIR}/.repo_manifest" && git branch master)
+		(cd "${ROOT_DIR}" && "${REPO}" init -u .repo_manifest)
+		# Kokoro does not support '<linkfile>' manifest tags. Parse the
+		# manifest and symlink files here.
+		"$(get_script_dir)/symlink_repo.py" "${ROOT_DIR}"
+	fi
+}
diff --git a/build/bash/symlink_repo.py b/build/bash/symlink_repo.py
new file mode 100755
index 0000000..eefa46b
--- /dev/null
+++ b/build/bash/symlink_repo.py
@@ -0,0 +1,57 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 The Hafnium Authors.
+#
+# 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
+#
+#     https://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.
+
+"""Parse Repo manifest and symlink files specified in <linkfile> tags.
+
+This is a workaround for Kokoro which does not support <linkfile>.
+"""
+
+import argparse
+import os
+import sys
+import xml.etree.ElementTree as ET
+
+def main():
+	parser = argparse.ArgumentParser()
+	parser.add_argument("root_dir", help="root directory")
+	args = parser.parse_args()
+
+	manifest = os.path.join(args.root_dir, ".repo", "manifest.xml")
+	tree = ET.parse(manifest)
+	root = tree.getroot()
+	assert(root.tag == "manifest");
+
+	for proj in root:
+		if proj.tag != "project":
+			continue
+
+		proj_name = proj.attrib["name"]
+		proj_path = proj.attrib["path"]
+
+		for linkfile in proj:
+			if linkfile.tag != "linkfile":
+				continue
+
+			linkfile_src = linkfile.attrib["src"]
+			linkfile_dest = linkfile.attrib["dest"]
+			src_path = os.path.join(
+				args.root_dir, proj_path, linkfile_src)
+			dest_path = os.path.join(args.root_dir, linkfile_dest)
+
+			os.symlink(src_path, dest_path)
+
+if __name__ == "__main__":
+    sys.exit(main())