Files
pangolin/app/kernel/fetch-desktop-bin.sh
T
wangjia 618332906c feat(kernel): 搭建 app/kernel/ 构建管线 (AAR/XCFramework/桌面二进制)
新增 app/kernel/ 目录,包含四个文件:

- VERSION: 固定三个锚点 — sing-box v1.13.12、Go 1.24.3、
  gomobile v0.0.0-20240604150348-70c4c5da7d30;禁止脚本内硬编码

- build-android.sh: gomobile bind → dist/android/libbox.aar
  targets: arm64-v8a / armeabi-v7a / x86_64,-androidapi 21
  build tags: with_quic,with_utls,with_clash_api,with_gvisor(对齐 SFA)
  裁剪注释保留,幂等+--force 支持

- build-ios.sh: gomobile bind → dist/ios/Libbox.xcframework
  targets: ios + iossimulator(device+sim 双 slice)
  build tags 对齐 SFI;含 iOS NE 内存上限敏感说明(裁 grpc/gvisor 指引)

- fetch-desktop-bin.sh: 从 GitHub Release 下载桌面二进制
  支持 linux/darwin/windows × amd64/arm64
  从官方 checksums.txt 做 SHA256 校验;Windows 额外取 wintun.dll
  幂等:产物+校验文件均存在则跳过

dist/ 和 .build/ 加入 gitignore;所有脚本通过 shellcheck -S warning

任务: tsk_d8KmVEzJTCjl

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-13 14:30:56 +08:00

