Files
Adam Shiervani 1eea5e6bbc chore(scripts): simplify flash/build helpers and dedupe arg/device checks (#67)
- flash_system.sh: rename ota_tar -> system_tar (path is staged
  release-artifacts/<sku>/system.tar, not output/image/update_ota.tar)
  and only re-check device reachability after a --build, not on every
  invocation.
- common.sh: add require_arg and prompt for SKU via normalize_system_sku
  so aliases live in one place; align FLASH_SKU/SYSTEM_SKU precedence
  between build_system.sh and flash_system.sh.
- check_device.sh (new): one wrapper around check_ping/check_ssh used
  by both make check_device and direct CLI, removing the Makefile's
  hardcoded ping -c 1 / root@ duplication.
- release_r2.sh, release_github.sh, run_e2e_tests.sh, build_system.sh,
  flash_system.sh: route all value-taking options through require_arg
  for consistent missing-arg errors.
2026-05-11 10:19:09 +02:00

274 lines
8.0 KiB
Bash
Executable File

#!/usr/bin/env bash
set -e
set -o pipefail
# -----------------------------------------------------------------------------
# Color output helpers
# -----------------------------------------------------------------------------
HAS_TTY=true
if [ -z "$TERM" ] || [ "$TERM" = "dumb" ]; then
HAS_TTY=false
fi
# Use $'...' syntax for ANSI codes (portable in bash)
C_RST=$'\e[0m'
C_ERR=$'\e[31m'
C_OK=$'\e[32m'
C_WARN=$'\e[33m'
C_INFO=$'\e[35m'
if [ "$HAS_TTY" = true ] && command -v tput >/dev/null 2>&1; then
C_RST="$(tput sgr0 2>/dev/null || echo "$C_RST")"
C_ERR="$(tput setaf 1 2>/dev/null || echo "$C_ERR")"
C_OK="$(tput setaf 2 2>/dev/null || echo "$C_OK")"
C_WARN="$(tput setaf 3 2>/dev/null || echo "$C_WARN")"
C_INFO="$(tput setaf 5 2>/dev/null || echo "$C_INFO")"
fi
msg() { printf '%s%s%s\n' "$2" "$1" "$C_RST"; }
msg_info() { msg "$1" "$C_INFO"; }
msg_ok() { msg "$1" "$C_OK"; }
msg_err() { msg "$1" "$C_ERR"; }
msg_warn() { msg "$1" "$C_WARN"; }
# -----------------------------------------------------------------------------
# CLI argument helpers
# -----------------------------------------------------------------------------
require_arg() {
local option="$1"
local value="${2:-}"
if [ -z "$value" ]; then
msg_err "Error: ${option} requires a value"
exit 1
fi
}
# -----------------------------------------------------------------------------
# SSH helper
# -----------------------------------------------------------------------------
sshdev() {
if [ -z "${DEVICE_IP:-}" ]; then
msg_err "Error: DEVICE_IP is not set"
exit 1
fi
local user="${DEVICE_USER:-root}"
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no "${user}@${DEVICE_IP}" "$@"
}
# -----------------------------------------------------------------------------
# Connectivity checks
# -----------------------------------------------------------------------------
check_ping() {
local host=$1
if [ -z "$host" ]; then
msg_err "Error: device IP is required"
exit 1
fi
msg_info ">> Checking if device is reachable at ${host}..."
if ! ping -c 3 -W 5 "${host}" > /dev/null 2>&1; then
msg_err "Error: Cannot reach device at ${host}"
msg_err "Please verify the IP address and network connectivity"
exit 1
fi
msg_info "OK: Device is reachable"
}
check_ssh() {
local user=$1
local host=$2
if [ -z "$host" ]; then
msg_err "Error: device IP is required"
exit 1
fi
msg_info ">> Checking SSH connectivity to ${user}@${host}..."
if ! ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o ConnectTimeout=10 "${user}@${host}" "echo 'SSH connection successful'" > /dev/null 2>&1; then
msg_err "Error: Cannot establish SSH connection to ${user}@${host}"
msg_err "Please verify SSH access and credentials"
exit 1
fi
msg_info "OK: SSH connection successful"
}
wait_for_device() {
msg_info ">> Waiting for device to come back online..."
# Wait a bit for reboot to start
sleep 10
# Wait for ping (up to 120 seconds)
msg_info " Waiting for device to respond to ping..."
local max_attempts=60
local attempt=1
while [ $attempt -le $max_attempts ]; do
if ping -c 1 -W 2 "${DEVICE_IP}" > /dev/null 2>&1; then
msg_ok " OK: Device is responding to ping"
break
fi
attempt=$((attempt + 1))
sleep 2
done
if [ $attempt -gt $max_attempts ]; then
msg_err "Error: Device did not respond to ping within timeout"
exit 1
fi
# Wait for SSH (up to 60 seconds)
msg_info " Waiting for SSH to become available..."
max_attempts=30
attempt=1
while [ $attempt -le $max_attempts ]; do
if sshdev "echo 'SSH OK'" > /dev/null 2>&1; then
msg_ok " OK: SSH is available"
break
fi
attempt=$((attempt + 1))
sleep 2
done
if [ $attempt -gt $max_attempts ]; then
msg_err "Error: SSH did not become available within timeout"
exit 1
fi
# Wait for web interface (up to 180 seconds)
msg_info " Waiting for web interface..."
max_attempts=90
attempt=1
while [ $attempt -le $max_attempts ]; do
if curl -s --max-time 5 "http://${DEVICE_IP}" > /dev/null 2>&1; then
msg_ok " OK: Web interface is ready"
break
fi
attempt=$((attempt + 1))
sleep 2
done
if [ $attempt -gt $max_attempts ]; then
msg_err "Error: Web interface did not become available within timeout"
exit 1
fi
msg_ok "OK: Device is online and ready"
}
# -----------------------------------------------------------------------------
# Build artifact paths
# -----------------------------------------------------------------------------
OUTPUT_IMAGE_DIR="${ROOT_DIR:-$(pwd)}/output/image"
OTA_TAR_NAME="update_ota.tar"
FULL_IMG_NAME="update.img"
SD_IMG_ZIP_NAME="update_sd.img.zip"
OTA_TAR="${OUTPUT_IMAGE_DIR}/${OTA_TAR_NAME}"
FULL_IMG="${OUTPUT_IMAGE_DIR}/${FULL_IMG_NAME}"
SD_IMG_ZIP="${OUTPUT_IMAGE_DIR}/${SD_IMG_ZIP_NAME}"
# -----------------------------------------------------------------------------
# System release variants
# -----------------------------------------------------------------------------
SYSTEM_RELEASE_DIR="${ROOT_DIR:-$(pwd)}/release-artifacts/system"
SYSTEM_TAR_NAME="system.tar"
EMMC_SKU="jetkvm-v2"
EMMC_BOARD_CONFIG="BoardConfig_IPC/BoardConfig-EMMC-NONE-RV1106_JETKVM_V2.mk"
SDMMC_SKU="jetkvm-v2-sdmmc"
SDMMC_BOARD_CONFIG="BoardConfig_IPC/BoardConfig-SDMMC-NONE-RV1106_JETKVM_V2.mk"
normalize_system_sku() {
local target="$1"
case "$target" in
emmc|EMMC|jetkvm-v2)
echo "$EMMC_SKU"
;;
sd|SD|sdmmc|SDMMC|jetkvm-v2-sdmmc)
echo "$SDMMC_SKU"
;;
*)
msg_err "Error: unknown system target '${target}'" >&2
msg_err "Use one of: emmc, sdmmc, ${EMMC_SKU}, ${SDMMC_SKU}" >&2
return 1
;;
esac
}
system_variant_label() {
local sku="$1"
case "$sku" in
"$EMMC_SKU") echo "EMMC" ;;
"$SDMMC_SKU") echo "SDMMC" ;;
*)
msg_err "Error: no label mapped for SKU '${sku}'" >&2
return 1
;;
esac
}
system_variant_board_config() {
local sku="$1"
case "$sku" in
"$EMMC_SKU") echo "$EMMC_BOARD_CONFIG" ;;
"$SDMMC_SKU") echo "$SDMMC_BOARD_CONFIG" ;;
*)
msg_err "Error: no board config mapped for SKU '${sku}'" >&2
return 1
;;
esac
}
prompt_system_sku() {
local choice
if [ ! -t 0 ]; then
msg_err "Error: system target is required in non-interactive mode" >&2
msg_err "Set FLASH_SKU or SYSTEM_SKU to emmc or sdmmc." >&2
return 1
fi
{
echo ""
echo "Select system target:"
echo " 1) EMMC (${EMMC_SKU})"
echo " 2) SDMMC (${SDMMC_SKU})"
printf "Target [1/2]: "
} >&2
read -r choice
case "$choice" in
1) echo "$EMMC_SKU" ;;
2) echo "$SDMMC_SKU" ;;
*) normalize_system_sku "$choice" ;;
esac
}
system_variant_dir() {
local sku="$1"
echo "${SYSTEM_RELEASE_DIR}/${sku}"
}
# Recovery artifact filename per SKU (eMMC -> update.img, SDMMC ->
# update_sd.img.zip). Keep in sync with RECOVERY_ARTIFACT_BY_SKU in
# cloud-api/src/releases.ts.
recovery_artifact_for_sku() {
local sku="$1"
case "$sku" in
"$SDMMC_SKU") echo "$SD_IMG_ZIP_NAME" ;;
"$EMMC_SKU") echo "$FULL_IMG_NAME" ;;
*)
msg_err "Error: no recovery artifact mapped for SKU '${sku}'"
exit 1
;;
esac
}
# Absolute path of the recovery artifact in the build output dir.
recovery_source_for_sku() {
local sku="$1"
local artifact
# Capture separately so an unknown-SKU exit in recovery_artifact_for_sku
# (which would otherwise only kill the command-substitution subshell)
# actually fails this function.
artifact=$(recovery_artifact_for_sku "$sku") || return $?
echo "${OUTPUT_IMAGE_DIR}/${artifact}"
}