diff --git a/reticulum-daemon/build.sh b/reticulum-daemon/build.sh index 3d8a5a3b..f99642d3 100755 --- a/reticulum-daemon/build.sh +++ b/reticulum-daemon/build.sh @@ -43,9 +43,15 @@ echo "Built dist/archy-reticulum-daemon ($(du -h dist/archy-reticulum-daemon | c # 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))" diff --git a/reticulum-daemon/pyi_rthook_exit_builtins.py b/reticulum-daemon/pyi_rthook_exit_builtins.py new file mode 100644 index 00000000..0b999229 --- /dev/null +++ b/reticulum-daemon/pyi_rthook_exit_builtins.py @@ -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