visionA/local-tool/installer/linux/build-appimage.sh
jim800121chen b76acbe227 fix(local-tool): build-appimage.sh wheel 檢查改用 grep -i 不分大小寫
上一輪誤把關鍵字寫成 'kp',但 wheel 檔名是 'KneronPLUS-2.0.0-*.whl',
shell glob *kp*.whl 匹配不到,導致即使 wheel 實際存在仍 exit 1。

改用 ls | grep -i 不分大小寫比對「KneronPLUS」,同時更正錯誤訊息
從「kp wheel」改為「KneronPLUS wheel」。

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 23:40:17 +08:00

204 lines
7.9 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# visionA-local Linux AppImage builder
#
# 必須在 Linux x86_64 跑GitHub Actions ubuntu-latest 即可)。
# 需要的工具appimagetool、wails CLI、go 1.26+、pnpm、curl
#
# 前置payload/linux/ 應已由 `make payload-linux` 產出,
# visiona-local/build/bin/visiona-localWails app binary應已由 `make wails-linux` 產出。
#
# 用法:
# VERSION=0.1.0 bash installer/linux/build-appimage.sh
#
# 產物dist/visiona-local-${VERSION}-linux-x64.AppImage
set -euo pipefail
PROJECT_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
APPDIR="$PROJECT_ROOT/dist/visiona-local.AppDir"
VERSION="${VERSION:-0.1.0}"
# 平台守門:只能在 Linux 跑
if [ "$(uname -s)" != "Linux" ]; then
echo "❌ build-appimage.sh 只能在 Linux 上執行(目前:$(uname -s)"
exit 1
fi
echo "==> 清理舊 AppDir"
rm -rf "$APPDIR"
mkdir -p "$APPDIR/usr/bin" \
"$APPDIR/usr/lib/visiona-local/data" \
"$APPDIR/usr/lib/visiona-local/scripts" \
"$APPDIR/usr/lib/visiona-local/python" \
"$APPDIR/usr/lib/visiona-local/wheels" \
"$APPDIR/usr/share/applications" \
"$APPDIR/usr/share/icons/hicolor/256x256/apps"
echo "==> 複製 Wails app binary"
WAILS_BIN="$PROJECT_ROOT/visiona-local/build/bin/visiona-local"
if [ ! -f "$WAILS_BIN" ]; then
echo "❌ 找不到 Wails binary$WAILS_BIN"
echo " 請先執行make wails-linux"
exit 1
fi
cp "$WAILS_BIN" "$APPDIR/usr/bin/visiona-local"
chmod +x "$APPDIR/usr/bin/visiona-local"
echo "==> 複製 server binary + 工具(從 payload/linux/"
PAYLOAD_LINUX="$PROJECT_ROOT/payload/linux"
if [ ! -d "$PAYLOAD_LINUX" ]; then
echo "❌ 找不到 payload/linux/請先執行make payload-linux"
exit 1
fi
# server binary
if [ -f "$PAYLOAD_LINUX/bin/visiona-local-server" ]; then
cp "$PAYLOAD_LINUX/bin/visiona-local-server" "$APPDIR/usr/bin/visiona-local-server"
else
echo "⚠️ payload/linux/bin/visiona-local-server 不存在(需要在 Linux 上 go build server"
fi
# ffmpeg / ffprobe
# ffmpeg 為 LGPL v3 buildBtbN n7.1v2 TDD §4
for tool in ffmpeg ffprobe; do
if [ -f "$PAYLOAD_LINUX/bin/$tool" ]; then
cp "$PAYLOAD_LINUX/bin/$tool" "$APPDIR/usr/bin/$tool"
else
echo "⚠️ payload/linux/bin/$tool 不存在"
fi
done
chmod +x "$APPDIR/usr/bin/"* 2>/dev/null || true
# 把 ffmpeg 授權條款放到 AppImage 的 share/doc/
mkdir -p "$APPDIR/usr/share/doc/visiona-local"
if [ -f "$PAYLOAD_LINUX/bin/ffmpeg-LICENSE.txt" ]; then
cp "$PAYLOAD_LINUX/bin/ffmpeg-LICENSE.txt" "$APPDIR/usr/share/doc/visiona-local/ffmpeg-LICENSE.txt"
fi
echo "==> 檢查 Python runtime + wheelsbundled Python 必備,缺就自動補)"
# Python tarball
if [ ! -f "$PAYLOAD_LINUX/python/python.tar.gz" ]; then
echo "⚠️ payload/linux/python/python.tar.gz 不存在嘗試自動補make vendor-python-linux + payload-linux"
(cd "$PROJECT_ROOT" && make vendor-python-linux payload-linux)
fi
if [ ! -f "$PAYLOAD_LINUX/python/python.tar.gz" ]; then
echo "❌ python tarball 仍缺失:$PAYLOAD_LINUX/python/python.tar.gz"
echo " AppImage 必須內嵌 Python runtimeLinux 強制 bundled mode無此檔無法 build。"
echo " 請手動執行make vendor-python-linux"
exit 1
fi
# Wheels至少要有 numpy / opencv / pyusb / kp 4 個關鍵 wheelbridge scan 才能跑)
wheel_count=$(ls -1 "$PAYLOAD_LINUX/wheels/"*.whl 2>/dev/null | wc -l)
if [ "$wheel_count" -lt 4 ]; then
echo "⚠️ payload/linux/wheels 只找到 $wheel_count 個 wheel預期至少 4嘗試自動補make vendor-wheels-linux + payload-linux"
(cd "$PROJECT_ROOT" && make vendor-wheels-linux payload-linux)
wheel_count=$(ls -1 "$PAYLOAD_LINUX/wheels/"*.whl 2>/dev/null | wc -l)
fi
if [ "$wheel_count" -lt 4 ]; then
echo "❌ wheels 數量仍不足:$PAYLOAD_LINUX/wheels/ 只有 $wheel_count 個 .whl預期至少 4numpy / opencv / pyusb / kp"
echo " 請檢查 vendor/wheels/linux/ 或 visiona-local/wheels/linux/ 是否有 KneronPLUS wheel"
exit 1
fi
# 驗證關鍵 wheel 名稱存在(避免只下載到其他 wheel 卻缺 kp 等)
# 大小寫不敏感KneronPLUS wheel 檔名是大寫開頭pip 下載的是小寫
missing=()
for pkg in numpy opencv pyusb KneronPLUS; do
if ! ls "$PAYLOAD_LINUX/wheels/" 2>/dev/null | grep -iq "$pkg"; then
missing+=("$pkg")
fi
done
if [ ${#missing[@]} -gt 0 ]; then
echo "❌ 缺少關鍵 wheel${missing[*]}"
echo " 目前 wheels 目錄內容:"
ls -1 "$PAYLOAD_LINUX/wheels/" 2>/dev/null | sed 's/^/ /'
echo " KneronPLUS wheel 需手動放到 visiona-local/wheels/linux/(非公開套件)"
exit 1
fi
echo "==> ✅ python tarball + $wheel_count 個 wheel 齊備"
echo "==> 複製資料、腳本、Python runtime、wheels"
[ -d "$PAYLOAD_LINUX/data" ] && cp -R "$PAYLOAD_LINUX/data/." "$APPDIR/usr/lib/visiona-local/data/" || true
[ -d "$PAYLOAD_LINUX/scripts" ] && cp -R "$PAYLOAD_LINUX/scripts/." "$APPDIR/usr/lib/visiona-local/scripts/" || true
cp "$PAYLOAD_LINUX/python/python.tar.gz" "$APPDIR/usr/lib/visiona-local/python/"
cp "$PAYLOAD_LINUX/wheels/"*.whl "$APPDIR/usr/lib/visiona-local/wheels/"
# 複製 udev rule 到 lib 供 Wails app 首次啟動時使用
if [ -f "$PROJECT_ROOT/installer/linux/99-kneron.rules" ]; then
cp "$PROJECT_ROOT/installer/linux/99-kneron.rules" "$APPDIR/usr/lib/visiona-local/"
fi
if [ -f "$PROJECT_ROOT/installer/linux/install-udev.sh" ]; then
cp "$PROJECT_ROOT/installer/linux/install-udev.sh" "$APPDIR/usr/lib/visiona-local/"
chmod +x "$APPDIR/usr/lib/visiona-local/install-udev.sh"
fi
echo "==> 寫入 .desktop 與 icon"
cat > "$APPDIR/visiona-local.desktop" <<'DESKTOP'
[Desktop Entry]
Type=Application
Name=visionA-local
Comment=Local-first Edge AI development tool for Kneron KL520/KL720
Exec=visiona-local
Icon=visiona-local
Categories=Development;
Terminal=false
StartupWMClass=visionA-local
DESKTOP
cp "$APPDIR/visiona-local.desktop" "$APPDIR/usr/share/applications/"
# Icon (256x256 PNG),從 visiona-local/build/appicon.png 複製
APPICON="$PROJECT_ROOT/visiona-local/build/appicon.png"
if [ -f "$APPICON" ]; then
cp "$APPICON" "$APPDIR/visiona-local.png"
cp "$APPICON" "$APPDIR/usr/share/icons/hicolor/256x256/apps/visiona-local.png"
else
echo "⚠️ 找不到 appicon.pngAppImage 將無 icon"
fi
echo "==> 寫入 AppRun"
cat > "$APPDIR/AppRun" <<'APPRUN'
#!/bin/bash
# AppRun — AppImage 啟動 entry point
HERE="$(dirname "$(readlink -f "${0}")")"
export PATH="${HERE}/usr/bin:${PATH}"
export LD_LIBRARY_PATH="${HERE}/usr/lib:${LD_LIBRARY_PATH:-}"
# visionA-local 專屬環境變數:讓 Wails app 定位 bundle 內檔案
export VISIONA_BUNDLE_BIN_DIR="${HERE}/usr/bin"
export VISIONA_BUNDLE_LIB_DIR="${HERE}/usr/lib/visiona-local"
# Linux AppImage 強制走 bundled Python內嵌 python-build-standalone + wheels
# 避免 system Python 缺 numpy / kp / pyusb 導致 bridge scan 失敗。
export VISIONA_PYTHON_MODE=bundled
exec "${HERE}/usr/bin/visiona-local" "$@"
APPRUN
chmod +x "$APPDIR/AppRun"
echo "==> 檢查 appimagetool"
if ! command -v appimagetool &> /dev/null; then
echo "❌ appimagetool 未安裝。"
echo ""
echo " 一鍵安裝(推薦):"
echo " curl -fsSL https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage -o /tmp/appimagetool \\"
echo " && chmod +x /tmp/appimagetool \\"
echo " && sudo mv /tmp/appimagetool /usr/local/bin/appimagetool"
echo ""
echo " 或重跑 bootstrap-linux.sh會自動安裝所有依賴"
echo " bash scripts/bootstrap-linux.sh"
echo ""
exit 1
fi
echo "==> 用 appimagetool 打包"
mkdir -p "$PROJECT_ROOT/dist"
OUTPUT="$PROJECT_ROOT/dist/visiona-local-${VERSION}-linux-x64.AppImage"
ARCH=x86_64 appimagetool "$APPDIR" "$OUTPUT"
echo ""
echo "==> 完成:$OUTPUT"
ls -lh "$OUTPUT"