|
25 | 25 | OUTPUT = Path(__file__).parent.parent / "plugins.json" |
26 | 26 | MARKETPLACE_OUTPUT = Path(__file__).parent.parent / ".agents" / "plugins" / "marketplace.json" |
27 | 27 | PLUGINS_ROOT = Path(__file__).parent.parent / "plugins" |
28 | | -REQUEST_TIMEOUT_SECONDS = 45 |
| 28 | +REQUEST_TIMEOUT_SECONDS = 60 |
| 29 | +MAX_RETRIES = 3 |
29 | 30 | USER_AGENT = "awesome-codex-plugins-generator" |
30 | 31 | OPTIONAL_PLUGIN_FILES = ( |
31 | 32 | "README.md", |
@@ -103,12 +104,21 @@ def parse_plugins(readme_path: Path) -> list[dict[str, str]]: |
103 | 104 |
|
104 | 105 |
|
105 | 106 | def fetch_repo_archive(owner: str, repo: str) -> zipfile.ZipFile: |
106 | | - request = urllib.request.Request( |
107 | | - f"https://github.com/{owner}/{repo}/archive/HEAD.zip", |
108 | | - headers={"User-Agent": USER_AGENT}, |
109 | | - ) |
110 | | - with urllib.request.urlopen(request, timeout=REQUEST_TIMEOUT_SECONDS) as response: |
111 | | - return zipfile.ZipFile(io.BytesIO(response.read())) |
| 107 | + last_error = None |
| 108 | + for attempt in range(MAX_RETRIES): |
| 109 | + try: |
| 110 | + request = urllib.request.Request( |
| 111 | + f"https://github.com/{owner}/{repo}/archive/HEAD.zip", |
| 112 | + headers={"User-Agent": USER_AGENT}, |
| 113 | + ) |
| 114 | + with urllib.request.urlopen(request, timeout=REQUEST_TIMEOUT_SECONDS) as response: |
| 115 | + return zipfile.ZipFile(io.BytesIO(response.read())) |
| 116 | + except Exception as e: |
| 117 | + last_error = e |
| 118 | + if attempt < MAX_RETRIES - 1: |
| 119 | + import time |
| 120 | + time.sleep(2 ** attempt) # exponential backoff |
| 121 | + raise last_error |
112 | 122 |
|
113 | 123 |
|
114 | 124 | def resolve_plugin_root(names: set[str]) -> PurePosixPath: |
@@ -175,9 +185,16 @@ def collect_selected_paths( |
175 | 185 |
|
176 | 186 |
|
177 | 187 | def mirror_plugin_bundle(plugin: dict[str, str]) -> tuple[dict[str, object], str]: |
178 | | - archive = fetch_repo_archive(plugin["owner"], plugin["repo"]) |
| 188 | + owner_repo = f"{plugin['owner']}/{plugin['repo']}" |
| 189 | + try: |
| 190 | + archive = fetch_repo_archive(plugin["owner"], plugin["repo"]) |
| 191 | + except Exception as e: |
| 192 | + raise ValueError(f"Failed to fetch {owner_repo}: {e}") from e |
179 | 193 | names = {name for name in archive.namelist() if not name.endswith("/")} |
180 | | - plugin_root = resolve_plugin_root(names) |
| 194 | + try: |
| 195 | + plugin_root = resolve_plugin_root(names) |
| 196 | + except ValueError: |
| 197 | + raise ValueError(f"Archive for {owner_repo} does not contain .codex-plugin/plugin.json") from None |
181 | 198 | manifest = load_manifest(archive, plugin_root) |
182 | 199 | selected_paths = collect_selected_paths(manifest, names, plugin_root) |
183 | 200 |
|
|
0 commit comments