mirror of
https://gitcode.com/JianFeeeee/ModelRouter.git
synced 2026-09-19 16:39:15 +00:00
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.
This commit is contained in:
@ -1,11 +1,20 @@
|
||||
# ModelRouter GUI Windows builder
|
||||
# Self-sufficient cross-compilation environment for the embedded llmsproxy core.
|
||||
# Produces llmsproxy.exe (Go, windows/amd64, luajit tag) + lua51.dll (LuaJIT mingw build)
|
||||
# inside a mounted workspace: cmd/gui/bin/{llmsproxy.exe,lua51.dll}
|
||||
# Self-sufficient cross-compilation environment for the embedded llmsproxy core
|
||||
# AND for packaging the Windows NSIS installer.
|
||||
#
|
||||
# Produces inside a mounted workspace:
|
||||
# - llmsproxy.exe (Go, windows/amd64, luajit tag) + lua51.dll
|
||||
# - ModelRouter Setup <ver>.exe (electron-builder --win nsis; requires wine
|
||||
# so the uninstaller is generated — set USE_SYSTEM_WINE=true)
|
||||
#
|
||||
# Build: docker build -t modelrouter/win-builder cmd/gui/docker/win-builder
|
||||
# Usage: make gui-win-docker (or cmd/gui/scripts/dist-win-docker.sh)
|
||||
#
|
||||
# This image is the SINGLE wine provider for the NSIS step, so a host that has
|
||||
# no / broken wine (e.g. amd64-only Debian: no syswow64 -> c0000135) can still
|
||||
# produce a real installer. The NSIS step MUST run inside this image; running it
|
||||
# on the host was how the 1.3.0 264 KB degenerate exe got shipped.
|
||||
#
|
||||
# LuaJIT source is fetched from gitcode.com (CN-reachable mirror) with github
|
||||
# fallback; pass --build-arg LUAJIT_REPO to override.
|
||||
|
||||
@ -13,11 +22,24 @@ FROM golang:1.25
|
||||
|
||||
ARG LUAJIT_REPO=https://gitcode.com/openresty/luajit2.git
|
||||
|
||||
RUN apt-get update -qq \
|
||||
# i386 arch is required for wine32 (the NSIS uninstaller step runs a win32 exe
|
||||
# through wine's wow64 path, which needs the 32-bit runtime under /usr/lib/i386).
|
||||
RUN dpkg --add-architecture i386 \
|
||||
&& apt-get update -qq \
|
||||
&& DEBIAN_FRONTEND=noninteractive apt-get install -y -qq \
|
||||
gcc-mingw-w64-x86-64 make ca-certificates git \
|
||||
# NSIS step needs node + the electron-builder toolchain
|
||||
nodejs npm \
|
||||
# wine (32+64) for generating the NSIS uninstaller
|
||||
wine64 wine32:i386 \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# electron-builder resolves the uninstaller via the system wine when
|
||||
# USE_SYSTEM_WINE=true (or by default on Linux without a toolset). Pin it.
|
||||
ENV USE_SYSTEM_WINE=true
|
||||
ENV WINEDEBUG=-all
|
||||
ENV ELECTRON_BUILDER_CACHE=/workspace/cmd/gui/.cache
|
||||
|
||||
# LuaJIT cross-compiled for Windows; keeps lua51.dll and the cgo import lib
|
||||
# (libluajit-5.1.dll.a -> libluajit-5.1.a in the mingw lib dir).
|
||||
# NOTE: $LUAJIT_REPO deliberately unquoted in "sh -c" — quoting the ARG would
|
||||
|
||||
@ -1,23 +1,64 @@
|
||||
#!/usr/bin/env bash
|
||||
# One-shot Windows release build for the GUI:
|
||||
# One-shot Windows release build for the GUI — ENTIRELY inside docker.
|
||||
#
|
||||
# 1) cross-compile the embedded core in docker (llmsproxy.exe + lua51.dll)
|
||||
# 2) host-side electron-builder NSIS packaging (wine required on host)
|
||||
# 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)"
|
||||
cd "$ROOT/cmd/gui"
|
||||
IMAGE="${WIN_BUILDER_IMAGE:-modelrouter/win-builder}"
|
||||
PROXY="${GOPROXY:-https://goproxy.cn,direct}"
|
||||
CACHE_VOL="modelrouter-eb-cache"
|
||||
|
||||
# 1) core (docker)
|
||||
"$ROOT/cmd/gui/scripts/win-core-docker.sh"
|
||||
command -v docker >/dev/null || { echo "docker required"; exit 1; }
|
||||
|
||||
# 2) packaging (host, needs wine for electron-builder's signtool/nsis)
|
||||
command -v wine >/dev/null || { echo "wine required on host for NSIS packaging"; exit 1; }
|
||||
if ! command -v npx >/dev/null; then echo "node/npm required"; exit 1; fi
|
||||
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
|
||||
|
||||
echo "[dist-win] electron-builder --win nsis ..."
|
||||
# bin artifacts already refreshed by win-core-docker.sh; skip the prepare step
|
||||
npx electron-builder --win nsis
|
||||
docker volume create "$CACHE_VOL" >/dev/null 2>&1 || true
|
||||
|
||||
ls -la "$ROOT/cmd/build/gui-dist/"*.exe 2>/dev/null
|
||||
echo "[dist-win] done"
|
||||
# 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"
|
||||
Reference in New Issue
Block a user