From 1a4f296aa8a255e507d1abbe847828d53f0303e1 Mon Sep 17 00:00:00 2001 From: Quintine Date: Sat, 25 Jul 2026 16:53:38 +1000 Subject: [PATCH] =?UTF-8?q?tools:=20add=20deploy=5Fto=5Fdevice.sh=20?= =?UTF-8?q?=E2=80=94=20git-archive-over-ssh=20deploy=20that=20preserves=20?= =?UTF-8?q?symlinks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Copying the tree to a device with scp/file managers mangles symlinks (car_list.json et al become text files containing the target path), crashing the UI with JSONDecodeError. This script deploys via 'git archive HEAD | ssh tar -x', which preserves symlinks, verifies them on-device, and keeps the previous install for rollback. --- deploy_to_device.sh | 75 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100755 deploy_to_device.sh diff --git a/deploy_to_device.sh b/deploy_to_device.sh new file mode 100755 index 0000000..66b5c62 --- /dev/null +++ b/deploy_to_device.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# Deploy this repo to a comma device over SSH, preserving symlinks. +# +# Usage: +# ./deploy_to_device.sh [target-dir] +# +# Examples: +# ./deploy_to_device.sh 192.168.1.50 +# ./deploy_to_device.sh comma.local /data/openpilot +# +# Notes: +# - Deploys EXACTLY what is committed in git (git archive), so commit first. +# - Symlinks are preserved (unlike scp -r / file managers). +# - The existing install is kept as .old for rollback. +# - Only the last ~deploy is transferred (no .git, no .venv) — fast and small. + +set -euo pipefail + +DEVICE="${1:?usage: ./deploy_to_device.sh [target-dir]}" +TARGET="${2:-/data/openpilot}" +SSH_USER="${SSH_USER:-comma}" + +cd "$(dirname "$0")" + +# sanity: must be run from the repo root +if [ ! -d .git ]; then + echo "error: no .git here — run from the repo root" >&2 + exit 1 +fi + +# sanity: working tree must be committed (deploy uses git archive HEAD) +if [ -n "$(git status --porcelain)" ]; then + echo "warning: uncommitted changes exist — they will NOT be deployed." + echo " commit first, or press enter to deploy HEAD anyway." + read -r _ +fi + +echo "==> deploying HEAD ($(git rev-parse --short HEAD)) to ${SSH_USER}@${DEVICE}:${TARGET}" + +TMP="${TARGET}.deploy-new" +OLD="${TARGET}.old" + +# 1) stream the archive to the device and extract into a staging dir +git archive HEAD | ssh "${SSH_USER}@${DEVICE}" " + set -e + rm -rf '$TMP' + mkdir -p '$TMP' + tar -xf - -C '$TMP' +" + +# 2) verify symlinks landed correctly on the device +echo "==> verifying symlinks on device" +ssh "${SSH_USER}@${DEVICE}" " + set -e + for l in opendbc msgq rednose teleoprtc tinygrad \ + openpilot/sunnypilot/selfdrive/car/car_list.json; do + if [ ! -L '$TMP/'\$l ]; then + echo \"FATAL: \$l is not a symlink on device\" >&2 + exit 1 + fi + done + head -c 2 '$TMP/openpilot/sunnypilot/selfdrive/car/car_list.json' | grep -q '^{' + echo ' symlinks OK' +" + +# 3) swap into place (keep previous as .old) +ssh "${SSH_USER}@${DEVICE}" " + set -e + rm -rf '$OLD' + if [ -d '$TARGET' ]; then mv '$TARGET' '$OLD'; fi + mv '$TMP' '$TARGET' + echo '==> swapped into place (previous kept as $OLD)' +" + +echo "==> done. Reboot the device to start the new build."