feat(release): ship a Linux AppImage alongside the tarball (#55)

* feat(release): ship a Linux AppImage alongside the tarball

The Linux release was a bare, dynamically-linked binary built on
ubuntu-latest, so it only reliably ran on Ubuntu — Fedora/Arch users hit
missing/mismatched runtime libs. Add an AppImage that bundles the
x11/wayland/xkb/fontconfig/freetype libs so it launches across distros.

- bundle-appimage.sh: linuxdeploy populates an AppDir + deps, completions
  go beside the binary (usr/bin/completions, matching signature.rs's
  current_exe lookup), appimagetool packs it. Runs FUSE-less on CI.
- release.yml: new "Package Linux AppImage" step after the tarball,
  libfuse2/file added to the Linux deps, *.AppImage added to the upload
  list. The AppImage step avoids `rm -rf dist` so the tarball survives.
- README (en + zh): recommend the AppImage, keep the tarball as the bare
  fallback.

Note: glibc is not bundled, so ubuntu-latest still sets the glibc floor.

* fix(release): downscale AppImage icon to a resolution linuxdeploy accepts

linuxdeploy rejected the 1024x1024 app-icon.png (its valid list tops out at
512). Resize to 256x256 with ImageMagick's convert (added to the Linux apt
deps) before handing the icon to linuxdeploy.

---------

