build_mac_universal.sh 5.04 KB
#!/bin/bash
# macOS Build Script - Universal (Intel + Apple Silicon)
# 自动检测架构,自动安装依赖

set -e  # 遇错即停

echo "================================"
echo "Building Gemini Image Generator"
echo "================================"

# 检测架构
ARCH=$(uname -m)
echo "Detected architecture: $ARCH"

# 设置 Homebrew 路径
if [ "$ARCH" = "arm64" ]; then
    BREW_PREFIX="/opt/homebrew"
else
    BREW_PREFIX="/usr/local"
fi

# 检查 Homebrew 是否安装
if ! command -v brew &> /dev/null; then
    echo "Homebrew not found. Installing..."
    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    # 添加到当前 shell 的 PATH
    eval "$($BREW_PREFIX/bin/brew shellenv)"
fi

# 确保 brew 在 PATH 中
if ! command -v brew &> /dev/null; then
    eval "$($BREW_PREFIX/bin/brew shellenv)"
fi

# 检查 Python 3.11 是否安装
PYTHON_CMD="$BREW_PREFIX/bin/python3.11"
if [ ! -f "$PYTHON_CMD" ]; then
    echo "Python 3.11 not found. Installing via Homebrew..."
    brew install python@3.11
fi

# 验证 Python 可用
if [ ! -f "$PYTHON_CMD" ]; then
    echo "Error: Failed to install Python 3.11"
    exit 1
fi

echo "Using Python: $PYTHON_CMD"
$PYTHON_CMD --version

# 检查虚拟环境是否有效(macOS 用 bin/activate,Windows 用 Scripts/activate)
if [ ! -f ".venv/bin/activate" ]; then
    echo "Valid virtual environment not found, creating..."
    rm -rf .venv
    "$PYTHON_CMD" -m venv .venv
fi

# 激活虚拟环境
echo "Activating virtual environment..."
source .venv/bin/activate

# 安装依赖
echo "Installing dependencies..."
pip install --upgrade pip
pip install -r requirements.txt
pip install pyinstaller

# 清理旧构建 (保留 spec 文件,它是构建配置的唯一真相源)
echo "Cleaning previous builds..."
rm -rf build dist

# 构建 (所有配置都在 ZB100ImageGenerator.spec 里)
echo "Building executable..."
pyinstaller ZB100ImageGenerator.spec

# 验证 .app 构建结果
if [ ! -d "dist/ZB100ImageGenerator.app" ]; then
    echo "================================"
    echo "Build failed! (.app not produced)"
    echo "================================"
    exit 1
fi

# 打包 DMG 作为分发格式 (带 drag-to-install 布局)
# 为什么必须: .app 里有嵌套 symlink (PIL/.dylibs -> __dot__dylibs),
# cp/NAS/SMB/微信 等传输方式可能吞掉内层 symlink 导致目标机启动失败.
# .dmg 是 HFS+ 镜像, symlink 原样保存, 用户挂载拖拽即用.
echo "Creating DMG with drag-to-install layout..."
DMG_PATH="dist/ZB100ImageGenerator.dmg"
TMP_DMG="dist/.tmp_rw.dmg"
STAGE="dist/.dmg_stage"
VOL_NAME="ZB100ImageGenerator"

# 1. 准备 staging: .app + Applications 快捷方式
rm -rf "$STAGE"
mkdir -p "$STAGE"
cp -R "dist/ZB100ImageGenerator.app" "$STAGE/"
ln -s /Applications "$STAGE/Applications"

# 2. 先卸载可能残留的同名卷, 防止上次失败留下的挂载
hdiutil detach "/Volumes/$VOL_NAME" -force >/dev/null 2>&1 || true

# 3. 创建可写 DMG (UDRW), 便于随后调整窗口布局
rm -f "$TMP_DMG" "$DMG_PATH"
hdiutil create \
    -volname "$VOL_NAME" \
    -srcfolder "$STAGE" \
    -ov -format UDRW \
    "$TMP_DMG"

# 4. 挂载并用 AppleScript 布置窗口 (.app 在左, Applications 在右)
MOUNT_POINT="/Volumes/$VOL_NAME"
hdiutil attach "$TMP_DMG" -readwrite -noverify -noautoopen >/dev/null

# osascript 失败不致命 (可能因 Finder 自动化权限), DMG 仍然可用, 只是没布局
osascript <<OSASCRIPT_EOF || echo "Warning: Finder 布局失败 (可能需要授予 Finder 自动化权限), DMG 仍可用"
tell application "Finder"
    tell disk "$VOL_NAME"
        open
        set current view of container window to icon view
        set toolbar visible of container window to false
        set statusbar visible of container window to false
        set the bounds of container window to {200, 120, 800, 470}
        set theViewOptions to the icon view options of container window
        set arrangement of theViewOptions to not arranged
        set icon size of theViewOptions to 128
        set position of item "ZB100ImageGenerator.app" of container window to {160, 170}
        set position of item "Applications" of container window to {440, 170}
        update without registering applications
        delay 1
        close
    end tell
end tell
OSASCRIPT_EOF

sync
hdiutil detach "$MOUNT_POINT" -force >/dev/null

# 5. 压缩成最终只读 DMG
hdiutil convert "$TMP_DMG" -format UDZO -imagekey zlib-level=9 -o "$DMG_PATH" >/dev/null

# 6. 清理临时
rm -f "$TMP_DMG"
rm -rf "$STAGE"

if [ ! -f "$DMG_PATH" ]; then
    echo "================================"
    echo "Build partially failed: .app OK but DMG creation failed"
    echo "================================"
    exit 1
fi

echo "================================"
echo "Build successful!"
echo "Architecture: $ARCH"
echo "  App:  dist/ZB100ImageGenerator.app  ($(du -sh dist/ZB100ImageGenerator.app | awk '{print $1}'))"
echo "  DMG:  $DMG_PATH  ($(du -sh "$DMG_PATH" | awk '{print $1}'))"
echo "================================"
echo "分发请用 DMG, 不要直接拷贝 .app 目录 (symlink 易丢)."