Initial commit for TF-A CI scripts
Signed-off-by: Fathi Boudra <fathi.boudra@linaro.org>
diff --git a/script/run_local_ci.sh b/script/run_local_ci.sh
new file mode 100755
index 0000000..9376305
--- /dev/null
+++ b/script/run_local_ci.sh
@@ -0,0 +1,309 @@
+#!/bin/bash
+#
+# Copyright (c) 2019, Arm Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+set -e
+
+in_red() {
+ echo "$(tput setaf 1)${1:?}$(tput sgr0)"
+}
+export -f in_red
+
+in_green() {
+ echo "$(tput setaf 2)${1:?}$(tput sgr0)"
+}
+export -f in_green
+
+in_yellow() {
+ echo "$(tput setaf 3)${1:?}$(tput sgr0)"
+}
+export -f in_yellow
+
+print_success() {
+ in_green "$1: SUCCESS"
+}
+export -f print_success
+
+print_failure() {
+ in_red "$1: FAILURE"
+}
+export -f print_failure
+
+print_unstable() {
+ in_yellow "$1: UNSTABLE"
+}
+export -f print_unstable
+
+gen_makefile() {
+ local num="$(find -name "*.test" -type f | wc -l)"
+ local i=0
+
+ cat <<EOF >Makefile
+SHELL=/bin/bash
+
+all:
+
+EOF
+
+ # If we're using local checkouts for either TF or TFTF, we must
+ # serialise builds
+ while [ "$i" -lt "$num" ]; do
+ {
+ printf "all: %03d_run %03d_build\n" "$i" "$i"
+ if upon "$serialize_builds" && [ "$i" -gt 0 ]; then
+ printf "%03d_build: %03d_build\n" "$i" "$((i - 1))"
+ fi
+ echo
+ } >>Makefile
+ let "++i"
+ done
+
+ cat <<EOF >>Makefile
+
+%_run: %_build
+ @run_one_test "\$@"
+
+%_build:
+ @run_one_test "\$@"
+EOF
+}
+
+# This function is invoked from the Makefile. Descriptor 5 points to the active
+# terminal.
+run_one_test() {
+ id="${1%%_*}"
+ action="${1##*_}"
+ test_file="$(find -name "$id*.test" -printf "%f\n")"
+
+ mkdir -p "$id"
+
+ # Copy the test_file into the workspace directory with the name
+ # TEST_DESC, just like Jenkins would.
+ export TEST_DESC="$(basename "$test_file")"
+ cp "$test_file" "$id/TEST_DESC"
+
+ workspace="$id" test_desc="$test_file" "$ci_root/script/parse_test.sh"
+
+ set -a
+ source "$id/env"
+ set +a
+
+ # Makefiles don't like commas and colons in file names. We therefore
+ # replace them with _
+ config_subst="$(echo "$TEST_CONFIG" | tr ',:' '_')"
+ config_string="$id: $TEST_GROUP/$TEST_CONFIG"
+ workspace="$workspace/$TEST_GROUP/$config_subst"
+ mkdir -p "$workspace"
+
+ log_file="$workspace/artefacts/build.log"
+ if [ "$parallel" -gt 1 ]; then
+ console_file="$workspace/console.log"
+ exec 6>>"$console_file"
+ else
+ exec 6>&5
+ fi
+
+ # Unset make flags for build script
+ MAKEFLAGS=
+
+ case "$action" in
+ "build")
+ echo "building: $config_string" >&5
+ if ! bash $minus_x "$ci_root/script/build_package.sh" \
+ >&6 2>&1; then
+ {
+ print_failure "$config_string (build)"
+ if [ "$console_file" ]; then
+ echo " see $console_file"
+ fi
+ } >&5
+ exit 1
+ fi
+ ;;
+
+ "run")
+ # Local runs only for FVP unless asked not to
+ if echo "$RUN_CONFIG" | grep -q "^fvp" && \
+ not_upon "$skip_runs"; then
+ echo "running: $config_string" >&5
+ if bash $minus_x "$ci_root/script/run_package.sh" \
+ >&6 2>&1; then
+ if grep -q -e "--BUILD UNSTABLE--" \
+ "$log_file"; then
+ print_unstable "$config_string" >&5
+ else
+ print_success "$config_string" >&5
+ fi
+ exit 0
+ else
+ {
+ print_failure "$config_string (run)"
+ if [ "$console_file" ]; then
+ echo " see $console_file"
+ fi
+ } >&5
+ exit 1
+ fi
+ else
+ if grep -q -e "--BUILD UNSTABLE--" \
+ "$log_file"; then
+ print_unstable "$config_string (not run)" >&5
+ else
+ print_success "$config_string (not run)" >&5
+ fi
+ exit 0
+ fi
+ ;;
+
+ *)
+ in_red "Invalid action: $action!" >&5
+ exit 1
+ ;;
+ esac
+}
+export -f run_one_test
+
+workspace="${workspace:?}"
+ci_root="$(readlink -f "$(dirname "$0")/..")"
+
+# If this script was invoked with bash -x, have subsequent build/run invocations
+# to use -x as well.
+if echo "$-" | grep -q "x"; then
+ export minus_x="-x"
+fi
+
+# For a local run, when some variables as specified as "?", launch zenity to
+# prompt for test config via. GUI. If it's "??", then choose a directory.
+if [ "$test_groups" = "?" -o "$test_groups" = "??" ]; then
+ zenity_opts=(
+ --file-selection
+ --filename="$ci_root/group/README"
+ --multiple
+ --title "Choose test config"
+ )
+
+ if [ "$test_groups" = "??" ]; then
+ zenity_opts+=("--directory")
+ fi
+
+ # In case of multiple selections, zenity returns absolute paths of files
+ # separated by '|'. We remove the pipe characters, and make the paths
+ # relative to the group directory.
+ selections="$(cd "$ci_root"; zenity ${zenity_opts[*]})"
+ test_groups="$(echo "$selections" | tr '|' ' ')"
+ test_groups="$(echo "$test_groups" | sed "s#$ci_root/group/##g")"
+fi
+
+test_groups="${test_groups:?}"
+local_count=0
+
+if [ -z "$tf_root" ]; then
+ in_red "NOTE: NOT using local work tree for TF"
+else
+ tf_root="$(readlink -f $tf_root)"
+ tf_refspec=
+ in_green "Using local work tree for TF"
+ let "++local_count"
+fi
+
+if [ -z "$tftf_root" ]; then
+ in_red "NOTE: NOT using local work tree for TFTF"
+ tforg_user="${tforg_user:?}"
+else
+ tftf_root="$(readlink -f $tftf_root)"
+ tf_refspec=
+ in_green "Using local work tree for TFTF"
+ let "++local_count"
+fi
+
+if [ -z "$scp_root" ]; then
+ in_red "NOTE: NOT using local work tree for SCP"
+else
+ scp_root="$(readlink -f $scp_root)"
+ scp_refspec=
+ in_green "Using local work tree for SCP"
+ let "++local_count"
+fi
+
+# User preferences
+user_test_run="$test_run"
+user_dont_clean="$dont_clean"
+user_keep_going="$keep_going"
+user_primary_live="$primary_live"
+
+export ci_root
+export dont_clean=0
+export local_ci=1
+export parallel
+export test_run=0
+export primary_live=0
+
+rm -rf "$workspace"
+mkdir -p "$workspace"
+
+source "$ci_root/utils.sh"
+
+# SCP is not cloned by default
+export clone_scp
+export scp_root
+if not_upon "$scp_root" && upon "$clone_scp"; then
+ clone_scp=1
+else
+ clone_scp=0
+fi
+
+# Use clone_repos.sh to clone and share repositores that aren't local.
+no_tf="$tf_root" no_tftf="$tftf_root" no_ci="$ci_root" \
+ bash $minus_x "$ci_root/script/clone_repos.sh"
+
+set -a
+source "$workspace/env"
+set +a
+
+if [ "$local_count" -gt 0 ]; then
+ # At least one repository is local
+ serialize_builds=1
+else
+ dont_clean=0
+fi
+
+export -f upon not_upon
+
+# Generate test descriptions
+"$ci_root/script/gen_test_desc.py"
+
+# Iterate through test files in workspace
+pushd "$workspace"
+
+if not_upon "$parallel" || echo "$parallel" | grep -vq "[0-9]"; then
+ parallel=1
+ test_run="$user_test_run"
+ dont_clean="$user_dont_clean"
+ primary_live="$user_primary_live"
+fi
+
+if [ "$parallel" -gt 1 ]; then
+ msg="Running at most $parallel jobs in parallel"
+ if upon "$serialize_builds"; then
+ msg+=" (builds serialized)"
+ fi
+ msg+="..."
+fi
+
+# Generate Makefile
+gen_makefile
+
+if upon "$msg"; then
+ echo "$msg"
+ echo
+fi
+
+keep_going="${user_keep_going:-1}"
+if not_upon "$keep_going"; then
+ keep_going=
+fi
+
+MAKEFLAGS= make -r -j "$parallel" ${keep_going+-k} 5>&1 &>"make.log"