From 417cf4d664ee3bef318ce858461ba648043ef695 Mon Sep 17 00:00:00 2001 From: passio Date: Mon, 29 Jun 2026 17:11:43 +0800 Subject: [PATCH] =?UTF-8?q?docs:=20=E8=A1=A5=E5=85=85=20Deepin=2025/Linux?= =?UTF-8?q?=20=E6=89=93=E5=8C=85=E5=AE=89=E8=A3=85=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/deepin25/ZTools.desktop | 12 ++ docs/deepin25/build-deepin25.sh | 72 ++++++++++ docs/deepin25/install-deepin25.sh | 135 +++++++++++++++++++ docs/deepin25/readme.md | 210 ++++++++++++++++++++++++++++++ 4 files changed, 429 insertions(+) create mode 100644 docs/deepin25/ZTools.desktop create mode 100755 docs/deepin25/build-deepin25.sh create mode 100755 docs/deepin25/install-deepin25.sh create mode 100644 docs/deepin25/readme.md diff --git a/docs/deepin25/ZTools.desktop b/docs/deepin25/ZTools.desktop new file mode 100644 index 00000000..5e5db6b3 --- /dev/null +++ b/docs/deepin25/ZTools.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0 +Type=Application +Name=ZTools +Comment=ZTools application launcher +Exec=/opt/ZTools/ztools %U +Icon=/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon-ztools.png +Terminal=false +StartupNotify=true +StartupWMClass=ZTools +Categories=Utility; +MimeType=application/x-ztools-plugin; diff --git a/docs/deepin25/build-deepin25.sh b/docs/deepin25/build-deepin25.sh new file mode 100755 index 00000000..e8849d7f --- /dev/null +++ b/docs/deepin25/build-deepin25.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +REGISTRY="${NPM_REGISTRY:-https://registry.npmmirror.com}" +ARCH="${ZTOOLS_LINUX_ARCH:-x64}" + +log() { + printf '\n[deepin25-build] %s\n' "$*" +} + +fail() { + printf '\n[deepin25-build] ERROR: %s\n' "$*" >&2 + exit 1 +} + +ensure_command() { + command -v "$1" >/dev/null 2>&1 || fail "Missing command: $1" +} + +ensure_pnpm() { + if command -v pnpm >/dev/null 2>&1; then + return + fi + + log "pnpm not found; preparing temporary pnpm via npm exec" + ensure_command npm + npm_config_registry="$REGISTRY" npm exec --yes pnpm@10 -- --version >/dev/null + + local pnpm_bin + pnpm_bin="$(find "$HOME/.npm/_npx" -path '*/node_modules/.bin/pnpm' -type f 2>/dev/null | sort | tail -n 1 || true)" + [[ -n "$pnpm_bin" ]] || fail "Unable to locate pnpm under $HOME/.npm/_npx" + export PATH="$(dirname "$pnpm_bin"):$PATH" +} + +log "Project root: $ROOT_DIR" +cd "$ROOT_DIR" + +ensure_command node +ensure_pnpm + +log "Node: $(node --version)" +log "pnpm: $(pnpm --version)" +log "Registry: $REGISTRY" + +log "Cleaning previous build output" +rm -rf dist out node_modules internal-plugins/setting/node_modules internal-plugins/setting/dist + +log "Installing root dependencies with pnpm default node linker" +pnpm install --frozen-lockfile --registry="$REGISTRY" + +log "Installing setting plugin dependencies" +pnpm --dir internal-plugins/setting install --frozen-lockfile --node-linker=hoisted --registry="$REGISTRY" + +log "Building setting plugin" +pnpm --dir internal-plugins/setting build + +log "Running type checks" +pnpm typecheck + +log "Building Electron app" +./node_modules/.bin/electron-vite build + +log "Packaging Linux $ARCH artifacts" +./node_modules/.bin/electron-builder --linux --"$ARCH" + +log "Artifacts" +find dist -maxdepth 1 -type f \( -name '*.deb' -o -name '*.AppImage' -o -name 'update-linux-*.zip' \) -printf '%p %s bytes\n' | sort + +log "SHA-256" +sha256sum dist/*.deb dist/*.AppImage dist/update-linux-*.zip 2>/dev/null || true diff --git a/docs/deepin25/install-deepin25.sh b/docs/deepin25/install-deepin25.sh new file mode 100755 index 00000000..5b0fb9d7 --- /dev/null +++ b/docs/deepin25/install-deepin25.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)" +DESKTOP_TEMPLATE="$SCRIPT_DIR/ZTools.desktop" + +log() { + printf '\n[deepin25-install] %s\n' "$*" +} + +fail() { + printf '\n[deepin25-install] ERROR: %s\n' "$*" >&2 + exit 1 +} + +find_latest_deb() { + local latest + latest="$(find "$ROOT_DIR/dist" -maxdepth 1 -type f -name 'ZTools_*_*.deb' -printf '%T@ %p\n' 2>/dev/null | sort -nr | awk 'NR==1 {print $2}')" + [[ -n "$latest" ]] || fail "No deb package found in $ROOT_DIR/dist. Run docs/deepin25/build-deepin25.sh first." + printf '%s\n' "$latest" +} + +resolve_desktop_dir() { + if [[ -n "${XDG_DESKTOP_DIR:-}" ]]; then + printf '%s\n' "$XDG_DESKTOP_DIR" + return + fi + + if [[ -f "$HOME/.config/user-dirs.dirs" ]]; then + local configured + configured="$(awk -F= '$1 == "XDG_DESKTOP_DIR" {gsub(/"/, "", $2); print $2}' "$HOME/.config/user-dirs.dirs")" + if [[ -n "$configured" ]]; then + printf '%s\n' "${configured/#\$HOME/$HOME}" + return + fi + fi + + printf '%s\n' "$HOME/Desktop" +} + +resolve_icon_path() { + local candidates=( + "/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon-ztools.png" + "/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon.png" + "/usr/share/icons/hicolor/1024x1024/apps/ztools.png" + ) + + local icon + for icon in "${candidates[@]}"; do + if [[ -f "$icon" ]]; then + printf '%s\n' "$icon" + return + fi + done + + printf '%s\n' "ztools" +} + +write_desktop_file() { + local target="$1" + local mode="$2" + local icon_path + icon_path="$(resolve_icon_path)" + + sed "s|^Icon=.*$|Icon=$icon_path|" "$DESKTOP_TEMPLATE" > "$target" + chmod "$mode" "$target" +} + +install_deb() { + local deb="$1" + log "Installing $deb" + if command -v apt >/dev/null 2>&1; then + sudo apt install -y "$deb" + else + sudo dpkg -i "$deb" + sudo apt-get install -f -y + fi +} + +install_launcher() { + local desktop_dir + local launcher_path + local app_dir + local app_path + desktop_dir="$(resolve_desktop_dir)" + launcher_path="$desktop_dir/ZTools.desktop" + app_dir="${XDG_DATA_HOME:-$HOME/.local/share}/applications" + app_path="$app_dir/ztools.desktop" + + [[ -f "$DESKTOP_TEMPLATE" ]] || fail "Missing launcher template: $DESKTOP_TEMPLATE" + [[ -x /opt/ZTools/ztools ]] || fail "/opt/ZTools/ztools does not exist or is not executable" + + mkdir -p "$desktop_dir" + write_desktop_file "$launcher_path" 0755 + if command -v gio >/dev/null 2>&1; then + gio set "$launcher_path" metadata::trusted true 2>/dev/null || true + fi + + if command -v desktop-file-validate >/dev/null 2>&1; then + desktop-file-validate "$launcher_path" + fi + + mkdir -p "$app_dir" + write_desktop_file "$app_path" 0644 + + if command -v desktop-file-validate >/dev/null 2>&1; then + desktop-file-validate "$app_path" + fi + + if command -v update-desktop-database >/dev/null 2>&1; then + update-desktop-database "$app_dir" 2>/dev/null || true + fi + + if [[ -f /usr/share/icons/hicolor/1024x1024/apps/ztools.png ]] && command -v gtk-update-icon-cache >/dev/null 2>&1; then + gtk-update-icon-cache -q /usr/share/icons/hicolor 2>/dev/null || true + fi + + log "Launcher created: $launcher_path" + log "Application entry created: $app_path" +} + +if [[ "${1:-}" == "--launcher-only" ]]; then + install_launcher + log "Done. You can launch ZTools from the desktop icon, app launcher, or run: ztools" + exit 0 +fi + +DEB_PATH="${1:-$(find_latest_deb)}" +[[ -f "$DEB_PATH" ]] || fail "Package not found: $DEB_PATH" + +install_deb "$DEB_PATH" +install_launcher + +log "Done. You can launch ZTools from the desktop icon, app launcher, or run: ztools" diff --git a/docs/deepin25/readme.md b/docs/deepin25/readme.md new file mode 100644 index 00000000..50d8d7ad --- /dev/null +++ b/docs/deepin25/readme.md @@ -0,0 +1,210 @@ +# Deepin 25 打包和安装指南 + +本文记录在 Deepin 25 amd64 上编译、打包、安装 ZTools 的流程。推荐直接使用本目录里的两个脚本: + +```bash +./docs/deepin25/build-deepin25.sh +./docs/deepin25/install-deepin25.sh +``` + +`build-deepin25.sh` 负责清理旧产物、安装依赖、构建 setting 内置插件、执行类型检查、生成 Linux deb/AppImage/update zip。`install-deepin25.sh` 会安装最新 deb 包,并创建带图标的桌面启动器。 + +## 环境 + +建议使用 Node.js 20.19+ 或 22.12+。Deepin 25 上 Node 20.15.1 也能完成打包,但 `electron-vite`、Vite、UnoCSS 相关依赖会提示 engine warning。 + +查看当前环境: + +```bash +node --version +npm --version +dpkg --print-architecture +``` + +安装基础工具: + +```bash +sudo apt update +sudo apt install -y git curl python3 make g++ dpkg-dev fakeroot desktop-file-utils +``` + +## 一键编译 + +在项目根目录执行: + +```bash +./docs/deepin25/build-deepin25.sh +``` + +脚本默认使用 `https://registry.npmmirror.com`,可以通过环境变量改回 npm 官方源: + +```bash +NPM_REGISTRY=https://registry.npmjs.org ./docs/deepin25/build-deepin25.sh +``` + +脚本默认打 `x64` 包。需要指定架构时: + +```bash +ZTOOLS_LINUX_ARCH=x64 ./docs/deepin25/build-deepin25.sh +ZTOOLS_LINUX_ARCH=arm64 ./docs/deepin25/build-deepin25.sh +``` + +产物会生成在 `dist/`: + +```text +dist/ZTools-2.6.1-linux-x86_64.AppImage +dist/ZTools_2.6.1_amd64.deb +dist/update-linux-x64-2.6.1.zip +``` + +## 一键安装 + +打包完成后执行: + +```bash +./docs/deepin25/install-deepin25.sh +``` + +脚本会自动选择 `dist/` 里最新的 `ZTools_*_*.deb`,执行 `sudo apt install -y`,然后安装两个启动入口: + +- 桌面图标:当前用户桌面目录下的 `ZTools.desktop` +- 应用菜单:`~/.local/share/applications/ztools.desktop` + +桌面文件会被设为可执行;如果系统支持 `gio`,脚本还会尝试设置可信标记。脚本会刷新用户级 desktop database,方便 Deepin 启动器尽快识别菜单入口。 + +也可以指定 deb 路径: + +```bash +./docs/deepin25/install-deepin25.sh ./dist/ZTools_2.6.1_amd64.deb +``` + +如果 deb 已经安装,只想补桌面图标和应用菜单入口: + +```bash +./docs/deepin25/install-deepin25.sh --launcher-only +``` + +启动器使用 `/opt/ZTools` 安装目录里的图标: + +```ini +Icon=/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon-ztools.png +Exec=/opt/ZTools/ztools %U +``` + +deb 包会把图标安装到系统图标目录,例如: + +```text +/usr/share/icons/hicolor/1024x1024/apps/ztools.png +``` + +不要在桌面文件里写本机源码目录里的绝对图标路径,例如 `/home/passio/Codes/ZTools/build/icon.png`。安装到别的机器或移动项目目录后,这种路径会失效。 + +`install-deepin25.sh` 会优先使用 `/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon-ztools.png`。如果安装目录图标不存在,脚本会尝试 `/opt/ZTools/resources/app.asar.unpacked/resources/icons/icon.png` 和 `/usr/share/icons/hicolor/1024x1024/apps/ztools.png`,最后才回退到 `Icon=ztools`。 + +## 运行和卸载 + +安装后可以从桌面启动器启动,也可以在终端运行: + +```bash +ztools +``` + +卸载: + +```bash +sudo apt remove ztools +``` + +AppImage 不需要安装: + +```bash +chmod +x dist/ZTools-2.6.1-linux-x86_64.AppImage +./dist/ZTools-2.6.1-linux-x86_64.AppImage +``` + +## 常见问题 + +### 启动时报 Cannot find module '@electron-toolkit/utils' + +根目录依赖必须用 pnpm 安装。这个仓库有 `pnpm-lock.yaml`,`electron-builder` 会通过 `pnpm list --prod` 收集生产依赖。如果根目录用 npm 安装后直接打包,生产依赖可能不会进入 `app.asar`,启动时就会缺 `@electron-toolkit/utils`。 + +`build-deepin25.sh` 已经处理了这件事:根目录使用 pnpm 默认 node linker,setting 插件使用 pnpm hoisted node linker。 + +### 系统没有 pnpm + +脚本会先查找全局 `pnpm`。如果没有,会用 `npm exec --yes pnpm@10` 准备一个临时 pnpm,并把 npx 缓存里的 pnpm 加入当前脚本的 `PATH`。 + +如果你想手动安装: + +```bash +npm install -g pnpm +``` + +### setting 插件缺少 oxc-parser native binding + +Deepin 25 amd64/glibc 环境下,setting 插件使用 hoisted 安装可以避开该问题。脚本里对应命令是: + +```bash +pnpm --dir internal-plugins/setting install --frozen-lockfile --node-linker=hoisted +pnpm --dir internal-plugins/setting build +``` + +### npm 或 Electron 下载超时 + +可以切换 registry: + +```bash +NPM_REGISTRY=https://registry.npmmirror.com ./docs/deepin25/build-deepin25.sh +``` + +Electron 和 electron-builder 的下载缓存通常在: + +```text +$HOME/.cache/electron +$HOME/.cache/electron-builder +``` + +### apt 提示 _apt 无法访问本地 deb + +如果你看到类似提示: + +```text +N: 由于文件 '.../dist/ZTools_2.6.1_amd64.deb' 无法被用户 '_apt' 访问,已脱离沙盒并提权为根用户来进行下载。 +``` + +这通常是本地文件权限或路径权限导致的 apt 提示。只要安装退出码为 0,ZTools 已经安装成功。可以用下面命令确认: + +```bash +which ztools +dpkg -l ztools +``` + +## 验证产物 + +查看 deb 元数据: + +```bash +dpkg-deb --info dist/ZTools_2.6.1_amd64.deb +``` + +确认 asar 内包含运行时依赖: + +```bash +npx asar list dist/linux-unpacked/resources/app.asar | grep '@electron-toolkit/utils' +``` + +本次已验证的产物: + +```text +ZTools-2.6.1-linux-x86_64.AppImage 117M +ZTools_2.6.1_amd64.deb 79M +update-linux-x64-2.6.1.zip 15M +``` + +SHA-256: + +```text +b56d762e6f0d19772423d9cfe5e69fcf4969846a94e58e9a3d7f9d7b4ab01a3d dist/ZTools-2.6.1-linux-x86_64.AppImage +519430877bea0c7f73c9c535f56577e6cd625c9ed147d9cc465e8a73894dbfb9 dist/ZTools_2.6.1_amd64.deb +e4458d2df8016f4094f71ebf4e53529fe009680951ff47e786b472f6f73391c5 dist/update-linux-x64-2.6.1.zip +```