Update build scripts and tests for ports/switch OTA paths.

Point launcher, fused build, docs, and gitignore at the relocated Switch port tree.
This commit is contained in:
Andrew Quenehen
2026-08-06 10:24:04 -03:00
parent 9aa8b4e371
commit 75cd28435c
10 changed files with 76 additions and 76 deletions
+16 -16
View File
@@ -37,22 +37,22 @@ mobile/ios/build/
# Final packaged build artifacts (mac/win/web/android/ios/switch) — see scripts/build.sh
/dist/
# Native Switch OTA launcher build outputs
native/switch-ota-launcher/build/
native/switch-ota-launcher/build-host/
native/switch-ota-launcher/*.nro
native/switch-ota-launcher/*.nacp
native/switch-ota-launcher/*.elf
native/switch-ota-launcher/*.map
native/switch-ota-launcher/romfs/logo.rgba
native/switch-ota-launcher/romfs/logo.png
native/switch-ota-launcher/romfs/cacert.pem
native/switch-ota-launcher/romfs/ota-bootstrap.nro
native/switch-ota-bootstrap/build/
native/switch-ota-bootstrap/*.nro
native/switch-ota-bootstrap/*.nacp
native/switch-ota-bootstrap/*.elf
native/switch-ota-bootstrap/*.map
# Switch OTA launcher build outputs
ports/switch/ota-launcher/build/
ports/switch/ota-launcher/build-host/
ports/switch/ota-launcher/*.nro
ports/switch/ota-launcher/*.nacp
ports/switch/ota-launcher/*.elf
ports/switch/ota-launcher/*.map
ports/switch/ota-launcher/romfs/logo.rgba
ports/switch/ota-launcher/romfs/logo.png
ports/switch/ota-launcher/romfs/cacert.pem
ports/switch/ota-launcher/romfs/ota-bootstrap.nro
ports/switch/ota-bootstrap/build/
ports/switch/ota-bootstrap/*.nro
ports/switch/ota-bootstrap/*.nacp
ports/switch/ota-bootstrap/*.elf
ports/switch/ota-bootstrap/*.map
# Legacy manual convenience-copy location (superseded by /dist/android/)
mobile/dist/
+3 -3
View File
@@ -41,10 +41,10 @@ Fused game builds can also use Docker when native `nacptool`/`elf2nro` are absen
In-console OTA uses a **separate DEVKITPRO NRO** (not LÖVE). The LÖVE
self-updater (`Check.lua`) is disabled on NX. Source:
`native/switch-ota-launcher/`. Host protocol tests (no toolchain):
`ports/switch/ota-launcher/`. Host protocol tests (no toolchain):
```sh
make -C native/switch-ota-launcher host-test
make -C ports/switch/ota-launcher host-test
# or
scripts/switch/build_ota_launcher.sh # host-test first; NRO needs DEVKITPRO/Docker
```
@@ -59,7 +59,7 @@ Release-like build from repo root:
scripts/build_switch.sh --fetch --fused --version X.Y.Z
```
See `native/switch-ota-launcher/README.md` and
See `ports/switch/ota-launcher/README.md` and
`scripts/switch/ota_launcher.manifest`.
### Windows (Git Bash / MSYS2 / WSL)
+3 -3
View File
@@ -45,8 +45,8 @@ APP_AUTHOR := bryanthaboi, port by andrewqsantos
APP_VERSION ?= 0.0.0
# Prefer project Switch icon if present
ICON := $(TOPDIR)/../../assets/switch/icon.jpg
LOGO_RGBA_SRC := $(TOPDIR)/assets/logo.rgba
ICON := $(TOPDIR)/../assets/icon.jpg
LOGO_RGBA_SRC := $(TOPDIR)/../assets/logo.rgba
LOGO_ROMFS := $(CURDIR)/$(ROMFS)/logo.rgba
#---------------------------------------------------------------------------------
@@ -131,7 +131,7 @@ ifneq ($(ROMFS),)
export NROFLAGS += --romfsdir=$(CURDIR)/$(ROMFS)
endif
BOOTSTRAP_DIR := $(TOPDIR)/../switch-ota-bootstrap
BOOTSTRAP_DIR := $(TOPDIR)/../ota-bootstrap
BOOTSTRAP_ROMFS := $(CURDIR)/$(ROMFS)/ota-bootstrap.nro
.PHONY: $(BUILD) clean all host-test sync-romfs bootstrap-romfs
+4 -4
View File
@@ -11,7 +11,7 @@ with `envSetNextLoad`.
The LÖVE self-updater (`src/update/Check.lua`) stays **disabled** on NX.
Wire format (also in Lua): `src/update/SwitchOta.lua`.
NACP icon: `assets/switch/icon.jpg`.
NACP icon: `ports/switch/assets/icon.jpg`.
## Layout on microSD
@@ -25,7 +25,7 @@ sdmc:/switch/gen1recomp/pokemon-love2d/ <- saves (never touched by OTA)
## Host tests (no DEVKITPRO)
```bash
cd native/switch-ota-launcher
cd ports/switch/ota-launcher
make host-test
```
@@ -40,7 +40,7 @@ Needs `DEVKITPRO` with packages roughly:
```bash
export DEVKITPRO=/opt/devkitpro # typical
cd native/switch-ota-launcher
cd ports/switch/ota-launcher
make
# -> gen1recomp.nro
```
@@ -62,7 +62,7 @@ Docker fallback uses the same pin as fused builds (`scripts/switch/dkp-docker.im
## OTA logo asset
The launcher draws a pre-scaled logo from `romfs:/logo.rgba` (no PNG decoder in
the NRO). The baked blob lives at `assets/logo.rgba` and is copied into romfs at
the NRO). The baked blob lives at `../assets/logo.rgba` and is copied into romfs at
build time. After changing `assets/logo/logo.png`, regenerate:
```bash
+1 -1
View File
@@ -23,7 +23,7 @@ from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
DEFAULT_SRC = ROOT / "assets/logo/logo.png"
DEFAULT_OUT = ROOT / "native/switch-ota-launcher/assets/logo.rgba"
DEFAULT_OUT = ROOT / "ports/switch/assets/logo.rgba"
DEFAULT_MAX_W = 320
DEFAULT_MAX_H = 90
+2 -2
View File
@@ -15,7 +15,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
LOVE_NX_TAG="11.5-nx1"
LOVE_NX_DIR="$ROOT/.bazinga/love-nx/$LOVE_NX_TAG"
LOVE_ELF="$LOVE_NX_DIR/love.elf"
ICON="$ROOT/assets/switch/icon.jpg"
ICON="$ROOT/ports/switch/assets/icon.jpg"
APP_NAME="gen1recomp"
APP_AUTHOR="bryanthaboi, port by andrewqsantos"
DKP_IMAGE_FILE="$ROOT/scripts/switch/dkp-docker.image"
@@ -93,7 +93,7 @@ run_fused_docker() {
set -euo pipefail
nacptool --create '$APP_NAME' '$APP_AUTHOR' '$VERSION' /work/control.nacp
elf2nro /src/.bazinga/love-nx/$LOVE_NX_TAG/love.elf /out/$out_base \
--icon=/src/assets/switch/icon.jpg \
--icon=/src/ports/switch/assets/icon.jpg \
--nacp=/work/control.nacp \
--romfsdir=/work/romfs
"
+2 -2
View File
@@ -14,7 +14,7 @@ SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=common.sh
. "$SCRIPT_DIR/common.sh"
LAUNCHER_DIR="$ROOT/native/switch-ota-launcher"
LAUNCHER_DIR="$ROOT/ports/switch/ota-launcher"
OUT_NRO="${1:-$ROOT/dist/switch/gen1recomp-launcher.nro}"
APP_VERSION="${2:-${GEN1_LAUNCHER_VERSION:-0.0.0}}"
DKP_IMAGE_FILE="$ROOT/scripts/switch/dkp-docker.image"
@@ -59,7 +59,7 @@ if command -v docker >/dev/null 2>&1; then
say "building launcher NRO via Docker ($image, NACP $APP_VERSION)"
if ! docker run --rm \
-v "$ROOT:/work" \
-w /work/native/switch-ota-launcher \
-w /work/ports/switch/ota-launcher \
-e "APP_VERSION=$APP_VERSION" \
"$image" \
bash -lc 'pacman -Sy --noconfirm switch-curl switch-mbedtls switch-zlib switch-zziplib >/dev/null 2>&1 || true; make clean; make all APP_VERSION="$APP_VERSION"'; then
+2 -2
View File
@@ -102,7 +102,7 @@ Pick one:
Then re-run: scripts/build_switch.sh --fetch --fused
See docs/switch-build.md and native/switch-ota-launcher/README.md.
See docs/switch-build.md and ports/switch/ota-launcher/README.md.
EOF
)"
}
@@ -121,7 +121,7 @@ Re-run with a clean tree:
If packages look wrong, reinstall:
bash scripts/switch/install_devkitpro_deps.sh
See native/switch-ota-launcher/README.md.
See ports/switch/ota-launcher/README.md.
EOF
)"
fi
+9 -9
View File
@@ -395,7 +395,7 @@ if [ -f "$ROOT/scripts/switch/build_ota_launcher.sh" ] \
&& grep -q 'ota_launcher_deps_ready' "$ROOT/scripts/switch/build_ota_launcher.sh" \
&& grep -q 'fail_missing_devkitpro' "$ROOT/scripts/switch/build_ota_launcher.sh" \
&& grep -q 'preflight_fused_build' "$ROOT/scripts/build_switch.sh" \
&& [ -f "$ROOT/native/switch-ota-launcher/Makefile" ]
&& [ -f "$ROOT/ports/switch/ota-launcher/Makefile" ]
then
ok "native OTA launcher sources + build_ota_launcher.sh present"
else
@@ -415,20 +415,20 @@ else
bad "legacy separate OTA-only packer / asset still present"
fi
if grep -q 'ota_ui_prompt_update' "$ROOT/native/switch-ota-launcher/src/main.c" \
&& grep -q 'ota_net_init' "$ROOT/native/switch-ota-launcher/src/main.c" \
&& grep -q 'framebufferCreate\|COL_RAIL' "$ROOT/native/switch-ota-launcher/src/ota_ui.c" \
&& grep -q '^ROMFS' "$ROOT/native/switch-ota-launcher/Makefile" \
&& grep -q 'cacert.pem' "$ROOT/native/switch-ota-launcher/Makefile"
if grep -q 'ota_ui_prompt_update' "$ROOT/ports/switch/ota-launcher/src/main.c" \
&& grep -q 'ota_net_init' "$ROOT/ports/switch/ota-launcher/src/main.c" \
&& grep -q 'framebufferCreate\|COL_RAIL' "$ROOT/ports/switch/ota-launcher/src/ota_ui.c" \
&& grep -q '^ROMFS' "$ROOT/ports/switch/ota-launcher/Makefile" \
&& grep -q 'cacert.pem' "$ROOT/ports/switch/ota-launcher/Makefile"
then
ok "launcher UI uses framebuffer (no prompt when up to date)"
else
bad "launcher missing branded ota_ui / ROMFS"
fi
if [ -f "$ROOT/native/switch-ota-launcher/src/ota_unzip.c" ] \
&& grep -q 'zzip/zzip.h' "$ROOT/native/switch-ota-launcher/src/ota_unzip.c" \
&& grep -q 'ota_unzip_extract_file' "$ROOT/native/switch-ota-launcher/src/main.c"
if [ -f "$ROOT/ports/switch/ota-launcher/src/ota_unzip.c" ] \
&& grep -q 'zzip/zzip.h' "$ROOT/ports/switch/ota-launcher/src/ota_unzip.c" \
&& grep -q 'ota_unzip_extract_file' "$ROOT/ports/switch/ota-launcher/src/main.c"
then
ok "launcher wires zziplib ota_unzip_extract_file"
else
+34 -34
View File
@@ -457,8 +457,8 @@ test('AC-008: Gates de regressão anti-“erro invisível” @spec:AC-008', () =
});
test('AC-009: Protocolo C host-testável espelha SwitchOta.lua @spec:AC-009', () => {
const proto = read('native/switch-ota-launcher/src/ota_protocol.c');
const header = read('native/switch-ota-launcher/include/ota_protocol.h');
const proto = read('ports/switch/ota-launcher/src/ota_protocol.c');
const header = read('ports/switch/ota-launcher/include/ota_protocol.h');
assert.match(header, /OTA_CHECK_TIMEOUT_SEC\s+6/);
assert.match(header, /ota_compare_semver/);
assert.match(header, /ota_parse_release/);
@@ -476,7 +476,7 @@ test('AC-009: Protocolo C host-testável espelha SwitchOta.lua @spec:AC-009', ()
// Compile + run C host tests (gcc)
const r = spawnSync(
'make',
['-C', path.join(root, 'native/switch-ota-launcher'), 'host-test'],
['-C', path.join(root, 'ports/switch/ota-launcher'), 'host-test'],
{ encoding: 'utf8' }
);
assert.equal(r.status, 0, `host-test failed:\n${r.stdout}\n${r.stderr}`);
@@ -485,17 +485,17 @@ test('AC-009: Protocolo C host-testável espelha SwitchOta.lua @spec:AC-009', ()
test('AC-010: Fonte do launcher e Makefile DEVKITPRO existem @spec:AC-010', () => {
for (const rel of [
'native/switch-ota-launcher/Makefile',
'native/switch-ota-launcher/README.md',
'native/switch-ota-launcher/src/main.c',
'native/switch-ota-launcher/src/ota_net.c',
'native/switch-ota-launcher/src/ota_fs.c',
'ports/switch/ota-launcher/Makefile',
'ports/switch/ota-launcher/README.md',
'ports/switch/ota-launcher/src/main.c',
'ports/switch/ota-launcher/src/ota_net.c',
'ports/switch/ota-launcher/src/ota_fs.c',
'scripts/switch/build_ota_launcher.sh',
'docs/switch-build.md',
]) {
assert.ok(fs.existsSync(path.join(root, rel)), `missing ${rel}`);
}
const main = read('native/switch-ota-launcher/src/main.c');
const main = read('ports/switch/ota-launcher/src/main.c');
assert.match(main, /envSetNextLoad|ota_fs_handoff_to_game/);
assert.match(main, /gen1recomp-game\.nro|OTA_GAME_NRO_NAME/);
assert.match(main, /Quiet by default|stays quiet|LÖVE self-updater stays off|self-updater stays off/i);
@@ -505,13 +505,13 @@ test('AC-010: Fonte do launcher e Makefile DEVKITPRO existem @spec:AC-010', () =
assert.doesNotMatch(main, /\u2026/, 'OTA UI strings must be ASCII (no Unicode ellipsis)');
assert.doesNotMatch(main, /ota_ui_alert\([^)]*Install failed/, 'generic install alert removed');
assert.doesNotMatch(main, /consoleInit/, 'no terminal console UI');
assert.ok(fs.existsSync(path.join(root, 'native/switch-ota-launcher/src/ota_ui.c')));
const otaUi = read('native/switch-ota-launcher/src/ota_ui.c');
assert.ok(fs.existsSync(path.join(root, 'ports/switch/ota-launcher/src/ota_ui.c')));
const otaUi = read('ports/switch/ota-launcher/src/ota_ui.c');
assert.match(otaUi, /COL_RAIL_R|rail|FFD600|255,\s*214/);
assert.match(otaUi, /logo\.rgba/);
assert.doesNotMatch(otaUi, /stb_image/);
assert.ok(
fs.existsSync(path.join(root, 'native/switch-ota-launcher/assets/logo.rgba')),
fs.existsSync(path.join(root, 'ports/switch/assets/logo.rgba')),
'pre-baked OTA logo asset'
);
assert.ok(
@@ -521,44 +521,44 @@ test('AC-010: Fonte do launcher e Makefile DEVKITPRO existem @spec:AC-010', () =
assert.match(otaUi, /ota_ui_sanitize_ascii/);
assert.match(otaUi, /draw_text_wrapped_centered/);
assert.match(otaUi, /ota_ui_alert_error/);
assert.match(read('native/switch-ota-launcher/src/ota_net.c'), /ota_net_init/);
assert.match(read('native/switch-ota-launcher/src/main.c'), /ota_net_init/);
assert.match(read('native/switch-ota-launcher/src/ota_net.c'), /CURLOPT_SSL_VERIFYPEER,\s*1L/);
assert.match(read('native/switch-ota-launcher/src/ota_net.c'), /romfs:\/cacert\.pem/);
assert.doesNotMatch(read('native/switch-ota-launcher/src/ota_net.c'), /CURLOPT_SSL_VERIFYPEER,\s*0L/);
assert.match(read('native/switch-ota-launcher/Makefile'), /^ROMFS\s*:=/m);
assert.match(read('native/switch-ota-launcher/Makefile'), /cacert\.pem/);
assert.match(read('native/switch-ota-launcher/Makefile'), /logo\.rgba/);
assert.match(read('ports/switch/ota-launcher/src/ota_net.c'), /ota_net_init/);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /ota_net_init/);
assert.match(read('ports/switch/ota-launcher/src/ota_net.c'), /CURLOPT_SSL_VERIFYPEER,\s*1L/);
assert.match(read('ports/switch/ota-launcher/src/ota_net.c'), /romfs:\/cacert\.pem/);
assert.doesNotMatch(read('ports/switch/ota-launcher/src/ota_net.c'), /CURLOPT_SSL_VERIFYPEER,\s*0L/);
assert.match(read('ports/switch/ota-launcher/Makefile'), /^ROMFS\s*:=/m);
assert.match(read('ports/switch/ota-launcher/Makefile'), /cacert\.pem/);
assert.match(read('ports/switch/ota-launcher/Makefile'), /logo\.rgba/);
const mk = read('native/switch-ota-launcher/Makefile');
const mk = read('ports/switch/ota-launcher/Makefile');
assert.match(mk, /libnx\/switch_rules|DEVKITPRO/);
assert.match(mk, /-lcurl/);
assert.match(mk, /-lzzip/);
assert.match(mk, /assets\/switch\/icon\.jpg/, 'uses project Switch icon');
assert.match(mk, /ports\/switch\/assets\/icon\.jpg|assets\/icon\.jpg/, 'uses project Switch icon');
assert.ok(fs.existsSync(path.join(root, 'native/switch-ota-launcher/src/ota_unzip.c')));
assert.match(read('native/switch-ota-launcher/src/ota_unzip.c'), /zzip\/zzip\.h/);
assert.match(read('native/switch-ota-launcher/src/main.c'), /ota_unzip_extract_file/);
assert.match(read('native/switch-ota-launcher/src/main.c'), /GAME_MEMBER_IN_ZIP|switch\/gen1recomp\//);
assert.match(read('native/switch-ota-launcher/src/main.c'), /LAUNCHER_MEMBER_IN_ZIP|ota_fs_stage_launcher_bootstrap/);
assert.match(read('native/switch-ota-launcher/src/main.c'), /ota_fs_stage_launcher_bootstrap\([\s\S]*\) != 0/);
assert.match(read('native/switch-ota-launcher/src/main.c'), /return 2.*bootstrap|bootstrap.*return 2/i);
assert.match(read('native/switch-ota-launcher/src/ota_fs.c'), /ota_fs_atomic_replace_nro/);
assert.match(read('native/switch-ota-launcher/src/ota_fs.c'), /remove\(dest\)/);
assert.doesNotMatch(read('native/switch-ota-launcher/src/ota_fs.c'), /#ifdef _WIN32[\s\S]*remove\(dest\)/);
assert.ok(fs.existsSync(path.join(root, 'ports/switch/ota-launcher/src/ota_unzip.c')));
assert.match(read('ports/switch/ota-launcher/src/ota_unzip.c'), /zzip\/zzip\.h/);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /ota_unzip_extract_file/);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /GAME_MEMBER_IN_ZIP|switch\/gen1recomp\//);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /LAUNCHER_MEMBER_IN_ZIP|ota_fs_stage_launcher_bootstrap/);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /ota_fs_stage_launcher_bootstrap\([\s\S]*\) != 0/);
assert.match(read('ports/switch/ota-launcher/src/main.c'), /return 2.*bootstrap|bootstrap.*return 2/i);
assert.match(read('ports/switch/ota-launcher/src/ota_fs.c'), /ota_fs_atomic_replace_nro/);
assert.match(read('ports/switch/ota-launcher/src/ota_fs.c'), /remove\(dest\)/);
assert.doesNotMatch(read('ports/switch/ota-launcher/src/ota_fs.c'), /#ifdef _WIN32[\s\S]*remove\(dest\)/);
assert.doesNotMatch(read('scripts/switch/install_devkitpro_deps.sh'), /switch-minizip/);
assert.match(read('scripts/switch/install_devkitpro_deps.sh'), /switch-zziplib/);
assert.match(read('scripts/switch/install_devkitpro_deps.sh'), /switch-dev/);
const buildDoc = read('docs/switch-build.md');
assert.match(buildDoc, /native\/switch-ota-launcher|build_ota_launcher/);
assert.match(buildDoc, /ports\/switch\/ota-launcher|build_ota_launcher/);
assert.match(buildDoc, /native packages.*or.*Docker|native or Docker/i);
assert.match(buildDoc, /--fused|install_devkitpro_deps/);
assert.match(buildDoc, /Requires DEVKITPRO|DEVKITPRO is[\s\S]*required/i);
assert.doesNotMatch(buildDoc, /switch-ota\.zip/);
assert.doesNotMatch(buildDoc, /--ota\b/);
const readme = read('native/switch-ota-launcher/README.md');
const readme = read('ports/switch/ota-launcher/README.md');
assert.match(readme, /DEVKITPRO|devkitPro/i);
assert.match(readme, /Docker|devkita64/i);
assert.match(readme, /Quiet|quiet|silen/i);