Files
xuetang/app/scripts/package_macos.sh
T
2026-09-08 11:40:15 +08:00

153 lines
5.6 KiB
Bash
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
set -euo pipefail
script_dir="$(cd "$(dirname "$0")" && pwd -P)"
project_root="$(cd "$script_dir/.." && pwd -P)"
# shellcheck source=macos_helpers.sh
source "$script_dir/macos_helpers.sh"
macos_install_exit_trap 1
macos_require_darwin
/bin/bash "$script_dir/check_macos_entrypoints.sh"
NODE_BIN=""
NPM_BIN=""
use_node_pair() {
local node_candidate="$1"
local npm_candidate="$2"
local major version
[[ -x "$node_candidate" && -x "$npm_candidate" ]] || return 1
version="$("$node_candidate" --version 2>/dev/null || true)"
major="${version#v}"
major="${major%%.*}"
case "$major" in
''|*[!0-9]*) return 1 ;;
esac
[[ "$major" -ge 20 ]] || return 1
NODE_BIN="$node_candidate"
NPM_BIN="$npm_candidate"
export PATH="$(dirname "$NODE_BIN"):$PATH"
}
locate_node() {
local bin_dir node_candidate npm_candidate
node_candidate="$(command -v node 2>/dev/null || true)"
npm_candidate="$(command -v npm 2>/dev/null || true)"
if use_node_pair "$node_candidate" "$npm_candidate"; then
return 0
fi
for bin_dir in /opt/homebrew/bin /usr/local/bin; do
if use_node_pair "$bin_dir/node" "$bin_dir/npm"; then
return 0
fi
done
if [[ -n "${HOME:-}" ]]; then
for node_candidate in "$HOME"/.nvm/versions/node/*/bin/node; do
[[ -x "$node_candidate" ]] || continue
npm_candidate="$(dirname "$node_candidate")/npm"
if use_node_pair "$node_candidate" "$npm_candidate"; then
return 0
fi
done
fi
return 1
}
install_local_node() {
local architecture archive archive_path cache_root curl_bin download_dir
local expected extracted install_dir node_version shasums_path actual
node_version="${DOCTOR_NODE_VERSION:-22.14.0}"
case "$(uname -m)" in
arm64) architecture="arm64" ;;
x86_64) architecture="x64" ;;
*) macos_die "不支持的 Mac CPU 架构:$(uname -m)" ;;
esac
if [[ -n "${XDG_CACHE_HOME:-}" ]]; then
cache_root="$XDG_CACHE_HOME/DoctorWorkstation/tools"
elif [[ -n "${HOME:-}" ]]; then
cache_root="$HOME/Library/Caches/DoctorWorkstation/tools"
else
macos_die "无法确定 Node 工具缓存目录:HOME 与 XDG_CACHE_HOME 均未设置。"
fi
install_dir="$cache_root/node-v$node_version-darwin-$architecture"
if use_node_pair "$install_dir/bin/node" "$install_dir/bin/npm"; then
return 0
fi
if [[ -e "$install_dir" ]]; then
macos_die "Node 缓存不完整,请删除后重试:$install_dir"
fi
curl_bin="$(command -v curl 2>/dev/null || true)"
[[ -n "$curl_bin" ]] || macos_die "未找到用于下载 Node.js 的 curl。"
mkdir -p "$cache_root"
download_dir="$(mktemp -d "$cache_root/doctor-node.XXXXXX")"
macos_register_temp_dir "$download_dir"
archive="node-v$node_version-darwin-$architecture.tar.gz"
archive_path="$download_dir/$archive"
shasums_path="$download_dir/SHASUMS256.txt"
printf '未检测到 Node.js 20+ 与 npm,正在下载 Node.js %s%s)…\n' \
"$node_version" "$architecture"
if ! "$curl_bin" --proto '=https' --tlsv1.2 -fsSL \
"https://nodejs.org/dist/v$node_version/$archive" -o "$archive_path"; then
macos_die "Node.js 下载失败,请检查网络后重试。"
fi
if ! "$curl_bin" --proto '=https' --tlsv1.2 -fsSL \
"https://nodejs.org/dist/v$node_version/SHASUMS256.txt" -o "$shasums_path"; then
macos_die "Node.js 校验文件下载失败。"
fi
expected="$(/usr/bin/awk -v file="$archive" '$2 == file { print $1; exit }' "$shasums_path")"
actual="$(/usr/bin/shasum -a 256 "$archive_path" | /usr/bin/awk '{print $1}')"
[[ -n "$expected" && "$actual" == "$expected" ]] || macos_die "Node.js 下载包 SHA-256 校验失败。"
/usr/bin/tar -xzf "$archive_path" -C "$download_dir"
extracted="$download_dir/node-v$node_version-darwin-$architecture"
[[ -d "$extracted" ]] || macos_die "Node.js 下载包结构无效。"
if [[ ! -e "$install_dir" ]]; then
/bin/mv "$extracted" "$install_dir"
fi
use_node_pair "$install_dir/bin/node" "$install_dir/bin/npm" || \
macos_die "Node.js 安装完成,但 node/npm 无法执行。"
}
macos_ensure_uv
cd "$project_root"
printf '正在同步 Python 与 PyInstaller 构建依赖…\n'
"$MACOS_UV_BIN" sync --locked --extra build
python_bin="$project_root/.venv/bin/python"
[[ -x "$python_bin" ]] || macos_die "uv 未生成可用的构建 Python$python_bin"
locate_node || install_local_node
printf 'Node.js: %snpm: %s\n' \
"$("$NODE_BIN" --version)" "$("$NPM_BIN" --version)"
printf '正在安装锁定的 companion 依赖…\n'
"$NPM_BIN" ci --prefix "$project_root/video_companion" --no-audit --no-fund
printf '正在构建 DoctorWorkstation.app…\n'
PYINSTALLER_PYTHON="$python_bin" SKIP_FRONTEND_INSTALL=1 \
/bin/bash "$script_dir/build_macos.sh"
artifact="$project_root/dist/DoctorWorkstation.app"
project_version="$(/usr/bin/awk -F '"' '/^version = "/ { print $2; exit }' \
"$project_root/pyproject.toml")"
[[ -n "$project_version" ]] || macos_die "无法从 pyproject.toml 读取版本号。"
case "$(uname -m)" in
arm64) release_arch="arm64" ;;
x86_64) release_arch="x64" ;;
*) macos_die "不支持的 Mac CPU 架构:$(uname -m)" ;;
esac
release_zip="$project_root/dist/DoctorWorkstation-macOS-$release_arch-$project_version.zip"
checksum_file="$release_zip.sha256"
rm -f -- "$release_zip" "$checksum_file"
printf '正在生成可分发 ZIP…\n'
/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$artifact" "$release_zip"
release_hash="$(/usr/bin/shasum -a 256 "$release_zip" | /usr/bin/awk '{print $1}')"
printf '%s %s\n' "$release_hash" "$(basename "$release_zip")" >"$checksum_file"
printf '\n打包成功:%s\n' "$artifact"
printf '分发包:%s\n' "$release_zip"
printf 'SHA-256%s\n' "$release_hash"