<commit_before>import { mkTempFile } from '../file-system'

export function createProgressFile(): Promise<string> {
  return mkTempFile('GitHubDesktop-lfs-progress')
}
<commit_msg>Take a shot at parsing LFS progress<commit_after>import { mkTempFile } from '../file-system'
import { IGitProgress, IGitProgressInfo, IGitOutput } from './git'

export function createProgressFile(): Promise<string> {
  return mkTempFile('GitHubDesktop-lfs-progress')
}

// The regex for parsing LFS progress lines. See
// https://github.com/git-lfs/git-lfs/blob/dce20b0d18213d720ff2897267e68960d296eb5e/docs/man/git-lfs-config.5.ronn
// for more info. At a high level:
//
// `<direction> <current>/<total files> <downloaded>/<total> <name>`
const LFSProgressLineRe = /^(.+?)\s{1}(\d+)\/(\d+)\s{1}(\d+)\/(\d+)\s{1}(.+)$/

export class GitLFSProgressParser {
  public parse(line: string): IGitProgress | IGitOutput {
    const cannotParseResult: IGitOutput = {
      kind: 'context',
      text: line,
      percent: 0,
    }

    const matches = line.match(LFSProgressLineRe)
    if (!matches || matches.length !== 7) {
      return cannotParseResult
    }

    const direction = matches[1]
    const current = parseInt(matches[2], 10)
    const totalFiles = parseInt(matches[3], 10)
    const downloadedBytes = parseInt(matches[4], 10)
    const totalBytes = parseInt(matches[5], 10)
    const name = matches[6]

    if (
      !direction ||
      !current ||
      !totalFiles ||
      !downloadedBytes ||
      !totalBytes ||
      !name
    ) {
      return cannotParseResult
    }

    if (
      isNaN(current) ||
      isNaN(totalFiles) ||
      isNaN(downloadedBytes) ||
      isNaN(totalBytes)
    ) {
      return cannotParseResult
    }

    const percent = downloadedBytes / totalBytes
    const info: IGitProgressInfo = {
      title: `Downloading ${name}…`,
      value: downloadedBytes,
      total: totalBytes,
      percent,
      done: false,
      text: line,
    }
    return {
      kind: 'progress',
      percent,
      details: info,
    }
  }
}
{'fraction_non_alphanumeric': 0.13720703125, 'fraction_numerical': 0.02294921875, 'mean_word_length': 2.9403846153846156, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 11, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '635135', 'n_tokens_mistral': 700, 'n_tokens_neox': 653, 'n_words': 145}