diff --git a/src/auracast/server/multicast_server.py b/src/auracast/server/multicast_server.py index 3f7fe3d..3aba39f 100644 --- a/src/auracast/server/multicast_server.py +++ b/src/auracast/server/multicast_server.py @@ -1371,160 +1371,12 @@ async def system_update(): log.error("git checkout failed: %s", stderr.decode()) raise HTTPException(status_code=500, detail=f"git checkout failed: {stderr.decode()}") - # 2. Run poetry install (use full path as poetry is in user's ~/.local/bin) - poetry_path = os.path.expanduser("~/.local/bin/poetry") - proc = await asyncio.create_subprocess_exec( - poetry_path, "install", - cwd=project_root, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - log.error("poetry install failed: %s", stderr.decode()) - raise HTTPException(status_code=500, detail=f"poetry install failed: {stderr.decode()}") - - # 3. Clone/update and build sw_openocd if needed - openocd_src = os.path.expanduser("~/sw_openocd") - openocd_repo_url = "ssh://git@gitea.summitwave.work:222/auracaster/sw_openocd.git" - openocd_branch = "change-8818" - openocd_marker = os.path.join(openocd_src, ".last_built_commit") - openocd_dir = os.path.join(project_root, 'src', 'openocd') - - if not os.path.isdir(openocd_src): - log.info("Installing sw_openocd build dependencies...") - proc = await asyncio.create_subprocess_exec( - "sudo", "apt", "install", "-y", - "git", "build-essential", "libtool", "autoconf", "texinfo", - "libusb-1.0-0-dev", "libftdi1-dev", "libhidapi-dev", "pkg-config", - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - log.warning("apt install deps failed: %s", stderr.decode()) - - proc = await asyncio.create_subprocess_exec( - "sudo", "apt-get", "install", "-y", "pkg-config", "libjim-dev", - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - log.warning("apt-get install libjim-dev failed: %s", stderr.decode()) - - log.info("Cloning sw_openocd branch %s...", openocd_branch) - proc = await asyncio.create_subprocess_exec( - "git", "clone", "--branch", openocd_branch, "--single-branch", - openocd_repo_url, openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - log.error("git clone sw_openocd failed: %s", stderr.decode()) - raise HTTPException(status_code=500, detail=f"git clone sw_openocd failed: {stderr.decode()}") - else: - log.info("Updating sw_openocd...") - proc = await asyncio.create_subprocess_exec( - "git", "fetch", "origin", openocd_branch, - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - await proc.communicate() - proc = await asyncio.create_subprocess_exec( - "git", "checkout", openocd_branch, - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - await proc.communicate() - proc = await asyncio.create_subprocess_exec( - "git", "pull", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - await proc.communicate() - - # Get current HEAD commit of sw_openocd - proc = await asyncio.create_subprocess_exec( - "git", "rev-parse", "HEAD", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, _ = await proc.communicate() - openocd_commit = stdout.decode().strip() - - last_built = "" - if os.path.isfile(openocd_marker): - with open(openocd_marker) as f: - last_built = f.read().strip() - - if openocd_commit != last_built: - log.info("Building sw_openocd (commit %s)...", openocd_commit) - - proc = await asyncio.create_subprocess_exec( - "./bootstrap", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - raise HTTPException(status_code=500, detail=f"openocd bootstrap failed: {stderr.decode()}") - - proc = await asyncio.create_subprocess_exec( - "./configure", "--enable-bcm2835gpio", "--enable-sysfsgpio", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - raise HTTPException(status_code=500, detail=f"openocd configure failed: {stderr.decode()}") - - proc = await asyncio.create_subprocess_exec( - "make", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - raise HTTPException(status_code=500, detail=f"openocd make failed: {stderr.decode()}") - - proc = await asyncio.create_subprocess_exec( - "sudo", "make", "install", - cwd=openocd_src, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - raise HTTPException(status_code=500, detail=f"openocd make install failed: {stderr.decode()}") - - with open(openocd_marker, 'w') as f: - f.write(openocd_commit) - log.info("sw_openocd built and installed (commit %s).", openocd_commit) - else: - log.info("sw_openocd up to date (commit %s), skipping build.", openocd_commit) - - # 4. Flash firmware to both SWD interfaces - log.info("Flashing firmware...") - flash_script = os.path.join(openocd_dir, 'flash.sh') - hex_file = os.path.join(openocd_dir, 'merged.hex') - - for interface in ["swd0", "swd1"]: - proc = await asyncio.create_subprocess_exec( - "bash", flash_script, "-i", interface, "-f", hex_file, - cwd=openocd_dir, - stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE - ) - stdout, stderr = await proc.communicate() - if proc.returncode != 0: - log.error("Flash %s failed: %s", interface, stderr.decode()) - raise HTTPException(status_code=500, detail=f"Flash {interface} failed: {stderr.decode()}") - log.info("Flash %s complete.", interface) - - # 5. Restart services via the update script - update_script = os.path.join(project_root, 'src', 'service', 'update_and_run_server_and_frontend.sh') - proc = await asyncio.create_subprocess_exec( + # 2. Hand off remaining work to the (now-updated) system_update.sh script + update_script = os.path.join(os.path.dirname(__file__), 'system_update.sh') + log.info("Handing off to system_update.sh...") + await asyncio.create_subprocess_exec( "bash", update_script, cwd=project_root, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE ) # Don't wait for completion as we'll be restarted await asyncio.sleep(0.5) diff --git a/src/auracast/server/system_update.sh b/src/auracast/server/system_update.sh new file mode 100644 index 0000000..b16511c --- /dev/null +++ b/src/auracast/server/system_update.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# system_update.sh - Runs after git checkout in the Python system_update endpoint. +# Called with the current working directory = project root. +# All output is also written to /tmp/system_update.log for debugging. + +exec > >(tee -a /tmp/system_update.log) 2>&1 + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)" +POETRY="$HOME/.local/bin/poetry" +OPENOCD_SRC="$HOME/sw_openocd" +OPENOCD_REPO="ssh://git@gitea.summitwave.work:222/auracaster/sw_openocd.git" +OPENOCD_BRANCH="change-8818" +OPENOCD_MARKER="$OPENOCD_SRC/.last_built_commit" +OPENOCD_DIR="$PROJECT_ROOT/src/openocd" + +echo "[system_update] Starting post-checkout update. project_root=$PROJECT_ROOT" + +# 1. poetry install +echo "[system_update] Running poetry install..." +(cd "$PROJECT_ROOT" && "$POETRY" install) +if [ $? -ne 0 ]; then + echo "[system_update] ERROR: poetry install failed" + exit 1 +fi + +# 2. Clone/update and build sw_openocd if needed +if [ ! -d "$OPENOCD_SRC" ]; then + echo "[system_update] Installing sw_openocd build dependencies..." + sudo apt install -y git build-essential libtool autoconf texinfo \ + libusb-1.0-0-dev libftdi1-dev libhidapi-dev pkg-config || \ + echo "[system_update] WARNING: apt install deps had errors, continuing" + sudo apt-get install -y pkg-config libjim-dev || \ + echo "[system_update] WARNING: apt-get install libjim-dev had errors, continuing" + + echo "[system_update] Cloning sw_openocd branch $OPENOCD_BRANCH..." + git clone --branch "$OPENOCD_BRANCH" --single-branch "$OPENOCD_REPO" "$OPENOCD_SRC" + if [ $? -ne 0 ]; then + echo "[system_update] ERROR: git clone sw_openocd failed" + exit 1 + fi +else + echo "[system_update] Updating sw_openocd..." + git -C "$OPENOCD_SRC" fetch origin "$OPENOCD_BRANCH" + git -C "$OPENOCD_SRC" checkout "$OPENOCD_BRANCH" + git -C "$OPENOCD_SRC" pull +fi + +OPENOCD_COMMIT=$(git -C "$OPENOCD_SRC" rev-parse HEAD) +LAST_BUILT="" +[ -f "$OPENOCD_MARKER" ] && LAST_BUILT=$(cat "$OPENOCD_MARKER") + +if [ "$OPENOCD_COMMIT" != "$LAST_BUILT" ]; then + echo "[system_update] Building sw_openocd (commit $OPENOCD_COMMIT)..." + + (cd "$OPENOCD_SRC" && ./bootstrap) + if [ $? -ne 0 ]; then echo "[system_update] ERROR: openocd bootstrap failed"; exit 1; fi + + (cd "$OPENOCD_SRC" && ./configure --enable-bcm2835gpio --enable-sysfsgpio) + if [ $? -ne 0 ]; then echo "[system_update] ERROR: openocd configure failed"; exit 1; fi + + (cd "$OPENOCD_SRC" && make) + if [ $? -ne 0 ]; then echo "[system_update] ERROR: openocd make failed"; exit 1; fi + + (cd "$OPENOCD_SRC" && sudo make install) + if [ $? -ne 0 ]; then echo "[system_update] ERROR: openocd make install failed"; exit 1; fi + + echo "$OPENOCD_COMMIT" > "$OPENOCD_MARKER" + echo "[system_update] sw_openocd built and installed (commit $OPENOCD_COMMIT)" +else + echo "[system_update] sw_openocd up to date (commit $OPENOCD_COMMIT), skipping build" +fi + +# 3. Flash firmware to both SWD interfaces +FLASH_SCRIPT="$OPENOCD_DIR/flash.sh" +HEX_FILE="$OPENOCD_DIR/merged.hex" + +for IFACE in swd0 swd1; do + echo "[system_update] Flashing $IFACE..." + bash "$FLASH_SCRIPT" -i "$IFACE" -f "$HEX_FILE" + if [ $? -ne 0 ]; then + echo "[system_update] ERROR: flash $IFACE failed" + exit 1 + fi + echo "[system_update] Flash $IFACE complete" +done + +# 4. Restart services (this will kill this process too) +echo "[system_update] Restarting services..." +bash "$PROJECT_ROOT/src/service/update_and_run_server_and_frontend.sh"