From 7b039b911d0222c23b715ba8d012f249a1a78d36 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:52:15 +0800 Subject: [PATCH 01/23] Add ARM64 support and GitHub Actions workflows - Update deployment target to macOS 11.0 for Apple Silicon support - Upgrade Sparkle to 2.x for better ARM64 compatibility - Add GitHub Actions workflows for automated ARM64 DMG builds - Add comprehensive documentation (PROJECT_OVERVIEW, COMPATIBILITY_ANALYSIS, ARM64_UPDATE_GUIDE, RELEASE_GUIDE) - Update .gitignore for build artifacts --- .github/workflows/README.md | 144 ++++++++++++ .github/workflows/build-and-release.yml | 149 ++++++++++++ .github/workflows/build-universal-dmg.yml | 189 +++++++++++++++ .gitignore | 51 +++- ARM64_UPDATE_GUIDE.md | 176 ++++++++++++++ COMPATIBILITY_ANALYSIS.md | 168 +++++++++++++ PROJECT_OVERVIEW.md | 273 ++++++++++++++++++++++ Podfile | 4 +- RELEASE_GUIDE.md | 159 +++++++++++++ Vagrant Manager.xcodeproj/project.pbxproj | 8 +- 10 files changed, 1305 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/build-and-release.yml create mode 100644 .github/workflows/build-universal-dmg.yml create mode 100644 ARM64_UPDATE_GUIDE.md create mode 100644 COMPATIBILITY_ANALYSIS.md create mode 100644 PROJECT_OVERVIEW.md create mode 100644 RELEASE_GUIDE.md diff --git a/.github/workflows/README.md b/.github/workflows/README.md new file mode 100644 index 0000000..b526b6a --- /dev/null +++ b/.github/workflows/README.md @@ -0,0 +1,144 @@ +# GitHub Actions Workflows + +本项目包含两个 GitHub Actions workflow 用于自动构建和发布 DMG 包。 + +## Workflows + +### 1. `build-and-release.yml` - ARM64 专用构建 + +专门用于构建 ARM64 (Apple Silicon) 版本的 DMG 包。 + +**触发方式:** +- 推送以 `v` 开头的 tag(例如:`v2.7.2`) +- 手动触发(Workflow Dispatch) + +**构建内容:** +- ARM64 架构的应用程序 +- DMG 安装包 +- 自动发布到 GitHub Releases + +### 2. `build-universal-dmg.yml` - 通用/多架构构建 + +支持构建多种架构的 DMG 包: +- Universal(同时支持 ARM64 和 x86_64) +- ARM64 only +- x86_64 only + +**触发方式:** +- 推送以 `v` 开头的 tag +- 手动触发(可选择构建类型) + +## 使用方法 + +### 自动发布(推荐) + +1. **创建并推送 tag:** + ```bash + git tag v2.7.2 + git push origin v2.7.2 + ``` + +2. **Workflow 会自动:** + - 检测到 tag 推送 + - 开始构建 + - 创建 DMG 包 + - 发布到 GitHub Releases + +### 手动触发 + +1. 进入 GitHub 仓库的 **Actions** 标签页 +2. 选择对应的 workflow +3. 点击 **Run workflow** +4. 输入版本号(例如:`v2.7.2`) +5. 选择构建类型(仅限 universal workflow) +6. 点击 **Run workflow** + +## 构建产物 + +构建完成后,会在 GitHub Releases 中创建: +- **Release 标题**:`Release v2.7.2 (arm64)` 或 `Release v2.7.2 (universal)` +- **DMG 文件**:`Vagrant Manager-2.7.2-arm64.dmg` 或 `Vagrant Manager-2.7.2-universal.dmg` + +## 系统要求 + +构建环境: +- macOS 14 (Sonoma) +- Xcode(通过 GitHub Actions 自动安装) +- Node.js 20(用于 appdmg) +- CocoaPods(自动安装) + +## 注意事项 + +1. **代码签名**:当前 workflow 使用 `CODE_SIGNING_REQUIRED=NO`,如果需要代码签名,需要: + - 配置代码签名证书 + - 更新 workflow 中的签名设置 + +2. **发布权限**:确保 GitHub token 有创建 Release 的权限(默认的 `GITHUB_TOKEN` 通常已足够) + +3. **DMG 配置**:DMG 的布局和样式在 `dmg/appdmg.json` 中配置 + +4. **版本号格式**:建议使用语义化版本号,例如 `v2.7.2`、`v2.8.0` 等 + +## 故障排除 + +### 构建失败 + +1. **检查日志**:在 GitHub Actions 中查看详细的构建日志 +2. **验证依赖**:确保 `Podfile` 和 `Podfile.lock` 正确 +3. **检查 Xcode 版本**:确保使用的 macOS runner 版本支持所需的 Xcode 版本 + +### DMG 创建失败 + +1. **检查 appdmg 配置**:验证 `dmg/appdmg.json` 格式正确 +2. **检查资源文件**:确保 `dmg/` 目录中的图片文件存在 +3. **验证 .app 文件**:确保 Xcode 构建成功生成了 .app 文件 + +### 发布失败 + +1. **检查权限**:确保 GitHub token 有创建 Release 的权限 +2. **检查 tag**:确保 tag 格式正确(以 `v` 开头) +3. **检查 Release 是否存在**:如果 Release 已存在,workflow 会失败 + +## 自定义配置 + +### 修改构建架构 + +编辑 workflow 文件中的 `-arch` 参数: +```yaml +-arch arm64 # 仅 ARM64 +-arch x86_64 # 仅 Intel +-arch arm64 -arch x86_64 # Universal +``` + +### 修改 macOS 版本 + +修改 `runs-on` 字段: +```yaml +runs-on: macos-14 # macOS 14 (Sonoma) +runs-on: macos-13 # macOS 13 (Ventura) +runs-on: macos-12 # macOS 12 (Monterey) +``` + +### 添加代码签名 + +如果需要代码签名,需要: +1. 在 GitHub Secrets 中添加证书和密钥 +2. 更新 workflow 中的签名步骤 + +示例: +```yaml +- name: Import Certificate + uses: apple-actions/import-codesign-certs@v1 + with: + p12-file-base64: ${{ secrets.CERTIFICATES_P12 }} + p12-password: ${{ secrets.CERTIFICATES_PASSWORD }} + +# 然后在 xcodebuild 命令中移除 CODE_SIGNING_REQUIRED=NO +``` + +## 相关文件 + +- `dmg/appdmg.json` - DMG 配置文件 +- `Podfile` - CocoaPods 依赖配置 +- `.github/workflows/` - Workflow 文件目录 + diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml new file mode 100644 index 0000000..1c0d658 --- /dev/null +++ b/.github/workflows/build-and-release.yml @@ -0,0 +1,149 @@ +name: Build and Release ARM64 DMG + +on: + push: + tags: + - 'v*' # 当推送以 v 开头的 tag 时触发(例如 v2.7.2) + workflow_dispatch: # 允许手动触发 + inputs: + version: + description: 'Version tag (e.g., v2.7.2)' + required: true + type: string + +jobs: + build-arm64-dmg: + name: Build ARM64 DMG + runs-on: macos-14 # macOS 14 (Sonoma) with Apple Silicon support + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install appdmg + run: npm install -g appdmg + + - name: Setup CocoaPods + uses: cocoapods-action@v1 + with: + podfile-path: Podfile + + - name: Install CocoaPods dependencies + run: pod install + + - name: Get version from tag + id: get_version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + else + VERSION="${GITHUB_REF#refs/tags/}" + fi + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + echo "VERSION_NAME=${VERSION#v}" >> $GITHUB_OUTPUT + echo "Building version: ${VERSION}" + + - name: Build Xcode project (ARM64) + run: | + xcodebuild clean -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release + + xcodebuild archive -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch arm64 \ + -sdk macosx \ + -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + + - name: Create export options plist + run: | + cat > exportOptions.plist < + + + + method + mac-application + signingStyle + manual + + + EOF + + - name: Export .app from archive + run: | + xcodebuild -exportArchive \ + -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ + -exportPath "$PWD/build/export" \ + -exportOptionsPlist "$PWD/exportOptions.plist" + + - name: Copy .app to dmg directory + run: | + cp -R "build/export/Vagrant Manager.app" "dmg/" + + - name: Create DMG + working-directory: dmg + run: | + appdmg appdmg.json "../Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" + + - name: Verify DMG + run: | + hdiutil verify "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" + hdiutil info "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" + + - name: Get DMG size + id: dmg_size + run: | + DMG_SIZE=$(du -h "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" | cut -f1) + echo "size=${DMG_SIZE}" >> $GITHUB_OUTPUT + echo "DMG size: ${DMG_SIZE}" + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.get_version.outputs.VERSION }} + name: Release ${{ steps.get_version.outputs.VERSION }} (ARM64) + body: | + ## Vagrant Manager ${{ steps.get_version.outputs.VERSION_NAME }} (ARM64) + + ### 🍎 Apple Silicon Support + This release is built for **Apple Silicon (ARM64)** Macs running macOS 11.0 or later. + + ### 📦 Installation + 1. Download the DMG file + 2. Open the DMG + 3. Drag "Vagrant Manager" to Applications folder + + ### 📋 Changes + - Built for Apple Silicon (ARM64) + - Requires macOS 11.0 (Big Sur) or later + - Updated Sparkle to 2.x for better ARM64 support + + ### 🔧 System Requirements + - macOS 11.0 (Big Sur) or later + - Apple Silicon Mac (M1/M2/M3/M4/M5) or Intel Mac with macOS 11.0+ + - Vagrant installed and in PATH + - VirtualBox or Parallels installed (if using those providers) + + ### 📊 Build Info + - **Architecture**: ARM64 + - **DMG Size**: ${{ steps.dmg_size.outputs.size }} + - **Build Date**: ${{ github.event.head_commit.timestamp || github.run_started_at }} + draft: false + prerelease: false + files: | + Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml new file mode 100644 index 0000000..37705b1 --- /dev/null +++ b/.github/workflows/build-universal-dmg.yml @@ -0,0 +1,189 @@ +name: Build and Release Universal DMG + +on: + push: + tags: + - 'v*' # 当推送以 v 开头的 tag 时触发 + workflow_dispatch: # 允许手动触发 + inputs: + version: + description: 'Version tag (e.g., v2.7.2)' + required: true + type: string + build_type: + description: 'Build type' + required: true + type: choice + options: + - universal + - arm64 + - x86_64 + default: universal + +jobs: + build-universal-dmg: + name: Build Universal DMG + runs-on: macos-14 # macOS 14 with Apple Silicon support + + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'npm' + + - name: Install appdmg + run: npm install -g appdmg + + - name: Setup CocoaPods + uses: cocoapods-action@v1 + with: + podfile-path: Podfile + + - name: Install CocoaPods dependencies + run: pod install + + - name: Get version from tag + id: get_version + run: | + if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then + VERSION="${{ github.event.inputs.version }}" + BUILD_TYPE="${{ github.event.inputs.build_type }}" + else + VERSION="${GITHUB_REF#refs/tags/}" + BUILD_TYPE="universal" + fi + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + echo "VERSION_NAME=${VERSION#v}" >> $GITHUB_OUTPUT + echo "BUILD_TYPE=${BUILD_TYPE}" >> $GITHUB_OUTPUT + echo "Building version: ${VERSION} (${BUILD_TYPE})" + + - name: Determine architectures + id: archs + run: | + BUILD_TYPE="${{ steps.get_version.outputs.BUILD_TYPE }}" + if [ "${BUILD_TYPE}" == "universal" ]; then + ARCHS="arm64 x86_64" + ARCH_SUFFIX="universal" + elif [ "${BUILD_TYPE}" == "arm64" ]; then + ARCHS="arm64" + ARCH_SUFFIX="arm64" + else + ARCHS="x86_64" + ARCH_SUFFIX="x86_64" + fi + echo "archs=${ARCHS}" >> $GITHUB_OUTPUT + echo "arch_suffix=${ARCH_SUFFIX}" >> $GITHUB_OUTPUT + echo "Building for architectures: ${ARCHS}" + + - name: Build Xcode project + run: | + xcodebuild clean -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release + + xcodebuild archive -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch ${{ steps.archs.outputs.archs }} \ + -sdk macosx \ + -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ + CODE_SIGN_IDENTITY="" \ + CODE_SIGNING_REQUIRED=NO \ + CODE_SIGNING_ALLOWED=NO + + - name: Create export options plist + run: | + cat > exportOptions.plist < + + + + method + mac-application + signingStyle + manual + + + EOF + + - name: Export .app from archive + run: | + xcodebuild -exportArchive \ + -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ + -exportPath "$PWD/build/export" \ + -exportOptionsPlist "$PWD/exportOptions.plist" + + - name: Verify architectures + run: | + file "build/export/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" + lipo -info "build/export/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" + + - name: Copy .app to dmg directory + run: | + cp -R "build/export/Vagrant Manager.app" "dmg/" + + - name: Create DMG + working-directory: dmg + run: | + appdmg appdmg.json "../Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + + - name: Verify DMG + run: | + hdiutil verify "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + hdiutil info "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + + - name: Get DMG size + id: dmg_size + run: | + DMG_SIZE=$(du -h "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" | cut -f1) + echo "size=${DMG_SIZE}" >> $GITHUB_OUTPUT + echo "DMG size: ${DMG_SIZE}" + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + with: + tag_name: ${{ steps.get_version.outputs.VERSION }} + name: Release ${{ steps.get_version.outputs.VERSION }} (${{ steps.archs.outputs.arch_suffix }}) + body: | + ## Vagrant Manager ${{ steps.get_version.outputs.VERSION_NAME }} (${{ steps.archs.outputs.arch_suffix }}) + + ### 🍎 Architecture Support + This release is built for **${{ steps.archs.outputs.arch_suffix }}** architecture. + ${{ steps.archs.outputs.arch_suffix == 'universal' && 'Supports both Apple Silicon (ARM64) and Intel (x86_64) Macs.' || '' }} + ${{ steps.archs.outputs.arch_suffix == 'arm64' && 'Supports Apple Silicon (M1/M2/M3/M4/M5) Macs only.' || '' }} + ${{ steps.archs.outputs.arch_suffix == 'x86_64' && 'Supports Intel Macs only.' || '' }} + + ### 📦 Installation + 1. Download the DMG file + 2. Open the DMG + 3. Drag "Vagrant Manager" to Applications folder + + ### 📋 Changes + - Built for ${{ steps.archs.outputs.arch_suffix }} architecture + - Requires macOS 11.0 (Big Sur) or later + - Updated Sparkle to 2.x for better ARM64 support + + ### 🔧 System Requirements + - macOS 11.0 (Big Sur) or later + ${{ steps.archs.outputs.arch_suffix == 'universal' && '- Apple Silicon (M1/M2/M3/M4/M5) or Intel Mac' || '' }} + ${{ steps.archs.outputs.arch_suffix == 'arm64' && '- Apple Silicon Mac (M1/M2/M3/M4/M5)' || '' }} + ${{ steps.archs.outputs.arch_suffix == 'x86_64' && '- Intel Mac' || '' }} + - Vagrant installed and in PATH + - VirtualBox or Parallels installed (if using those providers) + + ### 📊 Build Info + - **Architecture**: ${{ steps.archs.outputs.arch_suffix }} + - **DMG Size**: ${{ steps.dmg_size.outputs.size }} + - **Build Date**: ${{ github.event.head_commit.timestamp || github.run_started_at }} + draft: false + prerelease: false + files: | + Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + diff --git a/.gitignore b/.gitignore index 66ca847..611829b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -# OS X -.DS_Store - # Xcode +# build/ *.pbxuser !default.pbxuser @@ -13,16 +11,49 @@ build/ !default.perspectivev3 xcuserdata *.xccheckout -profile *.moved-aside DerivedData *.hmap *.ipa +*.xcuserstate +project.xcworkspace # CocoaPods -Pods -assets/clean.psd -assets/default.psd -assets/flat.psd -assets/indicators.psd -assets/problem.psd +# +Pods/ + +# App packaging +# +*.dmg +*.app.dSYM.zip +*.app.dSYM + +# Build artifacts +# +exportOptions.plist +*.xcarchive + +# OS X +# +.DS_Store +.AppleDouble +.LSOverride + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/ARM64_UPDATE_GUIDE.md b/ARM64_UPDATE_GUIDE.md new file mode 100644 index 0000000..f86afa9 --- /dev/null +++ b/ARM64_UPDATE_GUIDE.md @@ -0,0 +1,176 @@ +# ARM64 (Apple Silicon) 支持更新指南 + +## 已完成的配置更新 + +### 1. ✅ Podfile 更新 +- **平台版本**:从 `10.8` 更新到 `11.0` +- **Sparkle 版本**:从 `1.22.0` 更新到 `~> 2.0`(支持 ARM64) + +### 2. ✅ Xcode 项目配置更新 +- **MACOSX_DEPLOYMENT_TARGET**:所有配置从 `10.8` 更新到 `11.0` + - Debug 配置 + - Release 配置 + - 主应用目标配置 + +## 下一步操作 + +### 1. 更新 CocoaPods 依赖 + +运行以下命令更新依赖: + +```bash +cd /Users/kevin/projects/src/vagrant-manager +pod install +``` + +这将: +- 更新 Sparkle 到 2.x 版本 +- 重新生成 `Pods` 目录和 `Vagrant Manager.xcworkspace` + +### 2. 验证配置 + +在 Xcode 中打开项目: + +```bash +open "Vagrant Manager.xcworkspace" +``` + +检查以下设置: +1. **项目设置** → **General** → **Deployment Info** + - Minimum Deployments: macOS 11.0 +2. **构建设置** → **Architectures** + - 应该包含 `arm64` 和 `x86_64`(或使用默认的 `$(ARCHS_STANDARD)`) + +### 3. 构建测试 + +#### 仅 ARM64 构建(Apple Silicon) +```bash +xcodebuild -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch arm64 \ + -sdk macosx \ + -derivedDataPath ./build +``` + +#### 通用二进制构建(同时支持 Intel 和 Apple Silicon) +```bash +xcodebuild -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch arm64 -arch x86_64 \ + -sdk macosx \ + -derivedDataPath ./build +``` + +#### 在 Xcode 中构建 +1. 选择 **Product** → **Scheme** → **Edit Scheme** +2. 在 **Run** 和 **Archive** 的 **Build Configuration** 中选择 **Release** +3. 选择 **Product** → **Build** (⌘B) +4. 或选择 **Product** → **Archive** 创建发布版本 + +### 4. 验证架构 + +构建完成后,验证二进制文件的架构: + +```bash +# 查看应用包的架构 +file "build/Build/Products/Release/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" + +# 或使用 lipo 命令 +lipo -info "build/Build/Products/Release/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" +``` + +期望输出: +- 仅 ARM64:`arm64` +- 通用二进制:`arm64 x86_64` + +### 5. 测试 + +在 Apple Silicon Mac 上测试: + +1. **基本功能测试** + - 启动应用 + - 检查状态栏图标显示 + - 测试菜单功能 + +2. **Vagrant 集成测试** + - 检测 Vagrant 实例 + - 执行 Vagrant 命令(up, halt, suspend 等) + - 检查虚拟机状态显示 + - 测试 SSH 连接 + +3. **更新功能测试** + - 测试 Sparkle 自动更新功能 + - 验证版本检查 + +## 注意事项 + +### 系统要求 +- **最低 macOS 版本**:11.0 (Big Sur) 或更高 +- **Xcode 版本**:建议使用 Xcode 12.2 或更高版本(支持 Apple Silicon) + +### 向后兼容性 +- 更新到 macOS 11.0 后,应用将**不再支持** macOS 10.8 - 10.15 +- 如果需要支持旧版本 macOS,需要维护两个版本: + - 一个针对 macOS 10.8+(仅 Intel) + - 一个针对 macOS 11.0+(Intel + Apple Silicon) + +### Sparkle 2.x 变化 +- Sparkle 2.x 有一些 API 变化,但项目使用的 API 应该保持兼容 +- 如果遇到编译错误,可能需要更新 Sparkle 相关的代码 + +### Vagrant 在 Apple Silicon 上 +- Vagrant 本身可以在 Apple Silicon 上运行 +- 但某些虚拟机提供商可能需要特殊配置: + - **VirtualBox**:在 Apple Silicon 上支持有限,可能需要使用 UTM 或其他方案 + - **Parallels**:有原生 Apple Silicon 支持 + - **VMware Fusion**:有 Apple Silicon 版本 + +## 故障排除 + +### 如果构建失败 + +1. **清理构建** + ```bash + xcodebuild clean -workspace "Vagrant Manager.xcworkspace" -scheme "Vagrant Manager" + rm -rf build Pods Podfile.lock + pod install + ``` + +2. **检查 Sparkle 版本** + ```bash + pod search Sparkle + ``` + 确保使用支持 ARM64 的版本 + +3. **检查 Xcode 版本** + ```bash + xcodebuild -version + ``` + 确保使用 Xcode 12.2 或更高版本 + +### 如果运行时出错 + +1. **检查架构** + ```bash + arch + ``` + 在 Apple Silicon Mac 上应该显示 `arm64` + +2. **检查依赖库架构** + ```bash + file "Vagrant Manager.app/Contents/Frameworks/Sparkle.framework/Sparkle" + ``` + 应该包含 `arm64` + +## 相关资源 + +- [Apple Silicon 迁移指南](https://developer.apple.com/documentation/apple-silicon) +- [Sparkle 2.x 文档](https://sparkle-project.org/documentation/) +- [Vagrant 官方文档](https://www.vagrantup.com/docs) + +## 更新日期 + +配置更新完成日期:2025年1月 + diff --git a/COMPATIBILITY_ANALYSIS.md b/COMPATIBILITY_ANALYSIS.md new file mode 100644 index 0000000..40c0eb3 --- /dev/null +++ b/COMPATIBILITY_ANALYSIS.md @@ -0,0 +1,168 @@ +# Vagrant Manager 兼容性分析 + +## 1. Vagrant 版本兼容性 + +### ✅ 支持最新版 Vagrant + +**结论:项目应该能够支持最新版本的 Vagrant(包括 v2.4.9)** + +#### 技术分析: + +1. **使用标准 Vagrant CLI 命令** + - 项目通过执行标准的 Vagrant CLI 命令来与 Vagrant 交互 + - 使用的命令包括: + - `vagrant status` - 查询虚拟机状态 + - `vagrant global-status` - 查询全局状态 + - `vagrant version --machine-readable` - 检查版本 + - `vagrant up`, `vagrant halt`, `vagrant suspend`, `vagrant resume` 等标准操作命令 + +2. **命令兼容性** + - 这些命令都是 Vagrant 的核心命令,在 Vagrant 2.x 版本中保持稳定 + - 项目通过解析命令输出来获取信息,而不是依赖内部 API + - 只要 Vagrant CLI 的输出格式保持兼容,项目就能正常工作 + +3. **版本检查机制** + - 项目内置了 Vagrant 版本检查功能(`checkForVagrantUpdates:` 方法) + - 使用 `vagrant version --machine-readable` 命令获取版本信息 + - 支持版本比较和更新提示 + +4. **Vagrant 维护状态** + - 根据 [Vagrant GitHub 仓库](https://github.com/hashicorp/vagrant),Vagrant 仍在积极维护 + - 最新版本:v2.4.9(2025年8月发布) + - 项目使用标准的 Vagrant 命令,应该与最新版本兼容 + +### ⚠️ 潜在兼容性问题 + +1. **输出格式变化** + - 如果 Vagrant 未来改变命令输出格式,可能需要更新解析逻辑 + - 主要影响文件: + - `VagrantGlobalStatusScanner.m` - 解析 `vagrant global-status` 输出 + - `VagrantInstance.m` - 解析 `vagrant status` 输出 + +2. **新功能支持** + - 如果 Vagrant 添加新的命令或选项,需要手动添加支持 + - 项目支持自定义命令功能,可以通过此功能扩展支持 + +## 2. ARM64 (Apple Silicon) 支持 + +### ✅ 理论上支持,但需要配置更新 + +**结论:项目可以编译为 ARM64 版本,但需要更新 Xcode 项目配置** + +#### 技术分析: + +1. **代码层面兼容性** + - ✅ 使用标准的 Cocoa/AppKit 框架,这些框架在 Apple Silicon 上都有原生支持 + - ✅ 使用 Objective-C 和 ARC,完全兼容 ARM64 + - ✅ 没有使用任何架构特定的代码或汇编 + - ✅ 所有系统框架调用都是跨架构兼容的 + +2. **项目配置现状** + ```pbxproj + MACOSX_DEPLOYMENT_TARGET = 10.8; + SDKROOT = macosx; + ``` + - 当前配置没有明确指定架构 + - 没有 `EXCLUDED_ARCHS` 设置(这是好的,意味着不排除任何架构) + - 使用 `ONLY_ACTIVE_ARCH = YES`(Debug 配置),这意味着会为当前构建机器编译对应架构 + +3. **依赖项兼容性** + - **Sparkle 框架**(通过 CocoaPods) + - 当前版本:Sparkle 1.22.0(在 `Podfile.lock` 中) + - ⚠️ Sparkle 1.x 对 ARM64 的支持可能不完整 + - ✅ Sparkle 2.x 版本完全支持 ARM64 + - **建议**:升级到 Sparkle 2.x 以获得更好的 ARM64 支持 + - 更新方法: + ```ruby + # 在 Podfile 中指定版本 + pod 'Sparkle', '~> 2.0' + # 然后运行 + pod update Sparkle + ``` + +4. **构建要求** + - 需要在支持 Apple Silicon 的 Xcode 版本中构建 + - 建议使用 Xcode 12.2 或更高版本(支持 Apple Silicon) + - 最低部署目标可能需要更新(当前是 10.8,Apple Silicon 需要 macOS 11.0+) + +### 🔧 编译 ARM64 版本的建议步骤 + +1. **更新部署目标** + ```pbxproj + MACOSX_DEPLOYMENT_TARGET = 11.0; // 或更高,Apple Silicon 需要 macOS 11.0+ + ``` + +2. **明确指定架构(可选)** + ```pbxproj + ARCHS = "$(ARCHS_STANDARD)"; // 包含 arm64 和 x86_64 + // 或者只编译 ARM64 + ARCHS = "arm64"; + ``` + +3. **更新 Sparkle 依赖** + - 确保 Podfile 中使用支持 ARM64 的 Sparkle 版本 + - 运行 `pod update Sparkle` + +4. **测试构建** + ```bash + # 在 Apple Silicon Mac 上 + xcodebuild -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch arm64 \ + -sdk macosx + ``` + +5. **创建通用二进制(Universal Binary)** + ```bash + # 同时支持 Intel 和 Apple Silicon + xcodebuild -workspace "Vagrant Manager.xcworkspace" \ + -scheme "Vagrant Manager" \ + -configuration Release \ + -arch arm64 -arch x86_64 \ + -sdk macosx + ``` + +### ⚠️ 注意事项 + +1. **最低系统要求** + - Apple Silicon Mac 运行 macOS 11.0 (Big Sur) 或更高版本 + - 如果保持 10.8 作为最低版本,将无法在 Apple Silicon 上运行(因为 Apple Silicon 需要 macOS 11.0+) + +2. **Vagrant 在 Apple Silicon 上的运行** + - Vagrant 本身可以在 Apple Silicon 上运行 + - 但虚拟机提供商(如 VirtualBox)可能需要特殊配置 + - 某些 Vagrant box 可能需要 ARM64 版本 + +3. **测试建议** + - 在 Apple Silicon Mac 上完整测试所有功能 + - 测试 Vagrant 命令执行 + - 测试虚拟机状态检测 + - 测试各种 Vagrant 操作(up, halt, suspend 等) + +## 3. 总结 + +### Vagrant 版本支持 +- ✅ **支持最新版 Vagrant**:项目使用标准 CLI 命令,应该与 Vagrant 2.4.9 兼容 +- ⚠️ **需要测试**:建议在实际环境中测试最新版 Vagrant 的兼容性 + +### ARM64 支持 +- ✅ **代码兼容**:代码层面完全兼容 ARM64 +- ✅ **可以编译**:理论上可以编译为 ARM64 版本 +- 🔧 **需要配置**:需要更新 Xcode 项目配置和部署目标 +- ⚠️ **需要测试**:需要在实际的 Apple Silicon Mac 上测试 + +### 建议行动 +1. 更新 `MACOSX_DEPLOYMENT_TARGET` 到 11.0 或更高 +2. 更新 Sparkle 依赖到支持 ARM64 的版本 +3. 在 Apple Silicon Mac 上测试构建 +4. 测试与最新版 Vagrant 的兼容性 +5. 考虑创建 Universal Binary 以同时支持 Intel 和 Apple Silicon + +## 4. 相关资源 + +- [Vagrant GitHub](https://github.com/hashicorp/vagrant) +- [Vagrant 官方文档](https://www.vagrantup.com/) +- [Apple Silicon 迁移指南](https://developer.apple.com/documentation/apple-silicon) +- [Sparkle 更新框架](https://sparkle-project.org/) + diff --git a/PROJECT_OVERVIEW.md b/PROJECT_OVERVIEW.md new file mode 100644 index 0000000..5219133 --- /dev/null +++ b/PROJECT_OVERVIEW.md @@ -0,0 +1,273 @@ +# Vagrant Manager 项目概览 + +## 项目简介 + +**Vagrant Manager for OS X** 是一个 macOS 状态栏菜单应用程序,用于从统一位置管理所有 Vagrant 虚拟机。该项目由 Lanayo Technology 开发,采用 MIT 许可证。 + +- **项目类型**: macOS 原生应用程序 (Objective-C) +- **最低系统要求**: OS X 10.8 Mountain Lion 或更高版本 +- **开发工具**: Xcode, CocoaPods +- **许可证**: MIT License + +## 核心功能 + +### 1. 虚拟机管理 +- 自动检测 Vagrant 实例(通过 NFS 扫描、全局状态扫描、服务提供商检测) +- 支持书签功能,手动添加和管理 Vagrant 实例 +- 显示虚拟机状态(运行中、已停止、已暂停等) +- 支持多虚拟机实例管理 + +### 2. Vagrant 操作 +- **启动/停止**: `vagrant up`, `vagrant halt` +- **暂停/恢复**: `vagrant suspend`, `vagrant resume` +- **重启**: `vagrant reload` +- **配置**: `vagrant provision` +- **销毁**: `vagrant destroy` +- **SSH 连接**: `vagrant ssh` +- **RDP 连接**: `vagrant rdp` + +### 3. 自定义命令 +- 支持自定义命令管理 +- 可在主机或虚拟机内执行 +- 支持在终端中运行或后台执行 + +### 4. 服务提供商支持 +- **VirtualBox**: 默认支持 +- **Parallels**: 支持 Parallels Desktop +- **自定义提供商**: 支持添加自定义提供商 +- 自动检测提供商类型 + +### 5. 用户界面 +- 状态栏菜单应用(LSUIElement) +- 支持多种图标主题(clean, flat) +- 显示运行中的虚拟机数量 +- 任务输出窗口 +- 偏好设置窗口 +- 书签管理窗口 + +### 6. 其他特性 +- 自动更新(使用 Sparkle 框架) +- 检查 Vagrant 版本更新 +- 退出时自动停止所有虚拟机(可选) +- 启动时自动启动书签的虚拟机(可选) +- 定时刷新虚拟机状态 +- 系统唤醒后自动刷新 +- 通知中心集成 + +## 项目架构 + +### 核心类结构 + +``` +AppDelegate (应用程序主控制器) +├── VagrantManager (单例,管理所有 Vagrant 实例) +│ ├── VagrantInstance (Vagrant 实例,包含多个机器) +│ │ └── VagrantMachine (单个虚拟机) +│ ├── VirtualMachineServiceProvider (服务提供商接口) +│ │ ├── VirtualBoxServiceProvider +│ │ └── ParallelsServiceProvider +│ └── VagrantInstanceCache (实例缓存) +├── NativeMenu (状态栏菜单) +├── BookmarkManager (书签管理) +├── CustomCommandManager (自定义命令管理) +├── CustomProviderManager (自定义提供商管理) +└── 各种窗口控制器 + ├── PreferencesWindow + ├── AboutWindow + ├── ManageBookmarksWindow + ├── ManageCustomCommandsWindow + ├── ManageCustomProvidersWindow + └── TaskOutputWindow +``` + +### 主要组件 + +#### 1. **AppDelegate** (`AppDelegate.h/m`) +- 应用程序生命周期管理 +- 协调各个组件 +- 处理 Vagrant 命令执行 +- 管理窗口和通知 +- 处理应用更新 + +#### 2. **VagrantManager** (`VagrantManager.h/m`) +- 单例模式管理所有 Vagrant 实例 +- 实例发现和刷新 +- 服务提供商注册和管理 +- 实例状态同步 + +#### 3. **VagrantInstance** (`VagrantInstance.h/m`) +- 表示一个 Vagrant 项目目录 +- 包含多个 VagrantMachine +- 查询机器状态 +- 管理 Vagrantfile + +#### 4. **VagrantMachine** (`VagrantMachine.h/m`) +- 表示单个虚拟机 +- 状态管理(Unknown, NotCreated, PowerOff, Saved, Running, Restoring) +- 状态字符串转换 + +#### 5. **NativeMenu** (`NativeMenu.h/m`) +- 构建和管理状态栏菜单 +- 菜单项点击处理 +- 菜单刷新 + +#### 6. **扫描器组件** +- **NFSScanner**: 扫描 NFS 导出以发现 Vagrant 实例 +- **VagrantGlobalStatusScanner**: 解析 `vagrant global-status` 输出 +- **VirtualBoxServiceProvider**: 通过 VBoxManage 发现实例 +- **ParallelsServiceProvider**: 通过 prlctl 发现实例 + +#### 7. **管理器组件** +- **BookmarkManager**: 管理用户书签(持久化存储) +- **CustomCommandManager**: 管理自定义命令 +- **CustomProviderManager**: 管理自定义提供商 + +## 技术栈 + +### 开发框架 +- **Cocoa/AppKit**: macOS 原生 UI 框架 +- **Foundation**: 基础框架 +- **Sparkle**: 自动更新框架(通过 CocoaPods) + +### 依赖管理 +- **CocoaPods**: 依赖管理工具 +- 主要依赖: `Sparkle` (自动更新) + +### 构建系统 +- **Xcode Project**: 使用 Xcode 项目文件 +- **CocoaPods Workspace**: 使用 `.xcworkspace` 进行构建 + +## 文件结构 + +``` +vagrant-manager/ +├── Vagrant Manager/ # 主应用代码 +│ ├── AppDelegate.h/m # 应用程序委托 +│ ├── VagrantManager.h/m # Vagrant 管理器 +│ ├── VagrantInstance.h/m # Vagrant 实例 +│ ├── VagrantMachine.h/m # Vagrant 虚拟机 +│ ├── NativeMenu.h/m # 状态栏菜单 +│ ├── BookmarkManager.h/m # 书签管理 +│ ├── CustomCommandManager.h/m # 自定义命令管理 +│ ├── CustomProviderManager.h/m # 自定义提供商管理 +│ ├── 各种窗口控制器 +│ ├── 服务提供商实现 +│ ├── 扫描器组件 +│ └── 资源文件(图片、XIB 等) +├── dmg/ # DMG 构建配置 +│ ├── appdmg.json +│ └── 图标和背景图片 +├── Podfile # CocoaPods 配置 +├── Podfile.lock # 依赖锁定文件 +├── README.md # 项目说明 +├── LICENSE.md # MIT 许可证 +└── Vagrant Manager.xcodeproj/ # Xcode 项目文件 +``` + +## 数据流 + +### 实例发现流程 +1. **启动时**: AppDelegate 初始化 VagrantManager +2. **刷新触发**: 用户操作、定时器、系统唤醒等 +3. **多源扫描**: + - 从书签加载实例 + - NFS 扫描 + - Vagrant 全局状态扫描 + - 服务提供商扫描(如果启用) +4. **实例查询**: 并行查询每个实例的机器状态 +5. **状态更新**: 通过委托通知 UI 更新 +6. **菜单重建**: NativeMenu 根据新状态重建菜单 + +### 命令执行流程 +1. **用户点击菜单项**: NativeMenu 调用 AppDelegate +2. **构建命令**: 根据操作类型构建 Vagrant 命令 +3. **创建任务**: 使用 NSTask 执行命令 +4. **显示输出**: TaskOutputWindow 显示执行结果 +5. **完成通知**: 任务完成后发送通知 +6. **自动刷新**: 触发实例状态刷新 + +## 配置和偏好设置 + +### 用户偏好设置(NSUserDefaults) +- `haltOnExit`: 退出时停止所有虚拟机 +- `refreshEvery`: 启用定时刷新 +- `refreshEveryInterval`: 刷新间隔(秒) +- `statusBarIconTheme`: 状态栏图标主题(clean/flat) +- `showRunningVmCount`: 显示运行中的虚拟机数量 +- `usePathAsInstanceDisplayName`: 使用路径作为显示名称 +- `includeMachineNamesInMenu`: 在菜单中包含机器名称 +- `showTaskNotification`: 显示任务通知 +- `hideTaskWindows`: 隐藏任务窗口 +- `terminalPreference`: 终端偏好(Terminal/iTerm/Hyper) +- `terminalEditorPreference`: 终端编辑器偏好 +- `useProviderMachineDetection`: 使用提供商机器检测 +- `dontShowUpdateNotification`: 不显示更新通知 + +## 通知系统 + +项目使用 NSNotificationCenter 进行组件间通信: + +- `vagrant-manager.task-completed`: 任务完成 +- `vagrant-manager.theme-changed`: 主题更改 +- `vagrant-manager.refreshing-started/ended`: 刷新开始/结束 +- `vagrant-manager.instance-added/removed/updated`: 实例变化 +- `vagrant-manager.bookmarks-updated`: 书签更新 +- `vagrant-manager.update-available`: 更新可用 +- `vagrant-manager.started-shutdown`: 开始关闭 + +## 构建和分发 + +### 构建 DMG +1. 将编译好的 `Vagrant Manager.app` 放入 `dmg/` 目录 +2. 使用 `appdmg` 工具构建: + ```bash + appdmg dmg/appdmg.json + ``` + +### 发布流程 +- 开发分支: `develop` +- 发布分支: `master` (仅包含标记的发布版本) +- 自动更新: 通过 Sparkle 框架,从 `https://api.lanayo.com/appcast/vagrant_manager.xml` 获取更新 + +## 开发注意事项 + +### 代码规范 +- 使用 Objective-C 编写 +- 遵循 Cocoa 命名约定 +- 使用委托模式进行组件通信 +- 使用单例模式管理共享资源 + +### 线程安全 +- 使用 `@synchronized` 保护共享数据 +- 使用 GCD (Grand Central Dispatch) 进行并发操作 +- UI 更新必须在主线程 + +### 内存管理 +- 使用 ARC (Automatic Reference Counting) +- 注意循环引用(使用 `weak` 引用打破循环) + +## 已知限制 + +1. Vagrant 机器必须先初始化才能被检测到 +2. 需要 Vagrant 和 VirtualBox/Parallels 命令在 PATH 中 +3. 某些未检测到的机器需要手动配置书签 +4. 首次刷新时才会启动标记为"启动时启动"的书签 + +## 扩展点 + +### 添加新的服务提供商 +1. 实现 `VirtualMachineServiceProvider` 协议 +2. 在 `AppDelegate` 中注册提供商 +3. 实现 `getVagrantInstancePaths` 方法返回实例路径 + +### 添加新的 Vagrant 操作 +1. 在 `AppDelegate` 中添加操作方法 +2. 在 `NativeMenu` 中添加菜单项 +3. 实现命令构建和执行逻辑 + +## 相关资源 + +- 官方网站: http://vagrantmanager.com/ +- GitHub: https://github.com/lanayotech/vagrant-manager +- Windows 版本: https://github.com/lanayotech/vagrant-manager-windows + diff --git a/Podfile b/Podfile index 592691c..e6d195a 100644 --- a/Podfile +++ b/Podfile @@ -1,6 +1,6 @@ -platform :osx, '10.8' +platform :osx, '11.0' target "Vagrant Manager" do - pod 'Sparkle' + pod 'Sparkle', '~> 2.0' end diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md new file mode 100644 index 0000000..797e629 --- /dev/null +++ b/RELEASE_GUIDE.md @@ -0,0 +1,159 @@ +# 发布指南 + +## 快速开始 + +### 自动发布 ARM64 DMG + +1. **创建并推送版本 tag:** + ```bash + git tag v2.7.2 + git push origin v2.7.2 + ``` + +2. **GitHub Actions 会自动:** + - 检测到 tag 推送 + - 在 macOS 14 runner 上构建 ARM64 版本 + - 创建 DMG 安装包 + - 发布到 GitHub Releases + +3. **查看构建进度:** + - 访问 GitHub 仓库的 **Actions** 标签页 + - 查看最新的 workflow 运行状态 + +### 手动触发构建 + +1. 进入 GitHub 仓库 → **Actions** 标签页 +2. 选择 **Build and Release ARM64 DMG** workflow +3. 点击 **Run workflow** +4. 输入版本号(例如:`v2.7.2`) +5. 点击 **Run workflow** + +## Workflow 说明 + +### `build-and-release.yml` - ARM64 专用 + +**用途:** 快速构建和发布 ARM64 版本的 DMG + +**特点:** +- 专门针对 Apple Silicon Mac +- 构建速度快 +- 适合大多数用户(Apple Silicon 是主流) + +**触发:** +- 推送 `v*` tag +- 手动触发 + +### `build-universal-dmg.yml` - 通用构建 + +**用途:** 构建多种架构的 DMG + +**支持的架构:** +- `universal` - 同时支持 ARM64 和 x86_64(推荐) +- `arm64` - 仅 Apple Silicon +- `x86_64` - 仅 Intel Mac + +**触发:** +- 推送 `v*` tag(默认构建 universal) +- 手动触发(可选择架构) + +## 版本号规范 + +建议使用语义化版本号: +- `v2.7.2` - 补丁版本 +- `v2.8.0` - 次要版本 +- `v3.0.0` - 主要版本 + +## 发布检查清单 + +在创建 tag 之前,确保: + +- [ ] 代码已提交并推送到主分支 +- [ ] 版本号已更新(在 Xcode 项目中) +- [ ] CHANGELOG 已更新(如果有) +- [ ] 所有测试通过 +- [ ] README 中的版本信息已更新 + +## 发布后验证 + +1. **检查 Release:** + - 访问 GitHub Releases 页面 + - 确认 DMG 文件已上传 + - 检查 Release 说明是否正确 + +2. **下载测试:** + - 下载 DMG 文件 + - 在目标 Mac 上安装测试 + - 验证应用功能正常 + +3. **更新文档:** + - 更新项目 README(如果需要) + - 更新官方网站(如果有) + +## 故障排除 + +### Workflow 失败 + +**常见问题:** + +1. **CocoaPods 安装失败** + - 检查 `Podfile` 语法 + - 确保网络连接正常 + - 查看详细错误日志 + +2. **Xcode 构建失败** + - 检查 Xcode 项目配置 + - 确保所有依赖正确 + - 查看构建日志中的具体错误 + +3. **DMG 创建失败** + - 检查 `dmg/appdmg.json` 配置 + - 确保资源文件存在 + - 验证 .app 文件已正确生成 + +4. **Release 创建失败** + - 检查 GitHub token 权限 + - 确保 tag 格式正确 + - 检查 Release 是否已存在 + +### 获取帮助 + +- 查看 workflow 日志:GitHub Actions → 选择失败的运行 → 查看日志 +- 检查配置文件:`.github/workflows/` 目录 +- 参考文档:`.github/workflows/README.md` + +## 高级用法 + +### 同时发布多个架构 + +如果需要同时发布 ARM64 和 Universal 版本: + +1. 先推送 tag 触发 ARM64 构建 +2. 等待 ARM64 构建完成 +3. 手动触发 Universal 构建(使用相同的 tag) + +### 预发布版本 + +创建预发布版本(beta/alpha): + +```bash +git tag v2.8.0-beta.1 +git push origin v2.8.0-beta.1 +``` + +然后在 GitHub Releases 中手动将 Release 标记为 "Pre-release"。 + +### 代码签名(未来) + +如果需要代码签名,需要: + +1. 在 GitHub Secrets 中添加证书 +2. 更新 workflow 文件 +3. 参考 `.github/workflows/README.md` 中的代码签名部分 + +## 相关文件 + +- `.github/workflows/build-and-release.yml` - ARM64 构建 workflow +- `.github/workflows/build-universal-dmg.yml` - 通用构建 workflow +- `.github/workflows/README.md` - Workflow 详细文档 +- `dmg/appdmg.json` - DMG 配置文件 + diff --git a/Vagrant Manager.xcodeproj/project.pbxproj b/Vagrant Manager.xcodeproj/project.pbxproj index f3c30cd..fb781c6 100644 --- a/Vagrant Manager.xcodeproj/project.pbxproj +++ b/Vagrant Manager.xcodeproj/project.pbxproj @@ -1008,7 +1008,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; @@ -1051,7 +1051,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.0; SDKROOT = macosx; }; name = Release; @@ -1070,7 +1070,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Vagrant Manager/Vagrant Manager-Prefix.pch"; INFOPLIST_FILE = "Vagrant Manager/Vagrant Manager-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 2.7.1; PRODUCT_BUNDLE_IDENTIFIER = "lanayo.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; @@ -1092,7 +1092,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "Vagrant Manager/Vagrant Manager-Prefix.pch"; INFOPLIST_FILE = "Vagrant Manager/Vagrant Manager-Info.plist"; - MACOSX_DEPLOYMENT_TARGET = 10.8; + MACOSX_DEPLOYMENT_TARGET = 11.0; MARKETING_VERSION = 2.7.1; PRODUCT_BUNDLE_IDENTIFIER = "lanayo.${PRODUCT_NAME:rfc1034identifier}"; PRODUCT_NAME = "$(TARGET_NAME)"; From 7c6fa129354c66ff1a2478488207fdac1c9dfb2b Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:53:21 +0800 Subject: [PATCH 02/23] Fix CocoaPods action reference in GitHub Actions workflows - Replace invalid cocoapods-action@v1 with direct pod install command - Add conditional CocoaPods installation if not available --- .github/workflows/build-and-release.yml | 11 +++++------ .github/workflows/build-universal-dmg.yml | 11 +++++------ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 1c0d658..06704ae 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -29,13 +29,12 @@ jobs: - name: Install appdmg run: npm install -g appdmg - - name: Setup CocoaPods - uses: cocoapods-action@v1 - with: - podfile-path: Podfile - - name: Install CocoaPods dependencies - run: pod install + run: | + if ! command -v pod &> /dev/null; then + sudo gem install cocoapods + fi + pod install - name: Get version from tag id: get_version diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index 37705b1..f9b18e4 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -38,13 +38,12 @@ jobs: - name: Install appdmg run: npm install -g appdmg - - name: Setup CocoaPods - uses: cocoapods-action@v1 - with: - podfile-path: Podfile - - name: Install CocoaPods dependencies - run: pod install + run: | + if ! command -v pod &> /dev/null; then + sudo gem install cocoapods + fi + pod install - name: Get version from tag id: get_version From 37ea294acbf73c1e4f5f2334b1b5c2fc9ec9b95a Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:54:12 +0800 Subject: [PATCH 03/23] Remove npm cache from workflow - not needed for appdmg installation --- .github/workflows/build-and-release.yml | 1 - .github/workflows/build-universal-dmg.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 06704ae..0538f95 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -24,7 +24,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - name: Install appdmg run: npm install -g appdmg diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index f9b18e4..3c2494e 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -33,7 +33,6 @@ jobs: uses: actions/setup-node@v4 with: node-version: '20' - cache: 'npm' - name: Install appdmg run: npm install -g appdmg From 79a661f84aff03a6b8032634c935c19b411cec2e Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:56:43 +0800 Subject: [PATCH 04/23] Consolidate workflows: keep single unified workflow - Remove duplicate build-and-release.yml - Update build-universal-dmg.yml to default to ARM64 builds - Rename workflow to 'Build and Release DMG' - Update documentation to reflect single workflow --- .github/workflows/README.md | 40 +++--- .github/workflows/build-and-release.yml | 147 ---------------------- .github/workflows/build-universal-dmg.yml | 18 +-- 3 files changed, 24 insertions(+), 181 deletions(-) delete mode 100644 .github/workflows/build-and-release.yml diff --git a/.github/workflows/README.md b/.github/workflows/README.md index b526b6a..b51f769 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -1,31 +1,18 @@ # GitHub Actions Workflows -本项目包含两个 GitHub Actions workflow 用于自动构建和发布 DMG 包。 +本项目包含一个 GitHub Actions workflow 用于自动构建和发布 DMG 包。 -## Workflows +## Workflow -### 1. `build-and-release.yml` - ARM64 专用构建 - -专门用于构建 ARM64 (Apple Silicon) 版本的 DMG 包。 - -**触发方式:** -- 推送以 `v` 开头的 tag(例如:`v2.7.2`) -- 手动触发(Workflow Dispatch) - -**构建内容:** -- ARM64 架构的应用程序 -- DMG 安装包 -- 自动发布到 GitHub Releases - -### 2. `build-universal-dmg.yml` - 通用/多架构构建 +### `build-universal-dmg.yml` - DMG 构建和发布 支持构建多种架构的 DMG 包: -- Universal(同时支持 ARM64 和 x86_64) -- ARM64 only -- x86_64 only +- **ARM64**(默认)- Apple Silicon Mac +- **Universal** - 同时支持 ARM64 和 x86_64 +- **x86_64** - Intel Mac **触发方式:** -- 推送以 `v` 开头的 tag +- 推送以 `v` 开头的 tag(默认构建 ARM64) - 手动触发(可选择构建类型) ## 使用方法 @@ -40,24 +27,27 @@ 2. **Workflow 会自动:** - 检测到 tag 推送 - - 开始构建 + - 默认构建 ARM64 版本 - 创建 DMG 包 - 发布到 GitHub Releases ### 手动触发 1. 进入 GitHub 仓库的 **Actions** 标签页 -2. 选择对应的 workflow +2. 选择 **Build and Release DMG** workflow 3. 点击 **Run workflow** 4. 输入版本号(例如:`v2.7.2`) -5. 选择构建类型(仅限 universal workflow) +5. 选择构建类型(arm64/universal/x86_64,默认 arm64) 6. 点击 **Run workflow** ## 构建产物 构建完成后,会在 GitHub Releases 中创建: -- **Release 标题**:`Release v2.7.2 (arm64)` 或 `Release v2.7.2 (universal)` -- **DMG 文件**:`Vagrant Manager-2.7.2-arm64.dmg` 或 `Vagrant Manager-2.7.2-universal.dmg` +- **Release 标题**:`Release v2.7.2 (arm64)` 或 `Release v2.7.2 (universal)` 等 +- **DMG 文件**:根据构建类型命名,例如: + - `Vagrant Manager-2.7.2-arm64.dmg`(ARM64) + - `Vagrant Manager-2.7.2-universal.dmg`(Universal) + - `Vagrant Manager-2.7.2-x86_64.dmg`(Intel) ## 系统要求 diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml deleted file mode 100644 index 0538f95..0000000 --- a/.github/workflows/build-and-release.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: Build and Release ARM64 DMG - -on: - push: - tags: - - 'v*' # 当推送以 v 开头的 tag 时触发(例如 v2.7.2) - workflow_dispatch: # 允许手动触发 - inputs: - version: - description: 'Version tag (e.g., v2.7.2)' - required: true - type: string - -jobs: - build-arm64-dmg: - name: Build ARM64 DMG - runs-on: macos-14 # macOS 14 (Sonoma) with Apple Silicon support - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: '20' - - - name: Install appdmg - run: npm install -g appdmg - - - name: Install CocoaPods dependencies - run: | - if ! command -v pod &> /dev/null; then - sudo gem install cocoapods - fi - pod install - - - name: Get version from tag - id: get_version - run: | - if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then - VERSION="${{ github.event.inputs.version }}" - else - VERSION="${GITHUB_REF#refs/tags/}" - fi - echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT - echo "VERSION_NAME=${VERSION#v}" >> $GITHUB_OUTPUT - echo "Building version: ${VERSION}" - - - name: Build Xcode project (ARM64) - run: | - xcodebuild clean -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release - - xcodebuild archive -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release \ - -arch arm64 \ - -sdk macosx \ - -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ - CODE_SIGN_IDENTITY="" \ - CODE_SIGNING_REQUIRED=NO \ - CODE_SIGNING_ALLOWED=NO - - - name: Create export options plist - run: | - cat > exportOptions.plist < - - - - method - mac-application - signingStyle - manual - - - EOF - - - name: Export .app from archive - run: | - xcodebuild -exportArchive \ - -archivePath "$PWD/build/Vagrant Manager.xcarchive" \ - -exportPath "$PWD/build/export" \ - -exportOptionsPlist "$PWD/exportOptions.plist" - - - name: Copy .app to dmg directory - run: | - cp -R "build/export/Vagrant Manager.app" "dmg/" - - - name: Create DMG - working-directory: dmg - run: | - appdmg appdmg.json "../Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" - - - name: Verify DMG - run: | - hdiutil verify "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" - hdiutil info "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" - - - name: Get DMG size - id: dmg_size - run: | - DMG_SIZE=$(du -h "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg" | cut -f1) - echo "size=${DMG_SIZE}" >> $GITHUB_OUTPUT - echo "DMG size: ${DMG_SIZE}" - - - name: Create Release - id: create_release - uses: softprops/action-gh-release@v1 - with: - tag_name: ${{ steps.get_version.outputs.VERSION }} - name: Release ${{ steps.get_version.outputs.VERSION }} (ARM64) - body: | - ## Vagrant Manager ${{ steps.get_version.outputs.VERSION_NAME }} (ARM64) - - ### 🍎 Apple Silicon Support - This release is built for **Apple Silicon (ARM64)** Macs running macOS 11.0 or later. - - ### 📦 Installation - 1. Download the DMG file - 2. Open the DMG - 3. Drag "Vagrant Manager" to Applications folder - - ### 📋 Changes - - Built for Apple Silicon (ARM64) - - Requires macOS 11.0 (Big Sur) or later - - Updated Sparkle to 2.x for better ARM64 support - - ### 🔧 System Requirements - - macOS 11.0 (Big Sur) or later - - Apple Silicon Mac (M1/M2/M3/M4/M5) or Intel Mac with macOS 11.0+ - - Vagrant installed and in PATH - - VirtualBox or Parallels installed (if using those providers) - - ### 📊 Build Info - - **Architecture**: ARM64 - - **DMG Size**: ${{ steps.dmg_size.outputs.size }} - - **Build Date**: ${{ github.event.head_commit.timestamp || github.run_started_at }} - draft: false - prerelease: false - files: | - Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-arm64.dmg - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index 3c2494e..31873db 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -1,9 +1,9 @@ -name: Build and Release Universal DMG +name: Build and Release DMG on: push: tags: - - 'v*' # 当推送以 v 开头的 tag 时触发 + - 'v*' # 当推送以 v 开头的 tag 时触发,默认构建 ARM64 workflow_dispatch: # 允许手动触发 inputs: version: @@ -12,17 +12,17 @@ on: type: string build_type: description: 'Build type' - required: true + required: false type: choice options: - - universal - arm64 + - universal - x86_64 - default: universal + default: arm64 jobs: - build-universal-dmg: - name: Build Universal DMG + build-dmg: + name: Build DMG runs-on: macos-14 # macOS 14 with Apple Silicon support steps: @@ -49,10 +49,10 @@ jobs: run: | if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.version }}" - BUILD_TYPE="${{ github.event.inputs.build_type }}" + BUILD_TYPE="${{ github.event.inputs.build_type || 'arm64' }}" else VERSION="${GITHUB_REF#refs/tags/}" - BUILD_TYPE="universal" + BUILD_TYPE="arm64" fi echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT echo "VERSION_NAME=${VERSION#v}" >> $GITHUB_OUTPUT From e1a12d530adb6fa00e32c42f1fc6372160a94b38 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:57:34 +0800 Subject: [PATCH 05/23] Fix hdiutil info command in workflow - remove invalid usage --- .github/workflows/build-universal-dmg.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index 31873db..88d64a1 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -132,7 +132,7 @@ jobs: - name: Verify DMG run: | hdiutil verify "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" - hdiutil info "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + echo "DMG verification completed successfully" - name: Get DMG size id: dmg_size From 9340a39ddfdbd8fee524926e0bcbdd0a26896489 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:58:20 +0800 Subject: [PATCH 06/23] Update DMG filename to use vagrant-manager (lowercase with hyphen) --- .github/workflows/build-universal-dmg.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index 88d64a1..2addca5 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -127,17 +127,17 @@ jobs: - name: Create DMG working-directory: dmg run: | - appdmg appdmg.json "../Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + appdmg appdmg.json "../vagrant-manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" - name: Verify DMG run: | - hdiutil verify "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" + hdiutil verify "vagrant-manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" echo "DMG verification completed successfully" - name: Get DMG size id: dmg_size run: | - DMG_SIZE=$(du -h "Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" | cut -f1) + DMG_SIZE=$(du -h "vagrant-manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg" | cut -f1) echo "size=${DMG_SIZE}" >> $GITHUB_OUTPUT echo "DMG size: ${DMG_SIZE}" @@ -181,7 +181,7 @@ jobs: draft: false prerelease: false files: | - Vagrant Manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg + vagrant-manager-${{ steps.get_version.outputs.VERSION_NAME }}-${{ steps.archs.outputs.arch_suffix }}.dmg env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From c3cfcbeb179a16209bbae0765630caefeb398c7d Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 03:59:10 +0800 Subject: [PATCH 07/23] Remove documentation files (consolidated into workflow README) --- ARM64_UPDATE_GUIDE.md | 176 ------------------------ COMPATIBILITY_ANALYSIS.md | 168 ----------------------- PROJECT_OVERVIEW.md | 273 -------------------------------------- RELEASE_GUIDE.md | 159 ---------------------- 4 files changed, 776 deletions(-) delete mode 100644 ARM64_UPDATE_GUIDE.md delete mode 100644 COMPATIBILITY_ANALYSIS.md delete mode 100644 PROJECT_OVERVIEW.md delete mode 100644 RELEASE_GUIDE.md diff --git a/ARM64_UPDATE_GUIDE.md b/ARM64_UPDATE_GUIDE.md deleted file mode 100644 index f86afa9..0000000 --- a/ARM64_UPDATE_GUIDE.md +++ /dev/null @@ -1,176 +0,0 @@ -# ARM64 (Apple Silicon) 支持更新指南 - -## 已完成的配置更新 - -### 1. ✅ Podfile 更新 -- **平台版本**:从 `10.8` 更新到 `11.0` -- **Sparkle 版本**:从 `1.22.0` 更新到 `~> 2.0`(支持 ARM64) - -### 2. ✅ Xcode 项目配置更新 -- **MACOSX_DEPLOYMENT_TARGET**:所有配置从 `10.8` 更新到 `11.0` - - Debug 配置 - - Release 配置 - - 主应用目标配置 - -## 下一步操作 - -### 1. 更新 CocoaPods 依赖 - -运行以下命令更新依赖: - -```bash -cd /Users/kevin/projects/src/vagrant-manager -pod install -``` - -这将: -- 更新 Sparkle 到 2.x 版本 -- 重新生成 `Pods` 目录和 `Vagrant Manager.xcworkspace` - -### 2. 验证配置 - -在 Xcode 中打开项目: - -```bash -open "Vagrant Manager.xcworkspace" -``` - -检查以下设置: -1. **项目设置** → **General** → **Deployment Info** - - Minimum Deployments: macOS 11.0 -2. **构建设置** → **Architectures** - - 应该包含 `arm64` 和 `x86_64`(或使用默认的 `$(ARCHS_STANDARD)`) - -### 3. 构建测试 - -#### 仅 ARM64 构建(Apple Silicon) -```bash -xcodebuild -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release \ - -arch arm64 \ - -sdk macosx \ - -derivedDataPath ./build -``` - -#### 通用二进制构建(同时支持 Intel 和 Apple Silicon) -```bash -xcodebuild -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release \ - -arch arm64 -arch x86_64 \ - -sdk macosx \ - -derivedDataPath ./build -``` - -#### 在 Xcode 中构建 -1. 选择 **Product** → **Scheme** → **Edit Scheme** -2. 在 **Run** 和 **Archive** 的 **Build Configuration** 中选择 **Release** -3. 选择 **Product** → **Build** (⌘B) -4. 或选择 **Product** → **Archive** 创建发布版本 - -### 4. 验证架构 - -构建完成后,验证二进制文件的架构: - -```bash -# 查看应用包的架构 -file "build/Build/Products/Release/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" - -# 或使用 lipo 命令 -lipo -info "build/Build/Products/Release/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" -``` - -期望输出: -- 仅 ARM64:`arm64` -- 通用二进制:`arm64 x86_64` - -### 5. 测试 - -在 Apple Silicon Mac 上测试: - -1. **基本功能测试** - - 启动应用 - - 检查状态栏图标显示 - - 测试菜单功能 - -2. **Vagrant 集成测试** - - 检测 Vagrant 实例 - - 执行 Vagrant 命令(up, halt, suspend 等) - - 检查虚拟机状态显示 - - 测试 SSH 连接 - -3. **更新功能测试** - - 测试 Sparkle 自动更新功能 - - 验证版本检查 - -## 注意事项 - -### 系统要求 -- **最低 macOS 版本**:11.0 (Big Sur) 或更高 -- **Xcode 版本**:建议使用 Xcode 12.2 或更高版本(支持 Apple Silicon) - -### 向后兼容性 -- 更新到 macOS 11.0 后,应用将**不再支持** macOS 10.8 - 10.15 -- 如果需要支持旧版本 macOS,需要维护两个版本: - - 一个针对 macOS 10.8+(仅 Intel) - - 一个针对 macOS 11.0+(Intel + Apple Silicon) - -### Sparkle 2.x 变化 -- Sparkle 2.x 有一些 API 变化,但项目使用的 API 应该保持兼容 -- 如果遇到编译错误,可能需要更新 Sparkle 相关的代码 - -### Vagrant 在 Apple Silicon 上 -- Vagrant 本身可以在 Apple Silicon 上运行 -- 但某些虚拟机提供商可能需要特殊配置: - - **VirtualBox**:在 Apple Silicon 上支持有限,可能需要使用 UTM 或其他方案 - - **Parallels**:有原生 Apple Silicon 支持 - - **VMware Fusion**:有 Apple Silicon 版本 - -## 故障排除 - -### 如果构建失败 - -1. **清理构建** - ```bash - xcodebuild clean -workspace "Vagrant Manager.xcworkspace" -scheme "Vagrant Manager" - rm -rf build Pods Podfile.lock - pod install - ``` - -2. **检查 Sparkle 版本** - ```bash - pod search Sparkle - ``` - 确保使用支持 ARM64 的版本 - -3. **检查 Xcode 版本** - ```bash - xcodebuild -version - ``` - 确保使用 Xcode 12.2 或更高版本 - -### 如果运行时出错 - -1. **检查架构** - ```bash - arch - ``` - 在 Apple Silicon Mac 上应该显示 `arm64` - -2. **检查依赖库架构** - ```bash - file "Vagrant Manager.app/Contents/Frameworks/Sparkle.framework/Sparkle" - ``` - 应该包含 `arm64` - -## 相关资源 - -- [Apple Silicon 迁移指南](https://developer.apple.com/documentation/apple-silicon) -- [Sparkle 2.x 文档](https://sparkle-project.org/documentation/) -- [Vagrant 官方文档](https://www.vagrantup.com/docs) - -## 更新日期 - -配置更新完成日期:2025年1月 - diff --git a/COMPATIBILITY_ANALYSIS.md b/COMPATIBILITY_ANALYSIS.md deleted file mode 100644 index 40c0eb3..0000000 --- a/COMPATIBILITY_ANALYSIS.md +++ /dev/null @@ -1,168 +0,0 @@ -# Vagrant Manager 兼容性分析 - -## 1. Vagrant 版本兼容性 - -### ✅ 支持最新版 Vagrant - -**结论:项目应该能够支持最新版本的 Vagrant(包括 v2.4.9)** - -#### 技术分析: - -1. **使用标准 Vagrant CLI 命令** - - 项目通过执行标准的 Vagrant CLI 命令来与 Vagrant 交互 - - 使用的命令包括: - - `vagrant status` - 查询虚拟机状态 - - `vagrant global-status` - 查询全局状态 - - `vagrant version --machine-readable` - 检查版本 - - `vagrant up`, `vagrant halt`, `vagrant suspend`, `vagrant resume` 等标准操作命令 - -2. **命令兼容性** - - 这些命令都是 Vagrant 的核心命令,在 Vagrant 2.x 版本中保持稳定 - - 项目通过解析命令输出来获取信息,而不是依赖内部 API - - 只要 Vagrant CLI 的输出格式保持兼容,项目就能正常工作 - -3. **版本检查机制** - - 项目内置了 Vagrant 版本检查功能(`checkForVagrantUpdates:` 方法) - - 使用 `vagrant version --machine-readable` 命令获取版本信息 - - 支持版本比较和更新提示 - -4. **Vagrant 维护状态** - - 根据 [Vagrant GitHub 仓库](https://github.com/hashicorp/vagrant),Vagrant 仍在积极维护 - - 最新版本:v2.4.9(2025年8月发布) - - 项目使用标准的 Vagrant 命令,应该与最新版本兼容 - -### ⚠️ 潜在兼容性问题 - -1. **输出格式变化** - - 如果 Vagrant 未来改变命令输出格式,可能需要更新解析逻辑 - - 主要影响文件: - - `VagrantGlobalStatusScanner.m` - 解析 `vagrant global-status` 输出 - - `VagrantInstance.m` - 解析 `vagrant status` 输出 - -2. **新功能支持** - - 如果 Vagrant 添加新的命令或选项,需要手动添加支持 - - 项目支持自定义命令功能,可以通过此功能扩展支持 - -## 2. ARM64 (Apple Silicon) 支持 - -### ✅ 理论上支持,但需要配置更新 - -**结论:项目可以编译为 ARM64 版本,但需要更新 Xcode 项目配置** - -#### 技术分析: - -1. **代码层面兼容性** - - ✅ 使用标准的 Cocoa/AppKit 框架,这些框架在 Apple Silicon 上都有原生支持 - - ✅ 使用 Objective-C 和 ARC,完全兼容 ARM64 - - ✅ 没有使用任何架构特定的代码或汇编 - - ✅ 所有系统框架调用都是跨架构兼容的 - -2. **项目配置现状** - ```pbxproj - MACOSX_DEPLOYMENT_TARGET = 10.8; - SDKROOT = macosx; - ``` - - 当前配置没有明确指定架构 - - 没有 `EXCLUDED_ARCHS` 设置(这是好的,意味着不排除任何架构) - - 使用 `ONLY_ACTIVE_ARCH = YES`(Debug 配置),这意味着会为当前构建机器编译对应架构 - -3. **依赖项兼容性** - - **Sparkle 框架**(通过 CocoaPods) - - 当前版本:Sparkle 1.22.0(在 `Podfile.lock` 中) - - ⚠️ Sparkle 1.x 对 ARM64 的支持可能不完整 - - ✅ Sparkle 2.x 版本完全支持 ARM64 - - **建议**:升级到 Sparkle 2.x 以获得更好的 ARM64 支持 - - 更新方法: - ```ruby - # 在 Podfile 中指定版本 - pod 'Sparkle', '~> 2.0' - # 然后运行 - pod update Sparkle - ``` - -4. **构建要求** - - 需要在支持 Apple Silicon 的 Xcode 版本中构建 - - 建议使用 Xcode 12.2 或更高版本(支持 Apple Silicon) - - 最低部署目标可能需要更新(当前是 10.8,Apple Silicon 需要 macOS 11.0+) - -### 🔧 编译 ARM64 版本的建议步骤 - -1. **更新部署目标** - ```pbxproj - MACOSX_DEPLOYMENT_TARGET = 11.0; // 或更高,Apple Silicon 需要 macOS 11.0+ - ``` - -2. **明确指定架构(可选)** - ```pbxproj - ARCHS = "$(ARCHS_STANDARD)"; // 包含 arm64 和 x86_64 - // 或者只编译 ARM64 - ARCHS = "arm64"; - ``` - -3. **更新 Sparkle 依赖** - - 确保 Podfile 中使用支持 ARM64 的 Sparkle 版本 - - 运行 `pod update Sparkle` - -4. **测试构建** - ```bash - # 在 Apple Silicon Mac 上 - xcodebuild -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release \ - -arch arm64 \ - -sdk macosx - ``` - -5. **创建通用二进制(Universal Binary)** - ```bash - # 同时支持 Intel 和 Apple Silicon - xcodebuild -workspace "Vagrant Manager.xcworkspace" \ - -scheme "Vagrant Manager" \ - -configuration Release \ - -arch arm64 -arch x86_64 \ - -sdk macosx - ``` - -### ⚠️ 注意事项 - -1. **最低系统要求** - - Apple Silicon Mac 运行 macOS 11.0 (Big Sur) 或更高版本 - - 如果保持 10.8 作为最低版本,将无法在 Apple Silicon 上运行(因为 Apple Silicon 需要 macOS 11.0+) - -2. **Vagrant 在 Apple Silicon 上的运行** - - Vagrant 本身可以在 Apple Silicon 上运行 - - 但虚拟机提供商(如 VirtualBox)可能需要特殊配置 - - 某些 Vagrant box 可能需要 ARM64 版本 - -3. **测试建议** - - 在 Apple Silicon Mac 上完整测试所有功能 - - 测试 Vagrant 命令执行 - - 测试虚拟机状态检测 - - 测试各种 Vagrant 操作(up, halt, suspend 等) - -## 3. 总结 - -### Vagrant 版本支持 -- ✅ **支持最新版 Vagrant**:项目使用标准 CLI 命令,应该与 Vagrant 2.4.9 兼容 -- ⚠️ **需要测试**:建议在实际环境中测试最新版 Vagrant 的兼容性 - -### ARM64 支持 -- ✅ **代码兼容**:代码层面完全兼容 ARM64 -- ✅ **可以编译**:理论上可以编译为 ARM64 版本 -- 🔧 **需要配置**:需要更新 Xcode 项目配置和部署目标 -- ⚠️ **需要测试**:需要在实际的 Apple Silicon Mac 上测试 - -### 建议行动 -1. 更新 `MACOSX_DEPLOYMENT_TARGET` 到 11.0 或更高 -2. 更新 Sparkle 依赖到支持 ARM64 的版本 -3. 在 Apple Silicon Mac 上测试构建 -4. 测试与最新版 Vagrant 的兼容性 -5. 考虑创建 Universal Binary 以同时支持 Intel 和 Apple Silicon - -## 4. 相关资源 - -- [Vagrant GitHub](https://github.com/hashicorp/vagrant) -- [Vagrant 官方文档](https://www.vagrantup.com/) -- [Apple Silicon 迁移指南](https://developer.apple.com/documentation/apple-silicon) -- [Sparkle 更新框架](https://sparkle-project.org/) - diff --git a/PROJECT_OVERVIEW.md b/PROJECT_OVERVIEW.md deleted file mode 100644 index 5219133..0000000 --- a/PROJECT_OVERVIEW.md +++ /dev/null @@ -1,273 +0,0 @@ -# Vagrant Manager 项目概览 - -## 项目简介 - -**Vagrant Manager for OS X** 是一个 macOS 状态栏菜单应用程序,用于从统一位置管理所有 Vagrant 虚拟机。该项目由 Lanayo Technology 开发,采用 MIT 许可证。 - -- **项目类型**: macOS 原生应用程序 (Objective-C) -- **最低系统要求**: OS X 10.8 Mountain Lion 或更高版本 -- **开发工具**: Xcode, CocoaPods -- **许可证**: MIT License - -## 核心功能 - -### 1. 虚拟机管理 -- 自动检测 Vagrant 实例(通过 NFS 扫描、全局状态扫描、服务提供商检测) -- 支持书签功能,手动添加和管理 Vagrant 实例 -- 显示虚拟机状态(运行中、已停止、已暂停等) -- 支持多虚拟机实例管理 - -### 2. Vagrant 操作 -- **启动/停止**: `vagrant up`, `vagrant halt` -- **暂停/恢复**: `vagrant suspend`, `vagrant resume` -- **重启**: `vagrant reload` -- **配置**: `vagrant provision` -- **销毁**: `vagrant destroy` -- **SSH 连接**: `vagrant ssh` -- **RDP 连接**: `vagrant rdp` - -### 3. 自定义命令 -- 支持自定义命令管理 -- 可在主机或虚拟机内执行 -- 支持在终端中运行或后台执行 - -### 4. 服务提供商支持 -- **VirtualBox**: 默认支持 -- **Parallels**: 支持 Parallels Desktop -- **自定义提供商**: 支持添加自定义提供商 -- 自动检测提供商类型 - -### 5. 用户界面 -- 状态栏菜单应用(LSUIElement) -- 支持多种图标主题(clean, flat) -- 显示运行中的虚拟机数量 -- 任务输出窗口 -- 偏好设置窗口 -- 书签管理窗口 - -### 6. 其他特性 -- 自动更新(使用 Sparkle 框架) -- 检查 Vagrant 版本更新 -- 退出时自动停止所有虚拟机(可选) -- 启动时自动启动书签的虚拟机(可选) -- 定时刷新虚拟机状态 -- 系统唤醒后自动刷新 -- 通知中心集成 - -## 项目架构 - -### 核心类结构 - -``` -AppDelegate (应用程序主控制器) -├── VagrantManager (单例,管理所有 Vagrant 实例) -│ ├── VagrantInstance (Vagrant 实例,包含多个机器) -│ │ └── VagrantMachine (单个虚拟机) -│ ├── VirtualMachineServiceProvider (服务提供商接口) -│ │ ├── VirtualBoxServiceProvider -│ │ └── ParallelsServiceProvider -│ └── VagrantInstanceCache (实例缓存) -├── NativeMenu (状态栏菜单) -├── BookmarkManager (书签管理) -├── CustomCommandManager (自定义命令管理) -├── CustomProviderManager (自定义提供商管理) -└── 各种窗口控制器 - ├── PreferencesWindow - ├── AboutWindow - ├── ManageBookmarksWindow - ├── ManageCustomCommandsWindow - ├── ManageCustomProvidersWindow - └── TaskOutputWindow -``` - -### 主要组件 - -#### 1. **AppDelegate** (`AppDelegate.h/m`) -- 应用程序生命周期管理 -- 协调各个组件 -- 处理 Vagrant 命令执行 -- 管理窗口和通知 -- 处理应用更新 - -#### 2. **VagrantManager** (`VagrantManager.h/m`) -- 单例模式管理所有 Vagrant 实例 -- 实例发现和刷新 -- 服务提供商注册和管理 -- 实例状态同步 - -#### 3. **VagrantInstance** (`VagrantInstance.h/m`) -- 表示一个 Vagrant 项目目录 -- 包含多个 VagrantMachine -- 查询机器状态 -- 管理 Vagrantfile - -#### 4. **VagrantMachine** (`VagrantMachine.h/m`) -- 表示单个虚拟机 -- 状态管理(Unknown, NotCreated, PowerOff, Saved, Running, Restoring) -- 状态字符串转换 - -#### 5. **NativeMenu** (`NativeMenu.h/m`) -- 构建和管理状态栏菜单 -- 菜单项点击处理 -- 菜单刷新 - -#### 6. **扫描器组件** -- **NFSScanner**: 扫描 NFS 导出以发现 Vagrant 实例 -- **VagrantGlobalStatusScanner**: 解析 `vagrant global-status` 输出 -- **VirtualBoxServiceProvider**: 通过 VBoxManage 发现实例 -- **ParallelsServiceProvider**: 通过 prlctl 发现实例 - -#### 7. **管理器组件** -- **BookmarkManager**: 管理用户书签(持久化存储) -- **CustomCommandManager**: 管理自定义命令 -- **CustomProviderManager**: 管理自定义提供商 - -## 技术栈 - -### 开发框架 -- **Cocoa/AppKit**: macOS 原生 UI 框架 -- **Foundation**: 基础框架 -- **Sparkle**: 自动更新框架(通过 CocoaPods) - -### 依赖管理 -- **CocoaPods**: 依赖管理工具 -- 主要依赖: `Sparkle` (自动更新) - -### 构建系统 -- **Xcode Project**: 使用 Xcode 项目文件 -- **CocoaPods Workspace**: 使用 `.xcworkspace` 进行构建 - -## 文件结构 - -``` -vagrant-manager/ -├── Vagrant Manager/ # 主应用代码 -│ ├── AppDelegate.h/m # 应用程序委托 -│ ├── VagrantManager.h/m # Vagrant 管理器 -│ ├── VagrantInstance.h/m # Vagrant 实例 -│ ├── VagrantMachine.h/m # Vagrant 虚拟机 -│ ├── NativeMenu.h/m # 状态栏菜单 -│ ├── BookmarkManager.h/m # 书签管理 -│ ├── CustomCommandManager.h/m # 自定义命令管理 -│ ├── CustomProviderManager.h/m # 自定义提供商管理 -│ ├── 各种窗口控制器 -│ ├── 服务提供商实现 -│ ├── 扫描器组件 -│ └── 资源文件(图片、XIB 等) -├── dmg/ # DMG 构建配置 -│ ├── appdmg.json -│ └── 图标和背景图片 -├── Podfile # CocoaPods 配置 -├── Podfile.lock # 依赖锁定文件 -├── README.md # 项目说明 -├── LICENSE.md # MIT 许可证 -└── Vagrant Manager.xcodeproj/ # Xcode 项目文件 -``` - -## 数据流 - -### 实例发现流程 -1. **启动时**: AppDelegate 初始化 VagrantManager -2. **刷新触发**: 用户操作、定时器、系统唤醒等 -3. **多源扫描**: - - 从书签加载实例 - - NFS 扫描 - - Vagrant 全局状态扫描 - - 服务提供商扫描(如果启用) -4. **实例查询**: 并行查询每个实例的机器状态 -5. **状态更新**: 通过委托通知 UI 更新 -6. **菜单重建**: NativeMenu 根据新状态重建菜单 - -### 命令执行流程 -1. **用户点击菜单项**: NativeMenu 调用 AppDelegate -2. **构建命令**: 根据操作类型构建 Vagrant 命令 -3. **创建任务**: 使用 NSTask 执行命令 -4. **显示输出**: TaskOutputWindow 显示执行结果 -5. **完成通知**: 任务完成后发送通知 -6. **自动刷新**: 触发实例状态刷新 - -## 配置和偏好设置 - -### 用户偏好设置(NSUserDefaults) -- `haltOnExit`: 退出时停止所有虚拟机 -- `refreshEvery`: 启用定时刷新 -- `refreshEveryInterval`: 刷新间隔(秒) -- `statusBarIconTheme`: 状态栏图标主题(clean/flat) -- `showRunningVmCount`: 显示运行中的虚拟机数量 -- `usePathAsInstanceDisplayName`: 使用路径作为显示名称 -- `includeMachineNamesInMenu`: 在菜单中包含机器名称 -- `showTaskNotification`: 显示任务通知 -- `hideTaskWindows`: 隐藏任务窗口 -- `terminalPreference`: 终端偏好(Terminal/iTerm/Hyper) -- `terminalEditorPreference`: 终端编辑器偏好 -- `useProviderMachineDetection`: 使用提供商机器检测 -- `dontShowUpdateNotification`: 不显示更新通知 - -## 通知系统 - -项目使用 NSNotificationCenter 进行组件间通信: - -- `vagrant-manager.task-completed`: 任务完成 -- `vagrant-manager.theme-changed`: 主题更改 -- `vagrant-manager.refreshing-started/ended`: 刷新开始/结束 -- `vagrant-manager.instance-added/removed/updated`: 实例变化 -- `vagrant-manager.bookmarks-updated`: 书签更新 -- `vagrant-manager.update-available`: 更新可用 -- `vagrant-manager.started-shutdown`: 开始关闭 - -## 构建和分发 - -### 构建 DMG -1. 将编译好的 `Vagrant Manager.app` 放入 `dmg/` 目录 -2. 使用 `appdmg` 工具构建: - ```bash - appdmg dmg/appdmg.json - ``` - -### 发布流程 -- 开发分支: `develop` -- 发布分支: `master` (仅包含标记的发布版本) -- 自动更新: 通过 Sparkle 框架,从 `https://api.lanayo.com/appcast/vagrant_manager.xml` 获取更新 - -## 开发注意事项 - -### 代码规范 -- 使用 Objective-C 编写 -- 遵循 Cocoa 命名约定 -- 使用委托模式进行组件通信 -- 使用单例模式管理共享资源 - -### 线程安全 -- 使用 `@synchronized` 保护共享数据 -- 使用 GCD (Grand Central Dispatch) 进行并发操作 -- UI 更新必须在主线程 - -### 内存管理 -- 使用 ARC (Automatic Reference Counting) -- 注意循环引用(使用 `weak` 引用打破循环) - -## 已知限制 - -1. Vagrant 机器必须先初始化才能被检测到 -2. 需要 Vagrant 和 VirtualBox/Parallels 命令在 PATH 中 -3. 某些未检测到的机器需要手动配置书签 -4. 首次刷新时才会启动标记为"启动时启动"的书签 - -## 扩展点 - -### 添加新的服务提供商 -1. 实现 `VirtualMachineServiceProvider` 协议 -2. 在 `AppDelegate` 中注册提供商 -3. 实现 `getVagrantInstancePaths` 方法返回实例路径 - -### 添加新的 Vagrant 操作 -1. 在 `AppDelegate` 中添加操作方法 -2. 在 `NativeMenu` 中添加菜单项 -3. 实现命令构建和执行逻辑 - -## 相关资源 - -- 官方网站: http://vagrantmanager.com/ -- GitHub: https://github.com/lanayotech/vagrant-manager -- Windows 版本: https://github.com/lanayotech/vagrant-manager-windows - diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md deleted file mode 100644 index 797e629..0000000 --- a/RELEASE_GUIDE.md +++ /dev/null @@ -1,159 +0,0 @@ -# 发布指南 - -## 快速开始 - -### 自动发布 ARM64 DMG - -1. **创建并推送版本 tag:** - ```bash - git tag v2.7.2 - git push origin v2.7.2 - ``` - -2. **GitHub Actions 会自动:** - - 检测到 tag 推送 - - 在 macOS 14 runner 上构建 ARM64 版本 - - 创建 DMG 安装包 - - 发布到 GitHub Releases - -3. **查看构建进度:** - - 访问 GitHub 仓库的 **Actions** 标签页 - - 查看最新的 workflow 运行状态 - -### 手动触发构建 - -1. 进入 GitHub 仓库 → **Actions** 标签页 -2. 选择 **Build and Release ARM64 DMG** workflow -3. 点击 **Run workflow** -4. 输入版本号(例如:`v2.7.2`) -5. 点击 **Run workflow** - -## Workflow 说明 - -### `build-and-release.yml` - ARM64 专用 - -**用途:** 快速构建和发布 ARM64 版本的 DMG - -**特点:** -- 专门针对 Apple Silicon Mac -- 构建速度快 -- 适合大多数用户(Apple Silicon 是主流) - -**触发:** -- 推送 `v*` tag -- 手动触发 - -### `build-universal-dmg.yml` - 通用构建 - -**用途:** 构建多种架构的 DMG - -**支持的架构:** -- `universal` - 同时支持 ARM64 和 x86_64(推荐) -- `arm64` - 仅 Apple Silicon -- `x86_64` - 仅 Intel Mac - -**触发:** -- 推送 `v*` tag(默认构建 universal) -- 手动触发(可选择架构) - -## 版本号规范 - -建议使用语义化版本号: -- `v2.7.2` - 补丁版本 -- `v2.8.0` - 次要版本 -- `v3.0.0` - 主要版本 - -## 发布检查清单 - -在创建 tag 之前,确保: - -- [ ] 代码已提交并推送到主分支 -- [ ] 版本号已更新(在 Xcode 项目中) -- [ ] CHANGELOG 已更新(如果有) -- [ ] 所有测试通过 -- [ ] README 中的版本信息已更新 - -## 发布后验证 - -1. **检查 Release:** - - 访问 GitHub Releases 页面 - - 确认 DMG 文件已上传 - - 检查 Release 说明是否正确 - -2. **下载测试:** - - 下载 DMG 文件 - - 在目标 Mac 上安装测试 - - 验证应用功能正常 - -3. **更新文档:** - - 更新项目 README(如果需要) - - 更新官方网站(如果有) - -## 故障排除 - -### Workflow 失败 - -**常见问题:** - -1. **CocoaPods 安装失败** - - 检查 `Podfile` 语法 - - 确保网络连接正常 - - 查看详细错误日志 - -2. **Xcode 构建失败** - - 检查 Xcode 项目配置 - - 确保所有依赖正确 - - 查看构建日志中的具体错误 - -3. **DMG 创建失败** - - 检查 `dmg/appdmg.json` 配置 - - 确保资源文件存在 - - 验证 .app 文件已正确生成 - -4. **Release 创建失败** - - 检查 GitHub token 权限 - - 确保 tag 格式正确 - - 检查 Release 是否已存在 - -### 获取帮助 - -- 查看 workflow 日志:GitHub Actions → 选择失败的运行 → 查看日志 -- 检查配置文件:`.github/workflows/` 目录 -- 参考文档:`.github/workflows/README.md` - -## 高级用法 - -### 同时发布多个架构 - -如果需要同时发布 ARM64 和 Universal 版本: - -1. 先推送 tag 触发 ARM64 构建 -2. 等待 ARM64 构建完成 -3. 手动触发 Universal 构建(使用相同的 tag) - -### 预发布版本 - -创建预发布版本(beta/alpha): - -```bash -git tag v2.8.0-beta.1 -git push origin v2.8.0-beta.1 -``` - -然后在 GitHub Releases 中手动将 Release 标记为 "Pre-release"。 - -### 代码签名(未来) - -如果需要代码签名,需要: - -1. 在 GitHub Secrets 中添加证书 -2. 更新 workflow 文件 -3. 参考 `.github/workflows/README.md` 中的代码签名部分 - -## 相关文件 - -- `.github/workflows/build-and-release.yml` - ARM64 构建 workflow -- `.github/workflows/build-universal-dmg.yml` - 通用构建 workflow -- `.github/workflows/README.md` - Workflow 详细文档 -- `dmg/appdmg.json` - DMG 配置文件 - From f8d5cac053642b1e0af7de764b1fa92ae63a6324 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:02:21 +0800 Subject: [PATCH 08/23] Add quarantine removal and Gatekeeper bypass instructions - Remove quarantine attribute from .app before packaging - Add user instructions for bypassing Gatekeeper warning --- .github/workflows/build-universal-dmg.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build-universal-dmg.yml b/.github/workflows/build-universal-dmg.yml index 2addca5..99819f4 100644 --- a/.github/workflows/build-universal-dmg.yml +++ b/.github/workflows/build-universal-dmg.yml @@ -120,6 +120,10 @@ jobs: file "build/export/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" lipo -info "build/export/Vagrant Manager.app/Contents/MacOS/Vagrant Manager" + - name: Remove quarantine attribute from .app + run: | + xattr -cr "build/export/Vagrant Manager.app" + - name: Copy .app to dmg directory run: | cp -R "build/export/Vagrant Manager.app" "dmg/" @@ -161,6 +165,11 @@ jobs: 2. Open the DMG 3. Drag "Vagrant Manager" to Applications folder + **Note:** If macOS shows "Vagrant Manager is damaged" error: + - Right-click the app and select "Open" (don't double-click) + - Or run: `xattr -cr /Applications/Vagrant\ Manager.app` in Terminal + - Then try opening again + ### 📋 Changes - Built for ${{ steps.archs.outputs.arch_suffix }} architecture - Requires macOS 11.0 (Big Sur) or later From f64af25b153acb6a7b8071fe649147b235faf306 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:07:11 +0800 Subject: [PATCH 09/23] Update README.md: main branch, macOS 11.0+, ARM64 support --- README.md | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 299b0a5..1d7a0f2 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,54 @@ Looking for the Windows version? Check out [Vagrant Manager for Windows](https://github.com/lanayotech/vagrant-manager-windows) -# Vagrant Manager for OS X +# Vagrant Manager for macOS -Vagrant Manager is an OS X status bar menu app that lets you manage all of your vagrant machines from one central location. +Vagrant Manager is a macOS status bar menu app that lets you manage all of your vagrant machines from one central location. More information is available at http://vagrantmanager.com/ ![demo.gif](http://vagrantmanager.com/demo.gif) ## Downloads -Download Vagrant Manager from the [GitHub Releases Page](https://github.com/lanayotech/vagrant-manager/releases) +Download Vagrant Manager from the [GitHub Releases Page](https://github.com/kevin197011/vagrant-manager/releases) ## Installation Notes * Vagrant Manager can automatically detect most machines, undetected machines will require manual configuration via bookmarks. * Make sure that you have VirtualBox and Vagrant installed, and the `VBoxManage` and `vagrant` commands are in your path so that Vagrant Manager can execute them. If you use Parallels, ensure the `prlctl` command is also in your path. * Currently, vagrant machines must already be initialized in order for Vagrant Manager to detect them. Make sure you have run vagrant init on any machine you want to appear in Vagrant Manager. Once Vagrant Manager has detected a machine, you can bookmark it so that it will not disappear when you destroy the machine. You can also manually add a bookmark and specify the path to your Vagrantfile. -* Vagrant Manager requires OS X 10.8 Mountain Lion or higher +* Vagrant Manager requires macOS 11.0 (Big Sur) or higher + +## System Requirements +* macOS 11.0 (Big Sur) or later +* Apple Silicon (M1/M2/M3/M4/M5) or Intel Mac +* Vagrant installed and in PATH +* VirtualBox or Parallels installed (if using those providers) + +## Apple Silicon Support +Vagrant Manager now supports Apple Silicon (ARM64) Macs! The latest releases include native ARM64 builds for optimal performance on M1/M2/M3/M4/M5 Macs. + +**Note:** If macOS shows "Vagrant Manager is damaged" error after downloading: +* Right-click the app and select "Open" (don't double-click) +* Or run: `xattr -cr /Applications/Vagrant\ Manager.app` in Terminal +* Then try opening again ## Building DMG * Use [appdmg](https://github.com/LinusU/node-appdmg) to build the distribution DMG. * Put the `Vagrant Manager.app` file in the `dmg` foler * Run `appdmg dmg/appdmg.json ` +## Building DMG +* Use [appdmg](https://github.com/LinusU/node-appdmg) to build the distribution DMG. +* Put the `Vagrant Manager.app` file in the `dmg` folder +* Run `appdmg dmg/appdmg.json ` + +Or use the automated GitHub Actions workflow: +* Push a tag (e.g., `v2.8.0`) to automatically build and release DMG packages +* See `.github/workflows/README.md` for more details + ## Contributing to Vagrant Manager -We love code contributions! If you would like to contribute, here are some notes and guidlines: +We love code contributions! If you would like to contribute, here are some notes and guidelines: -* All development happens on the **develop** branch, so it is always the most up-to-date -* The **master** branch only contains tagged releases -* If you are going to be submitting a pull request, please branch from **develop**, and submit your pull request back to the **develop** branch +* All development happens on the **main** branch +* If you are going to be submitting a pull request, please branch from **main**, and submit your pull request back to the **main** branch * [Helpful article about forking](https://help.github.com/articles/fork-a-repo) * [Helpful article about pull requests](https://help.github.com/articles/using-pull-requests) From 58d60e8c77ac9f963f5cbf311d467deaf88908a1 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:13:00 +0800 Subject: [PATCH 10/23] Add Chinese and English language switching support Features: - Add LanguageManager for dynamic language switching - Support English and Simplified Chinese (zh-Hans) - Add language selector in Preferences window - Auto-detect system language on first launch - Save language preference to user defaults Changes: - Create LanguageManager.h/m for language management - Update PreferencesWindow to include language selector - Add zh-Hans.lproj with Chinese localization strings - Integrate LanguageManager in AppDelegate - Add language change notification handling - Create localization guide documentation --- LOCALIZATION_GUIDE.md | 113 ++++++++++++++++++ Vagrant Manager/AppDelegate.m | 10 ++ Vagrant Manager/LanguageManager.h | 20 ++++ Vagrant Manager/LanguageManager.m | 86 +++++++++++++ Vagrant Manager/PreferencesWindow.h | 2 + Vagrant Manager/PreferencesWindow.m | 32 +++++ .../zh-Hans.lproj/InfoPlist.strings | 10 ++ .../zh-Hans.lproj/Localizable.strings | 46 +++++++ 8 files changed, 319 insertions(+) create mode 100644 LOCALIZATION_GUIDE.md create mode 100644 Vagrant Manager/LanguageManager.h create mode 100644 Vagrant Manager/LanguageManager.m create mode 100644 Vagrant Manager/zh-Hans.lproj/InfoPlist.strings create mode 100644 Vagrant Manager/zh-Hans.lproj/Localizable.strings diff --git a/LOCALIZATION_GUIDE.md b/LOCALIZATION_GUIDE.md new file mode 100644 index 0000000..bdfa583 --- /dev/null +++ b/LOCALIZATION_GUIDE.md @@ -0,0 +1,113 @@ +# 本地化功能实现指南 + +## 已实现的功能 + +### 1. 语言管理器 (LanguageManager) +- `LanguageManager.h` / `LanguageManager.m` - 语言管理单例类 +- 支持动态切换语言 +- 自动检测系统语言 +- 保存用户语言偏好 + +### 2. 偏好设置窗口更新 +- 在 `PreferencesWindow` 中添加了语言选择器 +- 用户可以在偏好设置中选择语言 +- 切换语言后提示用户重启应用 + +### 3. 本地化文件 +- `zh-Hans.lproj/InfoPlist.strings` - 中文本地化信息 +- `zh-Hans.lproj/Localizable.strings` - 中文本地化字符串 + +## 需要在 Xcode 中完成的步骤 + +### 1. 添加新文件到项目 + +1. 打开 Xcode 项目 +2. 在项目导航器中,右键点击 "Vagrant Manager" 文件夹 +3. 选择 "Add Files to 'Vagrant Manager'..." +4. 添加以下文件: + - `LanguageManager.h` + - `LanguageManager.m` + - `zh-Hans.lproj/` 文件夹(包含其中的所有文件) + +### 2. 在 PreferencesWindow.xib 中添加语言选择器 + +1. 打开 `PreferencesWindow.xib` +2. 在 Interface Builder 中: + - 添加一个 `NSPopUpButton` 控件 + - 设置 Outlet 连接到 `languagePopUpButton` + - 设置 Action 连接到 `languagePopUpButtonClicked:` + - 添加标签 "Language" 或 "语言" + +### 3. 配置本地化支持 + +1. 在 Xcode 项目设置中: + - 选择项目 Target + - 进入 "Info" 标签 + - 在 "Localizations" 部分,确保包含: + - English (en) + - Chinese (Simplified) (zh-Hans) + +2. 确保 `Localizable.strings` 文件被正确本地化: + - 选择 `zh-Hans.lproj/Localizable.strings` + - 在 File Inspector 中,确保 "Localize..." 选项已启用 + +## 使用方法 + +### 在代码中使用本地化字符串 + +```objc +#import "LanguageManager.h" + +// 获取本地化字符串 +NSString *localized = [[LanguageManager sharedManager] localizedString:@"Preferences..."]; + +// 或者使用 NSLocalizedString(会自动使用 LanguageManager) +NSString *text = NSLocalizedString(@"Preferences...", nil); +``` + +### 切换语言 + +```objc +// 切换到中文 +[[LanguageManager sharedManager] setLanguage:@"zh-Hans"]; + +// 切换到英文 +[[LanguageManager sharedManager] setLanguage:@"en"]; +``` + +## 添加更多本地化字符串 + +在 `zh-Hans.lproj/Localizable.strings` 中添加新的键值对: + +``` +"Key" = "中文翻译"; +``` + +然后在代码中使用: + +```objc +NSString *text = [[LanguageManager sharedManager] localizedString:@"Key"]; +``` + +## 注意事项 + +1. **重启应用**:语言切换后需要重启应用才能完全生效 +2. **菜单重建**:语言更改时会自动重建菜单 +3. **系统语言检测**:首次启动时会自动检测系统语言 + +## 扩展支持 + +要添加更多语言: + +1. 创建新的 `.lproj` 文件夹(如 `zh-Hant.lproj` 用于繁体中文) +2. 在其中创建 `Localizable.strings` 文件 +3. 在 `LanguageManager.m` 的 `getAvailableLanguages` 方法中添加新语言 +4. 在 Xcode 项目设置中添加新的本地化 + +## 相关文件 + +- `LanguageManager.h` / `LanguageManager.m` - 语言管理器 +- `PreferencesWindow.h` / `PreferencesWindow.m` - 偏好设置窗口 +- `AppDelegate.m` - 应用委托(初始化语言管理器) +- `zh-Hans.lproj/` - 中文本地化文件 + diff --git a/Vagrant Manager/AppDelegate.m b/Vagrant Manager/AppDelegate.m index aa06036..3016fb4 100644 --- a/Vagrant Manager/AppDelegate.m +++ b/Vagrant Manager/AppDelegate.m @@ -12,6 +12,7 @@ #import "BookmarkManager.h" #import "CustomCommandManager.h" #import "CustomProviderManager.h" +#import "LanguageManager.h" @implementation AppDelegate { BOOL isRefreshingVagrantMachines; @@ -30,6 +31,9 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { //initialize data openWindows = [[NSMutableArray alloc] init]; + //initialize language manager + [LanguageManager sharedManager]; + //make sure process is running in the right state [self updateProcessType]; @@ -43,6 +47,7 @@ - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(showUpdateNotificationPreferenceChanged:) name:@"vagrant-manager.show-update-notification-preference-changed" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(bookmarksUpdated:) name:@"vagrant-manager.bookmarks-updated" object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(customCommandsUpdated:) name:@"vagrant-manager.custom-commands-updated" object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(languageChanged:) name:@"vagrant-manager.language-changed" object:nil]; //register for wake from sleep notification [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(receivedWakeNotification:) name:NSWorkspaceDidWakeNotification object:NULL]; @@ -143,6 +148,11 @@ - (void)customCommandsUpdated:(NSNotification*)notification { [_nativeMenu rebuildMenu]; } +- (void)languageChanged:(NSNotification*)notification { + // Rebuild menu when language changes + [_nativeMenu rebuildMenu]; +} + - (void)themeChanged:(NSNotification*)notification { [self updateRunningVmCount]; } diff --git a/Vagrant Manager/LanguageManager.h b/Vagrant Manager/LanguageManager.h new file mode 100644 index 0000000..8c43c7e --- /dev/null +++ b/Vagrant Manager/LanguageManager.h @@ -0,0 +1,20 @@ +// +// LanguageManager.h +// Vagrant Manager +// +// Copyright (c) 2024. All rights reserved. +// + +#import + +@interface LanguageManager : NSObject + ++ (LanguageManager*)sharedManager; + +- (NSArray*)getAvailableLanguages; +- (NSString*)getCurrentLanguage; +- (void)setLanguage:(NSString*)languageCode; +- (NSString*)localizedString:(NSString*)key; + +@end + diff --git a/Vagrant Manager/LanguageManager.m b/Vagrant Manager/LanguageManager.m new file mode 100644 index 0000000..d6b26ae --- /dev/null +++ b/Vagrant Manager/LanguageManager.m @@ -0,0 +1,86 @@ +// +// LanguageManager.m +// Vagrant Manager +// +// Copyright (c) 2024. All rights reserved. +// + +#import "LanguageManager.h" + +@implementation LanguageManager { + NSBundle *_languageBundle; +} + ++ (LanguageManager*)sharedManager { + static LanguageManager *manager; + @synchronized(self) { + if(manager == nil) { + manager = [[LanguageManager alloc] init]; + } + } + return manager; +} + +- (id)init { + self = [super init]; + if(self) { + [self loadLanguageBundle]; + } + return self; +} + +- (void)loadLanguageBundle { + NSString *languageCode = [self getCurrentLanguage]; + NSString *path = [[NSBundle mainBundle] pathForResource:languageCode ofType:@"lproj"]; + if(path) { + _languageBundle = [NSBundle bundleWithPath:path]; + } else { + _languageBundle = [NSBundle mainBundle]; + } +} + +- (NSArray*)getAvailableLanguages { + return @[ + @{@"code": @"en", @"name": @"English"}, + @{@"code": @"zh-Hans", @"name": @"简体中文"} + ]; +} + +- (NSString*)getCurrentLanguage { + NSString *savedLanguage = [[NSUserDefaults standardUserDefaults] stringForKey:@"appLanguage"]; + if(savedLanguage && [savedLanguage length] > 0) { + return savedLanguage; + } + + // 如果没有保存的语言,使用系统语言 + NSArray *preferredLanguages = [NSLocale preferredLanguages]; + if(preferredLanguages && [preferredLanguages count] > 0) { + NSString *systemLanguage = [preferredLanguages objectAtIndex:0]; + if([systemLanguage hasPrefix:@"zh"]) { + return @"zh-Hans"; + } + } + + return @"en"; +} + +- (void)setLanguage:(NSString*)languageCode { + [[NSUserDefaults standardUserDefaults] setObject:languageCode forKey:@"appLanguage"]; + [[NSUserDefaults standardUserDefaults] synchronize]; + + [self loadLanguageBundle]; + + // 发送通知,通知其他组件语言已更改 + [[NSNotificationCenter defaultCenter] postNotificationName:@"vagrant-manager.language-changed" object:nil]; +} + +- (NSString*)localizedString:(NSString*)key { + if(_languageBundle) { + NSString *localized = [_languageBundle localizedStringForKey:key value:key table:nil]; + return localized; + } + return NSLocalizedString(key, nil); +} + +@end + diff --git a/Vagrant Manager/PreferencesWindow.h b/Vagrant Manager/PreferencesWindow.h index cd1c976..89be4d1 100644 --- a/Vagrant Manager/PreferencesWindow.h +++ b/Vagrant Manager/PreferencesWindow.h @@ -31,6 +31,7 @@ @property (weak) IBOutlet NSPopUpButton *intervalMenu; @property (weak) IBOutlet NSButton *dontAnimateStatusIconCheckBox; @property (weak) IBOutlet NSButton *showTaskNotificationCheckBox; +@property (weak) IBOutlet NSPopUpButton *languagePopUpButton; - (IBAction)autoCloseCheckBoxClicked:(id)sender; @@ -51,6 +52,7 @@ - (IBAction)intervalMenuChanged:(id)sender; - (IBAction)dontAnimateStatusIconCheckBoxClicked:(id)sender; - (IBAction)showTaskNotificationCheckBoxClicked:(id)sender; +- (IBAction)languagePopUpButtonClicked:(id)sender; @end diff --git a/Vagrant Manager/PreferencesWindow.m b/Vagrant Manager/PreferencesWindow.m index 984d60b..39edbcb 100644 --- a/Vagrant Manager/PreferencesWindow.m +++ b/Vagrant Manager/PreferencesWindow.m @@ -6,6 +6,7 @@ // #import "PreferencesWindow.h" +#import "LanguageManager.h" @interface PreferencesWindow () @@ -92,6 +93,22 @@ - (void)windowDidLoad { [self.sendProfileDataCheckBox setState:[Util shouldSendProfileData] ? NSOnState : NSOffState]; [self.launchAtLoginCheckBox setState:[self willStartAtLogin] ? NSOnState : NSOffState]; + + // Setup language selector + [self.languagePopUpButton removeAllItems]; + NSArray *languages = [[LanguageManager sharedManager] getAvailableLanguages]; + NSString *currentLanguage = [[LanguageManager sharedManager] getCurrentLanguage]; + + for(NSDictionary *lang in languages) { + NSString *code = [lang objectForKey:@"code"]; + NSString *name = [lang objectForKey:@"name"]; + [self.languagePopUpButton addItemWithTitle:name]; + NSMenuItem *item = [self.languagePopUpButton lastItem]; + item.representedObject = code; + if([code isEqualToString:currentLanguage]) { + [self.languagePopUpButton selectItem:item]; + } + } } - (IBAction)haltOnExitCheckBoxClicked:(id)sender { @@ -252,6 +269,21 @@ - (IBAction)intervalMenuChanged:(id)sender { [[Util getApp] refreshTimerState]; } +- (IBAction)languagePopUpButtonClicked:(id)sender { + NSString *selectedLanguage = self.languagePopUpButton.selectedItem.representedObject; + if(selectedLanguage) { + [[LanguageManager sharedManager] setLanguage:selectedLanguage]; + + // Show alert to restart app + NSAlert *alert = [[NSAlert alloc] init]; + alert.messageText = NSLocalizedString(@"Language Changed", nil); + alert.informativeText = NSLocalizedString(@"Please restart the application for the language change to take effect.", nil); + alert.alertStyle = NSInformationalAlertStyle; + [alert addButtonWithTitle:NSLocalizedString(@"OK", nil)]; + [alert runModal]; + } +} + - (void)setLaunchOnLogin:(BOOL)launchOnLogin { NSURL *bundleURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]]; diff --git a/Vagrant Manager/zh-Hans.lproj/InfoPlist.strings b/Vagrant Manager/zh-Hans.lproj/InfoPlist.strings new file mode 100644 index 0000000..4e0a02a --- /dev/null +++ b/Vagrant Manager/zh-Hans.lproj/InfoPlist.strings @@ -0,0 +1,10 @@ +/* + InfoPlist.strings + Vagrant Manager + + Created on 2024. +*/ + +CFBundleName = "Vagrant Manager"; +CFBundleDisplayName = "Vagrant Manager"; + diff --git a/Vagrant Manager/zh-Hans.lproj/Localizable.strings b/Vagrant Manager/zh-Hans.lproj/Localizable.strings new file mode 100644 index 0000000..0f94bf3 --- /dev/null +++ b/Vagrant Manager/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,46 @@ +/* + Localizable.strings + Vagrant Manager + + Created on 2024. +*/ + +/* Preferences Window */ +"Language Changed" = "语言已更改"; +"Please restart the application for the language change to take effect." = "请重启应用程序以使语言更改生效。"; +"OK" = "确定"; + +/* Menu Items */ +"Preferences..." = "偏好设置..."; +"About Vagrant Manager" = "关于 Vagrant Manager"; +"Quit Vagrant Manager" = "退出 Vagrant Manager"; +"Refresh" = "刷新"; +"Check For Updates" = "检查更新"; +"Check For Vagrant Updates" = "检查 Vagrant 更新"; +"No Vagrant Instances" = "没有 Vagrant 实例"; +"Running" = "运行中"; +"Suspended" = "已暂停"; +"Stopped" = "已停止"; +"Unknown" = "未知"; + +/* Actions */ +"Up" = "启动"; +"Halt" = "停止"; +"Suspend" = "暂停"; +"Resume" = "恢复"; +"Reload" = "重启"; +"Provision" = "配置"; +"Destroy" = "销毁"; +"SSH" = "SSH"; +"RDP" = "RDP"; +"Open in Finder" = "在 Finder 中打开"; +"Open in Terminal" = "在终端中打开"; +"Edit Vagrantfile" = "编辑 Vagrantfile"; +"Add Bookmark" = "添加书签"; +"Remove Bookmark" = "移除书签"; + +/* Preferences */ +"Language" = "语言"; +"English" = "English"; +"简体中文" = "简体中文"; + From 1866d4e5c698b293b317d2a344cd9850f768ec86 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:13:59 +0800 Subject: [PATCH 11/23] Translate README to Chinese --- README.md | 78 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 1d7a0f2..b78a991 100644 --- a/README.md +++ b/README.md @@ -1,54 +1,56 @@ -Looking for the Windows version? Check out [Vagrant Manager for Windows](https://github.com/lanayotech/vagrant-manager-windows) +寻找 Windows 版本?请查看 [Vagrant Manager for Windows](https://github.com/lanayotech/vagrant-manager-windows) # Vagrant Manager for macOS -Vagrant Manager is a macOS status bar menu app that lets you manage all of your vagrant machines from one central location. -More information is available at http://vagrantmanager.com/ +Vagrant Manager 是一个 macOS 状态栏菜单应用程序,可让您从一个中心位置管理所有 Vagrant 虚拟机。 +更多信息请访问 http://vagrantmanager.com/ ![demo.gif](http://vagrantmanager.com/demo.gif) -## Downloads -Download Vagrant Manager from the [GitHub Releases Page](https://github.com/kevin197011/vagrant-manager/releases) +## 下载 +从 [GitHub Releases 页面](https://github.com/kevin197011/vagrant-manager/releases) 下载 Vagrant Manager -## Installation Notes -* Vagrant Manager can automatically detect most machines, undetected machines will require manual configuration via bookmarks. -* Make sure that you have VirtualBox and Vagrant installed, and the `VBoxManage` and `vagrant` commands are in your path so that Vagrant Manager can execute them. If you use Parallels, ensure the `prlctl` command is also in your path. -* Currently, vagrant machines must already be initialized in order for Vagrant Manager to detect them. Make sure you have run vagrant init on any machine you want to appear in Vagrant Manager. Once Vagrant Manager has detected a machine, you can bookmark it so that it will not disappear when you destroy the machine. You can also manually add a bookmark and specify the path to your Vagrantfile. -* Vagrant Manager requires macOS 11.0 (Big Sur) or higher +## 安装说明 +* Vagrant Manager 可以自动检测大多数虚拟机,未检测到的虚拟机需要通过书签进行手动配置。 +* 请确保您已安装 VirtualBox 和 Vagrant,并且 `VBoxManage` 和 `vagrant` 命令在您的 PATH 中,以便 Vagrant Manager 可以执行它们。如果您使用 Parallels,请确保 `prlctl` 命令也在您的 PATH 中。 +* 目前,vagrant 虚拟机必须已经初始化才能被 Vagrant Manager 检测到。请确保您已在任何想要出现在 Vagrant Manager 中的虚拟机上运行了 vagrant init。一旦 Vagrant Manager 检测到虚拟机,您可以将其添加为书签,这样在销毁虚拟机后它也不会消失。您也可以手动添加书签并指定 Vagrantfile 的路径。 +* Vagrant Manager 需要 macOS 11.0 (Big Sur) 或更高版本 -## System Requirements -* macOS 11.0 (Big Sur) or later -* Apple Silicon (M1/M2/M3/M4/M5) or Intel Mac -* Vagrant installed and in PATH -* VirtualBox or Parallels installed (if using those providers) +## 系统要求 +* macOS 11.0 (Big Sur) 或更高版本 +* Apple Silicon (M1/M2/M3/M4/M5) 或 Intel Mac +* Vagrant 已安装并在 PATH 中 +* VirtualBox 或 Parallels 已安装(如果使用这些提供商) -## Apple Silicon Support -Vagrant Manager now supports Apple Silicon (ARM64) Macs! The latest releases include native ARM64 builds for optimal performance on M1/M2/M3/M4/M5 Macs. +## Apple Silicon 支持 +Vagrant Manager 现在支持 Apple Silicon (ARM64) Mac!最新版本包含针对 M1/M2/M3/M4/M5 Mac 的原生 ARM64 构建,以获得最佳性能。 -**Note:** If macOS shows "Vagrant Manager is damaged" error after downloading: -* Right-click the app and select "Open" (don't double-click) -* Or run: `xattr -cr /Applications/Vagrant\ Manager.app` in Terminal -* Then try opening again +**注意:** 如果 macOS 在下载后显示 "Vagrant Manager 已损坏" 错误: +* 右键点击应用程序并选择"打开"(不要双击) +* 或在终端中运行:`xattr -cr /Applications/Vagrant\ Manager.app` +* 然后再次尝试打开 -## Building DMG -* Use [appdmg](https://github.com/LinusU/node-appdmg) to build the distribution DMG. -* Put the `Vagrant Manager.app` file in the `dmg` foler -* Run `appdmg dmg/appdmg.json ` +## 构建 DMG +* 使用 [appdmg](https://github.com/LinusU/node-appdmg) 构建分发 DMG。 +* 将 `Vagrant Manager.app` 文件放入 `dmg` 文件夹 +* 运行 `appdmg dmg/appdmg.json ` -## Building DMG -* Use [appdmg](https://github.com/LinusU/node-appdmg) to build the distribution DMG. -* Put the `Vagrant Manager.app` file in the `dmg` folder -* Run `appdmg dmg/appdmg.json ` +或使用自动化的 GitHub Actions workflow: +* 推送一个 tag(例如 `v2.8.0`)以自动构建和发布 DMG 包 +* 查看 `.github/workflows/README.md` 了解更多详情 -Or use the automated GitHub Actions workflow: -* Push a tag (e.g., `v2.8.0`) to automatically build and release DMG packages -* See `.github/workflows/README.md` for more details +## 语言支持 +Vagrant Manager 支持多语言: +* 英语 (English) +* 简体中文 (Simplified Chinese) -## Contributing to Vagrant Manager +您可以在偏好设置中切换语言。首次启动时会自动检测系统语言。 -We love code contributions! If you would like to contribute, here are some notes and guidelines: +## 贡献代码 -* All development happens on the **main** branch -* If you are going to be submitting a pull request, please branch from **main**, and submit your pull request back to the **main** branch -* [Helpful article about forking](https://help.github.com/articles/fork-a-repo) -* [Helpful article about pull requests](https://help.github.com/articles/using-pull-requests) +我们欢迎代码贡献!如果您想贡献代码,以下是一些说明和指南: + +* 所有开发都在 **main** 分支上进行 +* 如果您要提交 pull request,请从 **main** 分支创建分支,并将您的 pull request 提交回 **main** 分支 +* [关于 fork 的有用文章](https://help.github.com/articles/fork-a-repo) +* [关于 pull requests 的有用文章](https://help.github.com/articles/using-pull-requests) From 3560649046f331f04a24f6a8b5a53d9292bc424d Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:20:28 +0800 Subject: [PATCH 12/23] Add LanguageManager files to Xcode project - Add LanguageManager.h and LanguageManager.m to project - Add zh-Hans.lproj localization files to project - Fix linker error for missing LanguageManager symbols --- Vagrant Manager.xcodeproj/project.pbxproj | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Vagrant Manager.xcodeproj/project.pbxproj b/Vagrant Manager.xcodeproj/project.pbxproj index fb781c6..b1f8054 100644 --- a/Vagrant Manager.xcodeproj/project.pbxproj +++ b/Vagrant Manager.xcodeproj/project.pbxproj @@ -94,6 +94,7 @@ B12661181A00A650009B1635 /* NativeMenu.m in Sources */ = {isa = PBXBuildFile; fileRef = B12661171A00A650009B1635 /* NativeMenu.m */; }; B1357A71187CEB3B00811CBC /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B1357A70187CEB3B00811CBC /* Cocoa.framework */; }; B1357A7B187CEB3B00811CBC /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B1357A79187CEB3B00811CBC /* InfoPlist.strings */; }; + B18AA18F1887CA4600B4C277 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B18AA18E1887CA4600B4C277 /* Localizable.strings */; }; B1357A7D187CEB3B00811CBC /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = B1357A7C187CEB3B00811CBC /* main.m */; }; B1357A84187CEB3B00811CBC /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = B1357A83187CEB3B00811CBC /* AppDelegate.m */; }; B1357A89187CEB3B00811CBC /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B1357A88187CEB3B00811CBC /* Images.xcassets */; }; @@ -113,6 +114,7 @@ B1761B3D1A00C0140056582F /* NativeMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = B1761B3C1A00C0140056582F /* NativeMenuItem.m */; }; B17AA18B1887A75300B4C274 /* Util.m in Sources */ = {isa = PBXBuildFile; fileRef = B17AA18A1887A75300B4C274 /* Util.m */; }; B17AA18F1887CA4600B4C274 /* PreferencesWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = B17AA18D1887CA4600B4C274 /* PreferencesWindow.m */; }; + B18AA18C1887CA4600B4C275 /* LanguageManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B18AA18B1887CA4600B4C275 /* LanguageManager.m */; }; B17AA1901887CA4600B4C274 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = B17AA18E1887CA4600B4C274 /* PreferencesWindow.xib */; }; B17AA1961887DA5800B4C274 /* status_icon_problem.png in Resources */ = {isa = PBXBuildFile; fileRef = B17AA1931887DA5800B4C274 /* status_icon_problem.png */; }; B17AA1991887DB8C00B4C274 /* status_icon_off.png in Resources */ = {isa = PBXBuildFile; fileRef = B17AA1971887DB8C00B4C274 /* status_icon_off.png */; }; @@ -267,6 +269,7 @@ B1357A74187CEB3B00811CBC /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; B1357A78187CEB3B00811CBC /* Vagrant Manager-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "Vagrant Manager-Info.plist"; sourceTree = ""; }; B1357A7A187CEB3B00811CBC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + B18AA18D1887CA4600B4C276 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = ""; }; B1357A7C187CEB3B00811CBC /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; B1357A7E187CEB3B00811CBC /* Vagrant Manager-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Vagrant Manager-Prefix.pch"; sourceTree = ""; }; B1357A82187CEB3B00811CBC /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; @@ -295,6 +298,8 @@ B1761B3C1A00C0140056582F /* NativeMenuItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeMenuItem.m; sourceTree = ""; }; B17AA1891887A75300B4C274 /* Util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Util.h; sourceTree = ""; }; B17AA18A1887A75300B4C274 /* Util.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Util.m; sourceTree = ""; }; + B18AA18A1887CA4600B4C275 /* LanguageManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LanguageManager.h; sourceTree = ""; }; + B18AA18B1887CA4600B4C275 /* LanguageManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LanguageManager.m; sourceTree = ""; }; B17AA18C1887CA4600B4C274 /* PreferencesWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PreferencesWindow.h; sourceTree = ""; }; B17AA18D1887CA4600B4C274 /* PreferencesWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PreferencesWindow.m; sourceTree = ""; }; B17AA18E1887CA4600B4C274 /* PreferencesWindow.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PreferencesWindow.xib; sourceTree = ""; }; @@ -636,6 +641,8 @@ B1357A7E187CEB3B00811CBC /* Vagrant Manager-Prefix.pch */, B17AA1891887A75300B4C274 /* Util.h */, B17AA18A1887A75300B4C274 /* Util.m */, + B18AA18A1887CA4600B4C275 /* LanguageManager.h */, + B18AA18B1887CA4600B4C275 /* LanguageManager.m */, 8360A05618C2B37F002EA89B /* Environments.plist */, 83F1696D1923789900C54F13 /* VersionComparison.h */, 83F1696E1923789900C54F13 /* VersionComparison.m */, @@ -753,6 +760,7 @@ 83C4CDE31A060B3600611DCC /* reload@2x.png in Resources */, 83C4CE061A0628AC00611DCC /* vagrant_logo_refresh_1-clean@2x.png in Resources */, B1357A7B187CEB3B00811CBC /* InfoPlist.strings in Resources */, + B18AA18F1887CA4600B4C277 /* Localizable.strings in Resources */, B17AA1991887DB8C00B4C274 /* status_icon_off.png in Resources */, 83C4CE171A062BCF00611DCC /* vagrant_logo_refresh_3-clean.png in Resources */, 83C4CDF11A060D4600611DCC /* ssh@2x.png in Resources */, @@ -899,6 +907,7 @@ 8339DCA1187E756B0036E162 /* TaskOutputWindow.m in Sources */, B1357A7D187CEB3B00811CBC /* main.m in Sources */, B17AA18B1887A75300B4C274 /* Util.m in Sources */, + B18AA18C1887CA4600B4C275 /* LanguageManager.m in Sources */, B17AA18F1887CA4600B4C274 /* PreferencesWindow.m in Sources */, 837A30891A5D0D5500E12A40 /* ManageCustomCommandsWindow.m in Sources */, 83FD353D19826945002EEA2D /* ManageBookmarksWindow.m in Sources */, @@ -930,6 +939,7 @@ isa = PBXVariantGroup; children = ( B1357A7A187CEB3B00811CBC /* en */, + B18AA18D1887CA4600B4C276 /* zh-Hans */, ); name = InfoPlist.strings; sourceTree = ""; From 747b92a9dd07485828cd077efb314f6f5bdc03c5 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:20:44 +0800 Subject: [PATCH 13/23] Add Localizable.strings to Xcode project resources --- Vagrant Manager.xcodeproj/project.pbxproj | 1 + 1 file changed, 1 insertion(+) diff --git a/Vagrant Manager.xcodeproj/project.pbxproj b/Vagrant Manager.xcodeproj/project.pbxproj index b1f8054..671479a 100644 --- a/Vagrant Manager.xcodeproj/project.pbxproj +++ b/Vagrant Manager.xcodeproj/project.pbxproj @@ -636,6 +636,7 @@ 8360A05918C2B39B002EA89B /* Environment.m */, B1357A78187CEB3B00811CBC /* Vagrant Manager-Info.plist */, B1357A79187CEB3B00811CBC /* InfoPlist.strings */, + B18AA18E1887CA4600B4C277 /* Localizable.strings */, B1357A7C187CEB3B00811CBC /* main.m */, 83D5D6E519DEBBE10098B8F6 /* appicon_128.png */, B1357A7E187CEB3B00811CBC /* Vagrant Manager-Prefix.pch */, From f4cc70d92c78b58fcbf32a47f236578190c86d92 Mon Sep 17 00:00:00 2001 From: kk Date: Thu, 25 Dec 2025 04:34:01 +0800 Subject: [PATCH 14/23] Add language selector UI to Preferences window - Add language label and popup button to PreferencesWindow.xib - Connect languagePopUpButton outlet and action - Increase window height to accommodate new language selector --- Vagrant Manager/PreferencesWindow.xib | 35 ++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/Vagrant Manager/PreferencesWindow.xib b/Vagrant Manager/PreferencesWindow.xib index 7f8f7b5..048e058 100644 --- a/Vagrant Manager/PreferencesWindow.xib +++ b/Vagrant Manager/PreferencesWindow.xib @@ -21,6 +21,7 @@ + @@ -34,17 +35,17 @@ - + - + - + - + @@ -386,6 +387,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +