#!/usr/bin/env bash # # Exit immediately if a command exits with a non-zero status set -e # Function to display help message show_help() { echo "Usage: $0 [options] -r " echo echo "Required:" echo " -r, --remote Remote host IP address" echo echo "Optional:" echo " -u, --user Remote username (default: root)" echo " --run-go-tests Run go tests" echo " --run-go-tests-only Run go tests and exit" echo " --skip-ui-build Skip frontend/UI build" echo " --skip-native-build Skip native build" echo " --disable-docker Disable docker build" echo " -i, --install Build for release and install the app" echo " --help Display this help message" echo echo "Example:" echo " $0 -r 192.168.0.17" echo " $0 -r 192.168.0.17 -u admin" } # Default values SCRIPT_PATH=$(realpath "$(dirname $(realpath "${BASH_SOURCE[0]}"))") REMOTE_USER="root" REMOTE_PATH="/userdata/jetkvm/bin" SKIP_UI_BUILD=false SKIP_UI_BUILD_RELEASE=0 SKIP_NATIVE_BUILD=0 RESET_USB_HID_DEVICE=false LOG_TRACE_SCOPES="${LOG_TRACE_SCOPES:-jetkvm,cloud,websocket,native,jsonrpc}" RUN_GO_TESTS=false RUN_GO_TESTS_ONLY=false INSTALL_APP=false BUILD_IN_DOCKER=true DOCKER_BUILD_DEBUG=false DOCKER_BUILD_TAG=ghcr.io/jetkvm/buildkit:latest # Parse command line arguments while [[ $# -gt 0 ]]; do case $1 in -r|--remote) REMOTE_HOST="$2" shift 2 ;; -u|--user) REMOTE_USER="$2" shift 2 ;; --skip-ui-build) SKIP_UI_BUILD=true shift ;; --skip-native-build) SKIP_NATIVE_BUILD=1 shift ;; --reset-usb-hid) RESET_USB_HID_DEVICE=true shift ;; --disable-docker) BUILD_IN_DOCKER=false shift ;; --docker-build-debug) DOCKER_BUILD_DEBUG=true shift ;; --run-go-tests) RUN_GO_TESTS=true shift ;; --run-go-tests-only) RUN_GO_TESTS_ONLY=true RUN_GO_TESTS=true shift ;; -i|--install) INSTALL_APP=true shift ;; --help) show_help exit 0 ;; *) echo "Unknown option: $1" show_help exit 1 ;; esac done source ${SCRIPT_PATH}/build_utils.sh # Verify required parameters if [ -z "$REMOTE_HOST" ]; then msg_err "Error: Remote IP is a required parameter" show_help exit 1 fi # check if the current CPU architecture is x86_64 if [ "$(uname -m)" != "x86_64" ]; then msg_warn "Warning: This script is only supported on x86_64 architecture" BUILD_IN_DOCKER=true fi if [ "$BUILD_IN_DOCKER" = true ]; then build_docker_image fi # Build the development version on the host # When using `make build_release`, the frontend will be built regardless of the `SKIP_UI_BUILD` flag # check if static/index.html exists if [[ "$SKIP_UI_BUILD" = true && ! -f "static/index.html" ]]; then msg_warn "static/index.html does not exist, forcing UI build" SKIP_UI_BUILD=false fi if [[ "$SKIP_UI_BUILD" = false && "$JETKVM_INSIDE_DOCKER" != 1 ]]; then msg_info "▶ Building frontend" make frontend SKIP_UI_BUILD=0 SKIP_UI_BUILD_RELEASE=1 fi if [[ "$SKIP_UI_BUILD_RELEASE" = 0 && "$BUILD_IN_DOCKER" = true ]]; then msg_info "UI build is skipped when building in Docker" SKIP_UI_BUILD_RELEASE=1 fi if [ "$RUN_GO_TESTS" = true ]; then msg_info "▶ Building go tests" make build_dev_test msg_info "▶ Copying device-tests.tar.gz to remote host" ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /tmp/device-tests.tar.gz" < device-tests.tar.gz msg_info "▶ Running go tests" ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << 'EOF' set -e TMP_DIR=$(mktemp -d) cd ${TMP_DIR} tar zxf /tmp/device-tests.tar.gz ./gotestsum --format=testdox \ --jsonfile=/tmp/device-tests.json \ --post-run-command 'sh -c "echo $TESTS_FAILED > /tmp/device-tests.failed"' \ --raw-command -- ./run_all_tests -json GOTESTSUM_EXIT_CODE=$? if [ $GOTESTSUM_EXIT_CODE -ne 0 ]; then echo "❌ Tests failed (exit code: $GOTESTSUM_EXIT_CODE)" rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz exit 1 fi TESTS_FAILED=$(cat /tmp/device-tests.failed) if [ "$TESTS_FAILED" -ne 0 ]; then echo "❌ Tests failed $TESTS_FAILED tests failed" rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz exit 1 fi echo "✅ Tests passed" rm -rf ${TMP_DIR} /tmp/device-tests.tar.gz EOF if [ "$RUN_GO_TESTS_ONLY" = true ]; then msg_info "▶ Go tests completed" exit 0 fi fi if [ "$INSTALL_APP" = true ] then msg_info "▶ Building release binary" do_make build_release SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD} SKIP_UI_BUILD=${SKIP_UI_BUILD_RELEASE} # Copy the binary to the remote host as if we were the OTA updater. ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > /userdata/jetkvm/jetkvm_app.update" < bin/jetkvm_app # Reboot the device, the new app will be deployed by the startup process. ssh "${REMOTE_USER}@${REMOTE_HOST}" "reboot" else msg_info "▶ Building development binary" do_make build_dev SKIP_NATIVE_IF_EXISTS=${SKIP_NATIVE_BUILD} SKIP_UI_BUILD=${SKIP_UI_BUILD_RELEASE} # Kill any existing instances of the application ssh "${REMOTE_USER}@${REMOTE_HOST}" "killall jetkvm_app_debug || true" # Copy the binary to the remote host ssh "${REMOTE_USER}@${REMOTE_HOST}" "cat > ${REMOTE_PATH}/jetkvm_app_debug" < bin/jetkvm_app if [ "$RESET_USB_HID_DEVICE" = true ]; then msg_info "▶ Resetting USB HID device" msg_warn "The option has been deprecated and will be removed in a future version, as JetKVM will now reset USB gadget configuration when needed" # Remove the old USB gadget configuration ssh "${REMOTE_USER}@${REMOTE_HOST}" "rm -rf /sys/kernel/config/usb_gadget/jetkvm/configs/c.1/hid.usb*" ssh "${REMOTE_USER}@${REMOTE_HOST}" "ls /sys/class/udc > /sys/kernel/config/usb_gadget/jetkvm/UDC" fi # Deploy and run the application on the remote host ssh "${REMOTE_USER}@${REMOTE_HOST}" ash << EOF set -e # Set the library path to include the directory where librockit.so is located export LD_LIBRARY_PATH=/oem/usr/lib:\$LD_LIBRARY_PATH # Kill any existing instances of the application killall jetkvm_app || true killall jetkvm_app_debug || true # Navigate to the directory where the binary will be stored cd "${REMOTE_PATH}" # Make the new binary executable chmod +x jetkvm_app_debug # Run the application in the background PION_LOG_TRACE=${LOG_TRACE_SCOPES} ./jetkvm_app_debug | tee -a /tmp/jetkvm_app_debug.log EOF fi echo "Deployment complete."