Initial import of NousResearch/hermes-agent
Deploy Site / deploy-vercel (push) Has been cancelled
Deploy Site / deploy-docs (push) Has been cancelled
Docker / shell lint / Lint Dockerfile (hadolint) (push) Has been cancelled
Docker / shell lint / Lint docker/ shell scripts (shellcheck) (push) Has been cancelled
Docker Build and Publish / build-amd64 (push) Has been cancelled
Docker Build and Publish / build-arm64 (push) Has been cancelled
Lint (ruff + ty) / ruff + ty diff (push) Has been cancelled
Lint (ruff + ty) / ruff enforcement (blocking) (push) Has been cancelled
Lint (ruff + ty) / Windows footguns (blocking) (push) Has been cancelled
Nix Lockfile Fix / auto-fix-main (push) Has been cancelled
Nix Lockfile Fix / fix (push) Has been cancelled
Nix / nix (macos-latest) (push) Has been cancelled
Nix / nix (ubuntu-latest) (push) Has been cancelled
OSV-Scanner / Scan lockfiles (push) Has been cancelled
Build Skills Index / build-index (push) Has been cancelled
Tests / test (1) (push) Has been cancelled
Tests / test (2) (push) Has been cancelled
Tests / test (3) (push) Has been cancelled
Tests / test (4) (push) Has been cancelled
Tests / test (5) (push) Has been cancelled
Tests / test (6) (push) Has been cancelled
Tests / e2e (push) Has been cancelled
uv.lock check / uv lock --check (push) Has been cancelled
Docker Build and Publish / merge (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
Tests / save-durations (push) Has been cancelled
Deploy Site / deploy-vercel (push) Has been cancelled
Deploy Site / deploy-docs (push) Has been cancelled
Docker / shell lint / Lint Dockerfile (hadolint) (push) Has been cancelled
Docker / shell lint / Lint docker/ shell scripts (shellcheck) (push) Has been cancelled
Docker Build and Publish / build-amd64 (push) Has been cancelled
Docker Build and Publish / build-arm64 (push) Has been cancelled
Lint (ruff + ty) / ruff + ty diff (push) Has been cancelled
Lint (ruff + ty) / ruff enforcement (blocking) (push) Has been cancelled
Lint (ruff + ty) / Windows footguns (blocking) (push) Has been cancelled
Nix Lockfile Fix / auto-fix-main (push) Has been cancelled
Nix Lockfile Fix / fix (push) Has been cancelled
Nix / nix (macos-latest) (push) Has been cancelled
Nix / nix (ubuntu-latest) (push) Has been cancelled
OSV-Scanner / Scan lockfiles (push) Has been cancelled
Build Skills Index / build-index (push) Has been cancelled
Tests / test (1) (push) Has been cancelled
Tests / test (2) (push) Has been cancelled
Tests / test (3) (push) Has been cancelled
Tests / test (4) (push) Has been cancelled
Tests / test (5) (push) Has been cancelled
Tests / test (6) (push) Has been cancelled
Tests / e2e (push) Has been cancelled
uv.lock check / uv lock --check (push) Has been cancelled
Docker Build and Publish / merge (push) Has been cancelled
Build Skills Index / trigger-deploy (push) Has been cancelled
Tests / save-durations (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env python3
|
||||
"""分段推送到 Gitea:用 /contents API 分批上传文件
|
||||
|
||||
策略:
|
||||
1. 每批上传最多 20MB 的文件,控制在 nginx 的 ~30MB 限制内
|
||||
2. 按目录结构分批上传,保持提交历史相对整洁
|
||||
3. 小文件合并到同一 commit,大文件单独 commit
|
||||
"""
|
||||
|
||||
import os, base64, json, subprocess, sys, time
|
||||
|
||||
GITEA_URL = "https://git666.u7f.cn"
|
||||
OWNER = "sawz"
|
||||
REPO = "hermes-agent"
|
||||
AUTH = "Basic c2F3ejo0NTMyNDYyMnd3"
|
||||
|
||||
MAX_BATCH_SIZE = 20 * 1024 * 1024 # 20MB 批次上限(留余量)
|
||||
|
||||
def run_curl(method, path, data=None):
|
||||
"""执行 curl 请求"""
|
||||
url = f"{GITEA_URL}{path}"
|
||||
cmd = ["curl", "-s", "-w", "\n%{http_code}", "-X", method, url,
|
||||
"-H", f"Authorization: {AUTH}",
|
||||
"-H", "Content-Type: application/json"]
|
||||
if data:
|
||||
cmd.extend(["-d", json.dumps(data)])
|
||||
|
||||
for attempt in range(3):
|
||||
try:
|
||||
result = subprocess.run(cmd, capture_output=True, text=True, timeout=60)
|
||||
lines = result.stdout.strip().split("\n")
|
||||
if len(lines) < 2:
|
||||
return None, 0
|
||||
http_code = int(lines[-1])
|
||||
body = "\n".join(lines[:-1])
|
||||
if body:
|
||||
return json.loads(body), http_code
|
||||
return {}, http_code
|
||||
except Exception as e:
|
||||
if attempt < 2:
|
||||
time.sleep(2)
|
||||
continue
|
||||
print(f" API 错误: {e}")
|
||||
return None, 0
|
||||
|
||||
def get_last_sha():
|
||||
"""获取当前 main 分支的最新 commit SHA"""
|
||||
resp, code = run_curl("GET", f"/api/v1/repos/{OWNER}/{REPO}/branches/main")
|
||||
if resp and "commit" in resp:
|
||||
return resp["commit"]["id"]
|
||||
return None
|
||||
|
||||
def upload_file(local_path):
|
||||
"""上传单个文件到 Gitea"""
|
||||
repo_path = os.path.relpath(local_path, repo_dir)
|
||||
if repo_path.startswith("./"):
|
||||
repo_path = repo_path[2:]
|
||||
|
||||
with open(local_path, "rb") as f:
|
||||
content = base64.b64encode(f.read()).decode()
|
||||
|
||||
# 检查文件大小
|
||||
file_size = len(content) * 3 // 4 # base64 膨胀约 1/3
|
||||
if file_size > MAX_BATCH_SIZE:
|
||||
print(f" ⚠ 文件过大 ({file_size/1024/1024:.1f}MB): {repo_path}")
|
||||
return None
|
||||
|
||||
data = {
|
||||
"content": content,
|
||||
"message": f"add {repo_path}",
|
||||
"branch": "main"
|
||||
}
|
||||
|
||||
resp, code = run_curl("PUT", f"/api/v1/repos/{OWNER}/{REPO}/contents/{repo_path}", data)
|
||||
|
||||
if code == 201:
|
||||
return resp.get("commit", {}).get("sha", "")
|
||||
elif code == 404:
|
||||
print(f" ✗ 仓库不存在")
|
||||
return None
|
||||
elif code == 413:
|
||||
print(f" ✗ 413 太大: {repo_path} ({file_size/1024/1024:.1f}MB)")
|
||||
return None
|
||||
else:
|
||||
# 可能是文件已存在
|
||||
return None
|
||||
|
||||
def get_all_files(repo_root):
|
||||
"""递归获取所有需要上传的文件"""
|
||||
files = []
|
||||
exclude_dirs = {".git", "__pycache__", ".venv", ".vscode",
|
||||
".hermes-docker", ".notebooklm-home", ".notebooklm-cli-venv",
|
||||
".notebooklm-playwright", ".pip-cache", ".uv-cache", "venv"}
|
||||
exclude_files = {".DS_Store"}
|
||||
|
||||
for root, dirs, filenames in os.walk(repo_root):
|
||||
dirs[:] = [d for d in dirs if d not in exclude_dirs]
|
||||
for f in filenames:
|
||||
if f in exclude_files or f.endswith(".pyc"):
|
||||
continue
|
||||
filepath = os.path.join(root, f)
|
||||
filesize = os.path.getsize(filepath)
|
||||
files.append((filepath, filesize))
|
||||
|
||||
return files
|
||||
|
||||
def main():
|
||||
global repo_dir
|
||||
repo_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
# 先确保仓库和 main 分支存在
|
||||
resp, code = run_curl("GET", f"/api/v1/repos/{OWNER}/{REPO}")
|
||||
if not resp or "id" not in resp:
|
||||
print("仓库不存在!")
|
||||
sys.exit(1)
|
||||
|
||||
# 检查 main 分支
|
||||
branch, _ = run_curl("GET", f"/api/v1/repos/{OWNER}/{REPO}/branches/main")
|
||||
if not branch:
|
||||
# 用 README 初始化
|
||||
print("初始化仓库 (README)...")
|
||||
readme_b64 = base64.b64encode(b"# Hermes Agent\n\nBackup mirror").decode()
|
||||
data = {
|
||||
"content": readme_b64,
|
||||
"message": "Initial commit",
|
||||
"branch": "main"
|
||||
}
|
||||
resp, code = run_curl("PUT", f"/api/v1/repos/{OWNER}/{REPO}/contents/README.md", data)
|
||||
if code == 201:
|
||||
print(" 初始化成功")
|
||||
else:
|
||||
print(f" 初始化失败: {code}")
|
||||
sys.exit(1)
|
||||
|
||||
# 获取文件列表
|
||||
all_files = get_all_files(repo_dir)
|
||||
total_files = len(all_files)
|
||||
total_size = sum(sz for _, sz in all_files)
|
||||
print(f"共 {total_files} 个文件, {total_size/1024/1024:.1f}MB")
|
||||
|
||||
# 分批上传
|
||||
uploaded = 0
|
||||
skipped = 0
|
||||
batch_files = []
|
||||
batch_size = 0
|
||||
|
||||
for filepath, filesize in all_files:
|
||||
if filesize > MAX_BATCH_SIZE:
|
||||
print(f" ⚠ 超大文件跳过: {os.path.relpath(filepath, repo_dir)} ({filesize/1024/1024:.1f}MB)")
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
if batch_size + filesize > MAX_BATCH_SIZE and batch_files:
|
||||
# 提交当前批次
|
||||
for fp in batch_files:
|
||||
result = upload_file(fp)
|
||||
if result:
|
||||
uploaded += 1
|
||||
else:
|
||||
skipped += 1
|
||||
batch_files = []
|
||||
batch_size = 0
|
||||
print(f" 进度: {uploaded}/{total_files} (跳过 {skipped})")
|
||||
|
||||
batch_files.append(filepath)
|
||||
batch_size += filesize
|
||||
|
||||
# 提交最后一批
|
||||
if batch_files:
|
||||
for fp in batch_files:
|
||||
result = upload_file(fp)
|
||||
if result:
|
||||
uploaded += 1
|
||||
else:
|
||||
skipped += 1
|
||||
|
||||
print(f"\n完成!上传 {uploaded}, 跳过 {skipped}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user