blob: 55c791e70e372a6358b1a22d3a8e26061a588991 [file] [log] [blame] [edit]
#!/bin/bash
# Copyright 2025 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# rsninja.sh (this script) is a drop-in replacement for a ninja binary.
#
# rs-ninja.sh (from rsclient package) enables ResultStore features in ninja
# when it detects RSPROXY_FIFO in the environment (any intermediate
# ninja wrappers should take care to pass-through this variable).
# Otherwise, it falls back to the original ninja invocation.
# Using this script as a level of indirection allows the communication
# mechanism between rsproxy-wrap.sh and rs-ninja.sh (from rsclient) to
# change without breaking the build.
# See also rs-sub-ninja.sh, which a suitable drop-in replacement
# that includes rsproxy-wrap.sh.
# Use rsninja.sh when there is a need to insert other wrappers
# between rsproxy-wrap.sh and ninja (like in `fx build`).
set -euo pipefail
readonly SCRIPT_DIR="$(dirname "${BASH_SOURCE[0]}")"
# Get the HOST_PLATFORM for the prebuilt path.
# Sourcing platform.sh requires FUCHSIA_DIR to be set.
readonly FUCHSIA_DIR="$(readlink -f "$SCRIPT_DIR/../..")"
source "${FUCHSIA_DIR}/tools/devshell/lib/platform.sh"
# rsclient install path is set in manifests/prebuilts
readonly PREBUILT_RSCLIENT_DIR="${FUCHSIA_DIR}/prebuilt/rsclient/$HOST_PLATFORM"
readonly wrapper="$PREBUILT_RSCLIENT_DIR/bin/rs-ninja.sh"
readonly ninja_bin="$PREBUILT_NINJA"
# The RSPROXY_FIFO check is redundant with the rs-ninja.sh wrapper script, but
# harmless. Checking here lets us bypass unnecessary setup.
if [[ -z "${RSPROXY_FIFO+x}" ]]
then exec "$ninja_bin" "$@"
# no return
fi
if [ ! -x "$wrapper" ]
then
echo "Error: $wrapper is not executable, falling back to using $ninja_bin."
exec "$ninja_bin" "$@"
# no return
fi
# Proceed with using ResultStore features.
function new_uuid() {
"${PREBUILT_PYTHON3}" -S -c 'import uuid; print(uuid.uuid4())'
}
# Give sub-ninja a new invocation id.
# This is different from FX_BUILD_UUID.
# LINT.IfChange(related_invocations_env_vars)
# (Keep names of RESULTSTORE_* environment variables in-sync.)
if [[ -z "${RESULTSTORE_PARENT_BUILD_ID+x}" ]]
then
# This is a top-level invocation.
if [[ -n "${FX_BUILD_UUID+x}" ]]
then
# This is a top-level ninja invocation from 'fx build'.
# Use FX_BUILD_UUID as the ninja invocation id.
readonly RESULTSTORE_invocation_id="$FX_BUILD_UUID"
else
# This is a top-level ninja invocation from infra,
# or some other invocation from outside of 'fx'.
# Don't use BUILDBUCKET_ID.
readonly RESULTSTORE_invocation_id="$(new_uuid)"
fi
else
# This is a sub-build invocation.
readonly RESULTSTORE_invocation_id="$(new_uuid)"
fi
# Set additional build metadata based on environment variables
# set by parent invocations.
metadata=()
[[ -n "${FX_BUILD_UUID+x}" ]] && {
metadata+=( FX_BUILD_UUID="$FX_BUILD_UUID" )
}
[[ -n "${BUILDBUCKET_ID+x}" ]] && {
metadata+=( BUILDBUCKET_ID="$BUILDBUCKET_ID" )
}
# The following fields are passed from parent-to-child invocation.
# If not set (expected for top-level invocations), just ignore.
# See ninja_env below.
[[ -n "${RESULTSTORE_PARENT_BUILD_ID+x}" ]] && {
metadata+=( PARENT_BUILD_ID="$RESULTSTORE_PARENT_BUILD_ID" )
}
if [[ -z "${RESULTSTORE_PARENT_BUILD_LINK+x}" ]]
then
if [[ -n "${BUILDBUCKET_ID+x}" ]] then
# Link this top-level build invocation to buildbucket.
case "$BUILDBUCKET_ID" in
*/led/*)
metadata+=( PARENT_BUILD_LINK="http://go/lucibuild/$BUILDBUCKET_ID/+/build.proto" ) ;;
*)
metadata+=( PARENT_BUILD_LINK="http://go/bbid/$BUILDBUCKET_ID" ) ;;
esac
fi
else
metadata+=( PARENT_BUILD_LINK="$RESULTSTORE_PARENT_BUILD_LINK" )
fi
[[ -n "${RESULTSTORE_SIBLING_BUILDS_LINK+x}" ]] && {
metadata+=( SIBLING_BUILDS_LINK="$RESULTSTORE_SIBLING_BUILDS_LINK" )
}
readonly CFG="$SCRIPT_DIR/fuchsia-resultstore.cfg"
readonly RESULTSTORE_URL="$(grep "^results_url=" "$CFG" | cut -d= -f2)"
# If there are no sub-builds, this query will just return empty.
readonly SUB_BUILDS_LINK="$RESULTSTORE_URL/?q=PARENT_BUILD_ID:$RESULTSTORE_invocation_id"
metadata+=( SUB_BUILDS_LINK="$SUB_BUILDS_LINK" )
ninja_metadata_args=()
for md in "${metadata[@]}"
do ninja_metadata_args+=( --bes_metadata "$md" )
done
readonly ninja_env=(
# For this ninja invocation only:
NINJA_BUILD_ID="$RESULTSTORE_invocation_id"
# Replace the following environment variables with new values.
# These variables are not seen by build tools like ninja and bazel directly,
# but are used by their wrapper counterparts, like wrapper.bazel.sh.
# Sub-builds of this invocation will see this invocation as the parent.
RESULTSTORE_PARENT_BUILD_ID="$RESULTSTORE_invocation_id"
RESULTSTORE_PARENT_BUILD_LINK="$RESULTSTORE_URL/$RESULTSTORE_invocation_id"
# To sub-builds: "Your siblings are..."
RESULTSTORE_SIBLING_BUILDS_LINK="$SUB_BUILDS_LINK"
)
# LINT.ThenChange(
# //build/bazel/wrapper.bazel.sh:related_invocations_env_vars,
# //build/bazel/scripts/rsninja.sh:related_invocations_env_vars
# )
readonly full_cmd=(
env "${ninja_env[@]}"
"$wrapper"
"$ninja_bin"
"${ninja_metadata_args[@]}"
"$@"
)
exec "${full_cmd[@]}"