fetchHash downloads codehamr_checksums.txt and returns the hash for asset. The manifest is one line per asset, " "; we match the last field so a future prefix tweak still works. A scanner read error is surfaced, not dropped as "", nil: Apply treats "no entry" as a fatal misma
(ctx context.Context, asset string)
| 255 | |
| 256 | // orphanSweepAge is how old a .codehamr-update-* temp must be before the |
| 257 | // launch sweep treats it as orphaned rather than another instance's live |
| 258 | // download; comfortably past any Apply budget. |
| 259 | const orphanSweepAge = time.Hour |
| 260 | |
| 261 | // fetchHash downloads codehamr_checksums.txt and returns the hash for asset. |
| 262 | // The manifest is one line per asset, "<hex-sha256> <filename>"; we match the |
| 263 | // last field so a future prefix tweak still works. |
| 264 | // |
| 265 | // A scanner read error is surfaced, not dropped as "", nil: Apply treats "no |
| 266 | // entry" as a fatal mismatch, so silently turning a network glitch into "asset |
| 267 | // doesn't exist" would be a confusing error. |
| 268 | func fetchHash(ctx context.Context, asset string) (string, error) { |
| 269 | req, err := http.NewRequestWithContext(ctx, "GET", checksumsURL, nil) |
| 270 | if err != nil { |
| 271 | return "", err |
| 272 | } |
| 273 | resp, err := (&http.Client{Timeout: fetchTimeout}).Do(req) |
| 274 | if err != nil { |
| 275 | return "", err |
| 276 | } |
| 277 | defer resp.Body.Close() |
| 278 | if resp.StatusCode != http.StatusOK { |
| 279 | return "", fmt.Errorf("non-200: %d", resp.StatusCode) |
| 280 | } |
| 281 | sc := bufio.NewScanner(resp.Body) |
| 282 | for sc.Scan() { |
| 283 | line := strings.TrimSpace(sc.Text()) |
| 284 | if line == "" { |
| 285 | continue |
| 286 | } |
| 287 | fields := strings.Fields(line) |
| 288 | if len(fields) < 2 { |
| 289 | continue |
| 290 | } |
| 291 | if fields[len(fields)-1] == asset { |
no outgoing calls