diff --git a/scripts/mirror_sync.sh b/scripts/mirror_sync.sh index 2dd0e65..5ae629c 100755 --- a/scripts/mirror_sync.sh +++ b/scripts/mirror_sync.sh @@ -5,6 +5,9 @@ # bash scripts/mirror_sync.sh --id ipollowork # bash scripts/mirror_sync.sh --id ipollowork --depth 200 # 超大仓只取近期历史 # bash scripts/mirror_sync.sh --id orca --blobless # 大仓懒拉 blob,只走源码快照 +# bash scripts/mirror_sync.sh --id orca --tarball # 直接下载 tarball 绕过 git 端点 +# 说明:github.com 在本环境经沙箱代理 502 封死 git clone,脚本会自动把 github +# 上游改写为 codeload tarball 路线;非 github 上游不受影响。 # # 可见性由档案的 business.license.redistributable 决定(L1/L2 → public,L3 → private)。 # 这条规则不能手工绕过:把 source-available 项目公开镜像,等于替对方做了一次 @@ -31,6 +34,10 @@ NO_FETCH="0" # 大仓(尤其 blob 占比高)可把传输量从整包几百 MB 砍到几十 MB,且具备"克隆成功即落盘、 # 之后懒拉 blob 失败可重跑续传"的容错;代价是只能走源码快照(partial clone 不能按 mirror 推送)。 BLOBLESS="0" +# tarball 路线:直接下载上游源码 tarball(codeload.github.com 等),绕过被封锁的 +# git 智能 HTTP 端点。本环境 github.com 经沙箱代理 502 封死,git clone 永不可用, +# 故 github 上游默认走 tarball(自动派生 codeload URL),得到的是无历史的源码快照。 +TARBALL="" while [[ $# -gt 0 ]]; do case "$1" in @@ -42,6 +49,7 @@ while [[ $# -gt 0 ]]; do --set-public) SET_PUBLIC="1"; shift;; --no-fetch) NO_FETCH="1"; shift;; --blobless) BLOBLESS="1"; shift;; + --tarball) TARBALL="$2"; shift 2;; *) echo "未知参数: $1" >&2; exit 1;; esac done @@ -109,6 +117,14 @@ EXCLUDE_COUNT=${#EXCLUDE_PATHS[@]} [[ -z "${UPSTREAM}" ]] && { echo "档案缺少 mirror.upstream" >&2; exit 1; } +# github.com 在本环境经沙箱代理 502 封死 git 智能 HTTP 端点,git clone 永远失败。 +# 自动派生 codeload tarball URL(绕过 git 端点),github 上游默认走 tarball 路线。 +# 非 github 上游(gitea/gitlab 等)不受影响,仍走正常 git clone。 +if [[ -z "${TARBALL}" && "${UPSTREAM}" =~ ^https?://github\.com/([^/]+)/([^/]+?)(\.git)?/?$ ]]; then + TARBALL="https://codeload.github.com/${BASH_REMATCH[1]}/${BASH_REMATCH[2]}/tar.gz/refs/heads/main" + echo " 上游为 github.com(本环境 git 端点受限)→ 自动改用 tarball 路线: ${TARBALL}" +fi + echo "==> 镜像 ${ID}" echo " 上游 : ${UPSTREAM}" echo " 目标 : ${ORG}/${REPO_NAME}" @@ -195,12 +211,51 @@ cleanup_broken() { } trap cleanup_broken EXIT +# 从 tarball 构建源码快照裸仓:下载 → 解包 → 剔除非源码素材 → 单提交 → 裸仓克隆。 +# 适用于 git 端点不可达(本环境 github.com 被 502 封死)或仅需最新源码快照的场景。 +build_from_tarball() { + echo " 从 tarball 构建源码快照(绕过 git 端点)..." + SOURCE_ONLY_FORCE="yes" + rm -rf "${MIRROR_DIR}" + local tmp + tmp="$(mktemp -d)" + local tarball="${tmp}/src.tar.gz" + local ok=0 + for attempt in $(seq 1 8); do + if curl -sSL -C - -o "${tarball}" "${TARBALL}"; then + ok=1; break + fi + echo " ⚠ 第 ${attempt} 次下载失败,$(( attempt * 10 ))s 后重试 ..." + sleep $(( attempt * 10 )) + [[ ${attempt} -eq 8 ]] && { echo "tarball 下载八次均失败" >&2; exit 1; } + done + [[ ${ok} -eq 1 ]] || { echo "下载失败" >&2; exit 1; } + echo " 解包并剔除非源码素材 ..." + mkdir -p "${tmp}/src" + tar -xzf "${tarball}" -C "${tmp}/src" --strip-components=1 + find "${tmp}/src" -type f \( \ + -iname '*.png' -o -iname '*.gif' -o -iname '*.jpg' -o -iname '*.jpeg' \ + -o -iname '*.webp' -o -iname '*.ico' -o -iname '*.mp4' -o -iname '*.mov' \ + -o -iname '*.webm' -o -iname '*.wav' -o -iname '*.mp3' -o -iname '*.glb' \ + -o -iname '*.ttf' -o -iname '*.woff' -o -iname '*.woff2' -o -iname '*.eot' \ + -o -iname '*.pdf' -o -iname '*.zip' \) -delete + git -C "${tmp}/src" init -q + ( cd "${tmp}/src" && git add -A \ + && git -c user.name='agent-radar' -c user.email='radar@local' \ + commit -q -m "源码快照 @ $(date +%F) (tarball source-only)" ) + git clone --bare "${tmp}/src" "${MIRROR_DIR}" + rm -rf "${tmp}" + echo " 已构建本地裸仓(源码快照,无历史)" +} + if [[ -d "${MIRROR_DIR}" ]] && ! repo_ok; then echo " 清理上次中断的半成品裸仓 ..." rm -rf "${MIRROR_DIR}" fi -if [[ "${NO_FETCH}" == "1" ]]; then +if [[ -n "${TARBALL}" ]]; then + build_from_tarball +elif [[ "${NO_FETCH}" == "1" ]]; then # 跳过上游更新,直接用本地裸仓生成快照。 # 2026-09-02 需要这个:本地裸仓已是完整的,只想重跑一次快照(改了排除项), # 但 GitHub 恰好连不上("Empty reply from server"),脚本在 fetch 阶段就退出, @@ -295,8 +350,10 @@ P_ENC="$(/Users/figmarlite/.workbuddy/binaries/python/envs/default/bin/python -c # 所以推送前先量体积,超限则自动降级为「源码快照」:剔除图片/音视频/字体等 # 非源码素材——这些内容通常占一半以上体积,却不是"跟踪源码"要看的东西。 MAX_PUSH_MB="${MAX_PUSH_MB:-45}" -PACK_KB="$(git -C "${MIRROR_DIR}" count-objects -v | awk '/^size-pack:/{print $2}')" -PACK_MB=$(( PACK_KB / 1024 )) +# 既算打包对象(size-pack)也算松散对象(size):tarball 路线建的裸仓是松散对象, +# size-pack 为 0,不合并会误判体积=0、跳过 source-only 降级(orca 曾因此被错标 full)。 +PACK_KB="$(git -C "${MIRROR_DIR}" count-objects -v | awk '/^size-pack:/{sp=$2} /^size:/{sz=$2} END{print sp+sz}')" +PACK_MB=$(( ${PACK_KB:-0} / 1024 )) # blobless 镜像只能走源码快照:partial clone 不能按 mirror 推送。 [[ "${BLOBLESS}" == "1" ]] && SOURCE_ONLY_FORCE="yes" MIRROR_MODE="full" @@ -457,6 +514,7 @@ text = update_block(text, "mirror", { "gitea_repo": f"{'gitinbox'}/{sys.argv[3]}", "last_sync": today(), "mode": sys.argv[4], + "sync_note": f"已于 {today()} 镜像({sys.argv[4]} 模式,由 mirror_sync.sh 自动回写)。", }) p.write_text(text, encoding="utf-8") PY