| 1 | import type { ProjectCloneStage } from "@t3tools/contracts"; |
| 2 | |
| 3 | export interface GitCloneProgressLine { |
| 4 | readonly stage: ProjectCloneStage; |
| 5 | readonly percent: number | null; |
| 6 | /** Transfer detail after the count, e.g. `12.30 MiB | 5.00 MiB/s`. */ |
| 7 | readonly detail: string | null; |
| 8 | } |
| 9 | |
| 10 | const STAGE_PREFIXES: ReadonlyArray<readonly [RegExp, ProjectCloneStage]> = [ |
| 11 | [/^remote: Enumerating objects/, "counting"], |
| 12 | [/^remote: Counting objects/, "counting"], |
| 13 | [/^remote: Compressing objects/, "counting"], |
| 14 | [/^Receiving objects/, "receiving"], |
| 15 | [/^Resolving deltas/, "resolving"], |
| 16 | [/^Updating files/, "checkout"], |
| 17 | [/^Checking out files/, "checkout"], |
| 18 | ]; |
| 19 | |
| 20 | const PERCENT = /:\s+(\d+)%\s+\((\d+)\/(\d+)\)(?:,\s*(.*?))?\s*(?:,\s*done\.)?\s*$/; |
| 21 | |
| 22 | /** |
| 23 | * Parses one line of `git clone --progress` stderr. Git redraws each counter |
| 24 | * with a bare `\r`, so callers hand over each redraw as its own line. Lines |
| 25 | * that are not progress counters (hints, warnings, `Cloning into ...`) return |
| 26 | * null and are left for the error surface. |
| 27 | */ |
| 28 | export function parseGitCloneProgressLine(line: string): GitCloneProgressLine | null { |
| 29 | const trimmed = line.trim(); |
| 30 | const stageEntry = STAGE_PREFIXES.find(([pattern]) => pattern.test(trimmed)); |
| 31 | if (!stageEntry) return null; |
| 32 | const stage = stageEntry[1]; |
| 33 | const match = PERCENT.exec(trimmed); |
| 34 | if (!match) return { stage, percent: null, detail: null }; |
| 35 | const percent = Number(match[1]); |
| 36 | const rawDetail = match[4]?.trim() ?? ""; |
| 37 | // The trailer of a finished line is "done." which carries no information. |
| 38 | const detail = rawDetail.length > 0 && rawDetail !== "done." ? rawDetail : null; |
| 39 | return { |
| 40 | stage, |
| 41 | percent: Number.isFinite(percent) ? Math.max(0, Math.min(100, percent)) : null, |
| 42 | detail, |
| 43 | }; |
| 44 | } |