#!/usr/bin/env bash # compile-windows.sh — build Flutter Windows desktop app, package into # dist/ via the existing Inno Setup script (client/windows/installer/pangolin.iss). # # Mirrors ~/code/jiu/scripts/ci/compile-windows.sh's short-path fix, adapted: # - version derived via pangolin's ver_from_tag, not jiu's ad-hoc strip. # - pangolin's Windows client does NOT embed libbox — it bundles a # downloaded sing-box.exe + wintun.dll as a subprocess (see # client/windows/README.md, CLAUDE.md "client/ 移动端"'s sibling desktop # note). Those are fetched by app/kernel/fetch-desktop-bin.sh, NOT built # by scripts/build-libbox.sh — no JDK/NDK/gomobile needed on Windows. # - pangolin already has a working local packaging path: # client/windows/build.ps1 + client/windows/installer/pangolin.iss. This # script re-implements that flow in bash (matching the repo's # jiu-mirrored bash-script-per-platform convention) rather than shelling # out to build.ps1, so it can apply jiu's short-path fix below. # - jiu's short-path fix: the Forgejo Windows runner checks out under # C:\Windows\System32\config\systemprofile\.cache\act\...\hostexecutor, # which triggers WOW64 filesystem redirection that breaks CMake/Flutter # native paths. jiu copies client/ to C:\jiu-build\client and builds # there. pangolin's windows/CMakeLists.txt additionally resolves the # kernel binaries via a path RELATIVE to CMAKE_SOURCE_DIR # (client/windows/../../app/kernel/dist/desktop/windows-* — see # client/windows/CMakeLists.txt "Pangolin sing-box kernel" section), so # this script must copy app/kernel/dist alongside client/ preserving the # SAME relative layout (BUILD_ROOT/client + BUILD_ROOT/app/kernel/dist), # not just client/ alone like jiu does — jiu has no such cross-directory # kernel reference. # - dart-define is PANGOLIN_API_URL, not jiu's BASE_URL/PUBLIC_URL/APP_VERSION. # - pangolin.iss hardcodes `#define MyAppVersion "1.0.47"` (no #ifndef guard # like jiu's jiu-installer.iss), so ISCC's /D command-line override would # be silently ignored. This script `sed`s the version into the copied # .iss file instead of passing /DAppVer. # - output dist/pangolin-windows-x64-setup.exe (stable name — the .iss's # own OutputBaseFilename is version-suffixed "pangolin-setup-.exe", # so this script copies+renames it to the stable name deploy-client.sh # and release-client.sh expect). # - unsigned (like jiu) — first install shows a SmartScreen warning; no # code-signing cert configured (see report). set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=scripts/ci/_env.sh . "${SCRIPT_DIR}/_env.sh" TAG="${1:?usage: compile-windows.sh }" ver_file="/tmp/compile_windows_ver.$$" ver_from_tag client "$TAG" > "$ver_file" VER="" read -r VER < "$ver_file" || true # 无结尾换行的 read 退出码,见 compile-android.sh 同注释 rm -f "$ver_file" echo "==> compile-windows: tag=${TAG} version=${VER}" API_URL="${PANGOLIN_API_URL:-https://api.yanmeiai.com}" # ── [1/4] fetch sing-box.exe + wintun.dll into the ORIGINAL checkout ─────── # Must run before the short-path copy below (step 2), so app/kernel/dist/ # exists to be copied alongside client/. echo "==> compile-windows: fetching sing-box.exe + wintun.dll" bash app/kernel/fetch-desktop-bin.sh windows amd64 # ── [2/4] copy client/ + app/kernel/dist to a short path ─────────────────── BUILD_ROOT="/c/pangolin-build" BUILD_CLIENT="${BUILD_ROOT}/client" echo "==> copying client/ + app/kernel/dist to ${BUILD_ROOT}" rm -rf "$BUILD_ROOT" mkdir -p "${BUILD_ROOT}/app/kernel" cp -r client "$BUILD_CLIENT" cp -r app/kernel/dist "${BUILD_ROOT}/app/kernel/dist" # `cp -r` turns Flutter's plugin symlinks (windows/flutter/ephemeral/.plugin_symlinks/*) # into real directories. flutter's createPluginSymlinks only cleans up *symlinks*, so it # then fails to create a symlink over the copied real dir (errno 183 / PathExists). # Drop all regenerable artifacts so the build below recreates them cleanly (same fix as jiu). rm -rf "${BUILD_CLIENT}/windows/flutter/ephemeral" \ "${BUILD_CLIENT}/.dart_tool" \ "${BUILD_CLIENT}/build" # ── [3/4] build ────────────────────────────────────────────────────────────── # NOTE(controller): `flutter create` on an existing project only fills in # scaffolding it manages (ephemeral/, generated_plugins.cmake, ...) and should # not overwrite files that already exist — jiu relies on exactly this. But # pangolin's windows/ tree is more heavily customized than jiu's (CMakeLists # kernel-bundling block, runner.exe.manifest requireAdministrator + the # /MANIFESTUAC:NO link flag — see client/windows/README.md "已知坑"). Verify # on first real CI run that none of those get clobbered. pushd "$BUILD_CLIENT" > /dev/null flutter create --platforms=windows . --project-name pangolin_vpn flutter build windows --release "--dart-define=PANGOLIN_API_URL=${API_URL}" popd > /dev/null # ── [4/4] package with Inno Setup (existing client/windows/installer/pangolin.iss) ── ISCC="" for c in "/c/Program Files (x86)/Inno Setup 6/ISCC.exe" "/c/Program Files/Inno Setup 6/ISCC.exe"; do if [ -f "$c" ]; then ISCC="$c"; break; fi done if [ -z "$ISCC" ]; then echo "ERROR: Inno Setup (ISCC) not found. Install Inno Setup 6 on this runner first." >&2 exit 1 fi ISS="${BUILD_CLIENT}/windows/installer/pangolin.iss" # pangolin.iss hardcodes MyAppVersion (no #ifndef guard) — sed it to match the # release tag rather than relying on an ISCC /D override (which would be # shadowed by the unconditional #define — see header note above). sed -i "s/^#define MyAppVersion .*/#define MyAppVersion \"${VER}\"/" "$ISS" echo "==> building installer with Inno Setup (version ${VER})" # MSYS_NO_PATHCONV / MSYS2_ARG_CONV_EXCL disable Git Bash's automatic conversion # of paths, matching jiu's ISCC invocation fix. MSYS_NO_PATHCONV=1 MSYS2_ARG_CONV_EXCL='*' "$ISCC" "$ISS" # pangolin.iss has no explicit OutputDir -> Inno defaults to {src}\Output # (relative to the .iss file), filename OutputBaseFilename=pangolin-setup-. mkdir -p dist SETUP_SRC="C:\\pangolin-build\\client\\windows\\installer\\Output\\pangolin-setup-${VER}.exe" echo "==> copying installer -> dist/pangolin-windows-x64-setup.exe" powershell -NoProfile -Command \ "Copy-Item '${SETUP_SRC}' 'dist\\pangolin-windows-x64-setup.exe' -Force" echo "==> compile-windows: done — dist/ contents:" ls -lh dist/