@@ -2,14 +2,14 @@ import path from 'path';
2
2
import os from 'os' ;
3
3
4
4
import { CompositeDisposable } from 'event-kit' ;
5
-
6
5
import { GitProcess } from 'dugite' ;
7
6
import { parse as parseDiff } from 'what-the-diff' ;
8
7
9
8
import GitPromptServer from './git-prompt-server' ;
10
9
import AsyncQueue from './async-queue' ;
11
- import { getPackageRoot , getDugitePath , readFile , fileExists , writeFile , isFileExecutable } from './helpers' ;
10
+ import { getPackageRoot , getDugitePath , readFile , fileExists , fsStat , writeFile , isFileExecutable } from './helpers' ;
12
11
import GitTimingsView from './views/git-timings-view' ;
12
+ import WorkerManager from './worker-manager' ;
13
13
14
14
const LINE_ENDING_REGEX = / \r ? \n / ;
15
15
@@ -57,6 +57,7 @@ export default class GitShellOutStrategy {
57
57
}
58
58
59
59
this . prompt = options . prompt || ( query => Promise . reject ( ) ) ;
60
+ this . workerManager = options . workerManager ;
60
61
}
61
62
62
63
/*
@@ -131,6 +132,7 @@ export default class GitShellOutStrategy {
131
132
const options = {
132
133
env,
133
134
processCallback : child => {
135
+ // TODO: move callback to renderer process. send child.pid back to add cancel listener
134
136
child . on ( 'error' , err => {
135
137
console . warn ( 'Error executing: ' + formattedArgs + ':' ) ;
136
138
console . warn ( err . stack ) ;
@@ -156,51 +158,68 @@ export default class GitShellOutStrategy {
156
158
if ( process . env . PRINT_GIT_TIMES ) {
157
159
console . time ( `git:${ formattedArgs } ` ) ;
158
160
}
159
- return new Promise ( resolve => {
160
- timingMarker . mark ( 'nexttick' ) ;
161
- setImmediate ( ( ) => {
162
- timingMarker . mark ( 'execute' ) ;
163
- resolve ( GitProcess . exec ( args , this . workingDir , options )
164
- . then ( ( { stdout, stderr, exitCode} ) => {
165
- timingMarker . finalize ( ) ;
166
- if ( process . env . PRINT_GIT_TIMES ) {
167
- console . timeEnd ( `git:${ formattedArgs } ` ) ;
168
- }
169
- if ( gitPromptServer ) {
170
- gitPromptServer . terminate ( ) ;
171
- }
172
- subscriptions . dispose ( ) ;
173
-
174
- if ( diagnosticsEnabled ) {
175
- const headerStyle = 'font-weight: bold; color: blue;' ;
176
-
177
- console . groupCollapsed ( `git:${ formattedArgs } ` ) ;
178
- console . log ( '%cexit status%c %d' , headerStyle , 'font-weight: normal; color: black;' , exitCode ) ;
179
- console . log ( '%cstdout' , headerStyle ) ;
180
- console . log ( stdout ) ;
181
- console . log ( '%cstderr' , headerStyle ) ;
182
- console . log ( stderr ) ;
183
- console . groupEnd ( ) ;
184
- }
185
-
186
- if ( exitCode ) {
187
- const err = new GitError (
188
- `${ formattedArgs } exited with code ${ exitCode } \nstdout: ${ stdout } \nstderr: ${ stderr } ` ,
189
- ) ;
190
- err . code = exitCode ;
191
- err . stdErr = stderr ;
192
- err . stdOut = stdout ;
193
- err . command = formattedArgs ;
194
- return Promise . reject ( err ) ;
195
- }
196
- return stdout ;
197
- } ) ) ;
198
- } ) ;
161
+ return new Promise ( async ( resolve , reject ) => {
162
+ const { stdout, stderr, exitCode, timing} = await this . executeGitCommand ( args , options , timingMarker ) ;
163
+ if ( timing ) {
164
+ const { execTime, spawnTime, ipcTime} = timing ;
165
+ const now = performance . now ( ) ;
166
+ timingMarker . mark ( 'nexttick' , now - execTime - spawnTime - ipcTime ) ;
167
+ timingMarker . mark ( 'execute' , now - execTime - ipcTime ) ;
168
+ timingMarker . mark ( 'ipc' , now - ipcTime ) ;
169
+ }
170
+ timingMarker . finalize ( ) ;
171
+ if ( process . env . PRINT_GIT_TIMES ) {
172
+ console . timeEnd ( `git:${ formattedArgs } ` ) ;
173
+ }
174
+ if ( gitPromptServer ) {
175
+ gitPromptServer . terminate ( ) ;
176
+ }
177
+ subscriptions . dispose ( ) ;
178
+
179
+ if ( diagnosticsEnabled ) {
180
+ const headerStyle = 'font-weight: bold; color: blue;' ;
181
+
182
+ console . groupCollapsed ( `git:${ formattedArgs } ` ) ;
183
+ console . log ( '%cexit status%c %d' , headerStyle , 'font-weight: normal; color: black;' , exitCode ) ;
184
+ console . log ( '%cstdout' , headerStyle ) ;
185
+ console . log ( stdout ) ;
186
+ console . log ( '%cstderr' , headerStyle ) ;
187
+ console . log ( stderr ) ;
188
+ console . groupEnd ( ) ;
189
+ }
190
+
191
+ if ( exitCode ) {
192
+ const err = new GitError (
193
+ `${ formattedArgs } exited with code ${ exitCode } \nstdout: ${ stdout } \nstderr: ${ stderr } ` ,
194
+ ) ;
195
+ err . code = exitCode ;
196
+ err . stdErr = stderr ;
197
+ err . stdOut = stdout ;
198
+ err . command = formattedArgs ;
199
+ reject ( err ) ;
200
+ }
201
+ resolve ( stdout ) ;
199
202
} ) ;
200
203
} , { parallel : ! writeOperation } ) ;
201
204
/* eslint-enable no-console */
202
205
}
203
206
207
+ executeGitCommand ( args , options , marker = null ) {
208
+ if ( process . env . ATOM_GITHUB_INLINE_GIT_EXEC || ! WorkerManager . getInstance ( ) . isReady ( ) ) {
209
+ marker && marker . mark ( 'nexttick' ) ;
210
+ const promise = GitProcess . exec ( args , this . workingDir , options ) ;
211
+ marker && marker . mark ( 'execute' ) ;
212
+ return promise ;
213
+ } else {
214
+ const workerManager = this . workerManager || WorkerManager . getInstance ( ) ;
215
+ return workerManager . request ( {
216
+ args,
217
+ workingDir : this . workingDir ,
218
+ options,
219
+ } ) ;
220
+ }
221
+ }
222
+
204
223
/**
205
224
* Execute a git command that may create a commit. If the command fails because the GPG binary was invoked and unable
206
225
* to acquire a passphrase (because the pinentry program attempted to use a tty), retry with a `GitPromptServer`.
@@ -220,6 +239,7 @@ export default class GitShellOutStrategy {
220
239
221
240
async isGitRepository ( ) {
222
241
try {
242
+ await fsStat ( this . workingDir ) ; // fails if folder doesn't exist
223
243
await this . exec ( [ 'rev-parse' , '--resolve-git-dir' , path . join ( this . workingDir , '.git' ) ] ) ;
224
244
return true ;
225
245
} catch ( e ) {
0 commit comments