#!/usr/bin/env bash # ============================================================================= # v-baseline.sh —— S0 尺子①:取两端基线(平台侧共享层 / 客户端 profile) # 规格来源:交付物/功能打包到基础插件-分步实施方案-20260926.md §3.10.1 / §3.10.2 S0-1·S0-2 # ----------------------------------------------------------------------------- # 约定(§3.10.1 三条) # 1. 退出码即结论:rc=0 绿(两端都取到)/rc≠0 红(有面取不到,逐面标注) # 2. 只许测活体:本尺子取的是**远端真实共享层**与**本机真实 profile**,⛔ 不用快照/config 推断 # 3. 落点:脚本在 交付物/验证脚本/;读数落 tmp/p39/(⛔ 不入库,数值会漂) # 用法 # bash v-baseline.sh # 取两端基线,写读数文件 # bash v-baseline.sh --stable # 只打印**稳定块**(不含取数时间)⇒ 连跑两次逐字一致的比较对象 # ----------------------------------------------------------------------------- # 复核命令(照抄即可复现本条基线): # 平台侧:ssh root@47.77.182.89 'for p in /var/lib/dshs/bundled-plugins/*/; do ...; done' # —— 本脚本内 remote_block() 就是它;指纹算法 = 逐文件 sha256sum → 按字节序排序 → 再 sha256sum 取前 8 # 客户端:读 $DSH_DESKTOP_HOME/profiles/desktop/package.json 的 dsh.profile.bundles # ----------------------------------------------------------------------------- # ⛔ 只读:不写任何生产文件、不改任何工作区文件;唯一写动作 = 往 $OUT(=tmp/p39) 落读数 # ============================================================================= set -u SELF_DIR="$(cd "$(dirname "$0")" && pwd -W)" [ -d "$SELF_DIR" ] || SELF_DIR="$(cd "$(dirname "$0")" && pwd)" WS="$(cd "$SELF_DIR/../.." && pwd -W)" [ -d "$WS" ] || WS="$(cd "$SELF_DIR/../.." && pwd)" OUT="${P39_OUT:-$WS/tmp/p39}" DATE="$(date +%Y%m%d)" STABLE_ONLY=0 [ "${1:-}" = "--stable" ] && STABLE_ONLY=1 SSH_HOST="${P39_47:-root@47.77.182.89}" SHARED_DIR="${P39_SHARED:-/var/lib/dshs/bundled-plugins}" DSH_DESKTOP_HOME="${DSH_DESKTOP_HOME:-E:/github/dsh-desktop-0.1.7rc2/apps/desktop/.desktop-build/development/home-adapt}" PY="${PY:-E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe}" mkdir -p "$OUT" # ------------------------------- 平台侧 -------------------------------------- platform_block() { ssh -o BatchMode=yes -o ConnectTimeout=8 "$SSH_HOST" "DSH_SHARED_DIR='$SHARED_DIR' bash -s" <<'REMOTE' 2>/dev/null set -u D="${DSH_SHARED_DIR:-/var/lib/dshs/bundled-plugins}" [ -d "$D" ] || { echo "ERR no-such-dir $D"; exit 9; } for p in $(ls "$D" | sort); do d="$D/$p" [ -d "$d" ] || continue ver=$(grep -m1 '"version"' "$d/package.json" 2>/dev/null | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/') n=$(find "$d" -type f 2>/dev/null | wc -l) b=$(find "$d" -type f -printf '%s\n' 2>/dev/null | awk '{s+=$1} END{printf "%d", s+0}') fp=$(find "$d" -type f -print0 2>/dev/null | sort -z | xargs -0 sha256sum 2>/dev/null | sha256sum | cut -c1-8) printf 'PKG\t%s\t%s\t%s\t%s\t%s\n' "$p" "${ver:-?}" "$n" "$b" "$fp" done REMOTE } # ------------------------------- 客户端侧 ------------------------------------ client_block() { local pj="$DSH_DESKTOP_HOME/profiles/desktop/package.json" [ -f "$pj" ] || { echo "ERR no-such-profile $pj"; return 9; } "$PY" - "$pj" <<'PYEOF' 2>/dev/null import json, sys d = json.load(open(sys.argv[1], encoding='utf-8')) b = ((d.get('dsh') or {}).get('profile') or {}).get('bundles') or [] print("BUNDLE_COUNT\t%d" % len(b)) for x in b: print("BUNDLE\t%s" % x) print("LOCAL_SCOPE_COUNT\t%d" % sum(1 for x in b if str(x).startswith('@dsh-local/'))) PYEOF } PLAT_RAW="$(platform_block)"; PLAT_RC=$? CLI_RAW="$(client_block)"; CLI_RC=$? pl_err=0; cl_err=0 [ "$PLAT_RC" != 0 ] && pl_err=1 printf '%s\n' "$PLAT_RAW" | grep -q '^ERR' && pl_err=1 printf '%s\n' "$CLI_RAW" | grep -q '^ERR' && cl_err=1 PLAT_STABLE="$(printf '%s\n' "$PLAT_RAW" | sort)" CLI_STABLE="$(printf '%s\n' "$CLI_RAW")" if [ "$STABLE_ONLY" = "1" ]; then echo "### STABLE · 平台侧($SSH_HOST:$SHARED_DIR 包数+每包指纹)" printf '%s\n' "$PLAT_STABLE" echo "### STABLE · 客户端侧($DSH_DESKTOP_HOME/profiles/desktop bundle 清单)" printf '%s\n' "$CLI_STABLE" [ $((pl_err + cl_err)) -ne 0 ] && exit 1 exit 0 fi { echo "════ 基线 · 平台侧(共享层)════" echo "取数时间:$(date -Iseconds)" echo "复核命令:ssh $SSH_HOST 'ls $SHARED_DIR' 后逐包 find|sha256sum(见本脚本 platform_block())" echo "指纹算法:逐文件 sha256sum → 按路径字节序排序 → 再 sha256sum 取前 8 位" echo "⚠️ 本指纹 ⛔ 与平台 treeSha256 不同源:平台权威 treeSha256 见节点同步记录(.node-sync-reports.json)" echo "⚠️ 字节口径:本行 = 目录内全部文件 sizes 之和(含 node_modules);⛔ 与平台 pack/tgz 字节(如 mcn-suite 659 文件 / 2,018,751 B)**不是同一口径**,⛔ 不可互比" echo "---- 数据(PKG / 版本 / 文件数 / 字节 / 指纹8)----" printf '%s\n' "$PLAT_RAW" } > "$OUT/baseline-平台-$DATE.txt" { echo "════ 基线 · 客户端侧(本机 profile bundle 清单)════" echo "取数时间:$(date -Iseconds)" echo "复核命令:cat $DSH_DESKTOP_HOME/profiles/desktop/package.json → dsh.profile.bundles" echo "---- 数据 ----" printf '%s\n' "$CLI_RAW" } > "$OUT/baseline-客户端-$DATE.txt" printf '%s\n' "$PLAT_STABLE" > "$OUT/.stable-平台-$DATE.txt" printf '%s\n' "$CLI_STABLE" > "$OUT/.stable-客户端-$DATE.txt" echo "── v-baseline 结果 ──" if [ "$pl_err" = "0" ]; then echo "平台侧:✅ 取到 $(printf '%s\n' "$PLAT_RAW" | grep -c '^PKG') 个包" printf '%s\n' "$PLAT_RAW" | sed 's/^/ /' else echo "平台侧:❌ 未取到(rc=$PLAT_RC) ⇒ 原始输出:$(printf '%s' "$PLAT_RAW" | head -c 200)" fi if [ "$cl_err" = "0" ]; then echo "客户端侧:✅ 取到 $(printf '%s\n' "$CLI_RAW" | grep -c $'^BUNDLE\t') 个 bundle(@dsh-local/* 计 $(printf '%s\n' "$CLI_RAW" | sed -n 's/^LOCAL_SCOPE_COUNT\t//p') 个)" printf '%s\n' "$CLI_RAW" | sed 's/^/ /' else echo "客户端侧:❌ 未取到(rc=$CLI_RC) ⇒ 原始输出:$(printf '%s' "$CLI_RAW" | head -c 200)" fi echo "读数落盘:$OUT/baseline-平台-$DATE.txt · $OUT/baseline-客户端-$DATE.txt" echo "⛔ 基线数字只作开工对照,⛔ 不写进判据(判据一律取「前后一致」)" [ $((pl_err + cl_err)) -ne 0 ] && exit 1 exit 0