#!/bin/sh # macOS 应用打包入口:构建 release 可执行文件并组装最小 Tessera.app;脚本本身不运行测试或部署。 # 执行会产生构建产物,应在已确认的 macOS 构建环境中调用。 # 任一命令失败或使用未定义变量即退出,避免在失败编译后继续打包旧文件。 # 构建调用方显式执行此脚本才产生文件;阅读或 sh -n 仅检查语法,不会运行下方 Cargo。 set -eu # 此入口只能在 macOS 使用;构建授权由调用方确认,脚本不自动执行测试或部署。 if [ "$(uname -s)" != Darwin ]; then echo "Build this app bundle on macOS." >&2 exit 1 fi # 以脚本所在目录的父目录作为仓库根;清空这一次 cd 的 CDPATH,防止用户 shell 配置改变目录解析。 cd "$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)" # 锁定依赖并生成 release 可执行文件;附加参数原样交给 Cargo。 # 后续复制路径固定为 target/release/tessera,不会随 --target、--target-dir 或 CARGO_TARGET_DIR 自动调整。 # 这里确实触发编译,不是只验证清单;依赖锁不匹配时 --locked 要求失败而非自动更新 Cargo.lock。 cargo build --release --locked "$@" # 从 Cargo.toml 文本读取首个行首 version 值,空值由 test 拒绝;这不是 cargo metadata 的结构化查询。 # version 从清单文本读取,后面用于两个 plist 版本键;脚本不调用构建后的 Tessera 来查询版本。 version=$(awk -F '"' '$1 ~ /^version[[:space:]]*=/ { print $2; exit }' Cargo.toml) test -n "$version" # macOS bundle 约定:Contents/MacOS 保存入口二进制,Contents/Info.plist 保存系统识别信息。 bundle="$(pwd)/target/release/Tessera.app" # 创建/复用固定 release 产物目录,不清空旧 bundle;后面逐文件替换主二进制和元数据。 mkdir -p "$bundle/Contents/MacOS" # 先写临时文件再重命名,避免复制途中将半个二进制留作 bundle 的主程序。 cp target/release/tessera "$bundle/Contents/MacOS/tessera.new" mv -f "$bundle/Contents/MacOS/tessera.new" "$bundle/Contents/MacOS/tessera" # 生成最小 macOS bundle 元数据;应用名、入口与高分辨率标志供系统启动/显示使用。 # heredoc 展开本次 version,XML 文本与入口文件名相互对应;这里没有签名、公证或安装动作。 cat > "$bundle/Contents/Info.plist.new" < CFBundleIdentifiercom.entroia.tessera CFBundleNameTessera CFBundleDisplayNameTessera CFBundleExecutabletessera CFBundlePackageTypeAPPL CFBundleShortVersionString$version CFBundleVersion$version NSHighResolutionCapable PLIST # 元数据完整写入后再替换正式文件;这只是单文件替换,不表示整个 bundle 的构建具有事务回滚。 mv -f "$bundle/Contents/Info.plist.new" "$bundle/Contents/Info.plist" # 标准输出返回最终 app 路径,便于构建调用方定位产物。 printf '%s\n' "$bundle"