Files
ModelRouter/cmd/gui/scripts/dist-win-docker.sh
JianFeeeee 3698546d14 fix(build): run Windows NSIS packaging inside docker; add artifact size gate
The Windows installer has been broken since 1.3.0: electron-builder's NSIS step
needs wine to generate the uninstaller, but the host's wine was amd64-only (no
i386 runtime -> empty syswow64 -> `error c0000135`), so electron-builder silently
wrote a 264 KB installer shell with no payload. No check caught it and the broken
exe shipped. 1.4.0 reproduced the same failure this session.

Two fixes:

1. win-builder image gains node + wine32/wine64 (+ i386 arch). dist-win-docker.sh
   now runs BOTH the core cross-build and `npx electron-builder --win nsis`
   inside docker (USE_SYSTEM_WINE=true -> the image's wine). The wine prefix is
   initialized on first run in the shared cache volume, so syswow64/ntdll.dll
   exists - the exact thing the host lacked. The host needs no mingw/wine/node.

2. packaging/verify-dist.sh: a size-floor gate for GUI artifacts (exe >= 5 MB,
   deb/rpm/nsis.7z >= 10 MB). Wired into `make gui-dist` and `make gui-win-docker`
   and the dist-win-docker script, so a degenerate installer fails the build
   instead of reaching a Release. Verified: it rejects the 264 KB exe and passes
   the healthy artifacts.
2026-08-30 10:49:45 +08:00

64 lines
2.8 KiB
Bash
Executable File

#!/usr/bin/env bash
# One-shot Windows release build for the GUI — ENTIRELY inside docker.
#
# 1) cross-compile the embedded core in docker (llmsproxy.exe + lua51.dll)
# 2) electron-builder NSIS packaging ALSO inside docker (wine for the
# uninstaller step lives in the image — see Dockerfile). This is the fix
# for the 1.3.0/1.4.0 broken installers: the host had amd64-only wine
# (no syswow64 -> c0000135), which made electron-builder silently emit a
# 264 KB degenerate exe without its 86 MB payload.
#
# Outputs: cmd/build/gui-dist/"ModelRouter Setup <version>.exe"
# cmd/build/gui-dist/modelrouter-gui-<version>-x64.nsis.7z
#
# Needs: docker (any machine; no host mingw/wine/node required)
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
IMAGE="${WIN_BUILDER_IMAGE:-modelrouter/win-builder}"
PROXY="${GOPROXY:-https://goproxy.cn,direct}"
CACHE_VOL="modelrouter-eb-cache"
command -v docker >/dev/null || { echo "docker required"; exit 1; }
if ! docker image inspect "$IMAGE" >/dev/null 2>&1; then
echo "[dist-win-docker] building image $IMAGE (first run, ~5-10 min)..."
docker build -t "$IMAGE" "$ROOT/cmd/gui/docker/win-builder"
fi
docker volume create "$CACHE_VOL" >/dev/null 2>&1 || true
# 1) embedded core + 2) NSIS packaging — both inside the image so wine and node
# are the image's, never the host's. electron-builder downloads electron + nsis
# toolchains into ~/.cache on first run; the mounted volume keeps that warm so
# subsequent builds are incremental instead of re-fetching ~400 MB.
echo "[dist-win-docker] cross-compiling core + electron-builder NSIS in docker ..."
docker run --rm \
-v "$ROOT":/workspace \
-v "$CACHE_VOL":/root/.cache \
-e GOPROXY="$PROXY" \
-w /workspace \
"$IMAGE" bash -c '
set -euo pipefail
cp /opt/luajit2/src/lua51.dll /workspace/cmd/gui/bin/lua51.dll
GOOS=windows GOARCH=amd64 CGO_ENABLED=1 CC=x86_64-w64-mingw32-gcc \
go build -buildvcs=false -tags luajit -trimpath \
-o /workspace/cmd/gui/bin/llmsproxy.exe ./cmd/llmsproxy
echo " -> core built"
# wine needs one prefix initialization so its wow64 runtime (syswow64/ntdll)
# exists — the exact thing that was missing on the broken host. Use a shared
# prefix in the cache volume so it is initialized only on the first run.
export WINEPREFIX=/root/.cache/wineprefix
if [ ! -f "$WINEPREFIX/drive_c/windows/syswow64/ntdll.dll" ]; then
echo " -> initializing wine prefix (first run)"
WINEDEBUG=-all wineboot -i || true
fi
cd /workspace/cmd/gui
# node_modules ships in the repo (host npm install already ran); reuse it.
npx electron-builder --win nsis
'
echo "[dist-win-docker] verifying artifacts ..."
"$ROOT/packaging/verify-dist.sh" "$ROOT/cmd/build/gui-dist"
echo "[dist-win-docker] done"