From 81ffa0e19f473fdc74cd6fc0d5b27d8478723b16 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Fri, 23 Oct 2026 15:57:40 +0800 Subject: [PATCH] =?UTF-8?q?feat(GitMirror):=20=E6=94=AF=E6=8C=81=20CloneBa?= =?UTF-8?q?seUrl=20=E7=9B=B4=E8=BF=9E=E6=9C=AC=E5=9C=B0=20Gitea=EF=BC=8C?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E6=9C=AC=E5=9C=B0=E9=95=9C=E5=83=8F=E6=97=B6?= =?UTF-8?q?=E6=B8=85=E9=99=A4=E5=8F=AA=E8=AF=BB=E5=B1=9E=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GitMirror/config.example.ini | 3 +++ GitMirror/mirror.py | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/GitMirror/config.example.ini b/GitMirror/config.example.ini index 0dd07996..475f19db 100644 --- a/GitMirror/config.example.ini +++ b/GitMirror/config.example.ini @@ -1,5 +1,8 @@ [gitea] BaseUrl = https://git.gvsds.com +# git 拉取地址(留空则同 BaseUrl);与 Gitea 同机部署时填 http://127.0.0.1:3000 +# 可绕开 frp 隧道,避免大仓库传输被中断(curl 92 / early EOF) +CloneBaseUrl = OrgName = GVSDS # 留空则从 SecretsIni 的 [gitea] API_TOKEN 读取 ApiToken = diff --git a/GitMirror/mirror.py b/GitMirror/mirror.py index 0180d567..36eea02e 100644 --- a/GitMirror/mirror.py +++ b/GitMirror/mirror.py @@ -23,6 +23,7 @@ import os import secrets as py_secrets import shutil import sqlite3 +import stat import subprocess import threading import urllib.parse @@ -48,6 +49,15 @@ def _Now() -> str: return datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') +def _ForceRemove(Func, Path: str, ExcInfo) -> None: + """shutil.rmtree 的回调:git 对象文件在 Windows 上是只读的,先去掉只读再删""" + try: + os.chmod(Path, stat.S_IWRITE) + Func(Path) + except OSError: + pass + + # --------------------------------------------------------------------------- # 配置 # --------------------------------------------------------------------------- @@ -61,6 +71,9 @@ class MirrorConfig: raise MirrorError(f'配置文件不存在:{Path}') self.Path = Path self.GiteaBaseUrl = (Parser.get('gitea', 'BaseUrl', fallback='https://git.gvsds.com') or '').rstrip('/') + # git 拉取地址可与 API 地址不同:同机部署时直连 127.0.0.1 可绕开 frp 隧道 + # (大仓库经隧道传输常被中断,表现为 curl 92 / early EOF / invalid index-pack) + self.GiteaCloneUrl = (Parser.get('gitea', 'CloneBaseUrl', fallback='') or self.GiteaBaseUrl).rstrip('/') self.GiteaOrg = Parser.get('gitea', 'OrgName', fallback='GVSDS') self.GiteaToken = (Parser.get('gitea', 'ApiToken', fallback='') or '').strip() self.SecretsIni = Parser.get('gitea', 'SecretsIni', fallback='') @@ -406,7 +419,7 @@ class MirrorManager: Private = bool(Repo.get('private', True)) Local = os.path.join(self.Cfg.ReposDir, f'{RepoName}.git') SourceUrl = self._AuthUrl( - f'{self.Cfg.GiteaBaseUrl}/{self.Cfg.GiteaOrg}/{RepoName}.git', 'oauth2', self.Cfg.GiteaToken) + f'{self.Cfg.GiteaCloneUrl}/{self.Cfg.GiteaOrg}/{RepoName}.git', 'oauth2', self.Cfg.GiteaToken) TargetUrl = self._AuthUrl( f'https://github.com/{self.Cfg.GithubOrg}/{GithubName}.git', GITHUB_AUTH_USER, self.Cfg.GithubToken) @@ -452,7 +465,7 @@ class MirrorManager: if not os.path.isdir(Local): return try: - shutil.rmtree(Local) + shutil.rmtree(Local, onerror=_ForceRemove) logger.info('已删除本地镜像:%s', RepoName) except OSError as Error: logger.warning('删除本地镜像失败 %s:%s', RepoName, Error)