#!/usr/bin/env sh # sync-domains.sh — 依 Gitea 正本 marketplace 把所有 domain 存取庫同步到本機。 # # 用法: sync-domains.sh(不吃參數) # # 流程: # 1. 透過 jsc-gitea/tools/gitea.sh 讀正本 marketplace # (plugins/meta 的 .claude-plugin/marketplace.json),取得權威 domain 清單。 # 2. 本機缺少的 domain:用 gitea.sh clone-url plugins/{domain} 取網址後 clone。 # 3. 本機已有的 domain:git pull。工作區有未提交變更就跳過 pull,只在 stderr 提醒—— # 正在改的 repo 不該被自動 pull 覆蓋。 # # 根目錄: 交給 tools/plugins-root.sh 推導(JSC_PLUGINS_ROOT -> 從 $PWD 往上找 -> # 腳本位置上兩層 -> $HOME/plugins)。以 plugin 形式安裝時,「腳本位置上兩層」會落在 # plugin 快取目錄,單靠它一定推錯,所以推導規則抽成共用腳本。 # 存取庫目錄名: 先找 {root}/{domain},再找 {root}/jsc-{domain};都沒有才 clone 成 {root}/{domain}。 # # 輸出: 一行一個 domain,格式 {domain}{path}(stdout);警告與失敗說明走 stderr。 # 結束碼: 0=正本讀到、每個 domain 都在本機,而且每個既有存取庫都更新到最新 # 1=推導不出根目錄、讀不到正本 marketplace,或找不到 gitea.sh(不輸出任何 domain) # 2=正本讀到,但有 domain 沒能取得或 clone 失敗(已輸出其餘 domain) # 3=每個 domain 都在本機,但有存取庫沒更新到最新:工作區髒而跳過 pull, # 或 pull 失敗。stderr 會逐一列出這些路徑。**exit 0 才代表「全部最新」**; # 拿 3 當乾淨會讓後續步驟改在落後的檔案上。 # 同時發生時回較嚴重的那個:2 蓋過 3。 # 環境變數: JSC_PLUGINS_ROOT(根目錄) # JSC_SYNC_DRY_RUN=1(只印出會做什麼,不動檔案;不執行 pull/clone, # 所以也不因為「沒更新」回 3) set -u HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) . "$HERE/plugins-root.sh" DRY="${JSC_SYNC_DRY_RUN:-}" ROOT=$(jsc_plugins_root) || exit 1 GITEA="" for g in "$ROOT/gitea/tools/gitea.sh" "$ROOT/jsc-gitea/tools/gitea.sh"; do [ -f "$g" ] && { GITEA="$g"; break; } done [ -n "$GITEA" ] || { echo "找不到 gitea.sh:請先取得 jsc-gitea 存取庫" >&2; exit 1; } mkt=$(sh "$GITEA" api GET /repos/plugins/meta/raw/.claude-plugin/marketplace.json 2>/dev/null) || mkt="" [ -n "$mkt" ] || { echo "讀不到正本 marketplace:檢查 GITEA_HOST、GITEA_TOKEN 或 tea 登入" >&2; exit 1; } DOMAINS=$(printf '%s\n' "$mkt" | sed -n 's/.*"name": *"jsc-\([a-z0-9-]*\)".*/\1/p' | sort -u) [ -n "$DOMAINS" ] || { echo "正本 marketplace 裡沒有 jsc-{domain} 條目" >&2; exit 1; } repo_path() { # $1=domain;印出既有路徑(return 0)或預設路徑(return 1) for d in "$ROOT/$1" "$ROOT/jsc-$1"; do [ -d "$d" ] && { printf '%s' "$d"; return 0; } done printf '%s' "$ROOT/$1" return 1 } rc=0 stale=0 for domain in $DOMAINS; do if path=$(repo_path "$domain"); then if [ -n "$(git -C "$path" status --porcelain 2>/dev/null)" ]; then echo "工作區有未提交變更,跳過 pull,未更新到最新:$path" >&2 stale=1 elif [ "$DRY" = 1 ]; then echo "[dry-run] git -C $path pull --ff-only" >&2 elif ! git -C "$path" pull --quiet --ff-only >/dev/null 2>&1; then echo "pull 失敗,保留本機版本,未更新到最新:$path" >&2 stale=1 fi else url=$(sh "$GITEA" clone-url "plugins/$domain" 2>/dev/null) || url="" if [ -z "$url" ]; then echo "取不到 clone 網址,略過:plugins/$domain" >&2 rc=2 continue fi if [ "$DRY" = 1 ]; then echo "[dry-run] git clone $url $path" >&2 elif ! git clone --quiet "$url" "$path" >/dev/null 2>&1; then echo "clone 失敗:$url" >&2 rc=2 continue fi fi printf '%s\t%s\n' "$domain" "$path" done # 2(取不到或 clone 失敗)比 3(沒更新到最新)嚴重,優先回報。 [ "$rc" -eq 0 ] && [ "$stale" -eq 1 ] && rc=3 exit $rc