From 9b14e1ce7859c3881a19cecf19ad2d80f9985825 Mon Sep 17 00:00:00 2001 From: argszero Date: Wed, 5 Aug 2026 18:57:27 +0800 Subject: [PATCH 1/2] =?UTF-8?q?emrg:=20fix=20macOS=20pkg=20user-level=20in?= =?UTF-8?q?stall=20=E2=80=94=20--install-location=20+=20currentUserHome=20?= =?UTF-8?q?domain=20(rant=202026-08-05T18:45:35)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 双 bug 修复: 1. pkgbuild 未指定 --install-location → 默认装系统宗卷 / → '软件包正尝试将内容安装到系统宗卷' 报错 2. postinstall 复制源 /tmp/emrg-payload 为构建机路径,打包后立即删除 → 用户安装空复制 改法:payload 去掉 runtime/ 层,pkgbuild --install-location '/.emrg/install' + productbuild distribution currentUserHome 域(enable_localSystem=false) → 引擎直接装 ~/.emrg/install/,postinstall 只做 chown + GUI 复制到 ~/Applications/ 本机实测:pkgbuild+productbuild 构建成功,installer -pkg 安装到 ~/ .emrg/install(emrg 可运行)+ ~/Applications/EMRG.app + 卸载 EMRG.app --- packaging/make-installer.sh | 54 +++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index 5116d5f..f1cebad 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -1,8 +1,9 @@ #!/usr/bin/env bash # EMRG Phase 4 — platform installer wrapper (rant #12 §10/§13). # -# macOS: pkgbuild 用户级(R54)。payload 装临时位置 + postinstall 复制 -# (R104: runtime → ~/.emrg/install/ + GUI EMRG.app → ~/Applications/) +# macOS: 用户级 pkg(R54/R126)。pkgbuild --install-location '/.emrg/install' +# + distribution currentUserHome 域 → pkg 引擎直接装 ~/.emrg/install/ +# (R104: GUI EMRG.app → ~/Applications/,postinstall 复制) # R67: postinstall $HOME 陷阱(提权时取控制台用户真实 HOME) # R105: root 复制后 chown 回用户 # Windows: Inno Setup(R55 免 UAC;R97 {%USERPROFILE} 替代 {userhome}——旧版 iscc 不识) @@ -39,11 +40,14 @@ case "$PLATFORM" in exit 1 fi PKG_ROOT="$(mktemp -d)" - mkdir -p "$PKG_ROOT/payload/runtime" "$PKG_ROOT/payload/runtime/emrg-gui" - cp -R "$RUNTIME/." "$PKG_ROOT/payload/runtime/" - cp -R "$GUI_APP" "$PKG_ROOT/payload/runtime/emrg-gui/EMRG.app" + # R126: payload 不再套 runtime/ 层 —— 直接放 runtime 内容。 + # pkgbuild --install-location '/.emrg/install' + distribution currentUserHome 域 + # → pkg 引擎直接装到 ~/.emrg/install/(rant 2026-08-05T18:45:35) + mkdir -p "$PKG_ROOT/payload/emrg-gui" + cp -R "$RUNTIME/." "$PKG_ROOT/payload/" + cp -R "$GUI_APP" "$PKG_ROOT/payload/emrg-gui/EMRG.app" # 生成"卸载 EMRG.app"(R30/R31/R102:bash 包装调 emrg-uninstall + 删主 GUI + 提示拖废纸篓) - UNINSTALL_APP="$PKG_ROOT/payload/runtime/emrg-gui/卸载 EMRG.app" + UNINSTALL_APP="$PKG_ROOT/payload/emrg-gui/卸载 EMRG.app" mkdir -p "$UNINSTALL_APP/Contents/MacOS" cat > "$UNINSTALL_APP/Contents/Info.plist" <<'EOF' @@ -82,37 +86,53 @@ EOF mkdir -p "$PKG_ROOT/scripts" cat > "$PKG_ROOT/scripts/postinstall" <<'EOF' #!/bin/bash +# R126: pkg 引擎已把 payload 直接装到用户 home(currentUserHome 域), +# postinstall 不再从 /tmp 复制(旧实现依赖构建机路径 /tmp/emrg-payload, +# 用户机不存在 → 空安装;pkgbuild 未指定 --install-location → 默认装系统宗卷)。 # R67: GUI 安装器可能提权($HOME=/var/root)→ 取控制台用户真实 HOME USER="$(stat -f "%Su" /dev/console 2>/dev/null || echo "$USER")" [ -z "$USER" ] && USER="$(whoami)" HOME_DIR="$(dscl . -read "/Users/$USER" NFSHomeDirectory 2>/dev/null | awk '{print $2}')" [ -z "$HOME_DIR" ] && HOME_DIR="$HOME" -INSTALL_DEST="$HOME_DIR/.emrg/install" -# R104: ① runtime → ~/.emrg/install/ -mkdir -p "$INSTALL_DEST" -cp -R "/tmp/emrg-payload/runtime/." "$INSTALL_DEST/" +# $2 = 安装器传入的真实安装位置(currentUserHome 域下 = /.emrg/install) +INSTALL_DEST="${2:-$HOME_DIR/.emrg/install}" # R105: root 复制 → chown 回用户(否则用户无法更新 install/) chown -R "$USER":staff "$HOME_DIR/.emrg" 2>/dev/null || true # ② GUI EMRG.app → ~/Applications/(R104) -if [ -d "/tmp/emrg-payload/runtime/emrg-gui/EMRG.app" ]; then +if [ -d "$INSTALL_DEST/emrg-gui/EMRG.app" ]; then mkdir -p "$HOME_DIR/Applications" - cp -R "/tmp/emrg-payload/runtime/emrg-gui/EMRG.app" "$HOME_DIR/Applications/" + cp -R "$INSTALL_DEST/emrg-gui/EMRG.app" "$HOME_DIR/Applications/" chown -R "$USER":staff "$HOME_DIR/Applications/EMRG.app" 2>/dev/null || true fi # ③ 卸载 EMRG.app(R30:pkg 无原生卸载器,放置卸载 app) -if [ -d "/tmp/emrg-payload/runtime/emrg-gui/卸载 EMRG.app" ]; then - cp -R "/tmp/emrg-payload/runtime/emrg-gui/卸载 EMRG.app" "$HOME_DIR/Applications/" +if [ -d "$INSTALL_DEST/emrg-gui/卸载 EMRG.app" ]; then + cp -R "$INSTALL_DEST/emrg-gui/卸载 EMRG.app" "$HOME_DIR/Applications/" chown -R "$USER":staff "$HOME_DIR/Applications/卸载 EMRG.app" 2>/dev/null || true fi exit 0 EOF chmod +x "$PKG_ROOT/scripts/postinstall" - rm -rf /tmp/emrg-payload - cp -R "$PKG_ROOT/payload/runtime" /tmp/emrg-payload + # 组件包:--install-location '/.emrg/install'(currentUserHome 域下相对 home 锚点, + # 解析为 ~/.emrg/install/,不再落到系统宗卷 /) pkgbuild --root "$PKG_ROOT/payload" --scripts "$PKG_ROOT/scripts" \ --identifier "com.argszero.emrg" --version "$VERSION" \ + --install-location '/.emrg/install' \ + "$PKG_ROOT/EMRG-component.pkg" + # distribution:仅当前用户 home 域(enable_currentUserHome=true, localSystem=false) + # → 安装器显示"仅当前用户",装到 ~/.emrg/install/,不要求系统卷权限 + cat > "$PKG_ROOT/distribution.xml" < + + + + + + EMRG-component.pkg + +EOF + productbuild --distribution "$PKG_ROOT/distribution.xml" --package-path "$PKG_ROOT" \ "$DIST/artifacts/EMRG-$VERSION-macos-$(uname -m).pkg" - rm -rf "$PKG_ROOT" /tmp/emrg-payload + rm -rf "$PKG_ROOT" ;; linux) From f0cae96e956c65107526ad84cf8d1f61b4704f5f Mon Sep 17 00:00:00 2001 From: argszero Date: Wed, 5 Aug 2026 19:10:51 +0800 Subject: [PATCH 2/2] =?UTF-8?q?emrg:=20macOS=20pkg=20postinstall=20PATH=20?= =?UTF-8?q?anchor=20(R127/R19)=20=E2=80=94=20=E5=AE=89=E8=A3=85=E5=90=8E?= =?UTF-8?q?=20emrg=20=E5=91=BD=E4=BB=A4=E5=8F=AF=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rant 2026-08-05T18:45:35 验收项:安装后 emrg 命令可用(pkg postinstall 写 shell rc anchor R19)。Windows 有 HKCU PATH、Linux AppImage 有 ~/.local/bin 软链,唯 macOS 缺 —— 本 commit 补上: - postinstall 写 shell rc PATH anchor(# >>> EMRG PATH >>> 标记),格式与 bin/emrg-uninstall clean_environment() 完全一致(卸载对称清理) - 幂等:任一 rc 已含 anchor 则跳过;写所有存在的 rc(zsh 默认 + bash 兼容), 无 rc 兜底创建 ~/.zshrc(macOS 默认 zsh) - 验证:临时 HOME 实测安装写入 anchor、重复安装不重复写、 clean_environment regex 可完整匹配清理;470 pytest 全绿 --- packaging/make-installer.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packaging/make-installer.sh b/packaging/make-installer.sh index f1cebad..9edf450 100755 --- a/packaging/make-installer.sh +++ b/packaging/make-installer.sh @@ -109,6 +109,23 @@ if [ -d "$INSTALL_DEST/emrg-gui/卸载 EMRG.app" ]; then cp -R "$INSTALL_DEST/emrg-gui/卸载 EMRG.app" "$HOME_DIR/Applications/" chown -R "$USER":staff "$HOME_DIR/Applications/卸载 EMRG.app" 2>/dev/null || true fi +# ④ PATH anchor(R127/R19:安装后 emrg 命令可用 —— rant 2026-08-05T18:45:35 验收项)。 +# anchor 标记与 bin/emrg-uninstall clean_environment() 的 PATH_ANCHOR_START/END 完全一致, +# 卸载时按同标记清理(Windows 用 HKCU PATH,Linux AppImage 用 ~/.local/bin 软链,macOS 用 rc)。 +# 幂等:任一 rc 已含 anchor 则跳过;写所有存在的 rc(zsh 默认 + bash 兼容),无 rc 兜底建 ~/.zshrc。 +ANCHOR_START="# >>> EMRG PATH >>>" +ANCHOR_END="# <<< EMRG PATH <<<" +if ! grep -qsF "$ANCHOR_START" "$HOME_DIR/.zshrc" "$HOME_DIR/.bash_profile" "$HOME_DIR/.bashrc" "$HOME_DIR/.profile" 2>/dev/null; then + for RC in "$HOME_DIR/.zshrc" "$HOME_DIR/.bash_profile" "$HOME_DIR/.bashrc" "$HOME_DIR/.profile"; do + [ -f "$RC" ] || continue + printf '\n%s\nexport PATH="$HOME/.emrg/install/bin:$PATH"\n%s\n' "$ANCHOR_START" "$ANCHOR_END" >> "$RC" + chown "$USER":staff "$RC" 2>/dev/null || true + done + if [ ! -f "$HOME_DIR/.zshrc" ]; then + printf '\n%s\nexport PATH="$HOME/.emrg/install/bin:$PATH"\n%s\n' "$ANCHOR_START" "$ANCHOR_END" >> "$HOME_DIR/.zshrc" + chown "$USER":staff "$HOME_DIR/.zshrc" 2>/dev/null || true + fi +fi exit 0 EOF chmod +x "$PKG_ROOT/scripts/postinstall"