mirror of
https://github.com/jetkvm/rv1106-system.git
synced 2026-06-20 05:24:41 +00:00
- 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.
274 lines
8.0 KiB
Bash
Executable File
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}"
|
|
}
|