11import * as cp from 'child_process' ;
22import { Config } from './config' ;
3- import { GitCommandStatus , GitCommit , GitCommitDetails , GitCommitNode , GitFileChangeType , GitRef , GitResetMode , GitUnsavedChangesCmdResp } from './types' ;
3+ import { GitCommandStatus , GitCommit , GitCommitDetails , GitCommitNode , GitFileChangeType , GitRef , GitResetMode , GitUnsavedChanges } from './types' ;
44
55const eolRegex = / \r \n | \r | \n / g;
66const gitLogSeparator = 'XX7Nal-YARtTpjCikii9nJxER19D6diSyk-AWkPb' ;
@@ -24,15 +24,15 @@ export class DataSource {
2424
2525 public isGitRepository ( ) {
2626 return new Promise < boolean > ( ( resolve ) => {
27- cp . exec ( this . gitExecPath + ' rev-parse --git-dir', this . execOptions , ( err ) => {
27+ this . execGit ( ' rev-parse --git-dir', ( err ) => {
2828 resolve ( ! err ) ;
2929 } ) ;
3030 } ) ;
3131 }
3232
3333 public getBranches ( showRemoteBranches : boolean ) {
3434 return new Promise < string [ ] > ( ( resolve ) => {
35- cp . exec ( this . gitExecPath + ' branch' + ( showRemoteBranches ? ' -a' : '' ) , this . execOptions , ( err , stdout ) => {
35+ this . execGit ( ' branch' + ( showRemoteBranches ? ' -a' : '' ) , ( err , stdout ) => {
3636 if ( ! err ) {
3737 let lines = stdout . split ( eolRegex ) ;
3838 let branches : string [ ] = [ ] ;
@@ -106,7 +106,7 @@ export class DataSource {
106106 public async commitDetails ( commitHash : string ) {
107107 try {
108108 let details = await new Promise < GitCommitDetails > ( ( resolve , reject ) => {
109- cp . exec ( this . gitExecPath + ' show --quiet ' + commitHash + ' --format="' + gitCommitDetailsFormat + '"' , this . execOptions , ( err , stdout ) => {
109+ this . execGit ( ' show --quiet ' + commitHash + ' --format="' + gitCommitDetailsFormat + '"' , ( err , stdout ) => {
110110 if ( ! err ) {
111111 let lines = stdout . split ( eolRegex ) ;
112112 let commitInfo = lines [ 0 ] . split ( gitLogSeparator ) ;
@@ -127,7 +127,7 @@ export class DataSource {
127127 } ) ;
128128 let fileLookup : { [ file : string ] : number } = { } ;
129129 await new Promise ( ( resolve , reject ) => {
130- cp . exec ( this . gitExecPath + ' diff-tree --name-status -r -m --root --find-renames --diff-filter=AMDR ' + commitHash , this . execOptions , ( err , stdout ) => {
130+ this . execGit ( ' diff-tree --name-status -r -m --root --find-renames --diff-filter=AMDR ' + commitHash , ( err , stdout ) => {
131131 if ( ! err ) {
132132 let lines = stdout . split ( eolRegex ) ;
133133 for ( let i = 1 ; i < lines . length - 1 ; i ++ ) {
@@ -144,7 +144,7 @@ export class DataSource {
144144 } ) ;
145145 } ) ;
146146 await new Promise ( ( resolve , reject ) => {
147- cp . exec ( this . gitExecPath + ' diff-tree --numstat -r -m --root --find-renames --diff-filter=AMDR ' + commitHash , this . execOptions , ( err , stdout ) => {
147+ this . execGit ( ' diff-tree --numstat -r -m --root --find-renames --diff-filter=AMDR ' + commitHash , ( err , stdout ) => {
148148 if ( ! err ) {
149149 let lines = stdout . split ( eolRegex ) ;
150150 for ( let i = 1 ; i < lines . length - 1 ; i ++ ) {
@@ -169,20 +169,8 @@ export class DataSource {
169169 }
170170 }
171171
172- public async getCommitFile ( commitHash : string , filePath : string ) {
173- return new Promise < string > ( ( resolve ) => {
174- let args = [ 'show' , commitHash + ':' + filePath ] , stdout = '' , err = false ;
175- const cmd = cp . spawn ( this . gitPath , args , this . execOptions ) ;
176- cmd . stdout . on ( 'data' , ( d ) => { stdout += d ; } ) ;
177- cmd . on ( 'error' , ( ) => {
178- resolve ( '' ) ;
179- err = true ;
180- } ) ;
181- cmd . on ( 'exit' , ( code ) => {
182- if ( err ) return ;
183- resolve ( code === 0 ? stdout : '' ) ;
184- } ) ;
185- } ) ;
172+ public getCommitFile ( commitHash : string , filePath : string ) {
173+ return this . spawnGit ( [ 'show' , commitHash + ':' + filePath ] , stdout => stdout , '' ) ;
186174 }
187175
188176 public addTag ( tagName : string , commitHash : string ) {
@@ -225,22 +213,9 @@ export class DataSource {
225213 return this . runGitCommand ( 'reset --' + resetMode + ' ' + commitHash ) ;
226214 }
227215
228- private async runGitCommand ( command : string ) {
229- return new Promise < GitCommandStatus > ( ( resolve ) => {
230- cp . exec ( this . gitExecPath + ' ' + command , this . execOptions , ( err ) => {
231- if ( ! err ) {
232- resolve ( null ) ;
233- } else {
234- let lines = err . message . split ( eolRegex ) ;
235- resolve ( lines . slice ( 1 , lines . length - 1 ) . join ( '\n' ) ) ;
236- }
237- } ) ;
238- } ) ;
239- }
240-
241- private async getRefs ( showRemoteBranches : boolean ) {
216+ private getRefs ( showRemoteBranches : boolean ) {
242217 return new Promise < GitRef [ ] > ( ( resolve ) => {
243- cp . exec ( this . gitExecPath + ' show-ref ' + ( showRemoteBranches ? '' : '--heads --tags' ) + ' -d' , this . execOptions , ( err , stdout ) => {
218+ this . execGit ( ' show-ref ' + ( showRemoteBranches ? '' : '--heads --tags' ) + ' -d' , ( err , stdout ) => {
244219 if ( ! err ) {
245220 let lines = stdout . split ( eolRegex ) ;
246221 let refs : GitRef [ ] = [ ] ;
@@ -267,56 +242,72 @@ export class DataSource {
267242 } ) ;
268243 }
269244
270- private async getGitLog ( branch : string , num : number , showRemoteBranches : boolean ) {
271- return new Promise < GitCommit [ ] > ( ( resolve ) => {
272- let args = [ 'log' , '--max-count=' + num , '--format=' + gitLogFormat , '--date-order' ] , stdout = '' , err = false ;
273- if ( branch !== '' ) {
274- args . push ( escapeRefName ( branch ) ) ;
275- } else {
276- args . push ( '--branches' ) ;
277- if ( showRemoteBranches ) args . push ( '--remotes' ) ;
245+ private getGitLog ( branch : string , num : number , showRemoteBranches : boolean ) {
246+ let args = [ 'log' , '--max-count=' + num , '--format=' + gitLogFormat , '--date-order' ] ;
247+ if ( branch !== '' ) {
248+ args . push ( escapeRefName ( branch ) ) ;
249+ } else {
250+ args . push ( '--branches' ) ;
251+ if ( showRemoteBranches ) args . push ( '--remotes' ) ;
252+ }
253+
254+ return this . spawnGit ( args , ( stdout ) => {
255+ let lines = stdout . split ( eolRegex ) ;
256+ let gitCommits : GitCommit [ ] = [ ] ;
257+ for ( let i = 0 ; i < lines . length - 1 ; i ++ ) {
258+ let line = lines [ i ] . split ( gitLogSeparator ) ;
259+ if ( line . length !== 6 ) break ;
260+ gitCommits . push ( { hash : line [ 0 ] , parentHashes : line [ 1 ] . split ( ' ' ) , author : line [ 2 ] , email : line [ 3 ] , date : parseInt ( line [ 4 ] ) , message : line [ 5 ] } ) ;
278261 }
262+ return gitCommits ;
263+ } , [ ] ) ;
264+ }
265+
266+ private getGitUnsavedChanges ( ) {
267+ return new Promise < GitUnsavedChanges | null > ( ( resolve ) => {
268+ this . execGit ( 'status -s --branch --untracked-files --porcelain' , ( err , stdout ) => {
269+ if ( ! err ) {
270+ let lines = stdout . split ( eolRegex ) ;
271+ resolve ( lines . length > 2 ? { branch : lines [ 0 ] . substring ( 3 ) . split ( '...' ) [ 0 ] , changes : lines . length - 2 } : null ) ;
272+ } else {
273+ resolve ( null ) ;
274+ }
275+ } ) ;
276+ } ) ;
277+ }
279278
279+ private runGitCommand ( command : string ) {
280+ return new Promise < GitCommandStatus > ( ( resolve ) => {
281+ this . execGit ( command , ( err ) => {
282+ if ( ! err ) {
283+ resolve ( null ) ;
284+ } else {
285+ let lines = err . message . split ( eolRegex ) ;
286+ resolve ( lines . slice ( 1 , lines . length - 1 ) . join ( '\n' ) ) ;
287+ }
288+ } ) ;
289+ } ) ;
290+ }
291+
292+ private execGit ( command : string , callback : { ( error : Error | null , stdout : string , stderr : string ) : void } ) {
293+ cp . exec ( this . gitExecPath + ' ' + command , this . execOptions , callback ) ;
294+ }
295+
296+ private spawnGit < T > ( args : string [ ] , successValue : { ( stdout : string ) : T } , errorValue : T ) {
297+ return new Promise < T > ( ( resolve ) => {
298+ let stdout = '' , err = false ;
280299 const cmd = cp . spawn ( this . gitPath , args , this . execOptions ) ;
281300 cmd . stdout . on ( 'data' , ( d ) => { stdout += d ; } ) ;
282301 cmd . on ( 'error' , ( ) => {
283- resolve ( [ ] ) ;
302+ resolve ( errorValue ) ;
284303 err = true ;
285304 } ) ;
286305 cmd . on ( 'exit' , ( code ) => {
287306 if ( err ) return ;
288- if ( code === 0 ) {
289- let lines = stdout . split ( eolRegex ) ;
290- let gitCommits : GitCommit [ ] = [ ] ;
291- for ( let i = 0 ; i < lines . length - 1 ; i ++ ) {
292- let line = lines [ i ] . split ( gitLogSeparator ) ;
293- if ( line . length !== 6 ) break ;
294- gitCommits . push ( { hash : line [ 0 ] , parentHashes : line [ 1 ] . split ( ' ' ) , author : line [ 2 ] , email : line [ 3 ] , date : parseInt ( line [ 4 ] ) , message : line [ 5 ] } ) ;
295- }
296- resolve ( gitCommits ) ;
297- } else {
298- resolve ( [ ] ) ;
299- }
307+ resolve ( code === 0 ? successValue ( stdout ) : errorValue ) ;
300308 } ) ;
301309 } ) ;
302310 }
303-
304- private getGitUnsavedChanges ( ) {
305- try {
306- return new Promise < GitUnsavedChangesCmdResp > ( ( resolve , reject ) => {
307- cp . exec ( this . gitExecPath + ' status -s --branch --untracked-files --porcelain' , this . execOptions , ( err , stdout ) => {
308- if ( ! err ) {
309- let lines = stdout . split ( eolRegex ) ;
310- resolve ( lines . length > 2 ? { branch : lines [ 0 ] . substring ( 3 ) . split ( '...' ) [ 0 ] , changes : lines . length - 2 } : null ) ;
311- } else {
312- reject ( ) ;
313- }
314- } ) ;
315- } ) ;
316- } catch ( e ) {
317- return null ;
318- }
319- }
320311}
321312
322313function escapeRefName ( str : string ) {
0 commit comments