| 168 | * for Git. |
| 169 | */ |
| 170 | export class GitProgressParser implements IGitProgressParser { |
| 171 | private readonly steps: ReadonlyArray<IProgressStep> |
| 172 | |
| 173 | /* The provided steps should always occur in order but some |
| 174 | * might not happen at all (like remote compression of objects) so |
| 175 | * we keep track of the "highest" seen step so that we can fill in |
| 176 | * progress with the assumption that we've already seen the previous |
| 177 | * steps. |
| 178 | */ |
| 179 | private stepIndex = 0 |
| 180 | |
| 181 | private lastPercent = 0 |
| 182 | |
| 183 | /** |
| 184 | * Initialize a new instance of a Git progress parser. |
| 185 | * |
| 186 | * @param steps - A series of steps that could be present in the git |
| 187 | * output with relative weight between these steps. Note |
| 188 | * that order is significant here as once the parser sees |
| 189 | * a progress line that matches a step all previous steps |
| 190 | * are considered completed and overall progress is adjusted |
| 191 | * accordingly. |
| 192 | */ |
| 193 | public constructor(steps: ReadonlyArray<IProgressStep>) { |
| 194 | if (!steps.length) { |
| 195 | throw new Error('must specify at least one step') |
| 196 | } |
| 197 | |
| 198 | // Scale the step weight so that they're all a percentage |
| 199 | // adjusted to the total weight of all steps. |
| 200 | const totalStepWeight = steps.reduce((sum, step) => sum + step.weight, 0) |
| 201 | |
| 202 | this.steps = steps.map(step => ({ |
| 203 | title: step.title, |
| 204 | weight: step.weight / totalStepWeight, |
| 205 | })) |
| 206 | } |
| 207 | |
| 208 | /** |
| 209 | * Parse the given line of output from Git, returns either an `IGitProgress` |
| 210 | * instance if the line could successfully be parsed as a Git progress |
| 211 | * event whose title was registered with this parser or an `IGitOutput` |
| 212 | * instance if the line couldn't be parsed or if the title wasn't |
| 213 | * registered with the parser. |
| 214 | */ |
| 215 | public parse(line: string): IGitProgress | IGitOutput { |
| 216 | // In case we're parsing hook output or similar we want to |
| 217 | // strip out any control characters that may be present. IGitProgress |
| 218 | // is supposed to be readable text that can be used in tooltips and such. |
| 219 | const text = stripVTControlCharacters(line) |
| 220 | const progress = parse(text) |
| 221 | |
| 222 | if (!progress) { |
| 223 | return { kind: 'context', text, percent: this.lastPercent } |
| 224 | } |
| 225 | |
| 226 | let percent = 0 |
| 227 |
nothing calls this directly
no outgoing calls
no test coverage detected