-
Notifications
You must be signed in to change notification settings - Fork 399
Run git commands in dedicated renderer process #688
Changes from all commits
c07d65b
53384de
519ebfc
c9b2978
f91e8cd
8fe00d5
e9aa22d
169ab20
72b5ccc
761ff7d
54c1653
09fdc01
197b332
364b086
ed4c5ed
ca3411c
bc7ae77
3bda0a9
2228185
325f48b
2bd9e37
684ca4a
6494404
e7074b7
5d2fef3
9b3a288
0187c4b
de1918b
b86ad95
66a1a08
ff425c4
bcd2722
8bfa4ae
4557f46
097714d
ce2bcc3
8e211a1
e43c271
6505e04
23026e2
7b29cc7
045c009
1038161
29c36bb
cd71d68
77fdc0d
0bb8e57
d11877e
80956e2
94e0b8b
53bf504
5db1010
920b4ca
91908e5
d868091
c991157
5743cb3
dca043e
fc16dd5
a0df97c
652459d
7e7d4ce
aa09a96
863209d
bc3073c
55f9882
6502cbf
c3b875e
b7f4b20
5e34e0e
6359895
c39aaf6
95fb731
7a95446
5d309d1
3066270
4084aec
8727017
7bab3da
1740e9b
c3b4b23
e708668
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,14 +2,14 @@ import path from 'path'; | |
import os from 'os'; | ||
|
||
import {CompositeDisposable} from 'event-kit'; | ||
|
||
import {GitProcess} from 'dugite'; | ||
import {parse as parseDiff} from 'what-the-diff'; | ||
|
||
import GitPromptServer from './git-prompt-server'; | ||
import AsyncQueue from './async-queue'; | ||
import {getPackageRoot, getDugitePath, readFile, fileExists, writeFile, isFileExecutable} from './helpers'; | ||
import {getPackageRoot, getDugitePath, readFile, fileExists, fsStat, writeFile, isFileExecutable} from './helpers'; | ||
import GitTimingsView from './views/git-timings-view'; | ||
import WorkerManager from './worker-manager'; | ||
|
||
const LINE_ENDING_REGEX = /\r?\n/; | ||
|
||
|
@@ -57,6 +57,7 @@ export default class GitShellOutStrategy { | |
} | ||
|
||
this.prompt = options.prompt || (query => Promise.reject()); | ||
this.workerManager = options.workerManager; | ||
} | ||
|
||
/* | ||
|
@@ -131,6 +132,7 @@ export default class GitShellOutStrategy { | |
const options = { | ||
env, | ||
processCallback: child => { | ||
// TODO: move callback to renderer process. send child.pid back to add cancel listener | ||
child.on('error', err => { | ||
console.warn('Error executing: ' + formattedArgs + ':'); | ||
console.warn(err.stack); | ||
|
@@ -156,51 +158,68 @@ export default class GitShellOutStrategy { | |
if (process.env.PRINT_GIT_TIMES) { | ||
console.time(`git:${formattedArgs}`); | ||
} | ||
return new Promise(resolve => { | ||
timingMarker.mark('nexttick'); | ||
setImmediate(() => { | ||
timingMarker.mark('execute'); | ||
resolve(GitProcess.exec(args, this.workingDir, options) | ||
.then(({stdout, stderr, exitCode}) => { | ||
timingMarker.finalize(); | ||
if (process.env.PRINT_GIT_TIMES) { | ||
console.timeEnd(`git:${formattedArgs}`); | ||
} | ||
if (gitPromptServer) { | ||
gitPromptServer.terminate(); | ||
} | ||
subscriptions.dispose(); | ||
|
||
if (diagnosticsEnabled) { | ||
const headerStyle = 'font-weight: bold; color: blue;'; | ||
|
||
console.groupCollapsed(`git:${formattedArgs}`); | ||
console.log('%cexit status%c %d', headerStyle, 'font-weight: normal; color: black;', exitCode); | ||
console.log('%cstdout', headerStyle); | ||
console.log(stdout); | ||
console.log('%cstderr', headerStyle); | ||
console.log(stderr); | ||
console.groupEnd(); | ||
} | ||
|
||
if (exitCode) { | ||
const err = new GitError( | ||
`${formattedArgs} exited with code ${exitCode}\nstdout: ${stdout}\nstderr: ${stderr}`, | ||
); | ||
err.code = exitCode; | ||
err.stdErr = stderr; | ||
err.stdOut = stdout; | ||
err.command = formattedArgs; | ||
return Promise.reject(err); | ||
} | ||
return stdout; | ||
})); | ||
}); | ||
return new Promise(async (resolve, reject) => { | ||
const {stdout, stderr, exitCode, timing} = await this.executeGitCommand(args, options, timingMarker); | ||
if (timing) { | ||
const {execTime, spawnTime, ipcTime} = timing; | ||
const now = performance.now(); | ||
timingMarker.mark('nexttick', now - execTime - spawnTime - ipcTime); | ||
timingMarker.mark('execute', now - execTime - ipcTime); | ||
timingMarker.mark('ipc', now - ipcTime); | ||
} | ||
timingMarker.finalize(); | ||
if (process.env.PRINT_GIT_TIMES) { | ||
console.timeEnd(`git:${formattedArgs}`); | ||
} | ||
if (gitPromptServer) { | ||
gitPromptServer.terminate(); | ||
} | ||
subscriptions.dispose(); | ||
|
||
if (diagnosticsEnabled) { | ||
const headerStyle = 'font-weight: bold; color: blue;'; | ||
|
||
console.groupCollapsed(`git:${formattedArgs}`); | ||
console.log('%cexit status%c %d', headerStyle, 'font-weight: normal; color: black;', exitCode); | ||
console.log('%cstdout', headerStyle); | ||
console.log(stdout); | ||
console.log('%cstderr', headerStyle); | ||
console.log(stderr); | ||
console.groupEnd(); | ||
} | ||
|
||
if (exitCode) { | ||
const err = new GitError( | ||
`${formattedArgs} exited with code ${exitCode}\nstdout: ${stdout}\nstderr: ${stderr}`, | ||
); | ||
err.code = exitCode; | ||
err.stdErr = stderr; | ||
err.stdOut = stdout; | ||
err.command = formattedArgs; | ||
reject(err); | ||
} | ||
resolve(stdout); | ||
}); | ||
}, {parallel: !writeOperation}); | ||
/* eslint-enable no-console */ | ||
} | ||
|
||
executeGitCommand(args, options, marker = null) { | ||
if (process.env.ATOM_GITHUB_INLINE_GIT_EXEC || !WorkerManager.getInstance().isReady()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 for offering an env var to opt out of the workers for when someone runs this on their Raspberry Pi 😉 If I'm reading it right it'll prevent the first worker from spawning too? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yup 👍 . Second expression after |
||
marker && marker.mark('nexttick'); | ||
const promise = GitProcess.exec(args, this.workingDir, options); | ||
marker && marker.mark('execute'); | ||
return promise; | ||
} else { | ||
const workerManager = this.workerManager || WorkerManager.getInstance(); | ||
return workerManager.request({ | ||
args, | ||
workingDir: this.workingDir, | ||
options, | ||
}); | ||
} | ||
} | ||
|
||
/** | ||
* Execute a git command that may create a commit. If the command fails because the GPG binary was invoked and unable | ||
* 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 { | |
|
||
async isGitRepository() { | ||
try { | ||
await fsStat(this.workingDir); // fails if folder doesn't exist | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cool, cool. This fixes that uncaught-exception-in-Promise from the test suite I presume. |
||
await this.exec(['rev-parse', '--resolve-git-dir', path.join(this.workingDir, '.git')]); | ||
return true; | ||
} catch (e) { | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8"> | ||
<title></title> | ||
<script type="text/javascript"> | ||
const qs = require('querystring') | ||
const jsPath = qs.parse(window.location.search.substr(1)).js | ||
require(jsPath) | ||
</script> | ||
</head> | ||
<body> | ||
<h1>GitHub Package Git Execution Window</h1> | ||
<p> | ||
Hi there! I'm a window used by the GitHub package to execute Git commands in the background. My PID is <script>document.write(process.pid)</script>. | ||
</p> | ||
<p>Last command: <span id='command'></span></p> | ||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The day I discovered how
%c
works inconsole.log()
was a dangerous day.