diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..65a998d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +thirdparty/screeningzoom/**/*.cpp linguist-vendored=false +thirdparty/screeningzoom/**/*.h linguist-vendored=false +thirdparty/screeningzoom/**/*.hpp linguist-vendored=false + +# Wails auto-generated bindings +frontend/wailsjs/**/*.js linguist-generated=true diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml new file mode 100644 index 0000000..733dd58 --- /dev/null +++ b/.github/workflows/build-release.yml @@ -0,0 +1,182 @@ +name: Build Release + +on: + push: + branches: + - master + workflow_dispatch: + +permissions: + contents: write + +jobs: + build-windows: + runs-on: windows-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + cache-dependency-path: frontend/package-lock.json + + - name: Install frontend dependencies + working-directory: frontend + run: npm ci + + - name: Install Wails CLI + shell: pwsh + run: | + go install github.com/wailsapp/wails/v2/cmd/wails@v2.10.2 + "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + + - name: Read version + id: version + shell: pwsh + run: | + $version = (Get-Content version.json -Raw | ConvertFrom-Json).appVersion + if ([string]::IsNullOrWhiteSpace($version)) { + throw "version.json appVersion is empty" + } + "app_version=$($version.Trim())" | Out-File -FilePath $env:GITHUB_OUTPUT -Encoding utf8 -Append + + - name: Download runtime archive + shell: pwsh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + $appVersion = "${{ steps.version.outputs.app_version }}" + $repo = "${{ github.repository }}" + $runtimeDir = Join-Path $PWD "resources/runtime" + $runtimeArchive = Join-Path $runtimeDir "runtime.7z" + New-Item -ItemType Directory -Path $runtimeDir -Force | Out-Null + $downloaded = $false + + $candidates = @( + "https://github.com/$repo/releases/download/v$appVersion/runtime.7z" + ) + + $apiHeaders = @{ + Authorization = "Bearer $env:GITHUB_TOKEN" + "User-Agent" = "plotkitycat-actions" + } + + try { + $latestRelease = Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases/latest" -Headers $apiHeaders + $latestRuntime = $latestRelease.assets | Where-Object { $_.name -eq "runtime.7z" } | Select-Object -First 1 + if ($null -ne $latestRuntime -and -not [string]::IsNullOrWhiteSpace($latestRuntime.browser_download_url)) { + $candidates += $latestRuntime.browser_download_url + } + + $latestZip = $latestRelease.assets | Where-Object { $_.name -like "PlotKityCat-v*.zip" } | Select-Object -First 1 + if ($null -ne $latestZip -and -not [string]::IsNullOrWhiteSpace($latestZip.browser_download_url)) { + $zipPath = Join-Path $env:RUNNER_TEMP "latest-release.zip" + $extractDir = Join-Path $env:RUNNER_TEMP "latest-release" + Write-Host "Downloading fallback release zip from $($latestZip.browser_download_url)" + Invoke-WebRequest -Uri $latestZip.browser_download_url -OutFile $zipPath + if (Test-Path -LiteralPath $extractDir) { + Remove-Item -LiteralPath $extractDir -Recurse -Force + } + Expand-Archive -LiteralPath $zipPath -DestinationPath $extractDir -Force + $embeddedRuntime = Get-ChildItem -Path $extractDir -Recurse -Filter runtime.7z | Select-Object -First 1 + if ($null -ne $embeddedRuntime) { + Copy-Item -LiteralPath $embeddedRuntime.FullName -Destination $runtimeArchive -Force + $downloaded = $true + } + } + } catch { + Write-Host "Latest release lookup failed: $($_.Exception.Message)" + } + + if (-not $downloaded) { + foreach ($url in $candidates | Select-Object -Unique) { + try { + Write-Host "Downloading runtime from $url" + Invoke-WebRequest -Uri $url -OutFile $runtimeArchive + $downloaded = $true + break + } catch { + Write-Host "Runtime download failed from $url : $($_.Exception.Message)" + } + } + } + + if (-not $downloaded) { + throw "Unable to download runtime.7z from release assets." + } + + - name: Bootstrap vcpkg + shell: pwsh + run: | + $vcpkgRoot = Join-Path $env:RUNNER_TEMP "vcpkg" + git clone https://github.com/microsoft/vcpkg.git $vcpkgRoot + & (Join-Path $vcpkgRoot "bootstrap-vcpkg.bat") -disableMetrics + $vcpkgExe = Join-Path $vcpkgRoot "vcpkg.exe" + & $vcpkgExe install nlohmann-json:x64-windows-static + "VCPKG_ROOT=$vcpkgRoot" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append + + - name: Build screening zoom helper + shell: pwsh + run: | + $toolchain = Join-Path $env:VCPKG_ROOT "scripts/buildsystems/vcpkg.cmake" + cmake -S thirdparty/screeningzoom ` + -B thirdparty/screeningzoom/build ` + -DCMAKE_BUILD_TYPE=Release ` + -DCMAKE_TOOLCHAIN_FILE="$toolchain" ` + -DVCPKG_TARGET_TRIPLET=x64-windows-static + cmake --build thirdparty/screeningzoom/build --config Release + + - name: Build versioned app + shell: pwsh + run: .\tools\build-versioned-app.ps1 -Version "${{ steps.version.outputs.app_version }}" + + - name: Prepare update artifacts + shell: pwsh + run: .\tools\prepare-update-release.ps1 -Version "${{ steps.version.outputs.app_version }}" + + - name: Package full release + shell: pwsh + run: .\tools\package-release.ps1 -Version "${{ steps.version.outputs.app_version }}" + + - name: Upload app binary + uses: actions/upload-artifact@v4 + with: + name: PlotKityCat-build-${{ steps.version.outputs.app_version }} + path: build/bin/PlotKityCat.exe + if-no-files-found: error + + - name: Upload update artifacts + uses: actions/upload-artifact@v4 + with: + name: PlotKityCat-update-${{ steps.version.outputs.app_version }} + path: build/update/${{ steps.version.outputs.app_version }} + if-no-files-found: error + + - name: Upload full release package + uses: actions/upload-artifact@v4 + with: + name: PlotKityCat-release-${{ steps.version.outputs.app_version }} + path: build/release/PlotKityCat-v${{ steps.version.outputs.app_version }}.zip + if-no-files-found: error + + - name: Publish GitHub release + uses: softprops/action-gh-release@v2 + with: + tag_name: v${{ steps.version.outputs.app_version }} + name: v${{ steps.version.outputs.app_version }} + generate_release_notes: true + fail_on_unmatched_files: true + files: | + build/release/PlotKityCat-v${{ steps.version.outputs.app_version }}.zip + build/update/${{ steps.version.outputs.app_version }}/PlotKityCat-${{ steps.version.outputs.app_version }}-windows-amd64.exe + build/update/${{ steps.version.outputs.app_version }}/manifest.json + resources/runtime/runtime.7z diff --git a/.gitignore b/.gitignore index 1757a1b..9c5aada 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ build/update/ *.zip !/resources/runtime/ !/resources/runtime/.gitkeep +/resources/runtime/runtime.7z .runtime-staging/ .runtime-staging.7z .tools_py/ @@ -28,6 +29,7 @@ Thumbs.db /.runtime-pack/ __pycache__/ *.py[cod] +thirdparty/screeningzoom/build/ # Legacy root docs Tec.md diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index b384e73..3084341 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -1,9 +1,11 @@ # PlotKityCat Development +本地开发启动、runtime 与构建发布、Git 仓库约定。 + ## 环境 - Windows -- Go 1.21+ +- Go 1.22+ - Node.js 18+ - Wails v2 @@ -23,27 +25,19 @@ wails dev ## 版本 -应用版本唯一来源: - -- `version.json` - -相关脚本都会默认读取这里的 `appVersion`。 +应用版本唯一来源为 `version.json` 中的 `appVersion`。构建与发布脚本默认都读取这里的值。 ## Runtime -项目运行依赖便携 Python runtime: +项目运行依赖便携 Python runtime。约定如下: -- runtime 占位目录:`resources/runtime/` -- 发布输入:本地放置的 `resources/runtime/runtime.zip` +- 占位目录:`resources/runtime/` +- 本地发布输入:`resources/runtime/runtime.7z` - 本地展开目录:`runtime/` - 临时展开目录:`runtime.tmp/` - 元数据文件:`runtime.version.json` - -约定: - -- `resources/runtime/runtime.zip` 默认不提交到 Git -- 该文件应通过 GitHub Release asset 或其他制品存储分发 -- 仓库仅跟踪 runtime 脚本、元数据和第三方补丁源码 +- runtime 通过 GitHub Release asset 分发 +- 仓库仅跟踪 runtime 脚本和元数据 准备 runtime 压缩包: @@ -51,7 +45,7 @@ wails dev .\tools\prepare-runtime.ps1 -SourceRuntimeDir <你的 runtime 目录> ``` -当前默认应保留的核心库: +默认核心库: - Python 标准库 - numpy @@ -59,11 +53,11 @@ wails dev - scipy - PyQt5 -`runtime.version.json` 应同步填写实际 Python 与核心库版本,不要长期保留 `pending`。 +`runtime.version.json` 必须填写真实版本,`pending` 仅为占位值。 从零重建 runtime 的完整说明见 [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md)。 -## 打包入口 +## 构建与打包 构建 exe: @@ -71,13 +65,13 @@ wails dev .\tools\build-versioned-app.ps1 ``` -生成发布 zip: +生成完整发布包: ```powershell .\tools\package-release.ps1 ``` -生成自动更新发布物: +生成在线更新产物: ```powershell .\tools\prepare-update-release.ps1 @@ -86,15 +80,17 @@ wails dev 如果要覆盖默认版本: ```powershell -.\tools\build-versioned-app.ps1 -Version 0.0.2.1 -.\tools\package-release.ps1 -Version 0.0.2.1 -.\tools\prepare-update-release.ps1 -Version 0.0.2.1 +.\tools\build-versioned-app.ps1 -Version 0.0.3.5 +.\tools\package-release.ps1 -Version 0.0.3.5 +.\tools\prepare-update-release.ps1 -Version 0.0.3.5 ``` ## 发布前检查 - 确认 `version.json` 版本正确 -- 确认 `resources/runtime/runtime.zip` 存在 +- 确认 `resources/runtime/runtime.7z` 存在 +- 确认 `zoomit.exe` 已经准备好,优先放在 `resources/screeningzoom/zoomit.exe` +- 如果还没放到 `resources/screeningzoom/zoomit.exe`,至少确认存在开发构建产物 `thirdparty/screeningzoom/build/Release/zoomit.exe` - 确认 `runtime.version.json` 已填写真实版本 - 确认 `Scripts/` 中示例内容就是准备随包分发的内容 - 确认 `config/` 没有本机账号、缓存、更新状态等脏数据 @@ -107,10 +103,12 @@ wails dev - `frontend/` - `tools/` - `build/windows/` -- `resources/` 下需要随项目维护的静态资源 +- `resources/` 下需要随项目维护的静态资源与占位文件 - `resources/runtime/.gitkeep` +- `resources/screeningzoom/.gitkeep` - `README.md` - `DEVELOPMENT.md` +- `UPDATE_RELEASE.md` - `RUNTIME_BUILD.md` - `version.json` - `runtime.version.json` @@ -125,3 +123,5 @@ wails dev - `build/release/` - `build/update/` - `packaging/` + +发布服务器更新步骤见 [UPDATE_RELEASE.md](D:/projects/plotkitycat/UPDATE_RELEASE.md)。 diff --git a/README.md b/README.md index 2332bed..276005c 100644 --- a/README.md +++ b/README.md @@ -20,8 +20,7 @@ ## 简介 -请允许我为你介绍这只可爱的,小猫! -PlotKityCat 是一个开源的数学可视化工具,支持运行 Matplotlib 代码并生成交互式图形。集成 AI 功能,支持通过自然语言提示词生成绘图代码。软件采用便携式设计,支持优盘即插即用,方便在教室等不同环境下快速部署与演示。 +PlotKityCat 是一个面向数学教学场景的 AI-native 可视化工具。它基于 Matplotlib 执行绘图代码,支持自然语言生成可视化,并以便携式 runtime 支撑课堂演示与离线分发。 ## 视频介绍 @@ -31,7 +30,7 @@ https://github.com/user-attachments/assets/df8167a7-d1e9-4f6a-a42d-de15596a4456 PlotKityCat 源于对 GGBPuppy 开发过程中 GGB Web API 封闭性的反思。我们转向 Matplotlib,为初高中数学可视化提供 AI-native 方案。 -> 那天,我在研究GGB的webapi,AI总是写下错误的GGB代码,让我的另外一个项目GGBpuppy很受挫折。我突然发现一个GGB的api接口不完整,于是以开发者的口吻发了一封信给他们团队,结果收到了他们希望我付钱的要求......好吧,那天晚上关掉它肮脏线条和色彩的窗口,我梦见了Jobs..... +> 那天,我在研究 GGB 的 webapi,AI 总是写下错误的 GGB 代码,让我的另外一个项目 GGBPuppy 很受挫折。我突然发现一个 GGB 的 api 接口不完整,于是以开发者的口吻发了一封信给他们团队,结果收到了他们希望我付钱的要求......好吧,那天晚上关掉它肮脏线条和色彩的窗口,我梦见了 Jobs..... 1. **开源**:好的工具应该像太阳一样,太阳是闭源的吗? 2. **美**:拒绝 GGB 沉闷的色彩与线条。 @@ -39,36 +38,42 @@ PlotKityCat 源于对 GGBPuppy 开发过程中 GGB Web API 封闭性的反思。 PlotKityCat 支持优盘便携,旨在让老师将其带入教室、讲台及学生手中。 -## 功能特性 +## 设计原则 + +1. **开源**:以可审查、可扩展的技术栈承载教学工具。 +2. **美感**:避免传统数学软件沉闷的视觉体验。 +3. **AI 原生**:让老师通过自然语言驱动可视化生成,而不是先学编程。 -- **AI 绘图**:通过自然语言描述数学概念,由 AI 生成 Matplotlib 绘图代码。支持设计和生成代码双流程。 +## 功能特性 +- **AI 绘图**:通过自然语言描述数学概念,由 AI 生成 Matplotlib 绘图代码。 - **笔记系统**:集成 Markdown 与 LaTeX 公式渲染,绑定代码,看到可视化的结果,更看到可视化的设计。 -- **便携运行**:内置 Python 运行时,支持U盘即插即用,让小猫真的可以在课堂中一展身手。 -- **.pck导入导出** : 支持导出和导入场景包,希望用户之间可以交流自己的可视化成果。 +- **便携运行**:依赖便携 Python runtime,适合 U 盘和教室环境分发。 +- **场景包导入导出**:支持 `.pck` 场景包的交换与复用。 ## 技术栈 - **前端**: Vue 3, TypeScript, Vite - **后端**: Go, Wails Framework -- **运行时**: WinPython (Matplotlib, NumPy, PyQt5) +- **运行时**: WinPython (NumPy, Matplotlib, SciPy, PyQt5) - **AI 接口**: OpenAI API / 自定义兼容接口 ## 快速开始 -1. **下载**:获取便携版压缩包。 -2. **配置**:设置 AI 服务商 API Key。 -3. **运行**:新建场景,笔记区输入描述,右键点击可视化或可视化设计运行。 +1. 下载便携版压缩包。 +2. 配置 AI 服务商 API Key。 +3. 启动应用并新建场景。 +4. 在笔记区输入描述后运行可视化或可视化设计。 -## 开发者指南 +## 开发入口 -### 环境要求 - **Windows** -- **Go**: 1.21+ +- **Go**: 1.22+ - **Node.js**: 18+ - **Wails**: v2.x -### 开发启动 +开发启动: + ```powershell cd frontend npm install @@ -76,74 +81,31 @@ cd .. wails dev ``` -### 版本来源 - -应用版本唯一来源: - -- `version.json` - -### Runtime - -项目运行依赖便携 Python runtime: - -- runtime 占位目录:`resources/runtime/` -- 发布输入:本地放置的 `resources/runtime/runtime.zip` -- 本地展开目录:`runtime/` -- 临时展开目录:`runtime.tmp/` -- 元数据文件:`runtime.version.json` - -注意: - -- `resources/runtime/runtime.zip` 默认不提交到 Git -- 这个文件应作为 release asset 或外部制品分发 - -准备 runtime 压缩包: +runtime 打包入口: ```powershell .\tools\prepare-runtime.ps1 -SourceRuntimeDir <你的 runtime 目录> ``` -当前默认核心库: - -- Python 标准库 -- numpy -- matplotlib -- scipy -- PyQt5 - -如何从零重建 runtime,见 [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md)。 - -### 打包入口 - -构建 exe: +应用打包入口: ```powershell .\tools\build-versioned-app.ps1 -``` - -生成发布 zip: - -```powershell .\tools\package-release.ps1 -``` - -生成自动更新发布物: - -```powershell .\tools\prepare-update-release.ps1 ``` -更详细的开发与发布说明见 [DEVELOPMENT.md](D:/projects/PlotKityCat/DEVELOPMENT.md)。 +## 文档索引 + +- 开发与构建总说明: [DEVELOPMENT.md](D:/projects/plotkitycat/DEVELOPMENT.md) +- runtime 分发与重建: [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md) +- 在线更新与发布: [UPDATE_RELEASE.md](D:/projects/plotkitycat/UPDATE_RELEASE.md) ## 致谢 - [Matplotlib](https://matplotlib.org/): 本项目核心渲染引擎。 - [ManimCat](https://github.com/Wing900/ManimCat): 提供了开发的基础和灵感。 +- [ZoomIt (PowerToys)](https://github.com/microsoft/PowerToys/tree/main/src/modules/ZoomIt): 放映模式辅助功能的实现基础。 +## 愿景 - - -## 期待 - -期待更多的可视化资源可以被开发,开源,开放,打破教育资源长期以来的垄断,让我们的教育越来越清晰,越来越公平! - -希望有一天,我的用户足够多,我们可以开一个PlotKityCat交流社区! +期待更多的可视化资源可以被开发、开源、开放,打破教育资源长期以来的垄断,让教育越来越清晰、越来越公平。期待有一天能够建立一个 PlotKityCat 交流社区。 diff --git a/RUNTIME_BUILD.md b/RUNTIME_BUILD.md index d1985d7..ba8094a 100644 --- a/RUNTIME_BUILD.md +++ b/RUNTIME_BUILD.md @@ -2,53 +2,31 @@ ## 目标 -这份文档描述两件事: +Python runtime 的分发方式与从零重建流程。 +开发环境搭建见 [DEVELOPMENT.md](D:/projects/plotkitycat/DEVELOPMENT.md)。 -- 如何给别人分发现成的 Python runtime -- 如何从零重建 `resources/runtime/runtime.zip` +当前 runtime 仅使用原生 Python 包内容,不再注入 Matplotlib C++ fastpath 补丁。 -本项目的 runtime 是发布制品,不是源码仓库资产。 - -结论先说清楚: - -- `resources/runtime/runtime.zip` 默认不提交到 Git -- 仓库只跟踪 runtime 构建脚本、版本元数据和第三方补丁源码 -- 现成 runtime 应通过 GitHub Release asset、对象存储或内部制品库分发 - -## 仓库里有什么 +## 仓库约定 仓库中与 runtime 相关的内容: - `runtime.version.json` - `tools/prepare-runtime.ps1` - `tools/extract_winpython.py` -- `thirdparty/matplotlib_surface_fastpath/` - `resources/runtime/.gitkeep` 仓库中默认不会跟踪: -- `resources/runtime/runtime.zip` +- `resources/runtime/runtime.7z` - `runtime/` - `runtime.tmp/` -## 给别人交付现成 runtime - -如果只是让接手者继续打包发布,不要求他从零重建 runtime,最简单的交付方式是: - -1. 把本地现成的 `resources/runtime/runtime.zip` 上传为 GitHub Release asset,或放到稳定下载地址 -2. 告诉接手者把该文件放回: +## 分发现成 runtime -```text -resources/runtime/runtime.zip -``` - -3. 接手者即可继续运行: - -```powershell -.\tools\build-versioned-app.ps1 -.\tools\package-release.ps1 -.\tools\prepare-update-release.ps1 -``` +1. 将本地 `resources/runtime/runtime.7z` 上传为 GitHub Release asset +2. 接手者将文件放回 `resources/runtime/runtime.7z` +3. 接手者参照 [UPDATE_RELEASE.md](D:/projects/plotkitycat/UPDATE_RELEASE.md) 执行构建与打包 ## 从零重建 runtime @@ -59,43 +37,33 @@ resources/runtime/runtime.zip - 一个可用的 WinPython runtime 目录,版本需与 `runtime.version.json` 一致 - 如需从 WinPython 安装包提取目录,需要 Python 环境并安装 `py7zr` -当前仓库记录的目标 runtime 元数据见: - -- `runtime.version.json` +当前 runtime 目标元数据见 `runtime.version.json`。 当前版本要求: - distribution: `WinPython` - distributionVersion: `3.13.11.0 slim` - pythonVersion: `3.13.11` +- matplotlib: `3.11.0rc2` ### 2. 获取 WinPython runtime 目录 -你需要先拿到一个已经解压好的 WinPython 目录,目录内应至少包含: +准备一个已解压的 WinPython 目录,目录内至少包含: - `python.exe` - `Lib/` - `DLLs/` - `Lib/site-packages/` -如果你手里只有 WinPython 的 `.exe` 安装包,可用仓库脚本提取其内嵌 7z: +如果仅有 WinPython 的 `.exe` 安装包,可用仓库脚本提取其内嵌 7z: ```powershell python .\tools\extract_winpython.py --exe --archive <临时输出.7z> --dest <解压目标目录> ``` -注意: - -- 这个脚本依赖 `py7zr` -- 仓库不会自动帮你安装 `py7zr` - ### 3. 确认 runtime 版本元数据 -打开: - -- `runtime.version.json` - -确保里面的版本与准备注入的 runtime 实际一致,尤其是: +打开 `runtime.version.json`,确保其中版本和准备打包的 runtime 实际一致,至少核对: - `pythonVersion` - `numpy` @@ -103,25 +71,7 @@ python .\tools\extract_winpython.py --exe --archive < - `scipy` - `PyQt5` -`tools/prepare-runtime.ps1` 会根据 `pythonVersion` 选择 ABI 对应的扩展文件名,例如: - -- `cp313` 对应 `_surface_fastpath.cp313-win_amd64.pyd` - -### 4. 注入 PlotKityCat 的 Matplotlib surface fastpath - -`tools/prepare-runtime.ps1` 会自动把以下内容注入 runtime: - -- `thirdparty/matplotlib_surface_fastpath/src/mpl_surface_fastpath/` -- ABI 匹配的 `_surface_fastpath.cp-win_amd64.pyd` -- `thirdparty/matplotlib_surface_fastpath/vendor/win-amd64/` 下的 3 个 DLL - -这一步不要求接手者自行编译扩展,前提是仓库里已有目标 ABI 的 `.pyd`: - -- 当前仓库内已有 `cp312` 和 `cp313` 版本 - -如果未来升级 Python 小版本但 ABI 发生变化,必须同步补齐匹配的 `.pyd`。 - -### 5. 生成 runtime.zip +### 4. 生成 runtime.7z 在仓库根目录执行: @@ -129,29 +79,62 @@ python .\tools\extract_winpython.py --exe --archive < .\tools\prepare-runtime.ps1 -SourceRuntimeDir <你的WinPython目录> ``` +生成当前推荐的瘦身版 runtime,需显式启用以下裁剪开关: + +```powershell +.\tools\prepare-runtime.ps1 ` + -SourceRuntimeDir <你的WinPython目录> ` + -TrimQtForRelease ` + -TrimUnusedPythonPackagesForRelease ` + -TrimOptionalScientificPackagesForRelease ` + -TrimAIPythonPackagesForRelease ` + -TrimQtOptionalUiForRelease ` + -TrimPythonPackagingToolsForRelease ` + -TrimPythonRuntimeClutterForRelease ` + -TrimSuspiciousPythonPackagesForRelease +``` + +这些开关只作用于 staging 目录 `.runtime-pack/runtime`,不会修改原始 `SourceRuntimeDir`。 + 执行结果: -- 生成 `resources/runtime/runtime.zip` +- 生成 `resources/runtime/runtime.7z` - staging 目录默认使用 `.runtime-pack/` +- 默认使用仓库内 `tools/7zip/extra/x64/7za.exe` 生成 7z 压缩包 + +### 5. 裁剪开关含义 + +- `-TrimQtForRelease` + 删除 Qt 第一、第二梯队,例如 WebEngine、Designer、Multimedia、Location 及边缘平台插件 +- `-TrimUnusedPythonPackagesForRelease` + 删除 Jupyter、IPython、格式化工具、额外绘图库等低风险开发环境包 +- `-TrimOptionalScientificPackagesForRelease` + 删除 `cvxpy/scs/osqp/networkx/xarray/seaborn` 等非主链科学计算包 +- `-TrimAIPythonPackagesForRelease` + 删除 `langchain/google_genai/huggingface_hub/tiktoken` 等 Python AI 生态包 +- `-TrimQtOptionalUiForRelease` + 删除 `qml/`、边缘 Qt 插件,以及除中文外的大部分 Qt 翻译资源 +- `-TrimPythonPackagingToolsForRelease` + 删除 `pip/setuptools/wheel/pkg_resources` +- `-TrimPythonRuntimeClutterForRelease` + 删除 `__pycache__`、`testing/tests/examples/docs` 和 `PyQt5/Qt5/qsci` +- `-TrimSuspiciousPythonPackagesForRelease` + 删除 `ipympl/pydantic_ai/github/cryptography/lxml` ### 6. 人工验收 至少做这几项检查: -1. 解压生成的 `resources/runtime/runtime.zip` -2. 确认存在: - `Lib/site-packages/mpl_surface_fastpath/` -3. 确认存在: - `DLLs/libgomp-1.dll` - `DLLs/libstdc++-6.dll` - `DLLs/libgcc_s_seh-1.dll` -4. 确认扩展 ABI 与 `runtime.version.json` 的 `pythonVersion` 一致 +1. 使用 7-Zip 解压生成的 `resources/runtime/runtime.7z` +2. 确认存在 `Lib/site-packages/matplotlib/` +3. 确认 `runtime.version.json` 中的核心版本与实际包内容一致 +4. 确认 runtime 内不包含额外的本地开发补丁或外部编译依赖 ## 发布建议 -`runtime.zip` 不要放进普通 Git 提交历史。 +`runtime.7z` 不纳入 Git 提交历史。 -建议的分发方式: +分发方式: - GitHub Release assets - 对象存储 @@ -159,23 +142,12 @@ python .\tools\extract_winpython.py --exe --archive < 推荐约定: -- 每次 runtime 发生变化,都发布一个单独的 runtime asset +- 每次 runtime 发生变化,都发布到对应版本的 GitHub Release +- 当前使用的资产名是 `runtime.7z` - 在 release 说明里注明对应的 `runtime.version.json` -## 常见误区 - -### 误区 1:仓库里应该直接提交 `runtime.zip` - -不建议。这个文件体积大、变更频率低、二进制 diff 意义弱,更适合作为发布制品管理。 - -### 误区 2:只要有 `prepare-runtime.ps1`,别人就一定能重建 runtime - -不对。别人还需要: +下载地址格式(示例 `v0.0.3.1`): -- 正确版本的 WinPython 源目录 -- 与 `pythonVersion` 匹配的 fastpath `.pyd` -- 明确的分发和验收规则 - -### 误区 3:运行时依赖开发者本机 DLL 路径 - -不应该。runtime 必须只依赖它自身携带的 `DLLs/` 和包目录内容。 +```text +https://github.com/Wing900/PlotKityCat/releases/download/v版本号/runtime.7z +``` diff --git a/UPDATE_RELEASE.md b/UPDATE_RELEASE.md index 444636f..839c921 100644 --- a/UPDATE_RELEASE.md +++ b/UPDATE_RELEASE.md @@ -1,6 +1,9 @@ # PlotKityCat 更新发布说明 -这份文档只描述当前这套最小更新流程: +应用发布与在线更新流程。runtime 重建见 [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md)。 +本地开发环境准备见 [DEVELOPMENT.md](D:/projects/plotkitycat/DEVELOPMENT.md)。 + +当前发布模型: - 更新客户端只更新 `exe` - runtime 走整包发布,不走在线更新 @@ -9,11 +12,11 @@ - `stable/manifest.json` - `releases/PlotKityCat-版本号-windows-amd64.exe` -关于 runtime: +runtime 约定: -- `resources/runtime/runtime.zip` 默认不提交到 Git -- 它应作为 release asset 或其他外部分发制品单独保存 -- 从零重建 runtime 的流程见 [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md) +- `resources/runtime/runtime.7z` 作为 release asset 外部分发 +- 当前使用的资产名是 `runtime.7z` +- 从零重建流程见 [RUNTIME_BUILD.md](D:/projects/plotkitycat/RUNTIME_BUILD.md) ## 1. 先改版本号 @@ -25,18 +28,16 @@ ```json { - "appVersion": "0.0.1.9" + "appVersion": "0.0.3.1" } ``` -说明: +相关脚本如果不手动传 `-Version`,都会默认读取这里的 `appVersion`: - `tools/build-versioned-app.ps1` - `tools/prepare-update-release.ps1` - `tools/package-release.ps1` -这三个脚本如果不手动传 `-Version`,都会默认读取这里的 `appVersion`。 - ## 2. 构建应用 exe 在仓库根目录运行: @@ -48,14 +49,14 @@ powershell -ExecutionPolicy Bypass -File .\tools\build-versioned-app.ps1 或者显式指定版本: ```powershell -powershell -ExecutionPolicy Bypass -File .\tools\build-versioned-app.ps1 -Version 0.0.1.9 +powershell -ExecutionPolicy Bypass -File .\tools\build-versioned-app.ps1 -Version 0.0.3.1 ``` 产物: - [build/bin/PlotKityCat.exe](/D:/projects/PlotKityCat/build/bin/PlotKityCat.exe) -## 3. 生成给更新服务器用的 exe + manifest +## 3. 生成在线更新产物 运行: @@ -66,7 +67,7 @@ powershell -ExecutionPolicy Bypass -File .\tools\prepare-update-release.ps1 或者: ```powershell -powershell -ExecutionPolicy Bypass -File .\tools\prepare-update-release.ps1 -Version 0.0.1.9 +powershell -ExecutionPolicy Bypass -File .\tools\prepare-update-release.ps1 -Version 0.0.3.1 ``` 产物目录: @@ -75,15 +76,15 @@ powershell -ExecutionPolicy Bypass -File .\tools\prepare-update-release.ps1 -Ver 对应版本目录里会生成: -- `PlotKityCat-0.0.1.9-windows-amd64.exe` +- `PlotKityCat-0.0.3.1-windows-amd64.exe` - `manifest.json` 说明: -- `manifest.json` 里已经自动写好下载地址和 sha256 +- `manifest.json` 会自动写入下载地址和 sha256 - 默认下载地址前缀是 `https://update.5051001.xyz/plotkitycat/releases` -## 4. 生成给用户下载的完整 zip +## 4. 生成完整下载包 运行: @@ -94,21 +95,29 @@ powershell -ExecutionPolicy Bypass -File .\tools\package-release.ps1 或者: ```powershell -powershell -ExecutionPolicy Bypass -File .\tools\package-release.ps1 -Version 0.0.1.9 +powershell -ExecutionPolicy Bypass -File .\tools\package-release.ps1 -Version 0.0.3.1 ``` 产物: -- 便携目录:`build/release/PlotKityCat-v0.0.1.9` -- 压缩包:`build/release/PlotKityCat-v0.0.1.9.zip` +- 便携目录:`build/release/PlotKityCat-v0.0.3.1` +- 压缩包:`build/release/PlotKityCat-v0.0.3.1.zip` 说明: -- 这个 zip 里会包含: - - `PlotKityCat.exe` - - `resources/runtime/runtime.zip` - - `Scripts/` -- 因此发布完整包前,必须先在本地准备好 `resources/runtime/runtime.zip` +- 这个 zip 会包含 `PlotKityCat.exe`、`resources/runtime/runtime.7z`、`resources/runtime/7zip/` 和 `Scripts/` +- 这个 zip 还会包含 `resources/screeningzoom/zoomit.exe` +- 因此发布完整包前,必须先在本地准备好 `resources/runtime/runtime.7z` +- 并且必须准备好 `zoomit.exe`;推荐固定放在 `resources/screeningzoom/zoomit.exe` +- 当前推荐先按 [RUNTIME_BUILD.md](/D:/projects/plotkitycat/RUNTIME_BUILD.md:1) 用裁剪开关重建 runtime,再执行完整打包 + +`package-release.ps1` 对 `zoomit.exe` 的查找顺序固定为: + +1. `resources/screeningzoom/zoomit.exe` +2. `thirdparty/screeningzoom/build/Release/zoomit.exe` +3. `thirdparty/screeningzoom/build/zoomit.exe` + +如果三处都没有,脚本会直接失败,不再生成缺失放映工具的发布包。 ## 5. 上传到更新服务器 @@ -124,13 +133,13 @@ powershell -ExecutionPolicy Bypass -File .\tools\package-release.ps1 -Version 0. 先上传版本 exe: ```powershell -scp .\build\update\0.0.1.9\PlotKityCat-0.0.1.9-windows-amd64.exe root@149.28.135.102:/var/www/update.5051001.xyz/plotkitycat/releases/ +scp .\build\update\0.0.3.1\PlotKityCat-0.0.3.1-windows-amd64.exe root@149.28.135.102:/var/www/update.5051001.xyz/plotkitycat/releases/ ``` 再上传 manifest: ```powershell -scp .\build\update\0.0.1.9\manifest.json root@149.28.135.102:/var/www/update.5051001.xyz/plotkitycat/stable/manifest.json +scp .\build\update\0.0.3.1\manifest.json root@149.28.135.102:/var/www/update.5051001.xyz/plotkitycat/stable/manifest.json ``` 注意: @@ -149,42 +158,41 @@ curl.exe -I https://update.5051001.xyz/plotkitycat/stable/manifest.json 再验证 exe: ```powershell -curl.exe -I https://update.5051001.xyz/plotkitycat/releases/PlotKityCat-0.0.1.9-windows-amd64.exe +curl.exe -I https://update.5051001.xyz/plotkitycat/releases/PlotKityCat-0.0.3.1-windows-amd64.exe ``` 如果都返回 `200 OK`,说明更新源可用。 ## 7. 最短发布流程 -以后你如果只想记住最短流程,就按这个顺序: +仅记录最短发布顺序: 1. 改 [version.json](/D:/projects/PlotKityCat/version.json) 的 `appVersion` -2. 跑 `.\tools\build-versioned-app.ps1` -3. 跑 `.\tools\prepare-update-release.ps1` -4. 跑 `.\tools\package-release.ps1` +2. 执行 `.\tools\build-versioned-app.ps1` +3. 执行 `.\tools\prepare-update-release.ps1` +4. 执行 `.\tools\package-release.ps1` 5. 上传 `build/update/版本号/` 里的 `exe` 6. 把 `build/update/版本号/manifest.json` 覆盖到服务器 `stable/manifest.json` -## 8. 当前固定约定 +## 8. 固定约定 -- 更新 manifest 地址: - - `https://update.5051001.xyz/plotkitycat/stable/manifest.json` -- 更新 exe 文件名格式: - - `PlotKityCat-版本号-windows-amd64.exe` -- 完整发布包目录格式: - - `build/release/PlotKityCat-v版本号` -- 完整发布包 zip 格式: - - `build/release/PlotKityCat-v版本号.zip` +- 更新 manifest 地址:`https://update.5051001.xyz/plotkitycat/stable/manifest.json` +- 更新 exe 文件名格式:`PlotKityCat-版本号-windows-amd64.exe` +- 完整发布包目录格式:`build/release/PlotKityCat-v版本号` +- 完整发布包 zip 格式:`build/release/PlotKityCat-v版本号.zip` +- runtime release 页面格式:`https://github.com/Wing900/PlotKityCat/releases/tag/v版本号` +- runtime 下载地址格式:`https://github.com/Wing900/PlotKityCat/releases/download/v版本号/runtime.7z` +- 当前示例:`https://github.com/Wing900/PlotKityCat/releases/download/v0.0.3.1/runtime.7z` -## 9. 如果只想发完整包,不想更新在线更新 +## 9. 只发完整包,不更新在线更新 只需要: 1. 改 `version.json` -2. 跑 `.\tools\build-versioned-app.ps1` -3. 跑 `.\tools\package-release.ps1` +2. 执行 `.\tools\build-versioned-app.ps1` +3. 执行 `.\tools\package-release.ps1` -这样你会得到完整 zip,但不会更新服务器上的在线更新入口。 +这样会得到完整 zip,但不会更新服务器上的在线更新入口。 ## 10. 常见问题 @@ -202,9 +210,9 @@ curl.exe -I https://update.5051001.xyz/plotkitycat/releases/PlotKityCat-0.0.1.9- 因为 manifest 一更新,旧版本客户端就可能立刻看到新版本;如果这时 exe 还没上传完,下载会失败。 -### Q4. 哪些目录不该进 git? +### Q4. 哪些目录不需纳入 Git? -这些产物目录本来就已经忽略: +以下产物目录已在 `.gitignore` 中排除: - `build/bin/` - `build/release/` diff --git a/frontend/src/App.vue b/frontend/src/App.vue index d4ccee1..70d1817 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -1,5 +1,5 @@