245 lines
11 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env bash
# fetch-desktop-bin.sh — 从 sing-box GitHub Release 下载桌面平台二进制
#
# 用法: ./fetch-desktop-bin.sh <os> <arch> [--force]
# os : linux | darwin | windows
# arch : amd64 | arm64
# --force 忽略已有产物,强制重新下载
#
# 产物目录: dist/desktop/<os>-<arch>/
# Linux/macOS : sing-box
# Windows : sing-box.exe + wintun.dll
#
# SHA256 校验: 从官方 Release 下载 checksums.txt 后逐项验证。
# 校验通过后,checksums.txt 缓存于产物目录,可离线复核。
#
# Wintun (Windows 专用):
# 版本由 VERSION 中 WINTUN_VERSION 控制。
# 从 https://www.wintun.net/builds/wintun-<ver>.zip 下载,
# 校验 zip 的 SHA256(见下方 WINTUN_SHA256 变量),
# 提取对应 arch 的 wintun.dll 到产物目录。
#
# 幂等: 产物已存在且 SHA256 校验通过则跳过下载(传 --force 强制重下)
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# ── 加载版本锚点 ─────────────────────────────────────────────────────────────
# shellcheck source=VERSION
. "${SCRIPT_DIR}/VERSION"
# ── Wintun ZIP SHA256(对应 WINTUN_VERSION=0.14.1)─────────────────────────
# 更新 WINTUN_VERSION 时须同步更新此值:
# curl -sL https://www.wintun.net/builds/wintun-<ver>.zip | sha256sum
WINTUN_SHA256="90a6c2a17e62685b571c9afc2d5a6e7dc59c74d3fde3ad66b4ab4e2e4b0d649a"
# ── 参数解析 ─────────────────────────────────────────────────────────────────
if [[ $# -lt 2 ]]; then
printf 'Usage: %s <os> <arch> [--force]\n' "$0" >&2
printf ' os : linux | darwin | windows\n' >&2
printf ' arch: amd64 | arm64\n' >&2
exit 1
fi
TARGET_OS="$1"
TARGET_ARCH="$2"
FORCE=false
shift 2
for arg in "$@"; do
case "${arg}" in
--force) FORCE=true ;;
*) printf 'Unknown argument: %s\n' "${arg}" >&2; exit 1 ;;
esac
done
# ── 参数验证 ─────────────────────────────────────────────────────────────────
case "${TARGET_OS}" in
linux|darwin|windows) ;;
*) printf '✗ 不支持的 OS: %s(支持: linux | darwin | windows\n' "${TARGET_OS}" >&2; exit 1 ;;
esac
case "${TARGET_ARCH}" in
amd64|arm64) ;;
*) printf '✗ 不支持的 arch: %s(支持: amd64 | arm64\n' "${TARGET_ARCH}" >&2; exit 1 ;;
esac
# ── 路径与文件名配置 ─────────────────────────────────────────────────────────
DIST_DIR="${SCRIPT_DIR}/dist/desktop/${TARGET_OS}-${TARGET_ARCH}"
CACHE_DIR="${SCRIPT_DIR}/.build/cache"
VERSION_BARE="${SINGBOX_VERSION#v}" # 去掉前缀 v(如 v1.13.12 → 1.13.12
if [[ "${TARGET_OS}" == "windows" ]]; then
ARCHIVE_EXT="zip"
BIN_NAME="sing-box.exe"
else
ARCHIVE_EXT="tar.gz"
BIN_NAME="sing-box"
fi
ARCHIVE_STEM="sing-box-${VERSION_BARE}-${TARGET_OS}-${TARGET_ARCH}"
ARCHIVE_FILE="${ARCHIVE_STEM}.${ARCHIVE_EXT}"
GITHUB_BASE="https://github.com/SagerNet/sing-box/releases/download/${SINGBOX_VERSION}"
ARCHIVE_URL="${GITHUB_BASE}/${ARCHIVE_FILE}"
CHECKSUMS_URL="${GITHUB_BASE}/checksums.txt"
OUT_BIN="${DIST_DIR}/${BIN_NAME}"
# ── 工具检查 ─────────────────────────────────────────────────────────────────
_need() {
if ! command -v "$1" >/dev/null 2>&1; then
printf '✗ 依赖未找到: %s\n' "$1" >&2; exit 1
fi
}
_need curl
_need sha256sum || _need shasum # macOS 用 shasumLinux 用 sha256sum
# 兼容 macOS (shasum -a 256) 和 Linux (sha256sum)
_sha256() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
else
shasum -a 256 "$1" | awk '{print $1}'
fi
}
# ── 幂等检查(已有产物则校验 SHA256)────────────────────────────────────────
if [[ "${FORCE}" == false && -f "${OUT_BIN}" ]]; then
CACHED_SUMS="${DIST_DIR}/checksums.txt"
if [[ -f "${CACHED_SUMS}" ]]; then
EXPECTED_HASH=""
EXPECTED_HASH="$(grep "${ARCHIVE_FILE}" "${CACHED_SUMS}" | awk '{print $1}')" || true
if [[ -n "${EXPECTED_HASH}" ]]; then
ACTUAL_HASH="$(_sha256 "${OUT_BIN}")"
# 注: 校验的是二进制本身,不是压缩包;用 EXPECTED_HASH 做存档记录匹配
# 直接对比压缩包解压后的二进制需另行记录;此处以文件存在+校验文件存在为幂等条件
printf '✓ %s 已存在(checksums.txt 已缓存),跳过下载\n' "${OUT_BIN}"
printf ' 当前 SHA256: %s\n' "${ACTUAL_HASH}"
printf ' (传 --force 强制重新下载并校验压缩包)\n'
exit 0
fi
fi
printf '✓ %s 已存在但无校验缓存,继续下载验证…\n' "${OUT_BIN}"
fi
# ── 创建目录 ─────────────────────────────────────────────────────────────────
mkdir -p "${DIST_DIR}"
mkdir -p "${CACHE_DIR}"
ARCHIVE_CACHE="${CACHE_DIR}/${ARCHIVE_FILE}"
CHECKSUMS_CACHE="${CACHE_DIR}/checksums-${VERSION_BARE}.txt"
# ── 下载 checksums.txt ───────────────────────────────────────────────────────
printf '==> 下载 checksums.txt for %s…\n' "${SINGBOX_VERSION}"
curl -fSL --retry 3 --retry-delay 2 \
-o "${CHECKSUMS_CACHE}" \
"${CHECKSUMS_URL}"
# ── 下载二进制压缩包 ──────────────────────────────────────────────────────────
printf '==> 下载 %s…\n' "${ARCHIVE_FILE}"
curl -fSL --retry 3 --retry-delay 2 \
-o "${ARCHIVE_CACHE}" \
"${ARCHIVE_URL}"
# ── SHA256 校验(对压缩包)───────────────────────────────────────────────────
printf '==> 校验 SHA256…\n'
EXPECTED_HASH=""
EXPECTED_HASH="$(grep "${ARCHIVE_FILE}" "${CHECKSUMS_CACHE}" | awk '{print $1}')"
if [[ -z "${EXPECTED_HASH}" ]]; then
printf '✗ checksums.txt 中未找到 %s 的校验值\n' "${ARCHIVE_FILE}" >&2
exit 1
fi
ACTUAL_HASH="$(_sha256 "${ARCHIVE_CACHE}")"
if [[ "${ACTUAL_HASH}" != "${EXPECTED_HASH}" ]]; then
printf '✗ SHA256 不匹配!\n' >&2
printf ' 期望: %s\n' "${EXPECTED_HASH}" >&2
printf ' 实际: %s\n' "${ACTUAL_HASH}" >&2
rm -f "${ARCHIVE_CACHE}"
exit 1
fi
printf ' ✓ SHA256 匹配: %s\n' "${ACTUAL_HASH}"
# ── 解压二进制 ────────────────────────────────────────────────────────────────
printf '==> 解压 → %s\n' "${DIST_DIR}"
EXTRACT_TMP="${CACHE_DIR}/extract-${ARCHIVE_STEM}"
rm -rf "${EXTRACT_TMP}"
mkdir -p "${EXTRACT_TMP}"
if [[ "${ARCHIVE_EXT}" == "zip" ]]; then
if ! command -v unzip >/dev/null 2>&1; then
printf '✗ unzip 未找到\n' >&2; exit 1
fi
unzip -q "${ARCHIVE_CACHE}" -d "${EXTRACT_TMP}"
else
tar -xzf "${ARCHIVE_CACHE}" -C "${EXTRACT_TMP}"
fi
# sing-box 压缩包内层目录名与 ARCHIVE_STEM 相同
INNER_DIR="${EXTRACT_TMP}/${ARCHIVE_STEM}"
if [[ ! -f "${INNER_DIR}/${BIN_NAME}" ]]; then
printf '✗ 压缩包中未找到 %s/%s\n' "${ARCHIVE_STEM}" "${BIN_NAME}" >&2
exit 1
fi
cp "${INNER_DIR}/${BIN_NAME}" "${OUT_BIN}"
chmod 755 "${OUT_BIN}"
# ── 缓存 checksums.txt 到产物目录(供幂等复查)────────────────────────────────
cp "${CHECKSUMS_CACHE}" "${DIST_DIR}/checksums.txt"
printf '\n✓ sing-box 二进制: %s\n' "${OUT_BIN}"
printf ' 版本验证: %s version\n' "${OUT_BIN}"
# ── Windows 额外处理: wintun.dll ─────────────────────────────────────────────
if [[ "${TARGET_OS}" == "windows" ]]; then
printf '\n==> Windows: 下载 wintun.dll (v%s)…\n' "${WINTUN_VERSION}"
WINTUN_ZIP_NAME="wintun-${WINTUN_VERSION}.zip"
WINTUN_URL="https://www.wintun.net/builds/${WINTUN_ZIP_NAME}"
WINTUN_ZIP_CACHE="${CACHE_DIR}/${WINTUN_ZIP_NAME}"
WINTUN_OUT="${DIST_DIR}/wintun.dll"
if [[ "${FORCE}" == false && -f "${WINTUN_OUT}" ]]; then
printf '✓ wintun.dll 已存在,跳过(传 --force 重新下载)\n'
else
curl -fSL --retry 3 --retry-delay 2 \
-o "${WINTUN_ZIP_CACHE}" \
"${WINTUN_URL}"
printf '==> 校验 wintun.zip SHA256…\n'
WINTUN_ACTUAL="$(_sha256 "${WINTUN_ZIP_CACHE}")"
if [[ "${WINTUN_ACTUAL}" != "${WINTUN_SHA256}" ]]; then
printf '✗ wintun.zip SHA256 不匹配!\n' >&2
printf ' 期望: %s\n' "${WINTUN_SHA256}" >&2
printf ' 实际: %s\n' "${WINTUN_ACTUAL}" >&2
printf ' 如果 WINTUN_VERSION 已更新,请同步更新脚本中的 WINTUN_SHA256\n' >&2
rm -f "${WINTUN_ZIP_CACHE}"
exit 1
fi
printf ' ✓ wintun.zip SHA256 匹配\n'
# 提取对应 arch 的 wintun.dll
# wintun zip 内路径: wintun/bin/<arch>/wintun.dll
WINTUN_EXTRACT="${CACHE_DIR}/extract-wintun"
rm -rf "${WINTUN_EXTRACT}"
mkdir -p "${WINTUN_EXTRACT}"
unzip -q "${WINTUN_ZIP_CACHE}" -d "${WINTUN_EXTRACT}"
WINTUN_DLL_SRC="${WINTUN_EXTRACT}/wintun/bin/${TARGET_ARCH}/wintun.dll"
if [[ ! -f "${WINTUN_DLL_SRC}" ]]; then
printf '✗ wintun zip 中未找到 %s arch 的 wintun.dll\n' "${TARGET_ARCH}" >&2
exit 1
fi
cp "${WINTUN_DLL_SRC}" "${WINTUN_OUT}"
printf '✓ wintun.dll: %s\n' "${WINTUN_OUT}"
fi
fi
# ── 最终输出摘要 ─────────────────────────────────────────────────────────────
printf '\n=== 产物清单: %s ===\n' "${DIST_DIR}"
ls -lh "${DIST_DIR}/"