Co-authored-by: l0ng-ai <24760907+l0ng-ai@users.noreply.github.com>
This commit is contained in:
l0ng-ai
2026-07-13 10:43:26 +08:00
committed by GitHub
co-authored by l0ng-ai
parent 78a6f00ec8
commit b5beba6d80
4 changed files with 105 additions and 5 deletions
+86
View File
@@ -0,0 +1,86 @@
#!/bin/bash
# Usage: bundle-appimage.sh <target-triple> <arch-label>
# Package the release binary into a self-contained AppImage:
# dist/tty7-<version>-linux-<arch>.AppImage
#
# Unlike the bare tarball (bundle-linux.sh), this bundles the x11/wayland/xkb/
# fontconfig/freetype runtime libraries alongside the binary, so it launches on
# distros that don't ship the exact same set Ubuntu does — Fedora, Arch, etc.
# (glibc itself is NOT bundled — an AppImage still needs the host glibc to be
# >= the build machine's, so the release runner's Ubuntu sets the floor.)
#
# Completion signatures are loaded at runtime relative to the executable
# (<exe-dir>/completions — see terminal::signature), so they go beside the
# binary at usr/bin/completions inside the AppDir.
set -euo pipefail
TARGET="$1"
ARCH="$2"
VERSION="$(grep -m1 '^version' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')"
NAME="tty7-${VERSION}-linux-${ARCH}"
# AppImage tools need FUSE to self-mount; CI runners usually lack it, so extract
# and run instead. Harmless on machines that do have FUSE.
export APPIMAGE_EXTRACT_AND_RUN=1
# linuxdeploy is published per-arch; map Rust's arch label to its naming.
case "$ARCH" in
x86_64) LD_ARCH=x86_64 ;;
arm64 | aarch64) LD_ARCH=aarch64 ;;
*) echo "unsupported arch for AppImage: $ARCH" >&2; exit 1 ;;
esac
TOOLS="$(mktemp -d)"
LINUXDEPLOY="$TOOLS/linuxdeploy-${LD_ARCH}.AppImage"
APPIMAGETOOL="$TOOLS/appimagetool-${LD_ARCH}.AppImage"
curl -fsSL -o "$LINUXDEPLOY" \
"https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-${LD_ARCH}.AppImage"
curl -fsSL -o "$APPIMAGETOOL" \
"https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-${LD_ARCH}.AppImage"
chmod +x "$LINUXDEPLOY" "$APPIMAGETOOL"
# NB: don't wipe dist/ — the tarball step (bundle-linux.sh) runs first and its
# artifact must survive. Only clean our own AppDir.
APPDIR="dist/AppDir"
rm -rf "$APPDIR"
mkdir -p "$APPDIR/usr/bin"
cp "target/${TARGET}/release/tty7" "$APPDIR/usr/bin/tty7"
chmod +x "$APPDIR/usr/bin/tty7"
# A desktop entry + icon are mandatory AppImage metadata; linuxdeploy places
# them and generates AppRun. Icon basename must match the desktop's Icon= key.
cat > "$TOOLS/tty7.desktop" <<'DESKTOP'
[Desktop Entry]
Type=Application
Name=tty7
Comment=A fast, native terminal
Exec=tty7
Icon=tty7
Categories=System;TerminalEmulator;
Terminal=false
StartupWMClass=tty7
DESKTOP
# linuxdeploy only accepts fixed icon resolutions (…256, 384, 512 — NOT the
# source's 1024), so downscale to 256×256.
convert assets/app-icon.png -resize 256x256 "$TOOLS/tty7.png"
# Phase 1 — populate the AppDir: copy in dependent libs (ldd + patchelf) and
# install the desktop/icon into their standard locations.
"$LINUXDEPLOY" \
--appdir "$APPDIR" \
--executable "$APPDIR/usr/bin/tty7" \
--desktop-file "$TOOLS/tty7.desktop" \
--icon-file "$TOOLS/tty7.png"
# Runtime-loaded completion specs live beside the binary (not bundled by
# linuxdeploy, which only tracks ELF deps), so drop them in after populate.
mkdir -p "$APPDIR/usr/bin/completions"
cp assets/completions/*.json "$APPDIR/usr/bin/completions/"
# Phase 2 — pack the finished AppDir. Done separately from linuxdeploy so the
# completions added above are included.
"$APPIMAGETOOL" "$APPDIR" "dist/${NAME}.AppImage"
chmod +x "dist/${NAME}.AppImage"
rm -rf "$APPDIR" "$TOOLS"
echo "✅ dist/${NAME}.AppImage"
+11 -1
View File
@@ -50,7 +50,8 @@ jobs:
sudo apt-get update
sudo apt-get install -y pkg-config cmake clang libxkbcommon-dev \
libxkbcommon-x11-dev libfontconfig1-dev libfreetype6-dev \
libwayland-dev libx11-dev libxcb1-dev libzstd-dev libssl-dev
libwayland-dev libx11-dev libxcb1-dev libzstd-dev libssl-dev \
libfuse2 file imagemagick
- uses: dtolnay/rust-toolchain@stable
with:
@@ -89,6 +90,14 @@ jobs:
working-directory: tty7
run: bash .github/scripts/bundle-linux.sh "${{ matrix.target }}" "${{ matrix.arch }}"
# AppImage bundles the x11/wayland/xkb/font libs so it runs on Fedora/Arch/
# etc., not just Ubuntu. Kept separate from the tarball step so the tarball
# still ships even if AppImage tooling changes upstream.
- name: Package Linux AppImage
if: matrix.os == 'linux'
working-directory: tty7
run: bash .github/scripts/bundle-appimage.sh "${{ matrix.target }}" "${{ matrix.arch }}"
- name: Package Windows installer + zip
if: matrix.os == 'windows'
working-directory: tty7
@@ -104,3 +113,4 @@ jobs:
tty7/dist/*.tar.gz
tty7/dist/*.zip
tty7/dist/*-setup.exe
tty7/dist/*.AppImage
+4 -2
View File
@@ -43,8 +43,10 @@ Download the build for your platform from
- **Windows** — `…-windows-x86_64-setup.exe` (installer: Start Menu shortcut +
uninstall entry), or `…-windows-x86_64.zip` (portable: unzip and run
`tty7.exe`).
- **Linux** — `…-linux-x86_64.tar.gz`; extract and run `./tty7` (needs the usual
x11/wayland runtime libraries).
- **Linux** — `…-linux-x86_64.AppImage` (recommended: bundles the x11/wayland
libraries, so it runs on Fedora / Arch / etc. with no extra packages —
`chmod +x` and run), or `…-linux-x86_64.tar.gz` (bare binary; extract and run
`./tty7`, needs the usual x11/wayland runtime libraries installed).
## Features
+4 -2
View File
@@ -39,8 +39,10 @@ macOS、Windows、Linux 三平台原生构建,每个 release 一起打出。
Intel);打开后把 `tty7.app` 拖进「应用程序」即可。
- **Windows** —— `…-windows-x86_64-setup.exe`(安装包:带开始菜单快捷方式和
卸载入口),或 `…-windows-x86_64.zip`(便携版:解压后运行 `tty7.exe`)。
- **Linux** —— `…-linux-x86_64.tar.gz`;解压后运行 `./tty7`(需要常见的
x11/wayland 运行时库)。
- **Linux** —— `…-linux-x86_64.AppImage`(推荐:已打包 x11/wayland 依赖库,
Fedora / Arch 等发行版免装依赖,`chmod +x` 后直接运行),或
`…-linux-x86_64.tar.gz`(裸二进制,解压后运行 `./tty7`,需自行装齐常见的
x11/wayland 运行时库)。
## 功能