build: add artifact collection and Arch Linux packaging scripts

Introduce scripts to collect Tauri build artifacts across platforms and
generate a pacman package for Arch Linux. Update .gitignore to exclude
the releases directory and reorder existing entries.
This commit is contained in:
2026-05-26 15:44:57 +08:00
parent 7ca11db9a8
commit a3a268250b
5 changed files with 399 additions and 0 deletions
+1
View File
@@ -10,6 +10,7 @@ lerna-debug.log*
node_modules node_modules
dist dist
dist-ssr dist-ssr
releases
*.local *.local
# Editor directories and files # Editor directories and files
+40
View File
@@ -118,6 +118,46 @@ pnpm tauri build
# Tauri Android # Tauri Android
pnpm tauri android build pnpm tauri android build
# Pacman 包(Arch Linux,需先执行 pnpm tauri build
./scripts/pacman-pkg.sh
```
### 4. 收集发布产物
将各平台构建产物统一收集到 `releases/<version>/`,并规范命名:
```bash
# Linux / macOS
./scripts/collect-artifacts.sh
# Windows
scripts\collect-artifacts.cmd
```
脚本会**跳过不存在的构建产物**,因此可以放心运行——你当前平台没构建的产物会被忽略。覆盖范围:
| 平台 | 产物 |
|------|------|
| Web | `.tar.gz` `.zip` |
| Linux | `.AppImage` `.deb` `.rpm` `.pkg.tar.zst` |
| Windows | `.msi` `.exe` |
| macOS | `.dmg` |
| Android | `.apk`arm64 / x86_64 / universal |
输出示例:
```
releases/0.1.0/
├── bookmgr-client-0.1.0-android-arm64.apk
├── bookmgr-client-0.1.0-android-universal.apk
├── bookmgr-client-0.1.0-android-x86_64.apk
├── bookmgr-client-0.1.0-linux-amd64.AppImage
├── bookmgr-client-0.1.0-linux-amd64.deb
├── bookmgr-client-0.1.0-linux-x86_64.pkg.tar.zst
├── bookmgr-client-0.1.0-linux-x86_64.rpm
├── bookmgr-client-0.1.0-web.tar.gz
└── bookmgr-client-0.1.0-web.zip
``` ```
## 项目结构 ## 项目结构
+144
View File
@@ -0,0 +1,144 @@
@echo off
setlocal enabledelayedexpansion
set "SCRIPT_DIR=%~dp0"
set "ROOT=%SCRIPT_DIR%.."
:: ---------------------------------------------------------------
:: 读取版本号
:: ---------------------------------------------------------------
for /f "usebackq delims=" %%i in (`powershell -Command "try { (Get-Content '%ROOT%\src-tauri\tauri.conf.json' -Raw | ConvertFrom-Json).version } catch { Write-Output '0.0.0' }"`) do set "VERSION=%%i"
if "%VERSION%"=="0.0.0" (
echo 错误:无法读取 tauri.conf.json 中的版本号
exit /b 1
)
set "OUT_DIR=%ROOT%\releases\%VERSION%"
set "PKG=bookmgr-client"
set "DIST=%ROOT%\dist"
set "BUNDLE=%ROOT%\src-tauri\target\release\bundle"
echo ==^> 收集 %PKG% v%VERSION% 产物 → %OUT_DIR%
:: ---------------------------------------------------------------
:: 准备输出目录
:: ---------------------------------------------------------------
if exist "%OUT_DIR%" rmdir /s /q "%OUT_DIR%"
mkdir "%OUT_DIR%"
:: ---------------------------------------------------------------
:: Web — 从 dist/ 打 tar.gz 和 zip
:: ---------------------------------------------------------------
if exist "%DIST%\index.html" (
set "TARBALL=%OUT_DIR%\%PKG%-%VERSION%-web.tar.gz"
echo [web] !TARBALL!
tar -czf "!TARBALL!" -C "%DIST%" .
set "ZIPBALL=%OUT_DIR%\%PKG%-%VERSION%-web.zip"
echo [web] !ZIPBALL!
powershell -Command "Compress-Archive -Path '%DIST%\*' -DestinationPath '!ZIPBALL!' -Force"
) else (
echo [web] 跳过(dist/ 未就绪,请先运行 pnpm build
)
:: ---------------------------------------------------------------
:: Windows — msi / nsis
:: ---------------------------------------------------------------
if exist "%BUNDLE%\msi" (
for %%f in ("%BUNDLE%\msi\%PKG%_*.msi") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-windows-x86_64.msi"
echo [msi] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
if exist "%BUNDLE%\nsis" (
for %%f in ("%BUNDLE%\nsis\%PKG%_*.exe") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-windows-x86_64-setup.exe"
echo [nsis] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
:: ---------------------------------------------------------------
:: Linux — AppImage / deb / rpm / pacman
:: ---------------------------------------------------------------
if exist "%BUNDLE%\appimage" (
for %%f in ("%BUNDLE%\appimage\%PKG%_*_amd64.AppImage") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-linux-amd64.AppImage"
echo [appimage] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
if exist "%BUNDLE%\deb" (
for %%f in ("%BUNDLE%\deb\%PKG%_*_amd64.deb") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-linux-amd64.deb"
echo [deb] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
if exist "%BUNDLE%\rpm" (
for %%f in ("%BUNDLE%\rpm\%PKG%-*x86_64.rpm") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-linux-x86_64.rpm"
echo [rpm] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
if exist "%BUNDLE%\pacman" (
for %%f in ("%BUNDLE%\pacman\%PKG%-*.pkg.tar.zst") do (
if exist "%%f" (
set "fn=%%~nxf"
:: 替换 pkgrel 为 linux 标识
set "newname=!fn:-1-x86_64=-linux-x86_64!"
set "DST=%OUT_DIR%\!newname!"
echo [pacman] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
:: ---------------------------------------------------------------
:: Android — APK
:: ---------------------------------------------------------------
set "APK_DIR=%ROOT%\src-tauri\gen\android\app\build\outputs\apk"
if exist "%APK_DIR%" (
for %%a in (arm64 x86_64 universal) do (
set "SRC=%APK_DIR%\%%a\release\app-%%a-release.apk"
if exist "!SRC!" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-android-%%a.apk"
echo [apk] !DST!
copy /y "!SRC!" "!DST!" >nul
)
)
)
:: ---------------------------------------------------------------
:: macOS — dmg
:: ---------------------------------------------------------------
if exist "%BUNDLE%\dmg" (
for %%f in ("%BUNDLE%\dmg\%PKG%_*.dmg") do (
if exist "%%f" (
set "DST=%OUT_DIR%\%PKG%-%VERSION%-macos-arm64.dmg"
echo [dmg] !DST!
copy /y "%%f" "!DST!" >nul
)
)
)
:: ---------------------------------------------------------------
echo.
echo ==^> 完成
dir "%OUT_DIR%"
+140
View File
@@ -0,0 +1,140 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(dirname "$SCRIPT_DIR")"
VERSION=$(jq -r '.version' "$ROOT/src-tauri/tauri.conf.json")
OUT_DIR="$ROOT/releases/$VERSION"
PKG="bookmgr-client"
# ---------------------------------------------------------------
# 准备输出目录
# ---------------------------------------------------------------
rm -rf "$OUT_DIR"
mkdir -p "$OUT_DIR"
echo "==> 收集 $PKG v$VERSION 产物 → $OUT_DIR"
# ---------------------------------------------------------------
# Web — 从 dist/ 打 tar.gz 和 zip
# ---------------------------------------------------------------
DIST="$ROOT/dist"
if [[ -d "$DIST" ]] && [[ -f "$DIST/index.html" ]]; then
TARBALL="$OUT_DIR/${PKG}-${VERSION}-web.tar.gz"
echo " [web] $TARBALL"
tar -czf "$TARBALL" -C "$DIST" .
ZIPBALL="$OUT_DIR/${PKG}-${VERSION}-web.zip"
echo " [web] $ZIPBALL"
(cd "$DIST" && zip -qr "$ZIPBALL" .)
else
echo " [web] 跳过(dist/ 未就绪,请先运行 pnpm build"
fi
# ---------------------------------------------------------------
# Linux — AppImage / deb / rpm / pacman
# ---------------------------------------------------------------
BUNDLE="$ROOT/src-tauri/target/release/bundle"
if [[ -d "$BUNDLE/appimage" ]]; then
SRC=$(echo "$BUNDLE/appimage/${PKG}_"*_amd64.AppImage)
if [[ -f "$SRC" ]]; then
DST="$OUT_DIR/${PKG}-${VERSION}-linux-amd64.AppImage"
echo " [appimage] $DST"
cp "$SRC" "$DST"
fi
fi
if [[ -d "$BUNDLE/deb" ]]; then
SRC=$(echo "$BUNDLE/deb/${PKG}_"*_amd64.deb)
if [[ -f "$SRC" ]]; then
DST="$OUT_DIR/${PKG}-${VERSION}-linux-amd64.deb"
echo " [deb] $DST"
cp "$SRC" "$DST"
fi
fi
if [[ -d "$BUNDLE/rpm" ]]; then
SRC=$(echo "$BUNDLE/rpm/${PKG}-"*x86_64.rpm)
if [[ -f "$SRC" ]]; then
DST="$OUT_DIR/${PKG}-${VERSION}-linux-x86_64.rpm"
echo " [rpm] $DST"
cp "$SRC" "$DST"
fi
fi
if [[ -d "$BUNDLE/pacman" ]]; then
for f in "$BUNDLE/pacman/${PKG}-"*.pkg.tar.zst; do
[[ -f "$f" ]] || continue
base=$(basename "$f")
# bookmgr-client-0.1.0-1-x86_64.pkg.tar.zst → bookmgr-client-0.1.0-linux-x86_64.pkg.tar.zst
newname=$(echo "$base" | sed -E 's/-1-(x86_64|aarch64)/-linux-\1/')
DST="$OUT_DIR/$newname"
echo " [pacman] $DST"
cp "$f" "$DST"
done
fi
# ---------------------------------------------------------------
# Android — APK
# ---------------------------------------------------------------
APK_DIR="$ROOT/src-tauri/gen/android/app/build/outputs/apk"
if [[ -d "$APK_DIR" ]]; then
for arch in arm64 x86_64 universal; do
SRC="$APK_DIR/$arch/release/app-${arch}-release.apk"
if [[ -f "$SRC" ]]; then
DST="$OUT_DIR/${PKG}-${VERSION}-android-${arch}.apk"
echo " [apk] $DST"
cp "$SRC" "$DST"
fi
done
fi
# ---------------------------------------------------------------
# Windows — msi / nsis
# ---------------------------------------------------------------
if [[ -d "$BUNDLE/msi" ]]; then
for f in "$BUNDLE/msi/${PKG}_"*.msi; do
[[ -f "$f" ]] || continue
base=$(basename "$f")
# bookmgr-client_0.1.0_x64_en-US.msi → bookmgr-client-0.1.0-windows-x86_64.msi
newname=$(echo "$base" | sed -E 's/_/ /g; s/ /-/g; s/x64/x86_64/; s/en-US-//')
newname="${PKG}-${VERSION}-windows-${newname#${PKG}-${VERSION}-}"
DST="$OUT_DIR/$newname"
echo " [msi] $DST"
cp "$f" "$DST"
done
fi
if [[ -d "$BUNDLE/nsis" ]]; then
for f in "$BUNDLE/nsis/${PKG}_"*.exe; do
[[ -f "$f" ]] || continue
base=$(basename "$f")
newname=$(echo "$base" | sed -E 's/_/ /g; s/ /-/g; s/x64/x86_64/; s/en-US-//')
newname="${PKG}-${VERSION}-windows-${newname#${PKG}-${VERSION}-}"
DST="$OUT_DIR/$newname"
echo " [nsis] $DST"
cp "$f" "$DST"
done
fi
# ---------------------------------------------------------------
# macOS — dmg
# ---------------------------------------------------------------
if [[ -d "$BUNDLE/dmg" ]]; then
for f in "$BUNDLE/dmg/${PKG}_"*.dmg; do
[[ -f "$f" ]] || continue
base=$(basename "$f")
newname=$(echo "$base" | sed -E 's/_/ /g; s/ /-/g; s/x64/x86_64/; s/aarch64/arm64/')
newname="${PKG}-${VERSION}-macos-${newname#${PKG}-${VERSION}-}"
DST="$OUT_DIR/$newname"
echo " [dmg] $DST"
cp "$f" "$DST"
done
fi
# ---------------------------------------------------------------
echo ""
echo "==> 完成,共 $(find "$OUT_DIR" -maxdepth 1 -type f | wc -l) 个文件:"
ls -lh "$OUT_DIR"
+74
View File
@@ -0,0 +1,74 @@
#!/bin/bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
ROOT="$(dirname "$SCRIPT_DIR")"
# ---------------------------------------------------------------
# 1. 检查二进制
# ---------------------------------------------------------------
BIN="$ROOT/src-tauri/target/release/bookmgr-client"
if [[ ! -f "$BIN" ]]; then
echo "错误:未找到 $BIN,请先运行 pnpm tauri build"
exit 1
fi
# ---------------------------------------------------------------
# 2. 读取版本号
# ---------------------------------------------------------------
VERSION=$(jq -r '.version' "$ROOT/src-tauri/tauri.conf.json")
PKG="bookmgr-client"
PKGVER="${VERSION}-1"
ARCH="x86_64"
OUTPUT="${PKG}-${PKGVER}-${ARCH}.pkg.tar.zst"
DESKTOP_FILE="$ROOT/src-tauri/target/release/bundle/deb/${PKG}_${VERSION}_amd64/data/usr/share/applications/${PKG}.desktop"
ICON_FILE="$ROOT/src-tauri/icons/128x128.png"
echo "==> 打包 ${PKG} ${PKGVER} (${ARCH})"
# ---------------------------------------------------------------
# 3. 构建 PKGBUILD + 安装目录
# ---------------------------------------------------------------
BUILD_DIR=$(mktemp -d)
trap 'rm -rf "$BUILD_DIR"' EXIT
SRCDIR="$BUILD_DIR/src"
mkdir -p "$SRCDIR/usr/bin"
mkdir -p "$SRCDIR/usr/share/applications"
mkdir -p "$SRCDIR/usr/share/icons/hicolor/128x128/apps"
install -Dm755 "$BIN" "$SRCDIR/usr/bin/${PKG}"
install -Dm644 "$DESKTOP_FILE" "$SRCDIR/usr/share/applications/${PKG}.desktop"
install -Dm644 "$ICON_FILE" "$SRCDIR/usr/share/icons/hicolor/128x128/apps/${PKG}.png"
sed -i 's/^Categories=$/Categories=Utility;/' "$SRCDIR/usr/share/applications/${PKG}.desktop"
cat > "$BUILD_DIR/PKGBUILD" << PKGEOF
pkgname=${PKG}
pkgver=${VERSION}
pkgrel=1
pkgdesc="图书管理系统桌面客户端"
arch=(x86_64)
url="https://git.msksbr.com/msksbr/bookMgr-client"
license=(MIT)
depends=(gtk3 webkit2gtk-4.1 libappindicator-gtk3)
package() {
cp -r "\$srcdir/"* "\$pkgdir/"
}
PKGEOF
# ---------------------------------------------------------------
# 4. 用 makepkg 生成 .pkg.tar.zst
# ---------------------------------------------------------------
BUNDLE_DIR="$ROOT/src-tauri/target/release/bundle/pacman"
rm -rf "$BUNDLE_DIR"
mkdir -p "$BUNDLE_DIR"
cd "$BUILD_DIR"
makepkg -R
echo ""
echo "==> 输出: $(ls ./*.pkg.tar.zst)"
cp ./*.pkg.tar.zst "$BUNDLE_DIR/"
echo "==> 已复制到 $BUNDLE_DIR"