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/scripts/build_flatpak.sh b/.github/scripts/build_flatpak.sh index 3a86d9b..c72803d 100644 --- a/.github/scripts/build_flatpak.sh +++ b/.github/scripts/build_flatpak.sh @@ -1,26 +1,65 @@ #!/bin/bash set -e -PLATFORM=$1 -VERSION=${version:-"0.0.0"} +# ────────────────────────────────────────────── +# Utility Functions +# ────────────────────────────────────────────── -if [[ "$PLATFORM" == "ubuntu-24.04-arm" ]]; then - ARCH="arm64" - FLATPAK_ARCH="aarch64" -else - ARCH="x86-64" - FLATPAK_ARCH="x86_64" -fi +parse_platform() { + local platform="$1" + case "${platform}" in + ubuntu-24.04-arm) + echo "arm64 aarch64" + ;; + *) + echo "x86-64 x86_64" + ;; + esac +} -echo "Building Flatpak for architecture: $FLATPAK_ARCH (Release: $VERSION)" +# ────────────────────────────────────────────── +# Build Steps +# ────────────────────────────────────────────── -flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo +setup_runtime() { + local flatpak_arch="$1" -flatpak install --user -y flathub \ - org.freedesktop.Platform//25.08 \ - org.freedesktop.Sdk//25.08 \ - org.freedesktop.Sdk.Extension.rust-stable//25.08 + flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + flatpak install --user -y flathub \ + org.freedesktop.Platform//25.08 \ + org.freedesktop.Sdk//25.08 \ + org.freedesktop.Sdk.Extension.rust-stable//25.08 +} -flatpak-builder --user --arch="${FLATPAK_ARCH}" --force-clean --repo=repo build-dir .github/manifests/in.suyogtandel.picoforge.json +build_flatpak() { + local flatpak_arch="$1" + flatpak-builder --user --arch="${flatpak_arch}" --force-clean --repo=repo build-dir .github/manifests/in.suyogtandel.picoforge.json +} -flatpak build-bundle repo "picoforge_${VERSION}_${ARCH}.flatpak" in.suyogtandel.picoforge +bundle_flatpak() { + local version="$1" + local arch="$2" + flatpak build-bundle repo "picoforge_${version}_${arch}.flatpak" in.suyogtandel.picoforge +} + +# ────────────────────────────────────────────── +# Main +# ────────────────────────────────────────────── +main() { + local platform="${1}" + + local ver + ver="${version:-0.0.0}" + + local arch_flatpak_arch + arch_flatpak_arch="$(parse_platform "${platform}")" + read -r arch flatpak_arch <<< "${arch_flatpak_arch}" + + echo "Building Flatpak for architecture: ${flatpak_arch} (Release: ${ver})" + + setup_runtime "${flatpak_arch}" + build_flatpak "${flatpak_arch}" + bundle_flatpak "${ver}" "${arch}" +} + +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