<commit_before>import {WorkingDirectoryStatus, FileStatus, WorkingDirectoryFileChange} from '../models/status'
import Repository from '../models/repository'
import {Repository as ohnogit} from 'ohnogit'

import * as path from 'path'
import * as fs from 'fs'
import * as cp from 'child_process'

/** The encapsulation of the result from 'git status' */
export class StatusResult {
  private exists: boolean
  private workingDirectory: WorkingDirectoryStatus

  /** factory method when 'git status' is unsuccessful */
  public static NotFound(): StatusResult {
    return new StatusResult(false, new WorkingDirectoryStatus())
  }

  /** factory method for a successful 'git status' result  */
  public static FromStatus(status: WorkingDirectoryStatus): StatusResult {
    return new StatusResult(true, status)
  }

  public constructor(exists: boolean, workingDirectory: WorkingDirectoryStatus) {
    this.exists = exists
    this.workingDirectory = workingDirectory
  }

  /** true if the repository exists at the given location */
  public getExists(): boolean {
    return this.exists
  }

  /** the absolute path to the repository's working directory */
  public getWorkingDirectory(): WorkingDirectoryStatus {
    return this.workingDirectory
  }
}

/**
 * Interactions with a local Git repository
 */
export class LocalGitOperations {

   /**
    *  Retrieve the status for a given repository,
    *  and fail gracefully if the location is not a Git repository
    */
   public static async getStatus(repository: Repository): Promise<StatusResult> {
      const path = repository.getPath()
      const repo = ohnogit.open(path)

      await repo.refreshStatus()

      const statuses = repo.getCachedPathStatuses()
      let workingDirectory = new WorkingDirectoryStatus()

      for (const path in statuses) {
         const result = statuses[path]
         const status = this.mapStatus(repo, result)
         if (status !== FileStatus.Ignored) {
           workingDirectory.add(path, status)
         }
      }

      return StatusResult.FromStatus(workingDirectory)
  }

  /**
   *  Find the path to the embedded Git environment
   */
  private static resolveGit(): string {
    if (process.platform === 'darwin') {
      return path.join(__dirname, 'git/bin/git')
    } else if (process.platform === 'win32') {
      return path.join(__dirname, 'git/cmd/git.exe')
    } else {
      throw new Error('Git not supported on platform: ' + process.platform)
    }
  }

  /**
   *  Execute a command using the embedded Git environment
   */
  private static execGitCommand(args: string[], path: string): Promise<void> {
    return new Promise<void>(function(resolve, reject) {
      const gitLocation = LocalGitOperations.resolveGit()
      fs.stat(gitLocation, function (err, result) {

        if (err) {
          reject(err)
          return
        }

        const formatArgs = 'executing: git ' + args.join(' ')

        cp.execFile(gitLocation, args, { cwd: path, encoding: 'utf8' }, function(err, output, stdErr) {
          if (err) {
            console.error(formatArgs)
            reject(err)
            return
          }

          console.log(formatArgs)
          resolve()
        })

      })
    })
  }

  public static async createCommit(repository: Repository, title: string, files: WorkingDirectoryFileChange[]) {

    // TODO: if repository is unborn, reset to empty tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904

    // reset the index
    await this.execGitCommand([ 'reset', 'HEAD', '--mixed' ], repository.getPath())

    // stage each of the files
    // TODO: staging hunks needs to be done in here as well
    await files.map(async (file, index, array) => {
      await this.execGitCommand([ 'add', '-u', file.getPath() ], repository.getPath())
    })

    // TODO: sanitize this input
    await this.execGitCommand([ 'commit', '-m', title ] , repository.getPath())
  }

  private static mapStatus(repo: ohnogit, status: number): FileStatus {<commit_msg>We're Gonna Want A String<commit_after>import {WorkingDirectoryStatus, FileStatus, WorkingDirectoryFileChange} from '../models/status'
import Repository from '../models/repository'
import {Repository as ohnogit} from 'ohnogit'

import * as path from 'path'
import * as fs from 'fs'
import * as cp from 'child_process'

/** The encapsulation of the result from 'git status' */
export class StatusResult {
  private exists: boolean
  private workingDirectory: WorkingDirectoryStatus

  /** factory method when 'git status' is unsuccessful */
  public static NotFound(): StatusResult {
    return new StatusResult(false, new WorkingDirectoryStatus())
  }

  /** factory method for a successful 'git status' result  */
  public static FromStatus(status: WorkingDirectoryStatus): StatusResult {
    return new StatusResult(true, status)
  }

  public constructor(exists: boolean, workingDirectory: WorkingDirectoryStatus) {
    this.exists = exists
    this.workingDirectory = workingDirectory
  }

  /** true if the repository exists at the given location */
  public getExists(): boolean {
    return this.exists
  }

  /** the absolute path to the repository's working directory */
  public getWorkingDirectory(): WorkingDirectoryStatus {
    return this.workingDirectory
  }
}

/**
 * Interactions with a local Git repository
 */
export class LocalGitOperations {

   /**
    *  Retrieve the status for a given repository,
    *  and fail gracefully if the location is not a Git repository
    */
   public static async getStatus(repository: Repository): Promise<StatusResult> {
      const path = repository.getPath()
      const repo = ohnogit.open(path)

      await repo.refreshStatus()

      const statuses = repo.getCachedPathStatuses()
      let workingDirectory = new WorkingDirectoryStatus()

      for (const path in statuses) {
         const result = statuses[path]
         const status = this.mapStatus(repo, result)
         if (status !== FileStatus.Ignored) {
           workingDirectory.add(path, status)
         }
      }

      return StatusResult.FromStatus(workingDirectory)
  }

  /**
   *  Find the path to the embedded Git environment
   */
  private static resolveGit(): string {
    if (process.platform === 'darwin') {
      return path.join(__dirname, 'git/bin/git')
    } else if (process.platform === 'win32') {
      return path.join(__dirname, 'git/cmd/git.exe')
    } else {
      throw new Error('Git not supported on platform: ' + process.platform)
    }
  }

  /**
   *  Execute a command using the embedded Git environment
   */
  private static execGitCommand(args: string[], path: string): Promise<string> {
    return new Promise(function(resolve, reject) {
      const gitLocation = LocalGitOperations.resolveGit()
      fs.stat(gitLocation, function (err, result) {

        if (err) {
          reject(err)
          return
        }

        const formatArgs = 'executing: git ' + args.join(' ')

        cp.execFile(gitLocation, args, { cwd: path, encoding: 'utf8' }, function(err, output, stdErr) {
          if (err) {
            console.error(formatArgs)
            reject(err)
            return
          }

          console.log(formatArgs)
          resolve(output)
        })

      })
    })
  }

  public static async createCommit(repository: Repository, title: string, files: WorkingDirectoryFileChange[]) {

    // TODO: if repository is unborn, reset to empty tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904

    // reset the index
    await this.execGitCommand([ 'reset', 'HEAD', '--mixed' ], repository.getPath())

    // stage each of the files
    // TODO: staging hunks needs to be done in here as well
    await files.map(async (file, index, array) => {
      await this.execGitCommand([ 'add', '-u', file.getPath() ], repository.getPath())
    })

    // TODO: sanitize this input
    await this.execGitCommand([ 'commit', '-m', title ] , repository.getPath())
  }

  private static mapStatus(repo: ohnogit, status: number): FileStatus {
{'fraction_non_alphanumeric': 0.10520390292719539, 'fraction_numerical': 0.006755066299724793, 'mean_word_length': 3.0358404846037357, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6489055', 'n_tokens_mistral': 2248, 'n_tokens_neox': 2154, 'n_words': 687}