#!/bin/bash # ============================================================ # OpenDance Studio —— Windows 客户端发布打包(T-WIN-014) # # 产物(文档 §5.3 / §5.7): # opendance-windows-vX.Y.Z.zip ← **单个完整包,禁止 .partN 分卷** # SHA256SUMS ← 裸文件名,下载目录内 sha256sum -c 直接可用 # # 包内结构: # opendance-windows-vX.Y.Z/ # OpenDance.exe # OpenDance.pck # THIRD_PARTY.md # README.txt README.md # contracts/ # # 为什么强调"单个完整包":本项目的 Gitea 前置 IIS 默认 # maxAllowedContentLength = 30,000,000 字节(≈28.6 MiB), # 30.5 MB / 40 MB 的上传实测直接 HTTP 413。当时的应对是把整包拆成 # zip.part0/1/2(每卷 13 MiB)——这正是"分卷有问题"的根因: # 用户拿到的是无法直接解压的碎片,还要自己拼接。 # 现在改为:整包上传;若超过上限则**直接报错退出**,并提示运维放宽 # IIS/ARR 上限(做法见 opendance-web/deploy/proxy/README.md), # 绝不静默退回分卷。 # # 用法:bash build/package-release.sh [版本号] # ============================================================ set -euo pipefail PROJECT_DIR="$(cd "$(dirname "$0")/.." && pwd)" cd "$PROJECT_DIR" VERSION="${1:-$(sed -n 's/^version:[[:space:]]*//p' project.yaml | head -1)}" VERSION="${VERSION:-0.2.0}" NAME="opendance-windows-v${VERSION}" OUT_DIR="$PROJECT_DIR/dist-release" STAGE="$OUT_DIR/$NAME" # Gitea 前置 IIS 的实测上传上限(文档 §5.7 实测结论) UPLOAD_LIMIT_BYTES=30000000 log() { printf '\033[1;34m[package]\033[0m %s\n' "$*"; } warn() { printf '\033[1;33m[warn]\033[0m %s\n' "$*" >&2; } die() { printf '\033[1;31m[error]\033[0m %s\n' "$*" >&2; exit 1; } # ---- 0. 版本号一致性(文档 §11.2:产物名 / tag / 界面展示必须一致)---- bash "$PROJECT_DIR/build/check-version.sh" "$VERSION" || die "版本一致性校验失败,先统一 project.godot / project.yaml / 发布版本号" EXE="$PROJECT_DIR/build/windows/OpenDance.exe" PCK="$PROJECT_DIR/build/windows/OpenDance.pck" [ -f "$EXE" ] || die "未找到 $EXE,请先执行 bash build/export-windows.sh release" [ -f "$PCK" ] || die "未找到 $PCK,请先执行 bash build/export-windows.sh release" # ---- 1. 源产物自检:PE 头 + pck 魔数 ---- MAGIC=$(head -c 2 "$EXE" | od -An -tx1 | tr -d ' \n') [ "$MAGIC" = "4d5a" ] || die "$EXE 不是合法的 Windows PE 文件(头 $MAGIC)" PCK_MAGIC=$(head -c 4 "$PCK" | tr -d '\0') [ "$PCK_MAGIC" = "GDPC" ] || die "$PCK 不是合法的 Godot 资源包(头 '$PCK_MAGIC')" log "源产物校验通过:exe PE 头 MZ | pck 头 GDPC" # 产物 exe 的 PE 版本资源必须是本次发布版本 —— Windows「属性 → 详细信息」显示的就是它。 # v0.2.1 曾带着 0.1.0 发出去(导出预设里是硬编码的旧值,且没有任何环节复核产物)。 bash "$PROJECT_DIR/build/check-pe-version.sh" "$EXE" "$VERSION" \ || die "$EXE 的 PE 版本资源不是 v$VERSION;先跑 bash build/sync-export-version.sh $VERSION 再重新导出" log "产物 PE 版本资源校验通过(=$VERSION)" # ---- 2. 整理产物 ---- log "整理产物到 $STAGE …" rm -rf "$STAGE" mkdir -p "$STAGE" cp "$EXE" "$STAGE/OpenDance.exe" cp "$PCK" "$STAGE/OpenDance.pck" cp THIRD_PARTY.md README.txt "$STAGE/" if [ -f README.md ]; then cp README.md "$STAGE/"; fi cp -r contracts "$STAGE/contracts" # ---- 3. 打包(单个完整包) ---- ZIP="$OUT_DIR/$NAME.zip" # 清理历史分卷,避免 old .partN 被误当成本次产物上传 rm -f "$OUT_DIR/$NAME.zip".part* "$OUT_DIR/$NAME.zip" "$OUT_DIR/SHA256SUMS"* # 压缩方式:默认 deflate(Windows 资源管理器可直接解压)。 # ZIP_METHOD=lzma 时改用 LZMA —— 包体从约 38 MB 降到约 26 MB,可绕过 # 「Gitea 站点 IIS 的 maxAllowedContentLength = 30,000,000 字节」这道闸 # (见 opendance-web/deploy/proxy/README.md 第九节)。 # **代价**:Windows 10 的资源管理器不支持 LZMA(method 14) 的 zip,用户必须用 # 7-Zip / WinRAR / PeaZip 解压(Win11 24H2+ 起资源管理器原生支持 7z/zip 变体, # 但本项目未在 Windows 上实测)。因此只有在 IIS 上限确实无法放开时才用 LZMA。 ZIP_METHOD="${ZIP_METHOD:-deflate}" log "生成单个完整包 $NAME.zip(压缩方式:$ZIP_METHOD)…" case "$ZIP_METHOD" in deflate) ( cd "$OUT_DIR" && zip -qr "$NAME.zip" "$NAME" ) ;; lzma) command -v 7z >/dev/null 2>&1 || die "ZIP_METHOD=lzma 需要 7z(Debian/Ubuntu: apt install p7zip-full)" ( cd "$OUT_DIR" && rm -f "$NAME.zip" && 7z a -tzip -mm=LZMA -mx=9 "$NAME.zip" "$NAME" >/dev/null ) ;; *) die "未知 ZIP_METHOD=$ZIP_METHOD(可选:deflate / lzma)" ;; esac # LZMA 包额外做一次完整性测试与解压自检(zip/unzip 对 method 14 支持不一致) if [ "$ZIP_METHOD" = "lzma" ]; then 7z t "$ZIP" >/dev/null || die "LZMA 包完整性测试失败(7z t)" log "LZMA 包完整性测试通过(7z t)" fi # ---- 4. 完整性自检:解压后必须含 exe + pck(同目录)且 exe 仍是合法 PE ---- CHECK_DIR=$(mktemp -d) trap 'rm -rf "$CHECK_DIR"' EXIT if [ "$ZIP_METHOD" = "lzma" ]; then 7z x -y -o"$CHECK_DIR" "$ZIP" >/dev/null else unzip -q "$ZIP" -d "$CHECK_DIR" fi [ -f "$CHECK_DIR/$NAME/OpenDance.exe" ] || die "包内缺少 OpenDance.exe" [ -f "$CHECK_DIR/$NAME/OpenDance.pck" ] || die "包内缺少 OpenDance.pck(必须与 exe 同目录)" [ -f "$CHECK_DIR/$NAME/README.txt" ] || die "包内缺少 README.txt" [ -f "$CHECK_DIR/$NAME/THIRD_PARTY.md" ] || die "包内缺少 THIRD_PARTY.md" [ -d "$CHECK_DIR/$NAME/contracts" ] || die "包内缺少 contracts/ 契约快照" CHECK_MAGIC=$(head -c 2 "$CHECK_DIR/$NAME/OpenDance.exe" | od -An -tx1 | tr -d ' \n') [ "$CHECK_MAGIC" = "4d5a" ] || die "解压后的 OpenDance.exe 不是合法 PE 文件(头 $CHECK_MAGIC)" CHECK_PCK=$(head -c 4 "$CHECK_DIR/$NAME/OpenDance.pck" | tr -d '\0') [ "$CHECK_PCK" = "GDPC" ] || die "解压后的 OpenDance.pck 不是合法 Godot 资源包" log "整包完整性自检通过(解压后 exe + pck 同目录,PE/GDPC 头均合法)" # 再核一次**解压后**的 exe 版本资源:确认打包/解包环节没有换错文件 bash "$PROJECT_DIR/build/check-pe-version.sh" "$CHECK_DIR/$NAME/OpenDance.exe" "$VERSION" \ || die "包内 exe 的 PE 版本资源不是 v$VERSION" log "包内 exe 的 PE 版本资源 = v$VERSION" # pck 与 exe 必须同名同目录,否则 Godot 找不到资源 [ "$(basename "$CHECK_DIR/$NAME/OpenDance.exe" .exe)" = "$(basename "$CHECK_DIR/$NAME/OpenDance.pck" .pck)" ] \ || die "exe 与 pck 主文件名不一致,导出产物不可运行" # ---- 5. SHA256SUMS(裸文件名,下载目录内可直接校验) ---- ( cd "$OUT_DIR" && sha256sum "$NAME.zip" > SHA256SUMS ) log "已生成 $OUT_DIR/SHA256SUMS" # ---- 6. 体积与上传上限对比 ---- SIZE_BYTES=$(stat -c %s "$ZIP") SIZE_HUMAN=$(du -h "$ZIP" | cut -f1) log "包体 $SIZE_HUMAN($SIZE_BYTES 字节)| Gitea/IIS 实测上限 $UPLOAD_LIMIT_BYTES 字节" if [ "$SIZE_BYTES" -gt "$UPLOAD_LIMIT_BYTES" ]; then warn "整包超过当前 Gitea 前置 IIS 的上传上限,上传会返回 HTTP 413。" warn "请让运维放宽上限后重传(做法见 opendance-web/deploy/proxy/README.md):" warn " IIS requestFiltering/requestLimits@maxAllowedContentLength = 268435456" warn " ARR maxRequestBytes >= 268435456" warn " Gitea app.ini [attachment] MAX_SIZE >= 256MB" warn " nginx(若前置)client_max_body_size 256m;" warn "本脚本**不会**回退为 .partN 分卷——分卷包无法直接解压,是历史缺陷。" warn "若暂时无法放开 IIS 上限,可用 ZIP_METHOD=lzma 重跑本脚本:包体约 26 MB 可绕过 30 MB 闸," warn "但 Windows 10 资源管理器不能直接解压 LZMA zip,必须用 7-Zip / WinRAR(README 中已注明)。" else log "低于上限,可直接作为 Release 资产上传。" fi echo "" echo "产物:" echo " $ZIP" echo " $OUT_DIR/SHA256SUMS" if ( cd "$OUT_DIR" && sha256sum -c SHA256SUMS --status ); then echo " sha256 校验:OK" else die "sha256 自校验失败" fi echo "" if [ "$ZIP_METHOD" = "lzma" ]; then 7z l "$ZIP" | tail -14 else unzip -l "$ZIP" | sed -n '3,14p' fi echo "" echo "分发:上传 $NAME.zip 与 SHA256SUMS 两个资产;用户下载后" echo " sha256sum -c SHA256SUMS && unzip $NAME.zip 即可直接运行 OpenDance.exe。" echo "" echo "下一步(文档 §7.5:每次发布都要有一条读产物本身的验收):" echo " GODOT_BIN=/path/to/godot bash build/accept-release.sh $ZIP"