Files
wadamesh/scripts/build/gen-lua-builtin.py
T
Kaj SchittecatandClaude Opus 5.5 218bc6ed3e touch: beta_91, Home becomes widgets, backgrounds, GPS in the bar
Home is a grid of arrangeable widgets (24 kinds, presets, a layout per
orientation, Lua app widgets via wada.widget); Unread, Chat and Mentions
get a large size. Theme > Background puts an aurora (still by default, or
moving), a colour, a picture or nothing behind every screen, with glass
cards and a smoked-glass top bar. A GPS icon in the bar, a GPS battery
saver (u-blox GNSS stop/start where there is no power switch), and a
battery saver that no longer waits for Bluetooth and Wi-Fi to be off.
Also: navigation bar position, every settings page on the redesign's
cards, a faster app drawer, slower screensaver drift for burn-in, text
wrapping at spaces only, the V4-R8 Store Apps tab, and SDK Test marked
extended-SDK only (keeps the 2 MB V4 at 99.8%).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:14:04 +02:00

91 lines
4.2 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Bake the catalog's Lua apps into the firmware as seeded built-ins.
The Lua host already supports this: luaAppLaunchFile(id, title, embedded, len)
tries <data>/apps/<id>.lua first and falls back to an embedded source when the
file is not there. That file-first order is what makes a seeded app updatable —
download a newer version from the Store and the file simply wins.
This generates src/ui-touch/lua_builtin.h from deploy/apps/, i.e. exactly the
sources the Store serves, so a board that cannot reach the Store still ships
with the apps rather than an empty drawer.
It used to read out/firmware/apps/ instead. Nothing writes that directory --
deploy-apps.sh rsyncs deploy/apps/ straight to the VPS -- so it was a stale
mirror, and the "same sources the Store serves" guarantee was false: a bumped
app shipped to the Store while the baked-in copy stayed on whatever version was
mirrored last (#257).
Run from the repo root: python3 scripts/build/gen-lua-builtin.py
"""
import json, os, re, sys
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
APPS = os.path.join(ROOT, 'deploy/apps') # canonical; what deploy-apps.sh publishes
OUT = os.path.join(ROOT, 'src/ui-touch/lua_builtin.h')
DELIM = 'WADALUA' # raw-string delimiter: keeps Lua source verbatim
def main():
cat_path = os.path.join(APPS, 'apps.json')
if not os.path.exists(cat_path):
sys.exit('no catalog at ' + cat_path)
cat = json.load(open(cat_path, encoding='utf-8'))['apps']
entries = []
for app in cat:
aid, ver, name = app['id'], app['ver'], app['name']
# "seed": false keeps an app out of the image while still publishing it to
# the Store. Seeding is not free: it is flash on the boards that have the
# least of it, which are exactly the CAP_BUILTIN_LUA_APPS boards. An app
# that is large, or that needs hardware those boards do not have, earns its
# place rather than getting it by being in the catalog.
if app.get('seed') is False:
print(' skip %s: seed=false in apps.json' % aid)
continue
src = os.path.join(APPS, aid, ver, aid + '.lua')
if not os.path.exists(src):
print(' skip %s: no %s' % (aid, os.path.relpath(src, ROOT)))
continue
code = open(src, encoding='utf-8').read()
if (')' + DELIM + '"') in code:
sys.exit('%s contains the raw-string delimiter' % aid)
# An app that needs the extended SDK cannot run on a board without it, so it
# is baked in only where it can (CAP_LUA_SDK_EXT, every board but the 2 MB
# Heltec V4, the one with the least flash to give).
entries.append((aid, name, ver, code, app.get('requires') == 'sdk_ext'))
if not entries:
sys.exit('no app sources found under ' + APPS)
w = ['// Generated by scripts/build/gen-lua-builtin.py — DO NOT EDIT.',
'// Source: deploy/apps/ (the same .lua the Lua Store serves).',
'// Seeded built-ins: a downloaded <data>/apps/<id>.lua always wins.',
'#pragma once', '',
'struct LuaBuiltinApp { const char* id; const char* name; const char* ver; const char* src; };', '']
for aid, name, ver, code, ext in entries:
if ext: w.append('#if CAP_LUA_SDK_EXT')
w.append('static const char kLuaSrc_%s[] = R"%s(%s)%s";' % (aid, DELIM, code, DELIM))
if ext: w.append('#endif')
w.append('')
w.append('static const LuaBuiltinApp kLuaBuiltin[] = {')
for aid, name, ver, _, ext in entries:
if ext: w.append('#if CAP_LUA_SDK_EXT')
w.append(' { "%s", "%s", "%s", kLuaSrc_%s },' % (aid, name, ver, aid))
if ext: w.append('#endif')
w.append('};')
w.append('static const int kLuaBuiltinCount = (int)(sizeof(kLuaBuiltin)/sizeof(kLuaBuiltin[0]));')
w.append('')
open(OUT, 'w', encoding='utf-8').write('\n'.join(w))
total = sum(len(e[3]) for e in entries)
print('%s: %d apps, %d bytes of Lua' %
(os.path.relpath(OUT, ROOT), len(entries), total))
for aid, _, ver, code, ext in entries:
print(' %-10s v%-4s %6d B%s' % (aid, ver, len(code), ' (extended SDK only)' if ext else ''))
if __name__ == '__main__':
main()