blob: e680aa20c9bec40c977a6fc095617564ff8bf77f [file] [log] [blame]
#!/bin/bash
# Copyright 2022 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.
#### CATEGORY=Build
### Attempt to build a few known SDK-based OOT repos based on a core SDK
### produced from the local Fuchsia tree
##
## This command attempts to build some known SDK-based OOT repos with an SDK
## produced with the local Fuchsia tree and build configuration.
##
## Usage: fx validate-sdk [--local-bazel-rules] [--keep-tmp] [[REPO/CLNUM/PATCHSET] ...]
##
## It first runs the equivalent of 'fx build sdk:core sdk:driver'
##
## Then for each SDK-based repo from the list:
## sdk-samples/getting-started
## sdk-samples/drivers
## sdk-samples/fortune-teller
## it will clone the corresponding repo and attempt to build it with
## the local SDK produced by 'fx build sdk:core sdk:driver'
##
## Given that some of these repos, like getting-started and drivers, only
## update their SDK every few weeks, there will likely be a WIP roller CL
## that you may want to patch before attempting to build.
## If you want to patch a CL from these repos before validating the SDK,
## you can use the [REPO/CL/PATCHSET] syntax:
##
##
## --local-bazel-rules Use the version of the sdk-integration repo in
## the local Fuchsia tree (//third_party/sdk-integration)
## instead of the version checked-in on the samples.
## With this option, the in-tree sdk-integration will replace both
## the checked-in and patched-in sdk-integration.
##
## --keep-tmp Do not delete the temporary directories used to fetch and
## build the samples when they fail to build. This is useful
## to debug and iterate on fixes without having to download the samples again.
## If the build succeeds, the temp dirs will be deleted
## regardless of this flag.
##
## Examples:
## fx validate-sdk
## fx validate-sdk --local-bazel-rules
## fx validate-sdk drivers/715716/9 getting-started/691515/11
## fx validate-sdk --keep-tmp
source "${FUCHSIA_DIR}/tools/devshell/lib/style.sh" || exit $?
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $?
set -e -o pipefail
fx-config-read
# keep both in sync, as associatie arrays are not well supported in the
# version of Bash that ships with MacOS
declare -a REPO_NAMES=( "drivers" "getting-started" "fortune-teller" )
declare -a REPOS=(
"https://fuchsia.googlesource.com/sdk-samples/drivers"
"https://fuchsia.googlesource.com/sdk-samples/getting-started"
"https://fuchsia.googlesource.com/sdk-samples/fortune-teller"
)
readonly REPOS REPO_NAMES
function create_sdk {
fx-command-run build sdk:core sdk:driver
}
function is_valid_repo_name {
for r in "${REPO_NAMES[@]}"; do
if [[ "$r" == "$k" ]]; then
return 0
fi
done
return 1
}
function validate_patches {
while [[ $# -gt 0 ]]; do
if [[ "$1" =~ ^([a-z-]+)\/([0-9]+)\/([0-9]+)$ ]]; then
k="${BASH_REMATCH[1]}"
cl="${BASH_REMATCH[2]}"
ps="${BASH_REMATCH[3]}"
if ! is_valid_repo_name "$k"; then
fx-error "Invalid repo name '$k' in patch spec. Must be one of ${REPO_NAMES[@]}"
exit 1
fi
else
fx-error "Invalid patch spec, must be REPO_NAME/CL_NUM/PATCHSET: $1"
exit 1
fi
shift
done
}
function get_patches {
local repo_key="$1"
shift
local patches=()
while [[ $# -gt 0 ]]; do
if [[ "$1" =~ ^${repo_key}\/([0-9]+)\/([0-9]+)$ ]]; then
cl="${BASH_REMATCH[1]}"
ps="${BASH_REMATCH[2]}"
patches+=( "${cl}" "${ps}" )
fi
shift
done
echo "${patches[@]}"
}
function clone {
local git_url="$1"
local tmp_dir="$2"
git clone "$git_url" "$tmp_dir"
git -C "$tmp_dir" submodule update --recursive --init
}
function replace_sdk_integration {
local tmp_dir="$1"
local sample_bazel_rules="${tmp_dir}/third_party/sdk-integration"
local local_bazel_rules="${FUCHSIA_DIR}/third_party/sdk-integration"
if [[ ! -d "$sample_bazel_rules" ]]; then
fx-error "Unexpected error: cannot find Bazel rules in $sample_bazel_rules"
exit 1
fi
if [[ ! -d "$local_bazel_rules" ]]; then
fx-error "Unexpected error: cannot find local Bazel rules in $local_bazel_rules"
exit 1
fi
rm -Rf "${sample_bazel_rules}"
mkdir -p "${sample_bazel_rules}"
# copy contents instead of the entire directory to avoid copying the .git
# directory, as it is large and useless in this context
cp -R "${local_bazel_rules}"/* "${sample_bazel_rules}"
}
function patch {
local git_url="$1"
local tmp_dir="$2"
local cl_num="$3"
local cl_patchset="$4"
local cl_tail="${cl_num:(-2)}"
git -C "$tmp_dir" fetch "$git_url" \
"refs/changes/${cl_tail}/${cl_num}/${cl_patchset}"
git -C "$tmp_dir" checkout FETCH_HEAD --recurse-submodules
}
function build_sample {
local repo_key="$1"
local tmp_dir="$2"
local build_dir="$FUCHSIA_BUILD_DIR"
cd "$tmp_dir"
scripts/bootstrap.sh
LOCAL_FUCHSIA_PLATFORM_BUILD="$FUCHSIA_BUILD_DIR" tools/bazel build --config=fuchsia_${FUCHSIA_ARCH} src:samples_repository
}
function show_instructions {
local repo_key="$1"
local tmp_dir="$2"
if [[ -d "${tmp_dir}" ]]; then
echo >&2
fx-warn "Keeping temp directory for $repo_key. Use the instructions below to build it:"
echo >&2 "fx build sdk:core sdk:driver"
echo >&2 "cd $tmp_dir"
echo >&2 "LOCAL_FUCHSIA_PLATFORM_BUILD=\"$FUCHSIA_BUILD_DIR\" tools/bazel build --config=fuchsia_${FUCHSIA_ARCH} src:samples_repository"
fi
}
function cleanup {
local tmp_dir="$1"
if [[ -d "${tmp_dir}" ]]; then
rm -Rf "${tmp_dir}"
fi
}
function main {
use_sdk_intree=0
keep=0
patches=()
while [[ $# -gt 0 ]]; do
if [[ "$1" =~ ^-- ]]; then
if [[ "$1" == "--local-bazel-rules" ]]; then
use_sdk_intree=1
elif [[ "$1" == "--keep-tmp" ]]; then
keep=1
else
fx-error "Invalid syntax"
fx-command-help
exit 1
fi
else
patches+=( "$1" )
fi
shift
done
validate_patches "${patches[@]}"
fx-info "*** Creating the SDK..."
create_sdk
local i=0
for repo_key in "${REPO_NAMES[@]}"; do
local repo_url="${REPOS[$i]}"
i=$((i+1))
local message="*** Building $repo_key with local SDK, target arch $FUCHSIA_ARCH "
if [[ $use_sdk_intree -eq 1 ]]; then
message+="and in-tree sdk-integration "
fi
fx-info "$message..."
local tmp_dir="$(mktemp -d)"
if [[ $keep -eq 0 ]]; then
trap "cleanup ${tmp_dir}" EXIT
else
trap "show_instructions \"$repo_key\" \"$tmp_dir\"" EXIT
fi
clone "$repo_url" "$tmp_dir"
local repo_patches=( $(get_patches "$repo_key" "${patches[@]}" ) )
for (( pi=0; pi<${#repo_patches[@]}; pi+=2 )); do
patch "$repo_url" "$tmp_dir" "${repo_patches[$pi]}" "${repo_patches[$pi+1]}"
done
if [[ $use_sdk_intree -eq 1 ]]; then
replace_sdk_integration "$tmp_dir"
fi
build_sample "$repo_key" "$tmp_dir"
trap - EXIT
cleanup ${tmp_dir}
done
}
main "$@"