#!/usr/bin/env bash set -Eeuo pipefail revision="" force=false skip_build=false while (($# > 0)); do case "$1" in --revision) if (($# < 2)); then echo "--revision requires a full Git commit SHA." >&2 exit 2 fi revision="$2" shift 2 ;; --force) force=true shift ;; --skip-build) skip_build=true shift ;; *) echo "Unknown argument: $1" >&2 exit 2 ;; esac done command -v git >/dev/null 2>&1 || { echo "Git was not found on PATH." >&2 exit 1 } script_directory="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" root_directory="$(cd -- "$script_directory/.." && pwd -P)" module_relative_path="cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-lib" module_directory="$root_directory/$module_relative_path" pom_path="$module_directory/pom.xml" proto_relative_path="$module_relative_path/src/main/proto/cmvr" proto_directory="$root_directory/$proto_relative_path" checkout_directory="$module_directory/target/cmvr-es" read_pom_property() { local name="$1" local escaped_name="${name//./\\.}" local value value="$(sed -n "s:.*<$escaped_name>\([^<]*\).*:\1:p" "$pom_path" | head -n 1)" if [[ -z "$value" ]]; then echo "Cannot find Maven property '$name'." >&2 exit 1 fi printf '%s' "$value" } repository="$(read_pom_property 'cmvr.es.repository')" branch="$(read_pom_property 'cmvr.es.proto.branch')" local_proto_changes="$(git -C "$root_directory" status --porcelain -- "$proto_relative_path")" if [[ -n "$local_proto_changes" && "$force" != true ]]; then echo "Local proto files have uncommitted changes:" >&2 echo "$local_proto_changes" >&2 echo "Commit/stash them first, or rerun with --force." >&2 exit 1 fi if [[ -z "$revision" ]]; then echo "Looking up the latest '$branch' revision..." remote_line="$(git ls-remote "$repository" "refs/heads/$branch")" if [[ -z "$remote_line" || "$remote_line" == *$'\n'* ]]; then echo "Upstream branch '$branch' was not found or was ambiguous." >&2 exit 1 fi revision="${remote_line%%[[:space:]]*}" fi revision="${revision,,}" if [[ ! "$revision" =~ ^[0-9a-f]{40}$ ]]; then echo "Revision must be a full 40-character Git commit SHA: $revision" >&2 exit 1 fi mkdir -p -- "$(dirname -- "$checkout_directory")" if [[ -d "$checkout_directory/.git" ]]; then echo "Refreshing the existing upstream checkout..." git -C "$checkout_directory" remote set-url origin "$repository" git -C "$checkout_directory" fetch --filter=blob:none origin "$branch" else if [[ -e "$checkout_directory" ]]; then checkout_parent="$(cd -- "$(dirname -- "$checkout_directory")" && pwd -P)" expected_parent="$(cd -- "$module_directory/target" && pwd -P)" if [[ "$checkout_parent" != "$expected_parent" || "$(basename -- "$checkout_directory")" != "cmvr-es" ]]; then echo "Refusing to replace unexpected checkout path: $checkout_directory" >&2 exit 1 fi rm -rf -- "$checkout_directory" fi echo "Cloning the upstream proto repository..." git clone --filter=blob:none --sparse --single-branch \ --branch "$branch" "$repository" "$checkout_directory" fi git -C "$checkout_directory" sparse-checkout set \ protos/cmvr/api protos/cmvr/msgs protos/cmvr/common git -C "$checkout_directory" checkout --detach "$revision" actual_revision="$(git -C "$checkout_directory" rev-parse HEAD)" if [[ "$actual_revision" != "$revision" ]]; then echo "Expected revision $revision, but checked out $actual_revision." >&2 exit 1 fi echo "Syncing proto files from revision $revision..." for group in api msgs common; do source_directory="$checkout_directory/protos/cmvr/$group" destination_directory="$proto_directory/$group" if [[ ! -d "$source_directory" ]]; then echo "Upstream proto directory does not exist: $source_directory" >&2 exit 1 fi mkdir -p -- "$destination_directory" find "$destination_directory" -type f -name '*.proto' -delete while IFS= read -r -d '' source_file; do relative_path="${source_file#"$source_directory/"}" destination_file="$destination_directory/$relative_path" mkdir -p -- "$(dirname -- "$destination_file")" cp -- "$source_file" "$destination_file" done < <(find "$source_directory" -type f -name '*.proto' -print0) done sed -i \ "s#[^<]*#$revision#" \ "$pom_path" updated_revision="$(read_pom_property 'cmvr.es.proto.revision')" if [[ "$updated_revision" != "$revision" ]]; then echo "Unable to update cmvr.es.proto.revision in pom.xml." >&2 exit 1 fi echo echo "Updated files:" git -C "$root_directory" status --short -- \ "$proto_relative_path" "$module_relative_path/pom.xml" if [[ "$skip_build" != true ]]; then command -v mvn >/dev/null 2>&1 || { echo "Maven was not found on PATH. Proto files were updated, but the verification build was not run." >&2 exit 1 } echo echo "Running the gRPC verification build..." ( cd -- "$root_directory" mvn -pl cmvr-iot-api/cmvr-iot-edge/cmvr-iot-grpc-client \ -am clean package -DskipTests ) fi echo echo "CMVR-ES proto update completed: $revision" echo "Review and commit the proto files and pom.xml together."