diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index e65661f..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,95 +0,0 @@ -# A version tag builds the four packages, each on its own system, and publishes them. -name: Release -on: - push: - tags: ['v*'] -permissions: - contents: write -jobs: - version: - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v7 - # The tag must name the version each build file carries. - - run: | - v=${GITHUB_REF_NAME#v} - grep -qF "project(omaphoto VERSION $v " CMakeLists.txt || { echo "CMakeLists.txt is not $v"; exit 1; } - grep -qxF "pkgver=$v" packaging/arch/PKGBUILD || { echo "PKGBUILD is not $v"; exit 1; } - grep -qF "version = \"$v\";" flake.nix || { echo "flake.nix is not $v"; exit 1; } - deb: - needs: version - runs-on: ubuntu-24.04 - # One DEB per Ubuntu LTS: each names its own libraries. - strategy: - matrix: - include: - - codename: noble - base: ubuntu:24.04 - - codename: resolute - base: ubuntu:26.04 - steps: - - uses: actions/checkout@v7 - # The dev image carries ONNX Runtime, its notices and the model. - - run: docker build -t omaphoto-dev --build-arg BASE=${{ matrix.base }} -f Dockerfile.dev . - - run: | - docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/src" -w /src omaphoto-dev sh -c ' - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \ - -DOMAPHOTO_BUNDLE_ORT=ON -DOMAPHOTO_MODEL=/usr/local/share/omaphoto/u2net.onnx && - cmake --build build --target omaphoto && cd build && cpack -G DEB' - mv build/omaphoto_*.deb omaphoto-${{ matrix.codename }}_amd64.deb - - uses: actions/upload-artifact@v7 - with: - name: deb-${{ matrix.codename }} - path: omaphoto-${{ matrix.codename }}_amd64.deb - rpm: - needs: version - runs-on: ubuntu-24.04 - # One RPM per Fedora release: each names its own LibRaw. - strategy: - matrix: - release: [43, 44] - steps: - - uses: actions/checkout@v7 - - run: docker build -t omaphoto-fedora --build-arg RELEASE=${{ matrix.release }} scripts/distro/fedora - - run: | - docker run --rm -u "$(id -u):$(id -g)" -e HOME=/tmp -v "$PWD:/src" -w /src omaphoto-fedora sh -c ' - cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \ - -DOMAPHOTO_BUNDLE_ORT=ON -DOMAPHOTO_MODEL=/usr/local/share/omaphoto/u2net.onnx && - cmake --build build --target omaphoto && cd build && cpack -G RPM' - mv build/omaphoto-*.x86_64.rpm omaphoto-fc${{ matrix.release }}.x86_64.rpm - - uses: actions/upload-artifact@v7 - with: - name: rpm-fc${{ matrix.release }} - path: omaphoto-fc${{ matrix.release }}.x86_64.rpm - arch: - needs: version - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v7 - - run: docker build -t omaphoto-arch scripts/distro/arch - # makepkg refuses root; a user of the runner's id builds. - - run: | - docker run --rm -v "$PWD:/src" omaphoto-arch sh -c " - useradd -u $(id -u) builder && chown -R builder /src && - su builder -c 'cd /src/packaging/arch && makepkg -f'" - mv packaging/arch/omaphoto-[0-9]*-x86_64.pkg.tar.zst omaphoto-x86_64.pkg.tar.zst - - uses: actions/upload-artifact@v7 - with: - name: arch - path: omaphoto-x86_64.pkg.tar.zst - publish: - needs: [deb, rpm, arch] - runs-on: ubuntu-24.04 - steps: - - uses: actions/checkout@v7 - - uses: actions/download-artifact@v8 - with: - merge-multiple: true - path: packages - - working-directory: packages - run: sha256sum omaphoto-noble_amd64.deb omaphoto-resolute_amd64.deb omaphoto-fc43.x86_64.rpm omaphoto-fc44.x86_64.rpm omaphoto-x86_64.pkg.tar.zst > SHA256SUMS - - env: - GH_TOKEN: ${{ github.token }} - run: | - gh release create "$GITHUB_REF_NAME" packages/* --title "OmaPhoto ${GITHUB_REF_NAME#v}" \ - --notes "Install with the script for your system: see the README's Install section." diff --git a/.gitignore b/.gitignore index 809ae35..e828a54 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,7 @@ /packaging/arch/u2net.onnx /Compositor-Ref/ +/build-appimage/ +/AppDir/ +/*.AppImage +/release/ diff --git a/AGENTS.md b/AGENTS.md index d5b93b6..bd6f8f3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,7 +15,7 @@ To make or change an image in a `.comp` project, the source is not needed: read - The repository root: the app. C++20, Qt 6 Widgets (floor Qt 6.4), CMake, Qt Test. CPU raster only: QPainter plus the C kernels in `kernels/`, copied unchanged from Compositor's `Compositor/Rendering/*.c` and compiled in place. - `packaging/`: the desktop entry, MIME type, icons (Compositor's app icon) and the Arch `PKGBUILD`; `flake.nix` at the root for NixOS. - `scripts/install/`: one install script per distribution family, each fetching the latest release's package. -- `.github/workflows/release.yml`: a `v*` tag builds the DEBs, the RPMs and the Arch package and publishes them. +- `scripts/release.sh`: builds a tag's DEBs, RPMs, Arch package and AppImage in Docker and publishes them as a release on the project's Gitea, https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto (the GitHub repository is gone; GitHub suspended the account in 2026-10). - `docs/acceptance.md`: the MVP acceptance table, its screenshots in `docs/acceptance/`. - `TASKS.md`: ordered task list and progress truth. Its entries before 11.4b speak of the port's old home, `linux/` inside Compositor's repository. @@ -202,7 +202,7 @@ Deliberate name breaks: `MetalBrushCoverage` → `BrushCoverage`, `MetalLayerEff - Omarchy theme: `src/UI/OmarchyTheme` reads `~/.local/state/omarchy/current/theme/colors.toml` (Omarchy 4.x: flat `key = "value"` lines, `mode` dark or light, the twenty-two stock themes' keys required, `orange` optional and `yellow` its stand-in) into `OmarchyColors`, applies them as the application palette (Window and Text from `background` and `foreground`, Base from `darker_background`, Button from `lighter_background`, Highlight and Link from `accent` with the background as highlighted text, PlaceholderText from `dark_foreground`, BrightText from `orange` or `yellow`, Mid from `muted`, the disabled roles from `muted`) and sets the Fusion style, which follows a palette on every desktop where a platform style does not; no stylesheet is needed. Keys and values read in double or single quotes. A missing key, or a recognised key whose value is bare or half-quoted or no `#rrggbb`, refuses the file with the key's name; a file that exists but cannot be opened, or sits behind a folder that cannot be searched (`stat` fails other than `ENOENT`), is refused too; either way the app keeps the palette it has and logs a warning, where an absent file means the built-in dark, Swift's grays, installed before the first load. `omarchy-theme-set` removes `current/theme`, moves `next-theme` in and writes `theme.name`, so the watcher holds `current/`, `current/theme` and the file, adds them back after each load (a removed path leaves a `QFileSystemWatcher`) and renews the file's watch every load (it follows the inode, which an atomic replacement swaps), watches the nearest ancestor the watcher accepts while `current/` is missing or barred, letting it go once the directory is watched, and loads once 100 ms after the last event. A read that stops short (an error, or fewer bytes than the file holds) is refused like a malformed file. Each load logs the theme's name and mode on `omaphoto.app`. `main` makes the theme before the window. Widgets take colours from the palette, never from literals; the canvas keeps Swift's document grays. The UI font stays Qt's default: `omarchy font current` is not followed. - No updater. Distro packages own updates. - Custom cursors (`QCursor` pixmaps) come out garbled on the hardware cursor path with NVIDIA and Hyprland at a fractional scale; theme cursors render correctly (issue #9, hyprwm/Hyprland#16413). README gives the software-cursor setting; the app keeps its cursors and does not guess at drivers (the user's decision, 13.1). -- Distribution (11.4b): releases live on GitHub under fixed asset names (`omaphoto-noble_amd64.deb`, `omaphoto-resolute_amd64.deb`, `omaphoto-fc43.x86_64.rpm`, `omaphoto-fc44.x86_64.rpm`, `omaphoto-x86_64.pkg.tar.zst`; 1.0.0 had one DEB, `omaphoto_amd64.deb`, and 1.0.0 to 1.2.3 one RPM, `omaphoto.x86_64.rpm`) with `SHA256SUMS`, so `releases/latest/download/` always reaches the newest. `scripts/install/arch.sh` reads `/etc/os-release` (`ID` or `ID_LIKE`; Omarchy says `ID_LIKE=arch`), `fedora.sh` its `ID` or `ID_LIKE` and `VERSION_ID`, taking the RPM of release 43 or 44 and refusing any other, since each names its release's LibRaw (`libraw_r.so.23` on 43, `.25` on 44; found in 12.16, when 1.2.3's single RPM from Fedora 43 would not install on 44), and `ubuntu.sh` its `UBUNTU_CODENAME`, which Ubuntu's derivatives set to their base: each DEB names its release's Qt libraries (24.04's carry a `t64` suffix that 26.04's drop, and Debian 13 has neither), so the release carries one DEB per LTS, built on it (`Dockerfile.dev` takes the base as `BASE`), and the script takes the one whose codename matches, `noble` or `resolute`, refusing any other. Each refuses another system or another machine than x86_64, verify the package against the sums and install it with apt, dnf or pacman under sudo, so the package manager resolves dependencies; apt reads the file as its own user, so the download folder is opened to it. Fedora's script names RPM Fusion's `libheif-freeworld` when it is missing, since Fedora's libheif decodes no HEVC, and adds no repository itself. `nixos.sh` installs the flake at the newest release's tag, which GitHub's `releases/latest` redirect names, into the user's profile (`nix profile install`, the name every Nix still takes), so no user builds unreleased work from `main`. The README runs each script after downloading it, so the package manager's questions read the terminal and fish runs it too. `release.yml` builds each package with the command the distro checks use, the DEBs on the dev image over each base, the RPMs on Fedora 43 and 44 (`scripts/distro/fedora/Dockerfile` takes the release as `RELEASE`, 43 by default), the Arch package through `makepkg` as a user; the version is CMake's `project` version, the PKGBUILD's and the flake's, kept equal by hand, and the workflow's first job refuses a tag that names another. +- Distribution (11.4b): releases live on Gitea (git.zacharyzhang.com) under fixed asset names (`omaphoto-noble_amd64.deb`, `omaphoto-resolute_amd64.deb`, `omaphoto-fc43.x86_64.rpm`, `omaphoto-fc44.x86_64.rpm`, `omaphoto-x86_64.pkg.tar.zst`, `omaphoto-x86_64.AppImage` since 1.4.5; 1.0.0 had one DEB, `omaphoto_amd64.deb`, and 1.0.0 to 1.2.3 one RPM, `omaphoto.x86_64.rpm`) with `SHA256SUMS`. Gitea has no `releases/latest/download`, so each script asks the API for the newest release's tag (`/api/v1/repos/ZacharyZhang-NY/OmaPhoto/releases/latest`) and downloads from `releases/download//`. `scripts/install/arch.sh` reads `/etc/os-release` (`ID` or `ID_LIKE`; Omarchy says `ID_LIKE=arch`), `fedora.sh` its `ID` or `ID_LIKE` and `VERSION_ID`, taking the RPM of release 43 or 44 and refusing any other, since each names its release's LibRaw (`libraw_r.so.23` on 43, `.25` on 44; found in 12.16, when 1.2.3's single RPM from Fedora 43 would not install on 44), and `ubuntu.sh` its `UBUNTU_CODENAME`, which Ubuntu's derivatives set to their base: each DEB names its release's Qt libraries (24.04's carry a `t64` suffix that 26.04's drop, and Debian 13 has neither), so the release carries one DEB per LTS, built on it (`Dockerfile.dev` takes the base as `BASE`), and the script takes the one whose codename matches, `noble` or `resolute`, refusing any other. Each refuses another system or another machine than x86_64, verify the package against the sums and install it with apt, dnf or pacman under sudo, so the package manager resolves dependencies; apt reads the file as its own user, so the download folder is opened to it. Fedora's script names RPM Fusion's `libheif-freeworld` when it is missing, since Fedora's libheif decodes no HEVC, and adds no repository itself. `nixos.sh` installs the flake at the newest release's tag (`git+https://…?ref=refs/tags/`) into the user's profile (`nix profile install`, the name every Nix still takes), so no user builds unreleased work from `main`. The README runs each script after downloading it, so the package manager's questions read the terminal and fish runs it too. `scripts/release.sh vX.Y.Z` (with `GITEA_TOKEN` set, the tag already pushed) builds each package from `git archive` of the tag with the command the distro checks use, the DEBs on the dev image over each base, the RPMs on Fedora 43 and 44 (`scripts/distro/fedora/Dockerfile` takes the release as `RELEASE`, 43 by default), the Arch package through `makepkg` as a user, the AppImage on the noble dev image (`scripts/distro/appimage`, linuxdeploy and its Qt plugin pinned by checksum; `scripts/appimage.sh` adds Qt's Wayland shell, decoration and graphics plugins and libheif's HEVC plugin, and `packaging/appimage/omaphoto.sh`, an AppRun hook, puts the AppImage's `usr/share` first on `XDG_DATA_DIRS` so the model is found, and sets `LIBHEIF_PLUGIN_PATH`), then writes `SHA256SUMS`, creates the release and uploads every file; the version is CMake's `project` version, the PKGBUILD's and the flake's, kept equal by hand, and the script refuses a tag that names another. - Remove Background runs an open-licensed model on ONNX Runtime. - A `.comp` project is a directory on Linux; its layout matches the macOS package. - Shortcuts map ⌘ to Ctrl and ⌥ to Alt. diff --git a/CMakeLists.txt b/CMakeLists.txt index bd9fa02..5eaa144 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -293,7 +293,7 @@ set(CPACK_PACKAGE_NAME omaphoto) set(CPACK_PACKAGE_VENDOR "ZacharyZhang-NY") set(CPACK_PACKAGE_CONTACT "ZacharyZhang-NY") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Layered image editing for Linux, a port of Compositor") -set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/ZacharyZhang-NY/OmaPhoto") +set(CPACK_PACKAGE_HOMEPAGE_URL "https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto") set(CPACK_PACKAGING_INSTALL_PREFIX /usr) set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) set(CPACK_DEBIAN_PACKAGE_SECTION graphics) diff --git a/README.md b/README.md index 9149b92..718c97f 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,13 @@ Each script installs the newest release. The Arch, Ubuntu and Fedora scripts dow Arch and Omarchy: ```sh -curl -fsSLO https://raw.githubusercontent.com/ZacharyZhang-NY/OmaPhoto/main/scripts/install/arch.sh && bash arch.sh +curl -fsSLO https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/raw/branch/main/scripts/install/arch.sh && bash arch.sh ``` Ubuntu 24.04 or 26.04 LTS and systems built on them (Linux Mint 22, Pop!_OS 24.04): ```sh -curl -fsSLO https://raw.githubusercontent.com/ZacharyZhang-NY/OmaPhoto/main/scripts/install/ubuntu.sh && bash ubuntu.sh +curl -fsSLO https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/raw/branch/main/scripts/install/ubuntu.sh && bash ubuntu.sh ``` Each DEB names its Ubuntu release's libraries, so other Ubuntu releases and Debian build from source (below). @@ -49,7 +49,7 @@ Each DEB names its Ubuntu release's libraries, so other Ubuntu releases and Debi Fedora 43 or 44: ```sh -curl -fsSLO https://raw.githubusercontent.com/ZacharyZhang-NY/OmaPhoto/main/scripts/install/fedora.sh && bash fedora.sh +curl -fsSLO https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/raw/branch/main/scripts/install/fedora.sh && bash fedora.sh ``` Fedora's own libheif decodes no HEVC. For HEIC import, add [RPM Fusion](https://rpmfusion.org/Configuration) and install `libheif-freeworld`; the script reminds you. @@ -57,12 +57,12 @@ Fedora's own libheif decodes no HEVC. For HEIC import, add [RPM Fusion](https:// NixOS installs the release's flake into your profile: ```sh -curl -fsSLO https://raw.githubusercontent.com/ZacharyZhang-NY/OmaPhoto/main/scripts/install/nixos.sh && bash nixos.sh +curl -fsSLO https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/raw/branch/main/scripts/install/nixos.sh && bash nixos.sh ``` -Or add `github:ZacharyZhang-NY/OmaPhoto/`, a release tag, as a flake input and put its `packages.x86_64-linux.default` in your configuration. +Or add `git+https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto?ref=refs/tags/`, a release tag, as a flake input and put its `packages.x86_64-linux.default` in your configuration. -The packages themselves sit on the [releases page](https://github.com/ZacharyZhang-NY/OmaPhoto/releases). +The packages themselves sit on the [releases page](https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/releases). Any other x86_64 system can run the AppImage there, `omaphoto-x86_64.AppImage`: download it, `chmod +x` it and start it. ### Garbled cursors on NVIDIA with Hyprland diff --git a/TASKS.md b/TASKS.md index 3cd0491..8bce1fb 100644 --- a/TASKS.md +++ b/TASKS.md @@ -503,7 +503,8 @@ Reviews for this section ran on codex `gpt-6.1-sol` at `max` (agent `codex-sol`) - 13.19i review: round 1 PASS (the Qt behaviour probed on 6.4.2, 6.10.2 and 6.11.2, six mutants caught). - 13.19j work: `versionupdate.md` gains 13.19i's blend menu fix; `v1.4.5` tagged on main and pushed; the workflow's run is checked below. - [ ] 13.19j Tag `v1.4.5`; the release workflow publishes every package. - - [ ] 13.19k Live installs from GitHub in fresh containers. + - 2026-10-11: GitHub suspended the account; the project moved to Gitea (git.zacharyzhang.com), the workflow became `scripts/release.sh`, and releases gain an AppImage. + - [ ] 13.19k Live installs from Gitea in fresh containers. - [ ] 13.19l The acceptance checklist. ## Skills by phase diff --git a/docs/acceptance.md b/docs/acceptance.md index da6e841..8cd777e 100644 --- a/docs/acceptance.md +++ b/docs/acceptance.md @@ -32,7 +32,7 @@ The screenshots come from Qt's offscreen platform, so floating panels appear wit | Reload a project changed on disk | With unsaved edits open, another program renames a layer on disk. The app's alert asks, Revert is chosen, and the saved state shows with the new name. | [15](acceptance/15-shortcuts.png) | `ExternalChangeTests` | pass | | Follows the Omarchy theme | Starts in the built-in dark. A Catppuccin Latte `colors.toml` written while the app runs retints the window. | [16](acceptance/16-omarchy-light.png) | `OmarchyThemeTests` | pass | | Builds and tests on each system | The full suite, 334 binaries, passes on Ubuntu 24.04 (Qt 6.4.2), Ubuntu 26.04 (6.10.2), Arch (6.11.2), Fedora 43 and 44, and NixOS (6.11.2). Warnings count as errors. | — | `scripts/distro-check.sh` | pass | -| Packages and install scripts | Each install script runs from GitHub in a fresh container. On Ubuntu 24.04 and 26.04, Fedora 43 and 44 and Arch, it checks its package against `SHA256SUMS`, installs it and starts 1.4.5. On NixOS, `nixos.sh` resolves `v1.4.5`, builds its flake and starts 1.4.5. Debian 13 is refused, as intended. | — | `DesktopIntegrationTests`, `.github/workflows/release.yml` | pending | +| Packages and install scripts | Each install script runs from Gitea in a fresh container. On Ubuntu 24.04 and 26.04, Fedora 43 and 44 and Arch, it checks its package against `SHA256SUMS`, installs it and starts 1.4.5. On NixOS, `nixos.sh` resolves `v1.4.5`, builds its flake and starts 1.4.5. Debian 13 is refused, as intended. | — | `DesktopIntegrationTests`, `scripts/release.sh` | pending | ## New in 1.4.5 diff --git a/docs/writing-comp-files.md b/docs/writing-comp-files.md index 3f0632f..e1e621e 100644 --- a/docs/writing-comp-files.md +++ b/docs/writing-comp-files.md @@ -7,7 +7,7 @@ An OmaPhoto project (`.comp`) is a folder of PNG layer images plus a `manifest.j 1. Open a project in OmaPhoto 1.3 or later (save a new canvas somewhere, e.g. `~/Pictures/demo.comp`), and keep it open. 2. Ask an AI agent that can edit files on your computer (Claude Code, Codex and the like): - > Read docs/writing-comp-files.md in github.com/ZacharyZhang-NY/OmaPhoto, then design a moody night scene in ~/Pictures/demo.comp. Work in steps, one or two layers at a time. + > Read docs/writing-comp-files.md in git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto, then design a moody night scene in ~/Pictures/demo.comp. Work in steps, one or two layers at a time. 3. Watch the canvas. Each time the agent writes the project, OmaPhoto reloads it, usually within half a second. diff --git a/packaging/appimage/omaphoto.sh b/packaging/appimage/omaphoto.sh new file mode 100644 index 0000000..af34df5 --- /dev/null +++ b/packaging/appimage/omaphoto.sh @@ -0,0 +1,3 @@ +# The AppImage's model, MIME data and HEVC decoder come first. +export XDG_DATA_DIRS="$APPDIR/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}" +export LIBHEIF_PLUGIN_PATH="$APPDIR/usr/lib/libheif" diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index f19ea8d..0f909bc 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -4,7 +4,7 @@ pkgver=1.4.5 pkgrel=1 pkgdesc='Layered image editing for Linux, a port of Compositor' arch=('x86_64') -url='https://github.com/ZacharyZhang-NY/OmaPhoto' +url='https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto' license=('MIT') depends=('qt6-base' 'qt6-svg' 'qt6-imageformats' 'libheif' 'libraw' 'libde265' 'fontconfig' 'hicolor-icon-theme' 'shared-mime-info') makedepends=('cmake' 'ninja') diff --git a/scripts/appimage.sh b/scripts/appimage.sh new file mode 100755 index 0000000..673edf6 --- /dev/null +++ b/scripts/appimage.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# Builds omaphoto-x86_64.AppImage inside the AppImage image. +set -euo pipefail +id=io.github.ZacharyZhang_NY.OmaPhoto +cmake -S . -B build-appimage -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \ + -DOMAPHOTO_BUNDLE_ORT=ON -DOMAPHOTO_MODEL=/usr/local/share/omaphoto/u2net.onnx +cmake --build build-appimage --target omaphoto +rm -rf AppDir +DESTDIR="$PWD/AppDir" cmake --install build-appimage +# libheif loads its HEVC decoder as a plugin. +mkdir -p AppDir/usr/lib/libheif AppDir/apprun-hooks +cp /usr/lib/x86_64-linux-gnu/libheif/plugins/libheif-libde265.so AppDir/usr/lib/libheif/ +cp packaging/appimage/omaphoto.sh AppDir/apprun-hooks/ +# Qt's Wayland client needs its shell and decoration plugins. +qtplugins=/usr/lib/x86_64-linux-gnu/qt6/plugins +mkdir -p AppDir/usr/plugins +for dir in wayland-shell-integration wayland-decoration-client wayland-graphics-integration-client; do + cp -r "$qtplugins/$dir" AppDir/usr/plugins/ +done +export QMAKE=/usr/lib/qt6/bin/qmake6 APPIMAGE_EXTRACT_AND_RUN=1 OUTPUT=omaphoto-x86_64.AppImage +export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so" EXTRA_QT_MODULES=svg +linuxdeploy --appdir AppDir --plugin qt --output appimage \ + --desktop-file "AppDir/usr/share/applications/$id.desktop" \ + --icon-file "AppDir/usr/share/icons/hicolor/512x512/apps/$id.png" \ + --deploy-deps-only AppDir/usr/lib/libheif \ + --deploy-deps-only AppDir/usr/plugins/wayland-shell-integration \ + --deploy-deps-only AppDir/usr/plugins/wayland-decoration-client \ + --deploy-deps-only AppDir/usr/plugins/wayland-graphics-integration-client diff --git a/scripts/distro/appimage/Dockerfile b/scripts/distro/appimage/Dockerfile new file mode 100644 index 0000000..305fbe9 --- /dev/null +++ b/scripts/distro/appimage/Dockerfile @@ -0,0 +1,10 @@ +# The dev image plus linuxdeploy, pinned by checksum. +ARG DEV=omaphoto-dev +FROM $DEV +RUN curl -fsSL -o /usr/local/bin/linuxdeploy \ + https://github.com/linuxdeploy/linuxdeploy/releases/download/1-alpha-20251107-1/linuxdeploy-x86_64.AppImage \ + && curl -fsSL -o /usr/local/bin/linuxdeploy-plugin-qt \ + https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/1-alpha-20250213-1/linuxdeploy-plugin-qt-x86_64.AppImage \ + && echo "c20cd71e3a4e3b80c3483cef793cda3f4e990aca14014d23c544ca3ce1270b4d /usr/local/bin/linuxdeploy" | sha256sum -c - \ + && echo "15106be885c1c48a021198e7e1e9a48ce9d02a86dd0a1848f00bdbf3c1c92724 /usr/local/bin/linuxdeploy-plugin-qt" | sha256sum -c - \ + && chmod +x /usr/local/bin/linuxdeploy /usr/local/bin/linuxdeploy-plugin-qt diff --git a/scripts/install/arch.sh b/scripts/install/arch.sh index 4ef3097..85362f3 100755 --- a/scripts/install/arch.sh +++ b/scripts/install/arch.sh @@ -1,7 +1,14 @@ #!/usr/bin/env bash -# Installs OmaPhoto's latest package on Arch and Omarchy. +# Installs OmaPhoto's newest package on Arch and Omarchy. set -euo pipefail -base=https://github.com/ZacharyZhang-NY/OmaPhoto/releases/latest/download +repo=https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto +# The newest release's tag, from Gitea's API. +tag=$(curl -fsSL --proto '=https' https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/OmaPhoto/releases/latest | grep -o '"tag_name":"v[^"]*"' | cut -d'"' -f4) || tag= +if [ -z "$tag" ]; then + echo "No release found at $repo/releases." >&2 + exit 1 +fi +base=$repo/releases/download/$tag package=omaphoto-x86_64.pkg.tar.zst . /etc/os-release case " ${ID:-} ${ID_LIKE:-} " in diff --git a/scripts/install/fedora.sh b/scripts/install/fedora.sh index f45c2f3..e510be4 100755 --- a/scripts/install/fedora.sh +++ b/scripts/install/fedora.sh @@ -1,7 +1,14 @@ #!/usr/bin/env bash -# Installs OmaPhoto's latest RPM on Fedora 43 or 44. +# Installs OmaPhoto's newest RPM on Fedora 43 or 44. set -euo pipefail -base=https://github.com/ZacharyZhang-NY/OmaPhoto/releases/latest/download +repo=https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto +# The newest release's tag, from Gitea's API. +tag=$(curl -fsSL --proto '=https' https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/OmaPhoto/releases/latest | grep -o '"tag_name":"v[^"]*"' | cut -d'"' -f4) || tag= +if [ -z "$tag" ]; then + echo "No release found at $repo/releases." >&2 + exit 1 +fi +base=$repo/releases/download/$tag . /etc/os-release release= case " ${ID:-} ${ID_LIKE:-} " in diff --git a/scripts/install/nixos.sh b/scripts/install/nixos.sh index 674c893..92710cb 100755 --- a/scripts/install/nixos.sh +++ b/scripts/install/nixos.sh @@ -9,14 +9,11 @@ if [ "$(uname -m)" != x86_64 ]; then echo "OmaPhoto's flake builds for x86_64 alone." >&2 exit 1 fi -# The newest release's tag, as GitHub redirects to it. -latest=$(curl -fsSLI --proto '=https' -o /dev/null -w '%{url_effective}' https://github.com/ZacharyZhang-NY/OmaPhoto/releases/latest) -tag=${latest##*/} -case "$tag" in -v[0-9]*) ;; -*) - echo "No release found at $latest." >&2 +repo=https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto +# The newest release's tag, from Gitea's API. +tag=$(curl -fsSL --proto '=https' https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/OmaPhoto/releases/latest | grep -o '"tag_name":"v[^"]*"' | cut -d'"' -f4) || tag= +if [ -z "$tag" ]; then + echo "No release found at $repo/releases." >&2 exit 1 - ;; -esac -nix --extra-experimental-features "nix-command flakes" profile install "github:ZacharyZhang-NY/OmaPhoto/$tag" +fi +nix --extra-experimental-features "nix-command flakes" profile install "git+$repo?ref=refs/tags/$tag" diff --git a/scripts/install/ubuntu.sh b/scripts/install/ubuntu.sh index e412939..4c3c72f 100755 --- a/scripts/install/ubuntu.sh +++ b/scripts/install/ubuntu.sh @@ -1,7 +1,14 @@ #!/usr/bin/env bash -# Installs OmaPhoto's latest DEB on Ubuntu LTS and derivatives. +# Installs OmaPhoto's newest DEB on Ubuntu LTS and derivatives. set -euo pipefail -base=https://github.com/ZacharyZhang-NY/OmaPhoto/releases/latest/download +repo=https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto +# The newest release's tag, from Gitea's API. +tag=$(curl -fsSL --proto '=https' https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/OmaPhoto/releases/latest | grep -o '"tag_name":"v[^"]*"' | cut -d'"' -f4) || tag= +if [ -z "$tag" ]; then + echo "No release found at $repo/releases." >&2 + exit 1 +fi +base=$repo/releases/download/$tag . /etc/os-release # Each DEB names its LTS's libraries; derivatives name their base. case "${UBUNTU_CODENAME:-}" in diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 0000000..a2f6837 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# Builds a tag's packages and publishes a Gitea release. +set -euo pipefail +tag=${1:?"usage: GITEA_TOKEN=... scripts/release.sh vX.Y.Z"} +token=${GITEA_TOKEN:?"GITEA_TOKEN must hold a Gitea access token"} +api=https://git.zacharyzhang.com/api/v1/repos/ZacharyZhang-NY/OmaPhoto +repo=$(cd "$(dirname "$0")/.." && pwd) +cd "$repo" +version=${tag#v} +# The tag must name the version each build file carries. +if ! git show "$tag:CMakeLists.txt" | grep -qF "project(omaphoto VERSION $version "; then + echo "CMakeLists.txt at $tag is not $version" >&2 + exit 1 +fi +if ! git show "$tag:packaging/arch/PKGBUILD" | grep -qxF "pkgver=$version"; then + echo "The PKGBUILD at $tag is not $version" >&2 + exit 1 +fi +if ! git show "$tag:flake.nix" | grep -qF "version = \"$version\";"; then + echo "flake.nix at $tag is not $version" >&2 + exit 1 +fi +out=$repo/release/$tag +rm -rf "$out" +mkdir -p "$out" +work=$(mktemp -d) +trap 'rm -rf "$work"' EXIT +user="$(id -u):$(id -g)" +configure="cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr -DOMAPHOTO_BUNDLE_ORT=ON -DOMAPHOTO_MODEL=/usr/local/share/omaphoto/u2net.onnx && cmake --build build --target omaphoto" +# Each package builds from a fresh copy of the tag. +fresh() { + rm -rf "$work/src" + mkdir "$work/src" + git archive "$tag" | tar -x -C "$work/src" +} +build() { + docker run --rm -u "$user" -e HOME=/tmp -v "$work/src:/src" -w /src "$1" sh -c "$2" +} +# One DEB per Ubuntu LTS: each names its own libraries. +docker build -t omaphoto-dev --build-arg BASE=ubuntu:24.04 -f Dockerfile.dev . +docker build -t omaphoto-resolute --build-arg BASE=ubuntu:26.04 -f Dockerfile.dev . +for pair in noble:omaphoto-dev resolute:omaphoto-resolute; do + fresh + build "${pair#*:}" "$configure && cd build && cpack -G DEB" + mv "$work"/src/build/omaphoto_*.deb "$out/omaphoto-${pair%%:*}_amd64.deb" +done +# One RPM per Fedora release: each names its own LibRaw. +docker build -t omaphoto-fedora --build-arg RELEASE=43 scripts/distro/fedora +docker build -t omaphoto-fedora44 --build-arg RELEASE=44 scripts/distro/fedora +for pair in 43:omaphoto-fedora 44:omaphoto-fedora44; do + fresh + build "${pair#*:}" "$configure && cd build && cpack -G RPM" + mv "$work"/src/build/omaphoto-*.x86_64.rpm "$out/omaphoto-fc${pair%%:*}.x86_64.rpm" +done +# makepkg refuses root; a user of our id builds. +docker build --pull -t omaphoto-arch scripts/distro/arch +fresh +docker run --rm -v "$work/src:/src" omaphoto-arch sh -c "useradd -u $(id -u) builder && chown -R builder /src && su builder -c 'cd /src/packaging/arch && makepkg -f'" +mv "$work"/src/packaging/arch/omaphoto-[0-9]*-x86_64.pkg.tar.zst "$out/omaphoto-x86_64.pkg.tar.zst" +# The AppImage builds on Ubuntu 24.04, the oldest glibc here. +docker build -t omaphoto-appimage --build-arg DEV=omaphoto-dev scripts/distro/appimage +fresh +build omaphoto-appimage scripts/appimage.sh +mv "$work/src/omaphoto-x86_64.AppImage" "$out/" +names="omaphoto-noble_amd64.deb omaphoto-resolute_amd64.deb omaphoto-fc43.x86_64.rpm omaphoto-fc44.x86_64.rpm omaphoto-x86_64.pkg.tar.zst omaphoto-x86_64.AppImage" +(cd "$out" && sha256sum $names > SHA256SUMS) +# The tag must already be on Gitea. +notes="Install with the script for your system, or run the AppImage: see the README's Install section." +body=$(printf '{"tag_name":"%s","name":"OmaPhoto %s","body":"%s"}' "$tag" "$version" "$notes") +release=$(curl -fsS -X POST -H "Authorization: token $token" -H "Content-Type: application/json" -d "$body" "$api/releases") +id=$(echo "$release" | grep -o '"id":[0-9]*' | head -1 | cut -d: -f2) +for name in $names SHA256SUMS; do + echo "Uploading $name" + curl -fsS -o /dev/null -X POST -H "Authorization: token $token" -F "attachment=@$out/$name" "$api/releases/$id/assets?name=$name" +done +echo "Published https://git.zacharyzhang.com/ZacharyZhang-NY/OmaPhoto/releases/tag/$tag"