From a9e95ca2cb4b10c914847dc8c80fb048d7721529 Mon Sep 17 00:00:00 2001 From: Suyog Tandel Date: Tue, 21 Jul 2026 00:23:16 +0530 Subject: [PATCH] ci[release]: refactor appimage build script to include appimage auto update info --- .github/scripts/build_appimage.sh | 247 ++++++++++++++++++++---------- .github/workflows/release.yml | 3 + 2 files changed, 172 insertions(+), 78 deletions(-) diff --git a/.github/scripts/build_appimage.sh b/.github/scripts/build_appimage.sh index 77c1408..f81e26d 100644 --- a/.github/scripts/build_appimage.sh +++ b/.github/scripts/build_appimage.sh @@ -1,98 +1,189 @@ #!/bin/bash set -eo pipefail -VARIANT=${1:-"glibc-x86_64"} +# ────────────────────────────────────────────── +# Utility Functions +# ────────────────────────────────────────────── -echo "=== Building PicoForge AppImage for variant: ${VARIANT} ===" +detect_src_dir() { + if [ -f "/workspace/Cargo.toml" ]; then + echo "/workspace" + elif [ -f "/workspace/picoforge/Cargo.toml" ]; then + echo "/workspace/picoforge" + else + echo "Error: Cargo.toml not found in /workspace or /workspace/picoforge" + exit 1 + fi +} -# Locate PicoForge source directory -if [ -f "/workspace/Cargo.toml" ]; then - SRC_DIR="/workspace" -elif [ -f "/workspace/picoforge/Cargo.toml" ]; then - SRC_DIR="/workspace/picoforge" -else - echo "Error: Cargo.toml not found in /workspace or /workspace/picoforge" - exit 1 -fi +get_version() { + local version + version="$(grep -m 1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/')" + echo "${version:-0.0.0}" +} -cd "$SRC_DIR" +get_arch_name() { + local arch + arch="$(uname -m)" + case "${arch}" in + x86_64) echo "x86-64" ;; + aarch64) echo "aarch64" ;; + *) echo "${arch}" ;; + esac +} -# Extract version from Cargo.toml -VERSION=$(grep -m 1 '^version' Cargo.toml | sed -E 's/.*"([0-9]+\.[0-9]+\.[0-9]+)".*/\1/') -if [ -z "$VERSION" ]; then - VERSION="0.0.0" -fi -echo "PicoForge Version: ${VERSION}" +compute_output_name() { + local version="$1" + local variant="$2" + local arch_name="$3" -# Determine architecture and target naming -ARCH=$(uname -m) -if [ "$ARCH" == "x86_64" ]; then - ARCH_NAME="x86-64" -elif [ "$ARCH" == "aarch64" ]; then - ARCH_NAME="aarch64" -else - ARCH_NAME="$ARCH" -fi + case "${variant}" in + glibc-2.28-x86_64|glibc-2.28-aarch64) + echo "picoforge_${version}_glibc-2.28_${arch_name}.AppImage" + ;; + musl-x86_64|musl-aarch64) + echo "picoforge_${version}_musl_${arch_name}.AppImage" + ;; + *) + echo "picoforge_${version}_${variant}_${arch_name}.AppImage" + ;; + esac +} -# Define output filename based on variant -case "$VARIANT" in - glibc-2.28-x86_64|glibc-2.28-aarch64) - OUTPUT_NAME="picoforge_${VERSION}_glibc-2.28_${ARCH_NAME}.AppImage" - ;; - musl-x86_64|musl-aarch64) - OUTPUT_NAME="picoforge_${VERSION}_musl_${ARCH_NAME}.AppImage" - ;; - *) - OUTPUT_NAME="picoforge_${VERSION}_${VARIANT}_${ARCH_NAME}.AppImage" - ;; -esac +# ────────────────────────────────────────────── +# Build Steps +# ────────────────────────────────────────────── -echo "Building release binary with Cargo..." -cargo build --release +setup_update_info() { + local zsync_glob="$1" -BINARY_PATH="target/release/picoforge" -DESKTOP_FILE="data/in.suyogtandel.picoforge.desktop" -ICON_FILE="static/appIcons/in.suyogtandel.picoforge.svg" + if [ -z "${GITHUB_REPOSITORY_OWNER}" ] || [ -z "${GITHUB_REPOSITORY}" ]; then + return 0 + fi -if [ ! -f "$BINARY_PATH" ]; then - echo "Error: Binary not found at $BINARY_PATH" - exit 1 -fi + local repo_name="${GITHUB_REPOSITORY#*/}" + export UPDATE_INFORMATION="gh-releases-zsync|${GITHUB_REPOSITORY_OWNER}|${repo_name}|latest|${zsync_glob}" + echo "Set UPDATE_INFORMATION: ${UPDATE_INFORMATION}" +} -if [ ! -f "$DESKTOP_FILE" ]; then - echo "Error: Desktop file not found at $DESKTOP_FILE" - exit 1 -fi +build_release() { + echo "Building release binary with Cargo..." + cargo build --release +} -if [ ! -f "$ICON_FILE" ]; then - echo "Error: Icon file not found at $ICON_FILE" - exit 1 -fi +verify_assets() { + local binary="$1" + local desktop="$2" + local icon="$3" -echo "Packaging AppImage using linuxdeploy..." -export APPIMAGE_EXTRACT_AND_RUN=1 + if [ ! -f "${binary}" ]; then + echo "Error: Binary not found at ${binary}" + exit 1 + fi + if [ ! -f "${desktop}" ]; then + echo "Error: Desktop file not found at ${desktop}" + exit 1 + fi + if [ ! -f "${icon}" ]; then + echo "Error: Icon file not found at ${icon}" + exit 1 + fi +} -# Run linuxdeploy to bundle executable, desktop entry, icon, excluding host daemon libpcsclite -rm -rf AppDir -linuxdeploy \ - --appdir AppDir \ - --executable "$BINARY_PATH" \ - --desktop-file "$DESKTOP_FILE" \ - --icon-file "$ICON_FILE" \ - --exclude-library libpcsclite.so.1 \ - --output appimage +package_appimage() { + local output_name="$1" + local binary="$2" + local desktop="$3" + local icon="$4" -# Find generated AppImage file and rename to standard naming -GENERATED_APPIMAGE=$(ls -t *.AppImage 2>/dev/null | head -n 1) + echo "Packaging AppImage using linuxdeploy..." + export APPIMAGE_EXTRACT_AND_RUN=1 -if [ -z "$GENERATED_APPIMAGE" ]; then - echo "Error: AppImage generation failed" - exit 1 -fi + if [ -n "${UPDATE_INFORMATION}" ]; then + echo "Using UPDATE_INFORMATION: ${UPDATE_INFORMATION}" + else + echo "UPDATE_INFORMATION not set — AppImage will not support auto-update" + fi -mkdir -p /workspace/target/release -mv "$GENERATED_APPIMAGE" "/workspace/target/release/${OUTPUT_NAME}" -rm -rf AppDir + export LDAI_OUTPUT="${output_name}" -echo "=== Build Complete! Output: /workspace/target/release/${OUTPUT_NAME} ===" -ls -lh "/workspace/target/release/${OUTPUT_NAME}" + rm -rf AppDir + linuxdeploy \ + --appdir AppDir \ + --executable "${binary}" \ + --desktop-file "${desktop}" \ + --icon-file "${icon}" \ + --exclude-library libpcsclite.so.1 \ + --output appimage +} + +move_artifacts() { + local output_name="$1" + + local generated_appimage + generated_appimage="$(ls -t *.AppImage 2>/dev/null | head -n 1)" + if [ -z "${generated_appimage}" ]; then + echo "Error: AppImage generation failed" + exit 1 + fi + + mkdir -p /workspace/target/release + mv "${generated_appimage}" "/workspace/target/release/${output_name}" + + local generated_zsync + generated_zsync="$(ls -t *.zsync 2>/dev/null | head -n 1)" + if [ -n "${generated_zsync}" ]; then + mv "${generated_zsync}" "/workspace/target/release/${output_name}.zsync" + sed -i "s|^URL:.*|URL: ${output_name}|" "/workspace/target/release/${output_name}.zsync" + sed -i "s|^Filename:.*|Filename: ${output_name}|" "/workspace/target/release/${output_name}.zsync" + echo "Moved and patched zsync to ${output_name}.zsync" + fi +} + +cleanup() { + rm -rf AppDir +} + +print_summary() { + local output_name="$1" + echo "=== Build Complete! Output: /workspace/target/release/${output_name} ===" + ls -lh "/workspace/target/release/${output_name}" +} + +# ────────────────────────────────────────────── +# Main +# ────────────────────────────────────────────── +main() { + local variant="${1:-glibc-x86_64}" + echo "=== Building PicoForge AppImage for variant: ${variant} ===" + + local src_dir + src_dir="$(detect_src_dir)" + cd "${src_dir}" + + local version + version="$(get_version)" + echo "PicoForge Version: ${version}" + + local arch_name + arch_name="$(get_arch_name)" + + local output_name + output_name="$(compute_output_name "${version}" "${variant}" "${arch_name}")" + + local zsync_glob="${output_name/${version}/*}.zsync" + setup_update_info "${zsync_glob}" + build_release + + local binary="target/release/picoforge" + local desktop="data/in.suyogtandel.picoforge.desktop" + local icon="static/appIcons/in.suyogtandel.picoforge.svg" + + verify_assets "${binary}" "${desktop}" "${icon}" + package_appimage "${output_name}" "${binary}" "${desktop}" "${icon}" + move_artifacts "${output_name}" + cleanup + print_summary "${output_name}" +} + +main "$@" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 7be0fc2..81321b5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -152,6 +152,8 @@ jobs: mkdir -p target/release echo "Running build inside container..." podman run --rm \ + -e GITHUB_REPOSITORY_OWNER \ + -e GITHUB_REPOSITORY \ -v "${{ github.workspace }}":/workspace:z \ "${IMAGE_NAME}" \ /workspace/.github/scripts/build_appimage.sh ${{ matrix.appimage_variant }} @@ -180,6 +182,7 @@ jobs: target/release/*.deb target/release/*.appimage target/release/*.AppImage + target/release/*.zsync target/release/*.tar.gz target/release/*.msi target/release/*.dmg