@@ -104,7 +104,9 @@ echo "Updating formula at $FORMULA_PATH"
104104
105105python3 - " $FORMULA_PATH " " $VERSION " " $SHA256 " " $TARBALL_URL " << 'PY '
106106import hashlib
107+ import os
107108import sys
109+ import time
108110import urllib.request
109111import urllib.error
110112import pathlib
@@ -130,18 +132,51 @@ for idx, line in enumerate(text):
130132if old_version is None:
131133 raise SystemExit("could not locate version line in formula")
132134
135+ RETRY_ATTEMPTS = max(1, int(os.getenv("HOMEBREW_ASSET_RETRY_ATTEMPTS", "30")))
136+ RETRY_DELAY = max(1.0, float(os.getenv("HOMEBREW_ASSET_RETRY_SECONDS", "5")))
137+
138+
139+ class AssetUnavailable(Exception):
140+ def __init__(self, url, info):
141+ super().__init__(f"{info}: {url}")
142+ self.url = url
143+ self.info = info
144+
145+
133146def download_sha(url):
134- try:
135- with urllib.request.urlopen(url) as resp:
136- data = resp.read()
137- except urllib.error.HTTPError as exc:
138- raise SystemExit(
139- f"failed to download {url} ({exc.code} {exc.reason}). "
140- "The release asset may not be available yet; wait for the release workflow to finish."
141- )
142- except urllib.error.URLError as exc:
143- raise SystemExit(f"failed to download {url}: {exc.reason}")
144- return hashlib.sha256(data).hexdigest()
147+ for attempt in range(1, RETRY_ATTEMPTS + 1):
148+ try:
149+ with urllib.request.urlopen(url) as resp:
150+ data = resp.read()
151+ except urllib.error.HTTPError as exc:
152+ if exc.code == 404 and "releases/download" in url and attempt < RETRY_ATTEMPTS:
153+ print(
154+ f"asset not available yet at {url} (attempt {attempt}/{RETRY_ATTEMPTS}); "
155+ f"retrying in {RETRY_DELAY:.0f}s...",
156+ file=sys.stderr,
157+ )
158+ time.sleep(RETRY_DELAY)
159+ continue
160+ if exc.code == 404 and "releases/download" in url:
161+ raise AssetUnavailable(url, f"{exc.code} {exc.reason}")
162+ raise SystemExit(
163+ f"failed to download {url} ({exc.code} {exc.reason}). "
164+ "The release asset may not be available yet; wait for the release workflow to finish."
165+ )
166+ except urllib.error.URLError as exc:
167+ if attempt < RETRY_ATTEMPTS:
168+ print(
169+ f"network error downloading {url}: {exc.reason} (attempt {attempt}/{RETRY_ATTEMPTS}); "
170+ f"retrying in {RETRY_DELAY:.0f}s...",
171+ file=sys.stderr,
172+ )
173+ time.sleep(RETRY_DELAY)
174+ continue
175+ raise SystemExit(f"failed to download {url}: {exc.reason}")
176+ else:
177+ return hashlib.sha256(data).hexdigest()
178+
179+ raise AssetUnavailable(url, f"no response after {RETRY_ATTEMPTS} attempts")
145180
146181sha_cache = {source_url: source_sha}
147182
@@ -161,7 +196,18 @@ def update_pair(i, url_line):
161196 if j == len(text):
162197 raise SystemExit("expected sha256 line after url line")
163198 if updated_url not in sha_cache:
164- sha_cache[updated_url] = download_sha(updated_url)
199+ try:
200+ sha_cache[updated_url] = download_sha(updated_url)
201+ except AssetUnavailable as exc:
202+ fallback_url = source_url
203+ fallback_sha = source_sha
204+ print(
205+ f"warning: {exc.info} for {exc.url}; using source tarball {fallback_url} instead",
206+ file=sys.stderr,
207+ )
208+ updated_url = fallback_url
209+ url_line = url_line[:url_start] + updated_url + url_line[url_end:]
210+ sha_cache[updated_url] = fallback_sha
165211 new_sha = sha_cache[updated_url]
166212 sha_line = text[j]
167213 sha_start = sha_line.find('"') + 1
0 commit comments