#!/bin/sh # CI 公共步骤:Checkout 代码(流式下载+解压,带重试) # 用法:直接 source 或调用,需要 GITHUB_TOKEN 环境变量 set -eu python3 - <<'PY' import io, os, sys, tarfile, time, urllib.request, urllib.error url = f"{os.environ['GITHUB_API_URL']}/repos/{os.environ['GITHUB_REPOSITORY']}/archive/{os.environ['GITHUB_SHA']}.tar.gz" request = urllib.request.Request(url, headers={"Authorization": f"token {os.environ['GITHUB_TOKEN']}"}) last_err = None for attempt in range(5): try: with urllib.request.urlopen(request, timeout=120) as response: # 流式读取:先读少量数据确认连接成功,再大块读取 first_chunk = response.read(8192) buf = io.BytesIO() buf.write(first_chunk) while True: chunk = response.read(65536) if not chunk: break buf.write(chunk) buf.seek(0) with tarfile.open(fileobj=buf, mode='r:gz') as tar: root_prefix = tar.getmembers()[0].name.split('/', 1)[0] + '/' for member in tar.getmembers(): name = member.name if name == root_prefix[:-1]: continue if name.startswith(root_prefix): member.name = name[len(root_prefix):] if member.name: tar.extract(member, '.') break except urllib.error.HTTPError as e: last_err = e if e.code >= 500 and attempt < 4: wait = 2 ** attempt print(f"Checkout HTTP {e.code}, retrying in {wait}s (attempt {attempt+1}/5)...") time.sleep(wait) continue raise except Exception as e: last_err = e if attempt < 4: wait = 2 ** attempt print(f"Checkout error: {e}, retrying in {wait}s (attempt {attempt+1}/5)...") time.sleep(wait) continue raise else: raise last_err PY # CI pipeline speedup batch 1