Files
wadamesh/scripts/deploy-apps.sh
T
Kaj SchittecatandClaude Opus 5 8cc4a2b981 apps: add 2048 to the Store (pisti87, #265)
Community submission, reviewed before publishing rather than taken on trust.

The whole API surface it touches is ui.label / ui.canvas / ui.colors, sys.random,
timer.every(100) and two store keys for the high score. No network, no mesh
transmit, no filesystem, no dynamic code loading (load/loadstring/require/dofile),
no _G, metatable, debug or coroutine tricks, and no long-string or numeric-escape
obfuscation. Persistence is one bounded value. Nothing in it can reach past its
own window, so it needs no permission grant.

It also uses the real lifecycle contract — an app table with on_open/on_tick/
on_input/on_close, returned from the chunk — which is worth noting because the
published SDK page told people to do it a different way until today. He got it
right by reading the shipped apps.

Parse-checked against the firmware's own vendored Lua 5.4.7 rather than a system
interpreter, so the syntax is verified by the same parser the device runs. Not
run on hardware here; pisti87 reports it working on a T-Deck Plus.

deploy-apps.sh now also verifies that every apps.json entry has its
<id>/<ver>/<id>.lua and .json on disk. An entry pointing at a missing file lists
in the Store and then fails to install with nothing on screen to explain why —
the same failure the language check already prevents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 20:56:44 +02:00

74 lines
3.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# wadamesh app+language store deploy: publish deploy/apps/ to the firmware VPS.
#
# The device reads BOTH catalogs from the firmware host, NOT the site host:
# http://firmware.wadamesh.com/apps/apps.json <- Store > Apps
# http://firmware.wadamesh.com/apps/langs.json <- Store > Languages
# http://firmware.wadamesh.com/apps/lang/<ver>/<code>.lang
# so this tree lives under the FIRMWARE web root, alongside releases/ and latest*/.
#
# WHY THIS SCRIPT EXISTS: there wasn't one. release.sh rsyncs out/firmware/ (which
# does not contain apps/) and deploy-site.sh rsyncs deploy/site/ — so the store was
# only ever updated by someone remembering to rsync it by hand, and twice they did
# not. Translations sat at v8 on the server while the repo had v9/v10/v11, and a
# published app never appeared at all. Editing deploy/apps/ is not publishing it;
# running this is.
#
# Usage:
# WADAMESH_VPS=user@your-vps scripts/deploy-apps.sh # deploy
# WADAMESH_VPS=user@your-vps scripts/deploy-apps.sh --dry-run # preview only
#
# Optional:
# WADAMESH_FW_PATH=/srv/wadamesh/firmware # override the firmware web root
#
# The VPS target comes from the environment — never commit it.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
SRC="$ROOT/deploy/apps/"
DEST="${WADAMESH_VPS:?set WADAMESH_VPS=user@host}"
DEST_PATH="${WADAMESH_FW_PATH:-/srv/wadamesh/firmware}/apps"
DRY=""
[ "${1:-}" = "--dry-run" ] && DRY="--dry-run"
# Sanity-check the catalogs before shipping them: a device that gets malformed JSON
# shows an empty store with no clue why, and the versioned .lang dir each catalog
# entry points at has to actually exist or the download 404s on the device.
python3 - "$ROOT" <<'PY'
import json, os, sys
root = sys.argv[1]
apps_dir = os.path.join(root, "deploy", "apps")
langs = json.load(open(os.path.join(apps_dir, "langs.json")))["langs"]
missing = [f"{l['code']} v{l['ver']}" for l in langs
if not os.path.isfile(os.path.join(apps_dir, "lang", str(l["ver"]), l["code"] + ".lang"))]
if missing:
sys.exit("ABORT: langs.json points at files that do not exist: " + ", ".join(missing))
# Same check for apps: an entry whose <id>/<ver>/<id>.lua is absent shows up in the
# Store and then fails to install, with nothing on screen to say why.
apps = json.load(open(os.path.join(apps_dir, "apps.json")))["apps"]
bad = []
for a in apps:
base = os.path.join(apps_dir, a["id"], a["ver"])
for f in (a["id"] + ".lua", a["id"] + ".json"):
if not os.path.isfile(os.path.join(base, f)):
bad.append(f'{a["id"]} v{a["ver"]}: {f}')
if bad:
sys.exit("ABORT: apps.json points at files that do not exist: " + ", ".join(bad))
print(f"catalogs ok: {len(langs)} languages and {len(apps)} apps, every referenced file present")
PY
# --delete mirrors the repo: the store is generated content, the repo is the source
# of truth, and stale versioned dirs left on the server are how a device ends up
# offered a language file nothing points at any more.
rsync -avz $DRY --delete "$SRC" "$DEST:$DEST_PATH/"
if [ -z "$DRY" ]; then
echo
echo "deployed deploy/apps/ -> $DEST:$DEST_PATH"
echo "verify:"
echo " curl -s http://firmware.wadamesh.com/apps/langs.json"
echo " curl -s http://firmware.wadamesh.com/apps/apps.json"
fi