From 51ee3b3208311fe377838cb11ae85a2153080646 Mon Sep 17 00:00:00 2001 From: Horizontal42 <75383519+Horizontal42@users.noreply.github.com> Date: Wed, 12 Aug 2026 22:55:04 +0300 Subject: [PATCH] linux + macos release builds (unsigned) split bundle config into tauri.{windows,linux,macos}.conf.json so each platform only carries its own targets; gen-icon emits icon.icns; macos is ad-hoc signed since arm64 refuses unsigned downloads --- .github/workflows/release.yml | 34 ++++++++++++++++++++++---- ARCHITECTURE.md | 38 +++++++++++++++++++++++++++++- ARCHITECTURE.ru.md | 38 +++++++++++++++++++++++++++++- README.md | 38 +++++++++++++++++++++++------- README.ru.md | 34 +++++++++++++++++++++----- package.json | 2 +- scripts/gen-icon.ts | 37 ++++++++++++++++++++++++++++- src-tauri/Cargo.toml | 2 +- src-tauri/icons/icon.icns | Bin 0 -> 26795 bytes src-tauri/src/main.rs | 5 +++- src-tauri/tauri.conf.json | 12 +++------- src-tauri/tauri.linux.conf.json | 5 ++++ src-tauri/tauri.macos.conf.json | 8 +++++++ src-tauri/tauri.windows.conf.json | 11 +++++++++ 14 files changed, 231 insertions(+), 33 deletions(-) create mode 100644 src-tauri/icons/icon.icns create mode 100644 src-tauri/tauri.linux.conf.json create mode 100644 src-tauri/tauri.macos.conf.json create mode 100644 src-tauri/tauri.windows.conf.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 99c9617..4a1be59 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,18 +14,40 @@ jobs: fail-fast: false # tauri-action's find-or-create-release check races across parallel # matrix jobs and can create two separate release objects for the - # same tag, each missing the other's assets — force serial builds + # same tag, each missing the other's assets — force serial builds. + # Every platform added below shares that release object, so they all + # have to stay in this one serialized matrix. max-parallel: 1 matrix: include: - - target: x86_64-pc-windows-msvc + - os: windows-latest + target: x86_64-pc-windows-msvc arch: x64 - - target: aarch64-pc-windows-msvc + - os: windows-latest + target: aarch64-pc-windows-msvc arch: arm64 - runs-on: windows-latest + # 22.04 is the oldest runner with webkit2gtk-4.1 (what Tauri 2 + # needs); building on it keeps the glibc floor as low as possible + - os: ubuntu-22.04 + target: x86_64-unknown-linux-gnu + arch: x64 + - os: macos-latest + target: aarch64-apple-darwin + arch: arm64 + - os: macos-latest + target: x86_64-apple-darwin + arch: x64 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 + - if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y build-essential curl wget file \ + libwebkit2gtk-4.1-dev librsvg2-dev libssl-dev libxdo-dev \ + libayatana-appindicator3-dev patchelf + - uses: actions/setup-node@v4 with: node-version: 22 @@ -42,6 +64,10 @@ jobs: - run: npm ci + # TAURI_SIGNING_* below is the updater's minisign keypair, not OS code + # signing — there is no Apple certificate, so macOS builds are only + # ad-hoc signed (bundle.macOS.signingIdentity "-") and Gatekeeper still + # asks the user to allow them on first launch. - uses: tauri-apps/tauri-action@v0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index a0f9d2f..27136a5 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -215,6 +215,40 @@ recursing forever. deleted sheets become `.numi` files under `backups/deleted/` and are pruned by age. Saving is debounced at 400 ms. +## Platforms and packaging + +- One codebase, three desktop targets. `tauri.conf.json` holds everything + shared; the per-platform bits live in `tauri.windows.conf.json`, + `tauri.linux.conf.json` and `tauri.macos.conf.json`, which Tauri merges over + the base config (JSON Merge Patch) according to the target being built. Each + one only sets `bundle.targets` and that platform's bundler options — NSIS on + Windows, deb/rpm/AppImage on Linux, .app/.dmg on macOS. +- `release.yml` builds five artifacts on three runner families: Windows x64 and + arm64, Linux x64 (`ubuntu-22.04` — the oldest runner carrying webkit2gtk-4.1, + which keeps the glibc floor low), macOS arm64 and x64. Two separate macOS + targets rather than `universal-apple-darwin`: it matches how Windows already + ships per-architecture, halves each download, and gives the updater the + `darwin-aarch64`/`darwin-x86_64` keys it looks up by default. +- The whole matrix stays `max-parallel: 1`. Every job hands its assets to the + *same* GitHub Release object, and tauri-action's find-or-create check races if + two jobs reach it at once — adding platforms did not change that constraint, + it made it apply to more jobs. +- No OS code signing anywhere. Windows ships unsigned; macOS is *ad-hoc* signed + (`bundle.macOS.signingIdentity: "-"`), which needs no Apple certificate but is + required for Apple Silicon to run a downloaded binary at all — without it the + arm64 build is rejected as damaged rather than merely warned about. Gatekeeper + still asks the user to allow the app on first launch either way. +- `bundle.fileAssociations` covers `.numi`/`.sum` on Windows (NSIS registry + entries) and macOS (`CFBundleDocumentTypes`). On Linux it writes nothing + useful: registering an extension there also needs a shared-mime-info XML that + Tauri does not generate, so `.numi` files are opened by dragging them into the + window rather than from the file manager. +- `icons/icon.icns` is emitted by `scripts/gen-icon.ts` alongside the PNGs and + the `.ico`, hand-rolled the same dependency-free way: `icns` magic + total + length, then one `[OSType][length][PNG]` chunk per size, using the modern + PNG-payload tags `iconutil` produces (`icp4`/`icp5`, `ic07`–`ic14`). Rerun it + with `npm run icons` after touching the artwork. + ## Auto-update - `updater.ts` calls `tauri-plugin-updater`'s `check()` on boot; if a signed @@ -242,7 +276,9 @@ recursing forever. flipping it while the app is running takes effect immediately); the manual button ignores the toggle and always works. - The update endpoint is `latest.json` published alongside each GitHub - Release. `release.yml` signs both architectures with a minisign keypair: + Release. `release.yml` signs every platform's updater artifact with a + minisign keypair (this is Tauri's own update signing, unrelated to OS code + signing): the public half is embedded in `tauri.conf.json`; the private half + its password live only as `TAURI_SIGNING_PRIVATE_KEY(_PASSWORD)` repo secrets (write-only — there is no durable copy in the repo). Losing that key means diff --git a/ARCHITECTURE.ru.md b/ARCHITECTURE.ru.md index 30486cf..dfcc9ed 100644 --- a/ARCHITECTURE.ru.md +++ b/ARCHITECTURE.ru.md @@ -217,6 +217,40 @@ src-tauri/ удалённые листы становятся `.numi`-файлами в `backups/deleted/` и удаляются по возрасту. Сохранение откладывается на 400 мс. +## Платформы и упаковка + +- Одна кодовая база, три десктопных платформы. Всё общее лежит в + `tauri.conf.json`, платформенные куски — в `tauri.windows.conf.json`, + `tauri.linux.conf.json` и `tauri.macos.conf.json`, которые Tauri накладывает + поверх базового конфига (JSON Merge Patch) в зависимости от собираемой цели. + Каждый задаёт только `bundle.targets` и опции своего упаковщика: NSIS на + Windows, deb/rpm/AppImage на Linux, .app/.dmg на macOS. +- `release.yml` собирает пять артефактов на трёх видах раннеров: Windows x64 и + arm64, Linux x64 (`ubuntu-22.04` — самый старый раннер с webkit2gtk-4.1, что + держит планку glibc низко), macOS arm64 и x64. Две отдельные macOS-цели вместо + `universal-apple-darwin`: так же, как Windows уже собирается по архитектурам, + вдвое меньше вес загрузки, и апдейтер получает ключи `darwin-aarch64` / + `darwin-x86_64`, которые ищет по умолчанию. +- Вся матрица остаётся `max-parallel: 1`. Все джобы отдают артефакты в *один и + тот же* объект GitHub Release, а проверка find-or-create в tauri-action гонит, + если две джобы доходят до неё одновременно — добавление платформ это + ограничение не сняло, а распространило на большее число джоб. +- Подписи ОС нет нигде. Windows выходит неподписанным; macOS подписан *ad-hoc* + (`bundle.macOS.signingIdentity: "-"`) — сертификат Apple для этого не нужен, но + без него Apple Silicon вообще откажется запускать скачанный бинарник (сочтёт + повреждённым, а не просто предупредит). Gatekeeper в любом случае попросит + пользователя разрешить приложение при первом запуске. +- `bundle.fileAssociations` покрывает `.numi`/`.sum` на Windows (записи в реестр + из NSIS) и macOS (`CFBundleDocumentTypes`). На Linux он не даёт ничего + полезного: там для регистрации расширения нужен ещё XML для shared-mime-info, + который Tauri не генерирует, так что `.numi` открываются перетаскиванием в + окно, а не из файлового менеджера. +- `icons/icon.icns` создаёт `scripts/gen-icon.ts` рядом с PNG и `.ico`, вручную + и без зависимостей: магия `icns` + общая длина, дальше по чанку + `[OSType][длина][PNG]` на размер, с современными PNG-тегами, которые выдаёт + `iconutil` (`icp4`/`icp5`, `ic07`–`ic14`). После правки картинки перегенерить + через `npm run icons`. + ## Автообновление - `updater.ts` вызывает `check()` из `tauri-plugin-updater` при запуске; если @@ -245,7 +279,9 @@ src-tauri/ тике интервала, так что переключение прямо во время работы срабатывает сразу); ручная кнопка тумблер игнорирует и работает всегда. - Эндпоинт обновлений — `latest.json`, публикуемый вместе с каждым GitHub - Release. `release.yml` подписывает обе архитектуры парой ключей minisign: + Release. `release.yml` подписывает артефакт обновления каждой платформы парой + ключей minisign (это собственная подпись обновлений Tauri, к подписи кода в ОС + отношения не имеет): публичная половина зашита в `tauri.conf.json`; приватная половина + пароль живут только как секреты репозитория `TAURI_SIGNING_PRIVATE_KEY(_PASSWORD)` (write-only — в репозитории нет постоянной копии). Потеря этого ключа diff --git a/README.md b/README.md index bf56fc2..4e83165 100644 --- a/README.md +++ b/README.md @@ -29,16 +29,29 @@ Works in **English and Russian** at the same time: `5 метров в см`, `20 ## Install -Grab the latest `Summarum_*_x64-setup.exe` (or `arm64-setup.exe` on Windows -on ARM) from [Releases](../../releases), run it, done. The whole app is -about 2 MB. It checks for updates on its own after that. +Grab the build for your system from [Releases](../../releases). The whole app +is about 2 MB and checks for updates on its own after that. + +- **Windows** — `Summarum_*_x64-setup.exe` (or `arm64-setup.exe` on Windows on + ARM). Run it, done. +- **Linux** — `.AppImage` (`chmod +x`, then run) or the `.deb`/`.rpm` if you'd + rather install it properly. Self-updating only works on the AppImage; deb and + rpm are updated by downloading the next one. +- **macOS** — `.dmg`, Apple Silicon or Intel. These builds are not signed with + an Apple Developer certificate, so the first launch has to be a right-click → + **Open** rather than a double-click (or run + `xattr -cr /Applications/Summarum.app` once in a terminal). Every launch after + that is normal. Requirements: -- **Windows 10 (1803+) or Windows 11**, 64-bit. -- **[WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)** — +- **Windows 10 (1803+) or Windows 11**, 64-bit, plus the + **[WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)** — already part of Windows 11 and most updated Windows 10 systems; if it's missing, the installer downloads it automatically. +- **Linux** with `webkit2gtk-4.1` (Ubuntu 22.04+, Debian 12+, Fedora 36+) and + `libayatana-appindicator3` for the tray icon. +- **macOS 10.13** or newer. - Internet connection is only needed for live rates and market data — everything else works offline (rates fall back to a cached/bundled snapshot). @@ -165,19 +178,28 @@ To build from source you need: - [Node.js](https://nodejs.org/) 22.6 or newer (`npm run icons` relies on Node's built-in TypeScript support) -- [Rust](https://rustup.rs/) (stable, MSVC toolchain) -- [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) +- [Rust](https://rustup.rs/), stable +- On Windows: the MSVC toolchain plus + [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) with the "Desktop development with C++" workload (the MSVC linker) +- On Linux: `libwebkit2gtk-4.1-dev`, `libayatana-appindicator3-dev`, + `librsvg2-dev`, `libxdo-dev`, `libssl-dev`, `patchelf` and a C toolchain +- On macOS: Xcode Command Line Tools - See the [Tauri prerequisites](https://tauri.app/start/prerequisites/) page if anything refuses to compile +`npm run tauri build` produces whatever the host platform bundles — NSIS on +Windows, deb/rpm/AppImage on Linux, .app/.dmg on macOS. Cross-compiling +between the three is not supported; the release workflow builds each on its +own runner. + Stack: [Tauri 2](https://tauri.app) + TypeScript + CodeMirror 6. ## Credits Inspired by the excellent [Numi](https://numi.app) by Dmitry Nikolaev — if you're on macOS, buy it. Summarum is an independent project, built from -scratch for Windows. +scratch for Windows, Linux and macOS. ## License diff --git a/README.ru.md b/README.ru.md index 9ce57f8..bd3fcba 100644 --- a/README.ru.md +++ b/README.ru.md @@ -27,14 +27,28 @@ AAPL в USD → $213.55 ## Установка -Скачай последний `Summarum_*_x64-setup.exe` (или `arm64-setup.exe` для Windows on ARM) из [Releases](../../releases), запусти — готово. Весь установщик около 2 МБ. Дальше обновления проверяются сами. +Скачай сборку под свою систему из [Releases](../../releases). Приложение весит +около 2 МБ, дальше обновления проверяются сами. + +- **Windows** — `Summarum_*_x64-setup.exe` (или `arm64-setup.exe` для Windows on + ARM). Запусти — готово. +- **Linux** — `.AppImage` (`chmod +x` и запускай) либо `.deb`/`.rpm`, если хочется + поставить нормальным пакетом. Самообновление работает только у AppImage, deb и + rpm обновляются скачиванием следующей версии. +- **macOS** — `.dmg` для Apple Silicon или Intel. Сборки не подписаны сертификатом + Apple Developer, поэтому первый запуск — правый клик → **Открыть**, а не двойной + клик (либо один раз выполнить `xattr -cr /Applications/Summarum.app` в терминале). + Дальше запускается как обычно. Требования: -- **Windows 10 (1803+) или Windows 11**, 64-бит. -- **[WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)** — +- **Windows 10 (1803+) или Windows 11**, 64-бит, и + **[WebView2 Runtime](https://developer.microsoft.com/en-us/microsoft-edge/webview2/)** — уже встроен в Windows 11 и большинство обновлённых Windows 10; если отсутствует, установщик скачает его автоматически. +- **Linux** с `webkit2gtk-4.1` (Ubuntu 22.04+, Debian 12+, Fedora 36+) и + `libayatana-appindicator3` для иконки в трее. +- **macOS 10.13** или новее. - Интернет нужен только для живых курсов и рыночных данных — всё остальное работает офлайн (курсы берутся из кэша или встроенного снимка). @@ -159,17 +173,25 @@ npm run tauri build # собрать установщик Для сборки нужны: - [Node.js](https://nodejs.org/) 22.6 или новее -- [Rust](https://rustup.rs/) (stable, MSVC toolchain) -- [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) +- [Rust](https://rustup.rs/), stable +- На Windows: toolchain MSVC и + [Visual Studio Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/) с компонентом «Desktop development with C++» (нужен линковщик MSVC) +- На Linux: `libwebkit2gtk-4.1-dev`, `libayatana-appindicator3-dev`, + `librsvg2-dev`, `libxdo-dev`, `libssl-dev`, `patchelf` и компилятор C +- На macOS: Xcode Command Line Tools - Если что-то не собирается — см. [Tauri prerequisites](https://tauri.app/start/prerequisites/) +`npm run tauri build` собирает то, что умеет хост-платформа: NSIS на Windows, +deb/rpm/AppImage на Linux, .app/.dmg на macOS. Кросс-компиляция между ними не +поддерживается — релизный workflow собирает каждую платформу на своём раннере. + Стек: [Tauri 2](https://tauri.app) + TypeScript + CodeMirror 6. ## Благодарность Вдохновлён [Numi](https://numi.app) от Дмитрия Николаева — -если ты на macOS, купи его. Summarum — независимый проект, написанный с нуля для Windows. +если ты на macOS, купи его. Summarum — независимый проект, написанный с нуля для Windows, Linux и macOS. ## Лицензия diff --git a/package.json b/package.json index 311be76..4df55b8 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "summarum", "private": true, "version": "1.2.6", - "description": "Summarum — natural language calculator notebook for Windows", + "description": "Summarum — natural language calculator notebook", "type": "module", "scripts": { "dev": "vite", diff --git a/scripts/gen-icon.ts b/scripts/gen-icon.ts index 04e878a..2784cbb 100644 --- a/scripts/gen-icon.ts +++ b/scripts/gen-icon.ts @@ -113,7 +113,7 @@ function draw(size: number): Buffer { fs.mkdirSync(outDir, { recursive: true }); const pngs = new Map(); -for (const size of [16, 32, 48, 64, 128, 256, 512]) { +for (const size of [16, 32, 48, 64, 128, 256, 512, 1024]) { pngs.set(size, encodePng(size, draw(size))); } @@ -154,3 +154,38 @@ function buildIco(sizes: number[]): Buffer { fs.writeFileSync(path.join(outDir, "icon.ico"), buildIco([16, 32, 48, 64, 128, 256])); console.log("icon.ico (6 sizes)"); + +// .icns: "icns" magic + total length, then [OSType][length incl. header][PNG]. +// Both lengths are big-endian and count their own 8-byte header. The tag set +// mirrors what `iconutil` emits for a modern .iconset — every ic*/icp* entry +// below carries a plain PNG payload (10.7+), so no JPEG 2000 encoder is needed. +const ICNS_ENTRIES: Array<[string, number]> = [ + ["icp4", 16], + ["icp5", 32], + ["ic11", 32], // 16@2x + ["ic12", 64], // 32@2x + ["ic07", 128], + ["ic13", 256], // 128@2x + ["ic08", 256], + ["ic14", 512], // 256@2x + ["ic09", 512], + ["ic10", 1024], // 512@2x +]; + +function buildIcns(): Buffer { + const parts = ICNS_ENTRIES.map(([tag, size]) => { + const data = pngs.get(size)!; + const head = Buffer.alloc(8); + head.write(tag, 0, 4, "ascii"); + head.writeUInt32BE(8 + data.length, 4); + return Buffer.concat([head, data]); + }); + const body = Buffer.concat(parts); + const header = Buffer.alloc(8); + header.write("icns", 0, 4, "ascii"); + header.writeUInt32BE(8 + body.length, 4); + return Buffer.concat([header, body]); +} + +fs.writeFileSync(path.join(outDir, "icon.icns"), buildIcns()); +console.log(`icon.icns (${ICNS_ENTRIES.length} entries)`); diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index c489c8e..2647f10 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "summarum" version = "1.2.6" -description = "Summarum — natural language calculator notebook for Windows" +description = "Summarum — natural language calculator notebook" edition = "2021" [build-dependencies] diff --git a/src-tauri/icons/icon.icns b/src-tauri/icons/icon.icns new file mode 100644 index 0000000000000000000000000000000000000000..dd9c4d80d4c66c245fa532383cab60732eac3f32 GIT binary patch literal 26795 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 H|3m%{ejlq6 literal 0 HcmV?d00001 diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 5f2fc06..85f870e 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -1,6 +1,9 @@ // Summarum — Tauri shell: tray, hide-to-tray window, app-data storage, // currency rates fetching with an on-disk cache, extension script loading. -#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] +#![cfg_attr( + all(not(debug_assertions), target_os = "windows"), + windows_subsystem = "windows" +)] use serde::{Deserialize, Serialize}; use std::collections::HashSet; diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 9056d06..0539a82 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -28,14 +28,14 @@ }, "bundle": { "active": true, - "targets": ["nsis"], "createUpdaterArtifacts": true, "icon": [ "icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.png", - "icons/icon.ico" + "icons/icon.ico", + "icons/icon.icns" ], "fileAssociations": [ { @@ -44,13 +44,7 @@ "description": "Summarum calculation sheet", "role": "Editor" } - ], - "windows": { - "nsis": { - "installMode": "currentUser", - "languages": ["English", "Russian"] - } - } + ] }, "plugins": { "updater": { diff --git a/src-tauri/tauri.linux.conf.json b/src-tauri/tauri.linux.conf.json new file mode 100644 index 0000000..88aa25f --- /dev/null +++ b/src-tauri/tauri.linux.conf.json @@ -0,0 +1,5 @@ +{ + "bundle": { + "targets": ["deb", "rpm", "appimage"] + } +} diff --git a/src-tauri/tauri.macos.conf.json b/src-tauri/tauri.macos.conf.json new file mode 100644 index 0000000..c32199d --- /dev/null +++ b/src-tauri/tauri.macos.conf.json @@ -0,0 +1,8 @@ +{ + "bundle": { + "targets": ["app", "dmg"], + "macOS": { + "signingIdentity": "-" + } + } +} diff --git a/src-tauri/tauri.windows.conf.json b/src-tauri/tauri.windows.conf.json new file mode 100644 index 0000000..f445f53 --- /dev/null +++ b/src-tauri/tauri.windows.conf.json @@ -0,0 +1,11 @@ +{ + "bundle": { + "targets": ["nsis"], + "windows": { + "nsis": { + "installMode": "currentUser", + "languages": ["English", "Russian"] + } + } + } +}