#!/bin/bash # Usage: bundle-appimage.sh # Package the release binary into a self-contained AppImage: # dist/tty7--linux-.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 # (/completions — see terminal::signature), so they go beside the # binary at usr/bin/completions inside the AppDir. set -euo pipefail TARGET="$1" ARCH="$2" # Anchored on `= "` — see the note in bundle-macos.sh: the root manifest leads # with `version.workspace = true`, which a bare `^version` match would return # verbatim as the "version" and bake into every asset filename. VERSION="$(grep -m1 '^version = "' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/')" if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then echo "bundle-appimage: could not read a version from Cargo.toml (got '$VERSION')" >&2 exit 1 fi 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-app" "$APPDIR/usr/bin/tty7-app" chmod +x "$APPDIR/usr/bin/tty7-app" # The CLI, beside the GUI as everywhere else. Unlike the tarball, an AppImage is # mounted at a fresh /tmp/.mount_XXXX per run, so `core::cli_install` must copy # this onto PATH rather than symlink it — a link into the mount dies the moment # the app exits. That branch keys off $APPIMAGE, which the runtime sets. cp "target/${TARGET}/release/tty7" "$APPDIR/usr/bin/tty7" chmod +x "$APPDIR/usr/bin/tty7" # The in-app updater, beside the GUI the way every platform ships it. The GUI # copies it out of the mount into its staging directory before use — the mount # is gone by the time an install runs (see src/bin/tty7-updater.rs). cp "target/${TARGET}/release/tty7-updater" "$APPDIR/usr/bin/tty7-updater" chmod +x "$APPDIR/usr/bin/tty7-updater" # 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-app Icon=tty7 Categories=System;TerminalEmulator; Terminal=false StartupWMClass=tty7 DESKTOP # The release version, stamped where the in-app updater can read it back with # one `--appimage-extract` and no mount: a downloaded image must state the # version it claims before it may replace the installed one (`verify_update` # in src/bin/tty7-updater.rs). X-AppImage-Version is the AppImage convention # for exactly this. Appended outside the heredoc, which is quoted on purpose. echo "X-AppImage-Version=${VERSION}" >> "$TOOLS/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-app" \ --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"