feat: add ARM64 Linux build target and download detection (#427)

- CI: add ubuntu-24.04-arm matrix entry with aarch64-unknown-linux-gnu
- Node sidecar: download linux-arm64 Node.js bundle for ARM runners
- Download API: add linux-appimage-arm64 pattern for aarch64 AppImage
- Download banner: show both x64 and ARM64 Linux options (UA can't distinguish)
- Desktop updater: map Linux aarch64 to linux-appimage-arm64 for in-app updates
- Smoke test: fix AppImage search path for cross-target builds
This commit is contained in:
Elie Habib
2026-02-26 20:52:44 +04:00
committed by GitHub
parent bbe814c985
commit ab502f6062
5 changed files with 39 additions and 7 deletions

View File

@@ -55,6 +55,11 @@ jobs:
node_target: 'x86_64-unknown-linux-gnu'
label: 'Linux-x64'
timeout: 120
- platform: 'ubuntu-24.04-arm'
args: '--target aarch64-unknown-linux-gnu'
node_target: 'aarch64-unknown-linux-gnu'
label: 'Linux-ARM64'
timeout: 120
runs-on: ${{ matrix.platform }}
name: Build (${{ matrix.label }})
@@ -77,7 +82,7 @@ jobs:
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7
with:
toolchain: stable
targets: ${{ contains(matrix.platform, 'macos') && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
targets: ${{ contains(matrix.platform, 'macos') && 'aarch64-apple-darwin,x86_64-apple-darwin' || (matrix.label == 'Linux-ARM64' && 'aarch64-unknown-linux-gnu' || '') }}
- name: Rust cache
uses: swatinem/rust-cache@ad397744b0d591a723ab90405b7247fac0e6b8db
@@ -298,7 +303,7 @@ jobs:
shell: bash
run: |
sudo apt-get install -y xvfb imagemagick
APPIMAGE=$(find src-tauri/target/release/bundle/appimage -name '*.AppImage' | head -1)
APPIMAGE=$(find src-tauri/target -path '*/bundle/appimage/*.AppImage' | head -1)
if [ -z "$APPIMAGE" ]; then
echo "::error::No AppImage found after build"
exit 1

View File

@@ -10,6 +10,7 @@ const PLATFORM_PATTERNS = {
'macos-arm64': (name) => name.endsWith('_aarch64.dmg'),
'macos-x64': (name) => name.endsWith('_x64.dmg') && !name.includes('setup'),
'linux-appimage': (name) => name.endsWith('_amd64.AppImage'),
'linux-appimage-arm64': (name) => name.endsWith('_aarch64.AppImage'),
};
const VARIANT_IDENTIFIERS = {

View File

@@ -15,6 +15,7 @@ Supported targets:
- x86_64-apple-darwin
- aarch64-apple-darwin
- x86_64-unknown-linux-gnu
- aarch64-unknown-linux-gnu
Environment:
NODE_VERSION Node.js version to bundle (default: 22.14.0)
@@ -72,7 +73,14 @@ if [[ -z "${TARGET}" ]]; then
esac
;;
Linux)
TARGET="x86_64-unknown-linux-gnu"
case "${RUNNER_ARCH:-}" in
ARM64|arm64)
TARGET="aarch64-unknown-linux-gnu"
;;
*)
TARGET="x86_64-unknown-linux-gnu"
;;
esac
;;
*)
echo "Unsupported RUNNER_OS: ${RUNNER_OS}" >&2
@@ -96,7 +104,14 @@ if [[ -z "${TARGET}" ]]; then
esac
;;
Linux)
TARGET="x86_64-unknown-linux-gnu"
case "$(uname -m)" in
aarch64|arm64)
TARGET="aarch64-unknown-linux-gnu"
;;
*)
TARGET="x86_64-unknown-linux-gnu"
;;
esac
;;
MINGW*|MSYS*|CYGWIN*|Windows_NT)
TARGET="x86_64-pc-windows-msvc"
@@ -135,6 +150,12 @@ case "${TARGET}" in
NODE_RELATIVE_PATH="bin/node"
OUTPUT_NAME="node"
;;
aarch64-unknown-linux-gnu)
DIST_NAME="node-v${NODE_VERSION}-linux-arm64"
ARCHIVE_NAME="${DIST_NAME}.tar.gz"
NODE_RELATIVE_PATH="bin/node"
OUTPUT_NAME="node"
;;
*)
echo "Unsupported target: ${TARGET}" >&2
exit 1

View File

@@ -134,7 +134,9 @@ export class DesktopUpdater implements AppModule {
}
if (normalizedOs === 'linux') {
return normalizedArch === 'x86_64' ? 'linux-appimage' : null;
if (normalizedArch === 'x86_64') return 'linux-appimage';
if (normalizedArch === 'aarch64') return 'linux-appimage-arm64';
return null;
}
return null;

View File

@@ -31,7 +31,7 @@ function dismiss(panel: HTMLElement, fromDownload = false): void {
panel.addEventListener('transitionend', () => panel.remove(), { once: true });
}
type Platform = 'macos-arm64' | 'macos-x64' | 'macos' | 'windows' | 'linux' | 'unknown';
type Platform = 'macos-arm64' | 'macos-x64' | 'macos' | 'windows' | 'linux' | 'linux-x64' | 'linux-arm64' | 'unknown';
function detectPlatform(): Platform {
const ua = navigator.userAgent;
@@ -64,7 +64,8 @@ function allButtons(): DlButton[] {
{ cls: 'mac', href: '/api/download?platform=macos-arm64', label: `\uF8FF ${t('modals.downloadBanner.macSilicon')}` },
{ cls: 'mac', href: '/api/download?platform=macos-x64', label: `\uF8FF ${t('modals.downloadBanner.macIntel')}` },
{ cls: 'win', href: '/api/download?platform=windows-exe', label: `\u229E ${t('modals.downloadBanner.windows')}` },
{ cls: 'linux', href: '/api/download?platform=linux-appimage', label: `\u{1F427} ${t('modals.downloadBanner.linux')}` },
{ cls: 'linux', href: '/api/download?platform=linux-appimage', label: `\u{1F427} ${t('modals.downloadBanner.linux')} (x64)` },
{ cls: 'linux', href: '/api/download?platform=linux-appimage-arm64', label: `\u{1F427} ${t('modals.downloadBanner.linux')} (ARM64)` },
];
}
@@ -76,6 +77,8 @@ function buttonsForPlatform(p: Platform): DlButton[] {
case 'macos': return buttons.filter(b => b.cls === 'mac');
case 'windows': return buttons.filter(b => b.cls === 'win');
case 'linux': return buttons.filter(b => b.cls === 'linux');
case 'linux-x64': return buttons.filter(b => b.href.includes('linux-appimage') && !b.href.includes('arm64'));
case 'linux-arm64': return buttons.filter(b => b.href.includes('linux-appimage-arm64'));
default: return buttons;
}
}