Unify --fused with OTA launcher and require DEVKITPRO preflight for release builds.

This commit is contained in:
Andrew Quenehen
2026-08-06 08:28:31 -03:00
parent dc04a4e848
commit 15fc97a996
9 changed files with 289 additions and 111 deletions
+45 -33
View File
@@ -22,19 +22,25 @@ WSL — not cmd.exe or PowerShell (AD-008).
### macOS / Linux
1. Install [devkitPro pacman](https://devkitpro.org/wiki/devkitPro_pacman).
2. Install Switch tools:
2. Install Switch tools (**required for `--fused`**):
```sh
sudo dkp-pacman -S switch-dev
```
3. Ensure `nacptool` and `elf2nro` are on `PATH` (or under
`$DEVKITPRO/tools/bin` — the fused script prepends that when set).
3. OTA launcher toolchain — **native or Docker** (either is fine):
**Optional:** Install [Docker](https://docs.docker.com/get-docker/) so fused
builds can fall back to the pinned image when native tools are missing.
```sh
bash scripts/switch/install_devkitpro_deps.sh # native
# or install Docker (same pin as fused builds)
```
### Native OTA launcher (optional but required for in-console updates)
4. Ensure `DEVKITPRO` is exported (typical macOS: `/opt/devkitpro`) and
`nacptool` / `elf2nro` are on `PATH` (or under `$DEVKITPRO/tools/bin`).
Fused game builds can also use Docker when native `nacptool`/`elf2nro` are absent.
### Native OTA launcher (included in `--fused`)
In-console OTA uses a **separate DEVKITPRO NRO** (not LÖVE). Source:
`native/switch-ota-launcher/`. Host protocol tests (no toolchain):
@@ -45,26 +51,14 @@ make -C native/switch-ota-launcher host-test
scripts/switch/build_ota_launcher.sh # host-test first; NRO needs DEVKITPRO/Docker
```
Extra packages beyond `switch-dev`:
`--fused` always builds the fused game, native OTA launcher, and dual-NRO SD
zip. The same `*-switch.zip` is the OTA download asset. **DEVKITPRO is
required.** OTA launcher: native packages **or** Docker — both are supported.
Release-like build from repo root:
```sh
sudo dkp-pacman -S --noconfirm --needed switch-curl switch-mbedtls switch-zlib switch-zziplib
# or: bash scripts/switch/install_devkitpro_deps.sh
```
Packaging dual-NRO SD zip (launcher entry + fused game):
```sh
scripts/switch/pack_sd_zip.sh dist/switch/game.nro VERSION out.zip dist/switch/gen1recomp-launcher.nro
```
One-shot OTA release build (fused game + launcher + dual-NRO SD zip;
the same `*-switch.zip` is the OTA download asset):
```sh
# once: bash scripts/switch/install_devkitpro_deps.sh
export DEVKITPRO=/opt/devkitpro
scripts/build_switch.sh --fetch --ota --version X.Y.Z
scripts/build_switch.sh --fetch --fused --version X.Y.Z
```
See `native/switch-ota-launcher/README.md` and
@@ -86,8 +80,7 @@ See `native/switch-ota-launcher/README.md` and
| You install | Script does **not** install |
| ----------- | --------------------------- |
| bash, git, zip tooling the repo already expects | — |
| `dkp-pacman` + `switch-dev` (native fused) | `dkp-pacman -S …` |
| Docker (optional fused fallback) | Docker Engine |
| `dkp-pacman` + `switch-dev` + OTA packages **or** Docker | `dkp-pacman -S …` |
| A legal `.gb` ROM (to play) | Any ROM or game data |
---
@@ -100,7 +93,7 @@ See `native/switch-ota-launcher/README.md` and
| ---- | ------------ |
| `--fetch` | Downloads pinned **love.nro** + **love.elf** into `.bazinga/love-nx/11.5-nx1/` and verifies SHA-256 against `scripts/switch/love-nx-11.5-nx1.sha256`. |
| `--loose` | Packs `game.love`, copies pinned `love.nro` → `dist/switch/loose/` as `gen1recomp.nro` + `game.love` side by side. Needs the pin. |
| `--fused` | Builds `dist/switch/gen1recomp-<ver>-switch.nro` (game in romfs) via `nacptool` + `elf2nro`, then packs `dist/switch/gen1recomp-<ver>-switch.zip` (SD-ready tree). Needs the pin + toolchain (native or Docker). GitHub Releases publish the **zip only**. |
| `--fused` | Builds fused game NRO, OTA launcher NRO, and dual-NRO SD zip. **Requires DEVKITPRO** + `switch-dev`. OTA launcher: native packages or Docker. GitHub Releases publish the **zip only**. |
Rules:
@@ -145,13 +138,15 @@ scripts/build_switch.sh --fetch
# Loose pair for iteration (fetch + assemble)
scripts/build_switch.sh --fetch --loose
# Single fused NRO + SD-ready zip for a release-like artifact
# Fused game + OTA launcher + dual-NRO SD zip for a release-like artifact
scripts/build_switch.sh --fetch --fused --version 0.2.0
```
Outputs land under `dist/switch/` (and `dist/switch/loose/` for loose mode).
The fused path also writes `gen1recomp-<ver>-switch.nro.sha256` and
`gen1recomp-<ver>-switch.zip` (+ `.sha256` sidecar for the zip).
The fused path also writes `gen1recomp-<ver>-switch.nro` (game),
`gen1recomp-<ver>-launcher.nro`, `gen1recomp-<ver>-game.nro`,
`gen1recomp-<ver>-switch.nro.sha256`, and `gen1recomp-<ver>-switch.zip`
(+ `.sha256` sidecar for the zip).
Offline packaging smoke (no network, no nacptool required):
@@ -217,9 +212,26 @@ A Switch packaging failure fails the entire release job. The release asset is
### Runner provisioning
The self-hosted Mac runner must have **native switch-tools** (`nacptool` /
`elf2nro`) **and/or Docker** available. CI and release do not silently run
`dkp-pacman -S`; keep the runner image/host provisioned per this guide.
The self-hosted Mac runner **must** have **DEVKITPRO** installed and exported.
`--fused` preflight fails early with setup steps if it is missing.
**One-time setup on the runner** (if not already present):
```sh
# devkitPro pacman installer from https://devkitpro.org/wiki/devkitPro_pacman
sudo dkp-pacman -S switch-dev
export DEVKITPRO=/opt/devkitpro
export PATH="$DEVKITPRO/tools/bin:$PATH"
# OTA launcher — pick one:
bash scripts/switch/install_devkitpro_deps.sh # native
# or ensure Docker is installed (same pin as fused builds)
```
CI and release still run `scripts/build_switch.sh --fetch --fused`. Preflight
requires DEVKITPRO and either native OTA packages or Docker. Without all of
that, the job fails with the setup steps above. Scripts never auto-run
`dkp-pacman -S` during CI.
---
+3 -3
View File
@@ -30,15 +30,15 @@ Extract the zip at the **root** of the microSD so you get:
```text
sdmc:/switch/gen1recomp/gen1recomp.nro # native OTA launcher (hbmenu entry)
sdmc:/switch/gen1recomp/gen1recomp-game.nro # fused LÖVE game (when OTA layout ships)
sdmc:/switch/gen1recomp/gen1recomp-game.nro # fused LÖVE game
sdmc:/switch/gen1recomp/version.txt
sdmc:/switch/gen1recomp/pokemon-love2d/imports/
sdmc:/switch/gen1recomp/pokemon-love2d/imports/mods/
sdmc:/switch/gen1recomp/pokemon-love2d/imports/saves/...
```
Older single-NRO zips only had `gen1recomp.nro` (the fused game). New OTA-ready
zips use the dual-NRO layout above — open `gen1recomp` in hbmenu (the launcher).
Older single-NRO zips only had `gen1recomp.nro` (the fused game). Current
releases use the dual-NRO layout above — open `gen1recomp` in hbmenu (the launcher).
Merge folders if your OS asks. Any method works: **MTP** (DBI → Run MTP
responder + a client), **direct SD** (Hekate UMS or a card reader), or **FTP**.
+8 -2
View File
@@ -45,7 +45,13 @@ make
# → gen1recomp.nro
```
Or from repo root:
Or from repo root (as part of `--fused`):
```bash
scripts/build_switch.sh --fetch --fused --version X.Y.Z
```
Standalone launcher build:
```bash
scripts/switch/build_ota_launcher.sh
@@ -64,4 +70,4 @@ Manifest: `scripts/switch/ota_launcher.manifest`.
- Zip extraction uses `switch-zziplib` (`ota_unzip.c`) on device.
- OTA replaces launcher + game from the unified zip (NACP versions stay aligned).
- Sphaira HOME forwarders cache metadata until reinstalled (see docs/switch-install.md).
- Install toolchain deps once: `bash scripts/switch/install_devkitpro_deps.sh`
- Release runner: `switch-dev` + (`install_devkitpro_deps.sh` **or** Docker)
+29 -37
View File
@@ -5,10 +5,8 @@
# scripts/build_switch.sh --fetch
# scripts/build_switch.sh --loose [path/to/game.love]
# scripts/build_switch.sh --fused [--version X.Y.Z]
# scripts/build_switch.sh --ota [--version X.Y.Z]
# scripts/build_switch.sh --fetch --loose
# scripts/build_switch.sh --fetch --fused [--version X.Y.Z]
# scripts/build_switch.sh --fetch --ota [--version X.Y.Z]
#
# Modes:
# --fetch Download pinned love.nro + love.elf into
@@ -21,22 +19,19 @@
# (gen1recomp.nro + game.love side by side). Requires the pin
# (run --fetch first, or combine --fetch --loose).
#
# --fused Build a single gen1recomp-<ver>-switch.nro via nacptool+elf2nro,
# then pack dist/switch/gen1recomp-<ver>-switch.zip (SD-ready
# tree under switch/gen1recomp/). Uses native tools (PATH or
# $DEVKITPRO/tools/bin) first; else Docker from
# scripts/switch/dkp-docker.image (override GEN1_DKP_IMAGE).
# Requires the pin (run --fetch or combine). GitHub Releases
# publish the zip only; the versioned .nro stays local / PR CI.
# --fused Build fused gen1recomp-<ver>-switch.nro (game in romfs), native
# OTA launcher NRO, and dual-NRO SD zip (gen1recomp.nro launcher +
# gen1recomp-game.nro under switch/gen1recomp/). The same
# gen1recomp-<ver>-switch.zip is the OTA download asset.
# Requires DEVKITPRO + switch-dev; OTA launcher via native packages
# (install_devkitpro_deps.sh) or Docker.
# Uses native tools (PATH or $DEVKITPRO/tools/bin) first; else Docker
# from scripts/switch/dkp-docker.image (override GEN1_DKP_IMAGE).
# Requires the pin (run --fetch or combine). GitHub Releases publish
# the zip only; versioned .nro files stay local / PR CI.
#
# --ota Like --fused, plus native OTA launcher NRO and dual-NRO SD zip
# (gen1recomp.nro launcher + gen1recomp-game.nro). The same
# gen1recomp-<ver>-switch.zip is the OTA download asset. Needs
# DEVKITPRO switch-curl/mbedtls/zlib/zziplib — see
# scripts/switch/install_devkitpro_deps.sh.
#
# Combinable: --fetch alone, or --fetch with --loose / --fused / --ota.
# XOR: --loose, --fused, and --ota cannot be combined with each other.
# Combinable: --fetch alone, or --fetch with --loose / --fused.
# XOR: --loose and --fused cannot be combined with each other.
#
# Non-goals (never done by this script):
# MTP push, ROM install, dkp-pacman auto-install (use install_devkitpro_deps.sh).
@@ -49,7 +44,6 @@ DIST="$ROOT/dist/switch"
LOOSE=0
FUSED=0
FETCH=0
OTA=0
GAME_LOVE=""
VERSION="$(git -C "$ROOT" rev-parse --short HEAD 2>/dev/null || echo dev)"
@@ -58,14 +52,13 @@ say() { printf '\033[1;32m==>\033[0m %s\n' "$*" >&2; }
fail() { printf '\033[1;31merror:\033[0m %s\n' "$*" >&2; exit 1; }
usage() {
sed -n '2,40p' "$0" | sed 's/^# \{0,1\}//'
sed -n '2,38p' "$0" | sed 's/^# \{0,1\}//'
}
while [ $# -gt 0 ]; do
case "$1" in
--loose) LOOSE=1; shift ;;
--fused) FUSED=1; shift ;;
--ota) OTA=1; shift ;;
--fetch) FETCH=1; shift ;;
--version) VERSION="$2"; shift 2 ;;
-h|--help)
@@ -83,13 +76,12 @@ while [ $# -gt 0 ]; do
esac
done
MODE_COUNT=$((LOOSE + FUSED + OTA))
if [ "$MODE_COUNT" -gt 1 ]; then
fail "choose one of --loose, --fused, or --ota (XOR)"
if [ "$LOOSE" -eq 1 ] && [ "$FUSED" -eq 1 ]; then
fail "choose one of --loose or --fused (XOR)"
fi
if [ "$FETCH" -eq 0 ] && [ "$LOOSE" -eq 0 ] && [ "$FUSED" -eq 0 ] && [ "$OTA" -eq 0 ]; then
fail "specify --fetch, --loose, --fused, and/or --ota (see --help)"
if [ "$FETCH" -eq 0 ] && [ "$LOOSE" -eq 0 ] && [ "$FUSED" -eq 0 ]; then
fail "specify --fetch, --loose, and/or --fused (see --help)"
fi
if [ "$FETCH" -eq 1 ]; then
@@ -139,22 +131,22 @@ if [ "$LOOSE" -eq 1 ]; then
exec "$ROOT/scripts/switch/assemble_loose.sh" "$GAME_LOVE"
fi
if [ "$FUSED" -eq 1 ] || [ "$OTA" -eq 1 ]; then
if [ "$FUSED" -eq 1 ]; then
# shellcheck source=scripts/switch/common.sh
. "$ROOT/scripts/switch/common.sh"
preflight_fused_build
GAME_LOVE="$(pack_game_love)"
OUT_NRO="$DIST/gen1recomp-${VERSION}-switch.nro"
OUT_ZIP="$DIST/gen1recomp-${VERSION}-switch.zip"
"$ROOT/scripts/switch/build_fused.sh" "$GAME_LOVE" "$VERSION" "$OUT_NRO"
if [ "$OTA" -eq 1 ]; then
LAUNCHER_NRO="$DIST/gen1recomp-${VERSION}-launcher.nro"
say "building native OTA launcher"
"$ROOT/scripts/switch/build_ota_launcher.sh" "$LAUNCHER_NRO" "$VERSION"
say "packing dual-NRO SD zip (also the OTA download asset)"
"$ROOT/scripts/switch/pack_sd_zip.sh" "$OUT_NRO" "$VERSION" "$OUT_ZIP" "$LAUNCHER_NRO"
cp "$OUT_NRO" "$DIST/gen1recomp-${VERSION}-game.nro"
else
"$ROOT/scripts/switch/pack_sd_zip.sh" "$OUT_NRO" "$VERSION" "$OUT_ZIP"
fi
LAUNCHER_NRO="$DIST/gen1recomp-${VERSION}-launcher.nro"
say "building native OTA launcher"
"$ROOT/scripts/switch/build_ota_launcher.sh" "$LAUNCHER_NRO" "$VERSION"
say "packing dual-NRO SD zip (also the OTA download asset)"
"$ROOT/scripts/switch/pack_sd_zip.sh" "$OUT_NRO" "$VERSION" "$OUT_ZIP" "$LAUNCHER_NRO"
cp "$OUT_NRO" "$DIST/gen1recomp-${VERSION}-game.nro"
cp "$WORK/build-info.json" "$DIST/gen1recomp-${VERSION}-build-info.json"
say "done. See $DIST/"
@@ -167,4 +159,4 @@ if [ "$FETCH" -eq 1 ]; then
exit 0
fi
fail "specify --fetch, --loose, --fused, and/or --ota (see --help)"
fail "specify --fetch, --loose, and/or --fused (see --help)"
+13 -14
View File
@@ -22,15 +22,21 @@ DKP_IMAGE_FILE="$ROOT/scripts/switch/dkp-docker.image"
[ -d "$LAUNCHER_DIR" ] || fail "missing $LAUNCHER_DIR"
[ -f "$LAUNCHER_DIR/Makefile" ] || fail "missing Makefile"
if ! devkitpro_ready; then
fail_missing_devkitpro
fi
say "host-test ota_protocol (no DEVKITPRO required)"
make -C "$LAUNCHER_DIR" host-test
mkdir -p "$(dirname "$OUT_NRO")"
if [ -n "${DEVKITPRO:-}" ] && [ -f "$DEVKITPRO/libnx/switch_rules" ]; then
if ota_launcher_deps_ready; then
say "building launcher NRO with native DEVKITPRO (NACP $APP_VERSION)"
make -C "$LAUNCHER_DIR" clean || true
make -C "$LAUNCHER_DIR" all APP_VERSION="$APP_VERSION"
if ! make -C "$LAUNCHER_DIR" all APP_VERSION="$APP_VERSION"; then
fail_ota_launcher_toolchain
fi
cp "$LAUNCHER_DIR/gen1recomp.nro" "$OUT_NRO"
say "wrote $OUT_NRO"
exit 0
@@ -51,24 +57,17 @@ resolve_dkp_image() {
if command -v docker >/dev/null 2>&1; then
image="$(resolve_dkp_image)"
say "building launcher NRO via Docker ($image, NACP $APP_VERSION)"
docker run --rm \
if ! docker run --rm \
-v "$ROOT:/work" \
-w /work/native/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"'
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
fail_ota_launcher_toolchain
fi
cp "$LAUNCHER_DIR/gen1recomp.nro" "$OUT_NRO"
say "wrote $OUT_NRO"
exit 0
fi
fail "$(cat <<EOF
Cannot build Switch OTA launcher NRO: DEVKITPRO unset and Docker unavailable.
Host protocol tests already passed (make host-test).
Install DEVKITPRO switch-dev + switch-curl, or Docker, then re-run:
scripts/switch/build_ota_launcher.sh
See native/switch-ota-launcher/README.md and docs/switch-build.md.
EOF
)"
fail_missing_ota_deps
+124 -3
View File
@@ -38,16 +38,137 @@ fail_need_fetch() {
fail "${1:-missing pinned love-nx} — run: scripts/build_switch.sh --fetch"
}
# OTA launcher native build packages (shared with install_devkitpro_deps.sh).
OTA_LAUNCHER_PKGS=(switch-curl switch-mbedtls switch-zlib switch-zziplib)
ota_launcher_deps_ready() {
command -v dkp-pacman >/dev/null 2>&1 || return 1
local pkg
for pkg in "${OTA_LAUNCHER_PKGS[@]}"; do
dkp-pacman -Q "$pkg" >/dev/null 2>&1 || return 1
done
}
# Space-separated list of missing OTA launcher packages (empty when all installed).
ota_launcher_missing_pkgs() {
command -v dkp-pacman >/dev/null 2>&1 || return 0
local pkg missing=""
for pkg in "${OTA_LAUNCHER_PKGS[@]}"; do
if ! dkp-pacman -Q "$pkg" >/dev/null 2>&1; then
missing="${missing} ${pkg}"
fi
done
printf '%s' "$missing"
}
devkitpro_ready() {
[ -n "${DEVKITPRO:-}" ] && [ -f "$DEVKITPRO/libnx/switch_rules" ]
}
fail_missing_devkitpro() {
fail "$(cat <<'EOF'
--fused requires DEVKITPRO (release builds ship the OTA launcher for in-console updates).
One-time setup on the Mac self-hosted runner (or your dev machine):
1. Install devkitPro pacman: https://devkitpro.org/wiki/devkitPro_pacman
2. Install Switch tools: sudo dkp-pacman -S switch-dev
3. Export DEVKITPRO (typical macOS):
export DEVKITPRO=/opt/devkitpro
export PATH="$DEVKITPRO/tools/bin:$PATH"
4. OTA launcher toolchain (native or Docker — pick one):
bash scripts/switch/install_devkitpro_deps.sh
or install Docker (same pin as fused builds)
Then re-run: scripts/build_switch.sh --fetch --fused
See docs/switch-build.md (Runner provisioning).
EOF
)"
}
fail_missing_ota_deps() {
local missing
missing="$(ota_launcher_missing_pkgs)"
fail "$(cat <<EOF
--fused needs a way to build the OTA launcher: native dkp packages or Docker.
Missing dkp packages:${missing:- (dkp-pacman not on PATH)}
Pick one:
bash scripts/switch/install_devkitpro_deps.sh
or install Docker (build_ota_launcher.sh uses the pinned devkitPro image)
Then re-run: scripts/build_switch.sh --fetch --fused
See docs/switch-build.md and native/switch-ota-launcher/README.md.
EOF
)"
}
fail_ota_launcher_toolchain() {
if ! devkitpro_ready; then
fail_missing_devkitpro
fi
if ota_launcher_deps_ready; then
fail "$(cat <<'EOF'
OTA launcher native build failed after host-test passed.
Re-run with a clean tree:
scripts/switch/build_ota_launcher.sh
If packages look wrong, reinstall:
bash scripts/switch/install_devkitpro_deps.sh
See native/switch-ota-launcher/README.md.
EOF
)"
fi
fail_missing_ota_deps
}
# Fail fast before packing when --fused is requested.
preflight_fused_build() {
if ! devkitpro_ready; then
fail_missing_devkitpro
fi
ensure_dkp_tools_path
local game_ok=0
if command -v nacptool >/dev/null 2>&1 && command -v elf2nro >/dev/null 2>&1; then
game_ok=1
elif command -v docker >/dev/null 2>&1; then
game_ok=1
fi
if [ "$game_ok" -eq 0 ]; then
fail_fused_toolchain
fi
if ota_launcher_deps_ready; then
return 0
fi
if command -v docker >/dev/null 2>&1; then
return 0
fi
fail_missing_ota_deps
}
# Fused mode needs nacptool/elf2nro (native or Docker). Rich multi-OS hint.
fail_fused_toolchain() {
fail "$(cat <<'EOF'
fused packaging needs nacptool and elf2nro (devkitPro switch-dev).
fused packaging needs DEVKITPRO, nacptool, and elf2nro (devkitPro switch-dev).
Install options:
macOS: https://devkitpro.org/wiki/devkitPro_pacman (installer / pacman)
macOS: https://devkitpro.org/wiki/devkitPro_pacman
sudo dkp-pacman -S switch-dev
OTA launcher (native or Docker):
bash scripts/switch/install_devkitpro_deps.sh
or install Docker
Linux: https://devkitpro.org/wiki/devkitPro_pacman
Windows: Git Bash / MSYS2 / WSL with devkitPro tools on PATH
Docker: install Docker; build_fused.sh falls back to the pinned image
Docker: install Docker; fused game and OTA launcher can build in-container
Export DEVKITPRO (typical): export DEVKITPRO=/opt/devkitpro
See docs/switch-build.md for details.
EOF
+15 -5
View File
@@ -4,8 +4,15 @@
#
# bash scripts/switch/install_devkitpro_deps.sh
#
# Optional: speeds up local native OTA launcher builds. CI/release can fall back
# to Docker when these packages are not installed.
#
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=common.sh
. "$SCRIPT_DIR/common.sh"
if [ "$(id -u)" -ne 0 ]; then
echo "==> re-running with sudo…"
exec sudo -E bash "$0" "$@"
@@ -25,14 +32,17 @@ if ! command -v dkp-pacman >/dev/null 2>&1; then
exit 1
fi
if ! dkp-pacman -Q switch-dev >/dev/null 2>&1; then
echo "error: switch-dev is not installed (needed for nacptool/elf2nro)." >&2
echo " sudo dkp-pacman -S switch-dev" >&2
echo "Then re-run: bash scripts/switch/install_devkitpro_deps.sh" >&2
exit 1
fi
echo "==> DEVKITPRO=$DEVKITPRO"
# Named packages only (avoid interactive switch-dev group member prompt).
# ZIP reading uses switch-zziplib (dkp has no minizip port for Switch).
dkp-pacman -Sy --noconfirm --needed \
switch-curl \
switch-mbedtls \
switch-zlib \
switch-zziplib
dkp-pacman -Sy --noconfirm --needed "${OTA_LAUNCHER_PKGS[@]}"
echo "==> installed packages:"
dkp-pacman -Q | grep -E 'switch-(curl|mbedtls|zlib|zziplib|tools)|libnx|devkitA64' || true
+41 -11
View File
@@ -51,17 +51,17 @@ MISSING=""
printf '%s' "$HELP_LC" | grep -q 'fetch' || MISSING="${MISSING} fetch"
printf '%s' "$HELP_LC" | grep -q 'loose' || MISSING="${MISSING} loose"
printf '%s' "$HELP_LC" | grep -q 'fused' || MISSING="${MISSING} fused"
printf '%s' "$HELP_LC" | grep -q 'ota' || MISSING="${MISSING} ota"
printf '%s' "$HELP_LC" | grep -Eq 'devkitpro' || MISSING="${MISSING} DEVKITPRO"
printf '%s' "$HELP_LC" | grep -Eq 'auto-download|downloads' || MISSING="${MISSING} auto-download"
printf '%s' "$HELP_LC" | grep -Eq 'non-goal|does not|never' || MISSING="${MISSING} non-goals"
if [ -z "$MISSING" ]; then
ok "build_switch.sh --help mentions fetch, loose, fused, ota (+ auto-download/non-goals)"
ok "build_switch.sh --help mentions fetch, loose, fused, DEVKITPRO (+ auto-download/non-goals)"
else
bad "build_switch.sh --help missing:$MISSING"
fi
# ---------------------------------------------------------------------------
# 3. XOR --loose --fused / --ota exits non-zero
# 3. XOR --loose --fused exits non-zero
# ---------------------------------------------------------------------------
XOR_RC=0
"$ROOT/scripts/build_switch.sh" --loose --fused >/dev/null 2>&1 || XOR_RC=$?
@@ -70,13 +70,6 @@ if [ "$XOR_RC" -ne 0 ]; then
else
bad "build_switch.sh --loose --fused should exit non-zero"
fi
XOR_OTA_RC=0
"$ROOT/scripts/build_switch.sh" --fused --ota >/dev/null 2>&1 || XOR_OTA_RC=$?
if [ "$XOR_OTA_RC" -ne 0 ]; then
ok "build_switch.sh --fused --ota exits non-zero ($XOR_OTA_RC)"
else
bad "build_switch.sh --fused --ota should exit non-zero"
fi
# ---------------------------------------------------------------------------
# 4. assemble_loose without pin → stderr contains --fetch
@@ -188,7 +181,41 @@ else
fi
# ---------------------------------------------------------------------------
# 5c. fail_fused_toolchain mentions docs/switch-build.md
# 5c2. fail_missing_devkitpro cites install_devkitpro_deps.sh
# ---------------------------------------------------------------------------
MDK_ERR="$STAGING/missing-dkp.err"
MDK_RC=0
(
. "$SCRIPT_DIR/common.sh"
fail_missing_devkitpro
) >"$STAGING/missing-dkp.out" 2>"$MDK_ERR" || MDK_RC=$?
if [ "$MDK_RC" -ne 0 ] \
&& grep -q 'install_devkitpro_deps.sh' "$MDK_ERR" \
&& grep -q 'DEVKITPRO' "$MDK_ERR" \
&& grep -q 'switch-dev' "$MDK_ERR"; then
ok "fail_missing_devkitpro cites DEVKITPRO + switch-dev + install_devkitpro_deps.sh"
else
bad "fail_missing_devkitpro should cite setup steps (rc=$MDK_RC err=$(cat "$MDK_ERR"))"
fi
OTA_ERR="$STAGING/missing-ota.err"
OTA_RC=0
(
. "$SCRIPT_DIR/common.sh"
fail_missing_ota_deps
) >"$STAGING/missing-ota.out" 2>"$OTA_ERR" || OTA_RC=$?
if [ "$OTA_RC" -ne 0 ] \
&& grep -q 'install_devkitpro_deps.sh' "$OTA_ERR" \
&& grep -qi 'docker' "$OTA_ERR"; then
ok "fail_missing_ota_deps cites native or Docker options"
else
bad "fail_missing_ota_deps should cite native + Docker (rc=$OTA_RC err=$(cat "$OTA_ERR"))"
fi
# ---------------------------------------------------------------------------
# 5d. fail_fused_toolchain mentions docs/switch-build.md
# ---------------------------------------------------------------------------
FT_ERR="$STAGING/fused-toolchain.err"
FT_RC=0
@@ -365,6 +392,9 @@ else
fi
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" ]
then
ok "native OTA launcher sources + build_ota_launcher.sh present"
+11 -3
View File
@@ -529,12 +529,15 @@ test('AC-010: Fonte do launcher e Makefile DEVKITPRO existem @spec:AC-010', () =
assert.match(read('native/switch-ota-launcher/src/ota_fs.c'), /ota_fs_atomic_replace_nro/);
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, /switch-curl/);
assert.match(buildDoc, /--ota|install_devkitpro_deps/);
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');
assert.match(readme, /DEVKITPRO|devkitPro/i);
@@ -555,11 +558,16 @@ test('AC-011: Empacotamento dual-NRO e selftest @spec:AC-011', () => {
);
const buildSwitch = read('scripts/build_switch.sh');
assert.match(buildSwitch, /--ota/);
assert.doesNotMatch(buildSwitch, /--ota\b/);
assert.doesNotMatch(buildSwitch, /pack_ota_zip\.sh/);
assert.match(buildSwitch, /build_ota_launcher\.sh/);
assert.match(buildSwitch, /dual-NRO SD zip|OTA download asset/i);
const buildOtaLauncher = read('scripts/switch/build_ota_launcher.sh');
assert.match(buildOtaLauncher, /ota_launcher_deps_ready/);
assert.match(buildOtaLauncher, /fail_missing_devkitpro/);
assert.match(buildSwitch, /preflight_fused_build/);
const selftest = read('scripts/switch/selftest_build_switch.sh');
assert.match(selftest, /dual-NRO|gen1recomp-game\.nro/);
assert.match(selftest, /ota_launcher\.manifest/);