Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/deepin25/ZTools.desktop
Original file line number Diff line number Diff line change
@@ -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;
72 changes: 72 additions & 0 deletions docs/deepin25/build-deepin25.sh
Original file line number Diff line number Diff line change
@@ -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"
}
Comment on lines +22 to +35

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

在没有全局 pnpm 的情况下,通过 find 命令在 ~/.npm/_npx 目录下查找 pnpm 二进制文件是非常脆弱且依赖于 npm 内部实现的做法。不同版本的 npm 缓存结构可能不同,且在某些受限环境(如容器或只读家目录)下可能会失败。

建议采用创建临时包装脚本(Wrapper Script)并将其加入 PATH 的方式。这种方式更加标准、健壮,且不依赖于 npm 的内部缓存路径设计。

Suggested change
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"
}
ensure_pnpm() {
if command -v pnpm >/dev/null 2>&1; then
return
fi
log "pnpm not found; preparing temporary pnpm wrapper"
ensure_command npm
local tmp_bin_dir
tmp_bin_dir="$(mktemp -d)"
trap 'rm -rf "$tmp_bin_dir"' EXIT
cat << EOF > "$tmp_bin_dir/pnpm"
#!/bin/sh
export NPM_CONFIG_REGISTRY="$REGISTRY"
exec npm exec --yes pnpm@10 -- "\$@"
EOF
chmod +x "$tmp_bin_dir/pnpm"
export PATH="$tmp_bin_dir:\$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"
Comment on lines +62 to +66

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

直接调用 ./node_modules/.bin/ 下的二进制文件依赖于特定的目录结构。在 pnpm 环境下,使用 pnpm exec 来执行本地依赖的二进制文件是更推荐、更健壮的做法,它能自动处理路径解析和环境变量。

Suggested change
log "Building Electron app"
./node_modules/.bin/electron-vite build
log "Packaging Linux $ARCH artifacts"
./node_modules/.bin/electron-builder --linux --"$ARCH"
log "Building Electron app"
pnpm exec electron-vite build
log "Packaging Linux $ARCH artifacts"
pnpm exec 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
135 changes: 135 additions & 0 deletions docs/deepin25/install-deepin25.sh
Original file line number Diff line number Diff line change
@@ -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
Comment on lines +115 to +117

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

由于 /usr/share/icons/hicolor 是系统全局目录,非 root 用户运行 gtk-update-icon-cache 会因为权限不足而失败(虽然这里重定向了错误输出,但实际上缓存并没有被更新)。

建议使用 sudo 来执行该命令,以确保图标缓存能够成功刷新,从而使应用图标在桌面上立即生效。

Suggested change
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
if [[ -f /usr/share/icons/hicolor/1024x1024/apps/ztools.png ]] && command -v gtk-update-icon-cache >/dev/null 2>&1; then
sudo 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"
Comment on lines +129 to +130

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

如果用户传入了一个相对路径(例如 dist/ZTools_2.6.1_amd64.deb),在执行 apt install 时,apt 可能会因为路径不包含 ./ 或不是绝对路径而将其误判为软件源中的包名,导致安装失败。

建议使用 realpathDEB_PATH 转换为绝对路径,这样可以确保 aptdpkg 能够正确识别并安装本地文件。

Suggested change
DEB_PATH="${1:-$(find_latest_deb)}"
[[ -f "$DEB_PATH" ]] || fail "Package not found: $DEB_PATH"
DEB_PATH="${1:-$(find_latest_deb)}"
[[ -f "$DEB_PATH" ]] || fail "Package not found: $DEB_PATH"
DEB_PATH="$(realpath "$DEB_PATH")"


install_deb "$DEB_PATH"
install_launcher

log "Done. You can launch ZTools from the desktop icon, app launcher, or run: ztools"
Loading