#!/usr/bin/env bash # Build and package FieldCraft for Linux x86_64: # # $DIST/fieldcraft--linux-x86_64.tar.gz bin/fieldcraft, bin/fieldcraft-cli, the # .desktop entry, icons and licences # $DIST/fieldcraft--linux-x86_64.AppImage the app as one file (chmod +x, run) # # Usage: packaging/linux/package.sh [--skip-build] [--formats "tar appimage"] # # Build on an old distribution (CI: Ubuntu 22.04, glibc 2.35) so the binaries run on newer ones. # The AppImage uses appimagetool and the type 2 runtime at pinned releases, checked against their # SHA-256 (downloaded into $CARGO_TARGET_DIR). Optional: desktop-file-validate. # Adapted from SolidCraft's packaging/linux/package.sh (MIT OR Apache-2.0; see ATTRIBUTION.md). set -euo pipefail # shellcheck source=../env.sh . "$(dirname "${BASH_SOURCE[0]}")/../env.sh" HERE="$ROOT/packaging/linux" ICONSET="$ROOT/assets/app-icon/icon.iconset" SKIP_BUILD=0 FORMATS="tar appimage" while [ $# -gt 0 ]; do case "$1" in --skip-build) SKIP_BUILD=1; shift ;; --formats) FORMATS="$2"; shift 2 ;; -h | --help) sed -n '2,13p' "$0"; exit 0 ;; *) echo "unknown argument: $1" >&2; exit 2 ;; esac done has() { case " $FORMATS " in *" $1 "*) return 0 ;; *) return 1 ;; esac; } ARCH="$(uname -m)" # The AppImage tools, pinned (github.com/AppImage/appimagetool, github.com/AppImage/type2-runtime; # MIT). A version bump changes the SHA-256 below too. APPIMAGETOOL_VERSION=1.9.1 RUNTIME_VERSION=20251108 case "$ARCH" in x86_64) APPIMAGETOOL_SHA256=ed4ce84f0d9caff66f50bcca6ff6f35aae54ce8135408b3fa33abfc3cb384eb0 RUNTIME_SHA256=2fca8b443c92510f1483a883f60061ad09b46b978b2631c807cd873a47ec260d ;; *) echo "unsupported architecture $ARCH (release builds are x86_64)" >&2; exit 2 ;; esac APPIMAGETOOL_URL="https://github.com/AppImage/appimagetool/releases/download/$APPIMAGETOOL_VERSION/appimagetool-$ARCH.AppImage" RUNTIME_URL="https://github.com/AppImage/type2-runtime/releases/download/$RUNTIME_VERSION/runtime-$ARCH" BASENAME="fieldcraft-$VERSION-linux-$ARCH" echo "==> FieldCraft $VERSION for Linux $ARCH ($FORMATS)" if [ "$SKIP_BUILD" = 0 ]; then (cd "$ROOT" && cargo build --release --locked -p fieldcraft -p fieldcraft-cli) fi BIN="$CARGO_TARGET_DIR/release" WORK="$CARGO_TARGET_DIR/linux-package" STAGE="$WORK/root/usr" rm -rf "$WORK" # ---- an FHS tree, shared by both formats -------------------------------------------------------- install -Dm755 "$BIN/fieldcraft" "$STAGE/bin/fieldcraft" install -Dm755 "$BIN/fieldcraft-cli" "$STAGE/bin/fieldcraft-cli" strip "$STAGE/bin/fieldcraft" "$STAGE/bin/fieldcraft-cli" install -Dm644 "$HERE/$APP_ID.desktop" "$STAGE/share/applications/$APP_ID.desktop" # hicolor icons: . while read -r size file; do install -Dm644 "$ICONSET/$file" "$STAGE/share/icons/hicolor/${size}x${size}/apps/$APP_ID.png" done <<'ICONS' 16 icon_16x16.png 32 icon_32x32.png 64 icon_32x32@2x.png 128 icon_128x128.png 256 icon_256x256.png 512 icon_512x512.png 1024 icon_512x512@2x.png ICONS mkdir -p "$STAGE/share/doc/fieldcraft" copy_docs "$STAGE/share/doc/fieldcraft" if command -v desktop-file-validate >/dev/null; then desktop-file-validate "$STAGE/share/applications/$APP_ID.desktop" fi # ---- .tar.gz ------------------------------------------------------------------------------------ if has tar; then mkdir -p "$WORK/tar" cp -R "$STAGE" "$WORK/tar/$BASENAME" tar -C "$WORK/tar" -czf "$DIST/$BASENAME.tar.gz" "$BASENAME" echo "wrote $DIST/$BASENAME.tar.gz" fi # ---- AppImage ----------------------------------------------------------------------------------- # Usage: fetch ; downloads once and checks the hash every time. fetch() { if [ ! -s "$3" ]; then curl -fsSL -o "$3.part" "$1" && mv "$3.part" "$3"; fi if ! echo "$2 $3" | sha256sum --check --status; then echo "error: $3 does not match its pinned SHA-256 ($1)" >&2 rm -f "$3" exit 1 fi } if has appimage; then TOOL="$CARGO_TARGET_DIR/appimagetool-$APPIMAGETOOL_VERSION-$ARCH.AppImage" RUNTIME="$CARGO_TARGET_DIR/appimage-runtime-$RUNTIME_VERSION-$ARCH" fetch "$APPIMAGETOOL_URL" "$APPIMAGETOOL_SHA256" "$TOOL" fetch "$RUNTIME_URL" "$RUNTIME_SHA256" "$RUNTIME" chmod +x "$TOOL" APPDIR="$WORK/FieldCraft.AppDir" mkdir -p "$APPDIR" cp -R "$STAGE" "$APPDIR/usr" install -Dm755 "$HERE/AppRun" "$APPDIR/AppRun" cp "$HERE/$APP_ID.desktop" "$APPDIR/$APP_ID.desktop" cp "$ICONSET/icon_256x256.png" "$APPDIR/$APP_ID.png" ln -s "$APP_ID.png" "$APPDIR/.DirIcon" OUT="$DIST/$BASENAME.AppImage" rm -f "$OUT" # Extract-and-run: appimagetool is itself an AppImage, and CI runners have no FUSE. ARCH="$ARCH" APPIMAGE_EXTRACT_AND_RUN=1 "$TOOL" --no-appstream --runtime-file "$RUNTIME" "$APPDIR" "$OUT" echo "wrote $OUT" fi "$STAGE/bin/fieldcraft-cli" --version echo "==> done" ls -lh "$DIST"