Merge pull request 'Ship archy-rnodeconf as an OS-level tool on every node' (#71) from feat/reticulum-daemon-packaging into worktree-reticulum-tcp-interop
This commit is contained in:
commit
e64e5615cb
@ -1,6 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
# Build the PyInstaller single-binary for the OTA (plan Phase 1 packaging).
|
# Build the PyInstaller single-binaries for the OTA (plan Phase 1 packaging).
|
||||||
# Output: dist/archy-reticulum-daemon — drop next to /usr/local/bin/archipelago.
|
# Outputs: dist/archy-reticulum-daemon, dist/archy-rnodeconf — drop both next
|
||||||
|
# to /usr/local/bin/archipelago.
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
cd "$(dirname "${BASH_SOURCE[0]}")"
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ if [ ! -d .venv ]; then
|
|||||||
fi
|
fi
|
||||||
.venv/bin/pip install -q -r requirements.txt -r requirements-build.txt
|
.venv/bin/pip install -q -r requirements.txt -r requirements-build.txt
|
||||||
|
|
||||||
rm -rf build dist archy-reticulum-daemon.spec
|
rm -rf build dist archy-reticulum-daemon.spec archy-rnodeconf.spec
|
||||||
|
|
||||||
# --collect-submodules: RNS/LXMF load most of their own internals dynamically
|
# --collect-submodules: RNS/LXMF load most of their own internals dynamically
|
||||||
# (interface drivers, transport backends), which PyInstaller's static import
|
# (interface drivers, transport backends), which PyInstaller's static import
|
||||||
@ -30,3 +31,30 @@ rm -rf build dist archy-reticulum-daemon.spec
|
|||||||
reticulum_daemon.py
|
reticulum_daemon.py
|
||||||
|
|
||||||
echo "Built dist/archy-reticulum-daemon ($(du -h dist/archy-reticulum-daemon | cut -f1))"
|
echo "Built dist/archy-reticulum-daemon ($(du -h dist/archy-reticulum-daemon | cut -f1))"
|
||||||
|
|
||||||
|
# archy-rnodeconf: RNS's own official RNode config/diagnostic tool
|
||||||
|
# (RNS.Utilities.rnodeconf — reads/sets frequency, bandwidth, spreading
|
||||||
|
# factor, coding rate, TX power on an attached RNode; also verifies firmware
|
||||||
|
# signatures and can flash/bootstrap a board). Shipped alongside the daemon
|
||||||
|
# so every node can inspect and reconfigure its own radio without needing a
|
||||||
|
# full RNS/Python dev environment set up by hand — see the checkpoint in
|
||||||
|
# docs/RETICULUM-TRANSPORT-PROGRESS.md for the incident (two nodes silently
|
||||||
|
# running at different spreading factors, invisible without this tool) that
|
||||||
|
# motivated shipping it as a first-class OS tool rather than an ad hoc script.
|
||||||
|
RNODECONF_SRC="$(find .venv/lib -maxdepth 5 -path '*/site-packages/RNS/Utilities/rnodeconf.py' -print -quit)"
|
||||||
|
if [ -n "$RNODECONF_SRC" ] && [ -f "$RNODECONF_SRC" ]; then
|
||||||
|
# --runtime-hook: rnodeconf's own graceful_exit() calls the bare
|
||||||
|
# exit()/quit() builtins, which only exist in interactive Python (site.py
|
||||||
|
# injects them) — a frozen app hits NameError right as it tries to quit
|
||||||
|
# cleanly, after all the real work already succeeded. See
|
||||||
|
# pyi_rthook_exit_builtins.py.
|
||||||
|
.venv/bin/pyinstaller --onefile --name archy-rnodeconf --clean --noconfirm \
|
||||||
|
--collect-submodules RNS \
|
||||||
|
--collect-data RNS \
|
||||||
|
--runtime-hook pyi_rthook_exit_builtins.py \
|
||||||
|
-d noarchive \
|
||||||
|
"$RNODECONF_SRC"
|
||||||
|
echo "Built dist/archy-rnodeconf ($(du -h dist/archy-rnodeconf | cut -f1))"
|
||||||
|
else
|
||||||
|
echo "WARNING: rnodeconf.py not found at $RNODECONF_SRC (RNS version mismatch?) — skipping archy-rnodeconf build" >&2
|
||||||
|
fi
|
||||||
|
|||||||
18
reticulum-daemon/pyi_rthook_exit_builtins.py
Normal file
18
reticulum-daemon/pyi_rthook_exit_builtins.py
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
# PyInstaller runtime hook — see build.sh.
|
||||||
|
#
|
||||||
|
# `exit()`/`quit()` aren't part of the language; they're `site.Quitter`
|
||||||
|
# instances the interactive interpreter injects into builtins at startup
|
||||||
|
# (site.py). A frozen PyInstaller app never runs that interactive-mode
|
||||||
|
# init, so any bundled script that calls bare `exit()` (RNS's own
|
||||||
|
# rnodeconf.py does, in its graceful_exit() cleanup path) hits
|
||||||
|
# `NameError: name 'exit' is not defined` right as it tries to quit
|
||||||
|
# cleanly — the real work above it already completed, but the process
|
||||||
|
# still exits 1, which is a foot-gun for anything scripting off the exit
|
||||||
|
# code. Pre-define both as sys.exit so that path is a no-op crash-wise.
|
||||||
|
import builtins
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if not hasattr(builtins, "exit"):
|
||||||
|
builtins.exit = sys.exit
|
||||||
|
if not hasattr(builtins, "quit"):
|
||||||
|
builtins.quit = sys.exit
|
||||||
@ -257,6 +257,13 @@ ssh $SSH_OPTS "$TARGET_HOST" '
|
|||||||
NEED_INSTALL=""
|
NEED_INSTALL=""
|
||||||
command -v rsync >/dev/null 2>&1 || NEED_INSTALL="$NEED_INSTALL rsync"
|
command -v rsync >/dev/null 2>&1 || NEED_INSTALL="$NEED_INSTALL rsync"
|
||||||
command -v python3 >/dev/null 2>&1 || NEED_INSTALL="$NEED_INSTALL python3"
|
command -v python3 >/dev/null 2>&1 || NEED_INSTALL="$NEED_INSTALL python3"
|
||||||
|
# python3 -m venv exists but cannot bootstrap pip without the matching
|
||||||
|
# <major>.<minor>-venv package on Debian — needed for reticulum-daemon/
|
||||||
|
# build.sh (archy-reticulum-daemon / archy-rnodeconf packaging).
|
||||||
|
if command -v python3 >/dev/null 2>&1 && ! python3 -c "import ensurepip" >/dev/null 2>&1; then
|
||||||
|
PYVER=$(python3 -c "import sys; print(f\"{sys.version_info.major}.{sys.version_info.minor}\")")
|
||||||
|
NEED_INSTALL="$NEED_INSTALL python3.${PYVER#*.}-venv"
|
||||||
|
fi
|
||||||
if ! command -v node >/dev/null 2>&1 || ! command -v npm >/dev/null 2>&1; then
|
if ! command -v node >/dev/null 2>&1 || ! command -v npm >/dev/null 2>&1; then
|
||||||
echo " Node.js/npm not found — installing..."
|
echo " Node.js/npm not found — installing..."
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - 2>&1 | tail -3
|
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - 2>&1 | tail -3
|
||||||
@ -585,6 +592,20 @@ else
|
|||||||
echo " ⚠️ Rust not installed on target, skipping backend build"
|
echo " ⚠️ Rust not installed on target, skipping backend build"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# reticulum-daemon tools (archy-reticulum-daemon, archy-rnodeconf) — skip with
|
||||||
|
# --frontend-only. Non-fatal on failure: these are supplementary mesh/radio
|
||||||
|
# tools, not required for the rest of the deploy to succeed, and build.sh
|
||||||
|
# handles its own venv/pip setup so a first run here is slower than later ones.
|
||||||
|
if [ "$FRONTEND_ONLY" = true ]; then
|
||||||
|
echo " Skipping reticulum-daemon tools build (--frontend-only)"
|
||||||
|
else
|
||||||
|
progress "Building reticulum-daemon tools (archy-reticulum-daemon, archy-rnodeconf)"
|
||||||
|
section_start
|
||||||
|
ssh $SSH_OPTS "$TARGET_HOST" "cd $TARGET_DIR/reticulum-daemon && ./build.sh 2>&1" | sed 's/^/ /' \
|
||||||
|
|| echo " ⚠️ reticulum-daemon tools build failed — continuing without updating them"
|
||||||
|
section_end
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$LIVE" = true ]; then
|
if [ "$LIVE" = true ]; then
|
||||||
|
|
||||||
# Create rollback backup before deploying
|
# Create rollback backup before deploying
|
||||||
@ -608,6 +629,26 @@ if [ "$LIVE" = true ]; then
|
|||||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo cp $TARGET_DIR/core/target/release/archipelago /usr/local/bin/"
|
ssh $SSH_OPTS "$TARGET_HOST" "sudo cp $TARGET_DIR/core/target/release/archipelago /usr/local/bin/"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Deploy reticulum-daemon tools (archy-reticulum-daemon, archy-rnodeconf) —
|
||||||
|
# skip with --frontend-only. Non-fatal: archipelago falls back to its dev
|
||||||
|
# venv path (ARCHY_RETICULUM_DAEMON_PY/_SCRIPT) if the packaged binary
|
||||||
|
# isn't present, so a missing/failed build here degrades rather than
|
||||||
|
# breaks mesh. archipelago is already stopped from the backend-binary
|
||||||
|
# step above, so this is a clean window to swap both binaries.
|
||||||
|
if [ "$FRONTEND_ONLY" = true ]; then
|
||||||
|
echo " Skipping reticulum-daemon tools deploy (--frontend-only)"
|
||||||
|
else
|
||||||
|
progress "Deploying reticulum-daemon tools"
|
||||||
|
for tool in archy-reticulum-daemon archy-rnodeconf; do
|
||||||
|
if ssh $SSH_OPTS "$TARGET_HOST" "[ -f $TARGET_DIR/reticulum-daemon/dist/$tool ]" 2>/dev/null; then
|
||||||
|
ssh $SSH_OPTS "$TARGET_HOST" "sudo cp $TARGET_DIR/reticulum-daemon/dist/$tool /usr/local/bin/ && sudo chmod +x /usr/local/bin/$tool"
|
||||||
|
echo " $tool deployed"
|
||||||
|
else
|
||||||
|
echo " ⚠️ $tool not built — leaving existing /usr/local/bin/$tool (if any) in place"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# Deploy frontend (preserve aiui/ and claude-login.html — they are NOT part of the neode-ui build)
|
# Deploy frontend (preserve aiui/ and claude-login.html — they are NOT part of the neode-ui build)
|
||||||
progress "Deploying frontend"
|
progress "Deploying frontend"
|
||||||
ssh $SSH_OPTS "$TARGET_HOST" "sudo find /opt/archipelago/web-ui -mindepth 1 -maxdepth 1 ! -name 'aiui' ! -name 'claude-login.html' -exec rm -rf {} +"
|
ssh $SSH_OPTS "$TARGET_HOST" "sudo find /opt/archipelago/web-ui -mindepth 1 -maxdepth 1 ! -name 'aiui' ! -name 'claude-login.html' -exec rm -rf {} +"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user