import { ChildProcess } from "child_process" ; import { GitProcess , IGitExecutionOptions } from "dugite" ; export interface IGitOptions { lineHandler ? : ( line : string ) => Promise < void > ; processCallback ? : ( process : ChildProcess ) => void ; stdin ? : string | Buffer ; workDir ? : string ; trimTrailingNewline ? : boolean ; trace ? : boolean ; } export const emptyBlobName = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391" ; export const emptyTreeName = "4b825dc642cb6eb9a060e54bf8d69288fbee4904" ; function trimTrailingNewline ( str ) { return str . replace ( /\r?\n$/ , "" ) ; } export function git ( args , options ? ) { const workDir = options && options . workDir || "." ; if ( options && options . trace ) { process . stderr . write ( `Called 'git ${ args . join ( " " ) }' in '${ workDir }':\n${ new Error ( ) . stack }\n` ) ; } return new Promise < string > ( ( resolve , reject ) => { if ( options && options . lineHandler ) { const lineHandler = options . lineHandler ; if ( options . processCallback ) { reject ( new Error ( "line handler *and* process callback set" ) ) ; return ; } options . processCallback = ( process ) : void => { process . on ( "exit" , ( code , signal ) => { if ( signal ) { reject ( new Error ( `Received signal ${ signal }` ) ) ; } else if ( code ) { reject ( new Error ( `Received code ${ code }` ) ) ; } } ) ; if ( ! process . stdout ) { throw new Error ( `No stdout for "git ${ args . join ( " " ) }` ) ; } let linePromise ; const handleLine = ( line ) : boolean => { try { if ( ! linePromise ) { linePromise = lineHandler ( line ) ; } else { linePromise = linePromise . then ( ( ) => { return lineHandler ( line ) ; } ) ; } linePromise . catch ( ( reason ) => { reject ( reason ) ; process . kill ( ) ; } ) ; } catch ( reason ) { reject ( reason ) ; process . kill ( ) ; return false ; } return true ; } ; let buffer = "" ; process . stdout . on ( "data" , ( chunk ) => { buffer += chunk ; for ( ; ; ) { const eol = buffer . indexOf ( "\n" ) ; if ( eol < 0 ) { break ; } if ( ! handleLine ( buffer . substr ( 0 , eol ) ) ) { return ; } buffer = buffer . substr ( eol + 1 ) ; } } ) ; process . stdout . on ( "end" , ( ) => { if ( buffer . length > 0 ) { handleLine ( buffer ) ; } if ( linePromise ) { linePromise . then ( ( ) => { resolve ( "" ) ; } ) . catch ( ( reason ) => { reject ( reason ) ; } ) ; } else { resolve ( "" ) ; } } ) ; } ; } GitProcess . exec ( args , workDir , options as IGitExecutionOptions ) . then ( ( result ) => { if ( result . exitCode ) { reject ( new Error ( `git ${ args . join ( " " ) } failed: ${ result . exitCode },\n${ result . stderr }` ) ) ; return ; } if ( options && options . trace ) { process . stderr . write ( `Output of 'git ${ args . join ( " " ) }':\nstderr: ${ result . stderr }\nstdout: ${ result . stdout }\n` ) ; } resolve ( ! options || options . trimTrailingNewline === false ? result . stdout : trimTrailingNewline ( result . stdout ) ) ; } ) . catch ( ( reason ) => { reject ( reason ) ; } ) ; } ) ; } param { string } argument param { string | undefined } workDir returns { string | undefined } export async function revParse ( argument , workDir ? ) { const result = await GitProcess . exec ( [ "rev-parse" , "--verify" , "-q" , argument ] , workDir || "." ) ; return result . exitCode ? undefined : trimTrailingNewline ( result . stdout ) ; } param { string [ ] } rangeArgs param { string | undefined } workDir returns export async function revListCount ( rangeArgs , workDir = "." ) { const gitArgs = [ "rev-list" , "--count" ] ; if ( typeof ( rangeArgs ) === "string" ) { gitArgs . push ( rangeArgs ) ; } else { gitArgs . push ( ... rangeArgs ) ; } const result = await GitProcess . exec ( gitArgs , workDir ) ; if ( result . exitCode ) { throw new Error ( `Could not determine count for ${ rangeArgs }: ${ result . stderr }` ) ; } return parseInt ( result . stdout , 10 ) ; } param { string } commit param { string } workDir returns { boolean } export async function commitExists ( commit , workDir ) { return await revParse ( `${ commit }^{commit}` , workDir ) !== undefined ; } export async function gitConfig ( key , workDir ? ) { const result = await GitProcess . exec ( [ "config" , key ] , workDir || "." ) ; if ( result . exitCode !== 0 ) { return undefined ; } return trimTrailingNewline ( result . stdout ) ; } export async function gitConfigForEach ( key , callbackfn , workDir ? ) { const result = await GitProcess . exec ( [ "config" , "--get-all" , key ] , workDir || "." ) ; result . stdout . split ( /\r?\n/ ) . map ( callbackfn ) ; } export async function gitCommandExists ( command , workDir ? ) { const result = await GitProcess . exec ( [ command , "-h" ] , workDir || "." ) ; return result . exitCode === 129 ; }