diff --git a/extensions/typescript/src/utils/electron.ts b/extensions/typescript/src/utils/electron.ts index 25b780e4bfc6f69b67129e1dd0769a507c3ad1cf..a4e08453f9fc1360e077d95478a3ef3e1f9f5089 100644 --- a/extensions/typescript/src/utils/electron.ts +++ b/extensions/typescript/src/utils/electron.ts @@ -37,7 +37,7 @@ function generatePipeName(): string { return path.join(os.tmpdir(), randomName + '.sock'); } -function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string): any { +function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string, stdErrPipeName:string): any { // Set the two unique pipe names and the electron flag as process env var newEnv:any = {}; @@ -47,6 +47,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string newEnv['STDIN_PIPE_NAME'] = stdInPipeName; newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; + newEnv['STDERR_PIPE_NAME'] = stdErrPipeName; newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; return newEnv; @@ -70,29 +71,38 @@ export function fork(modulePath: string, args: string[], options: IForkOptions, callback(err, null); }; - // Generate two unique pipe names + // Generate three unique pipe names var stdInPipeName = generatePipeName(); var stdOutPipeName = generatePipeName(); + let stdErrPipeName = generatePipeName(); - var newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName); + + var newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName, stdErrPipeName); var childProcess: cp.ChildProcess; + // Begin listening to stderr pipe + let stdErrServer = net.createServer((stdErrStream) => { + // From now on the childProcess.stderr is available for reading + childProcess.stderr = stdErrStream; + }); + stdErrServer.listen(stdErrPipeName); + // Begin listening to stdout pipe - var server = net.createServer((stream) => { + let stdOutServer = net.createServer((stdOutStream) => { // The child process will write exactly one chunk with content `ready` when it has installed a listener to the stdin pipe - stream.once('data', (chunk:Buffer) => { + stdOutStream.once('data', (chunk:Buffer) => { // The child process is sending me the `ready` chunk, time to connect to the stdin pipe childProcess.stdin = net.connect(stdInPipeName); // From now on the childProcess.stdout is available for reading - childProcess.stdout = stream; + childProcess.stdout = stdOutStream; resolve(childProcess); }); }); - server.listen(stdOutPipeName); + stdOutServer.listen(stdOutPipeName); var serverClosed = false; var closeServer = () => { @@ -100,7 +110,8 @@ export function fork(modulePath: string, args: string[], options: IForkOptions, return; } serverClosed = true; - server.close(); + stdOutServer.close(); + stdErrServer.close(); }; // Create the process diff --git a/extensions/typescript/src/utils/electronForkStart.ts b/extensions/typescript/src/utils/electronForkStart.ts index 147041bf7d7a99d52bfe7f938eeff946393624e9..46a125060415e04ee6d861629201b9f2635d1f4b 100644 --- a/extensions/typescript/src/utils/electronForkStart.ts +++ b/extensions/typescript/src/utils/electronForkStart.ts @@ -26,9 +26,11 @@ var log = (function() { var stdInPipeName = process.env['STDIN_PIPE_NAME']; var stdOutPipeName = process.env['STDOUT_PIPE_NAME']; +var stdErrPipeName = process.env['STDERR_PIPE_NAME']; log('STDIN_PIPE_NAME: ' + stdInPipeName); log('STDOUT_PIPE_NAME: ' + stdOutPipeName); +log('STDERR_PIPE_NAME: ' + stdErrPipeName); log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']); // stdout redirection to named pipe @@ -44,8 +46,14 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A // handle process.stdout (process).__defineGetter__('stdout', function() { return stdOutStream; }); + // Create a writing stream to the stderr pipe + var stdErrStream = net.connect(stdErrPipeName); + + // unref stdErrStream to behave like a normal standard out + stdErrStream.unref(); + // handle process.stderr - (process).__defineGetter__('stderr', function() { return stdOutStream; }); + (process).__defineGetter__('stderr', function() { return stdErrStream; }); var fsWriteSyncString = function(fd, str, position, encoding) { // fs.writeSync(fd, string[, position[, encoding]]); @@ -79,14 +87,18 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A slicedBuffer = buffer.slice(off, off + len); } - stdOutStream.write(slicedBuffer); + if (fd === 1) { + stdOutStream.write(slicedBuffer); + } else { + stdErrStream.write(slicedBuffer); + } return slicedBuffer.length; }; // handle fs.writeSync(1, ...) var originalWriteSync = fs.writeSync; fs.writeSync = function(fd, data, position, encoding) { - if (fd !== 1) { + if (fd !== 1 || fd !== 2) { return originalWriteSync.apply(fs, arguments); } // usage: @@ -134,6 +146,7 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A // Unset the custom environmental variables that should not get inherited delete process.env['STDIN_PIPE_NAME']; delete process.env['STDOUT_PIPE_NAME']; + delete process.env['STDERR_PIPE_NAME']; delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; require(program); diff --git a/src/vs/base/node/stdFork.ts b/src/vs/base/node/stdFork.ts index cb5a510491a652ac7e4283edfd9e51eac7ab2663..4751a8fa83b957e676cf7d690f45a5c1d4899c42 100644 --- a/src/vs/base/node/stdFork.ts +++ b/src/vs/base/node/stdFork.ts @@ -38,7 +38,7 @@ function generatePipeName(): string { return path.join(os.tmpdir(), randomName + '.sock'); } -function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string): any { +function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string, stdErrPipeName:string): any { // Set the two unique pipe names and the electron flag as process env let newEnv:any = {}; @@ -48,6 +48,7 @@ function generatePatchedEnv(env:any, stdInPipeName:string, stdOutPipeName:string newEnv['STDIN_PIPE_NAME'] = stdInPipeName; newEnv['STDOUT_PIPE_NAME'] = stdOutPipeName; + newEnv['STDERR_PIPE_NAME'] = stdErrPipeName; newEnv['ATOM_SHELL_INTERNAL_RUN_AS_NODE'] = '1'; return newEnv; @@ -71,29 +72,37 @@ export function fork(modulePath: string, args: string[], options: IForkOpts, cal callback(err, null); }; - // Generate two unique pipe names + // Generate three unique pipe names let stdInPipeName = generatePipeName(); let stdOutPipeName = generatePipeName(); + let stdErrPipeName = generatePipeName(); - let newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName); + let newEnv = generatePatchedEnv(options.env || process.env, stdInPipeName, stdOutPipeName, stdErrPipeName); let childProcess: cp.ChildProcess; + // Begin listening to stderr pipe + let stdErrServer = net.createServer((stdErrStream) => { + // From now on the childProcess.stderr is available for reading + childProcess.stderr = stdErrStream; + }); + stdErrServer.listen(stdErrPipeName); + // Begin listening to stdout pipe - let server = net.createServer((stream) => { + let stdOutServer = net.createServer((stdOutStream) => { // The child process will write exactly one chunk with content `ready` when it has installed a listener to the stdin pipe - stream.once('data', (chunk:Buffer) => { + stdOutStream.once('data', (chunk:Buffer) => { // The child process is sending me the `ready` chunk, time to connect to the stdin pipe childProcess.stdin = net.connect(stdInPipeName); // From now on the childProcess.stdout is available for reading - childProcess.stdout = stream; + childProcess.stdout = stdOutStream; resolve(childProcess); }); }); - server.listen(stdOutPipeName); + stdOutServer.listen(stdOutPipeName); let serverClosed = false; let closeServer = () => { @@ -101,7 +110,8 @@ export function fork(modulePath: string, args: string[], options: IForkOpts, cal return; } serverClosed = true; - server.close(); + stdOutServer.close(); + stdErrServer.close(); }; // Create the process diff --git a/src/vs/base/node/stdForkStart.js b/src/vs/base/node/stdForkStart.js index bb58479fcd86da95ba73847090a7b0d700657579..dd543b81aecfac06d4947d4bf57c7b24b3b5951e 100644 --- a/src/vs/base/node/stdForkStart.js +++ b/src/vs/base/node/stdForkStart.js @@ -28,9 +28,11 @@ var log = (function() { var stdInPipeName = process.env['STDIN_PIPE_NAME']; var stdOutPipeName = process.env['STDOUT_PIPE_NAME']; +var stdErrPipeName = process.env['STDERR_PIPE_NAME']; log('STDIN_PIPE_NAME: ' + stdInPipeName); log('STDOUT_PIPE_NAME: ' + stdOutPipeName); +log('STDERR_PIPE_NAME: ' + stdErrPipeName); log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']); // stdout redirection to named pipe @@ -46,8 +48,14 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A // handle process.stdout process.__defineGetter__('stdout', function() { return stdOutStream; }); + // Create a writing stream to the stderr pipe + var stdErrStream = net.connect(stdErrPipeName); + + // unref stdErrStream to behave like a normal standard out + stdErrStream.unref(); + // handle process.stderr - process.__defineGetter__('stderr', function() { return stdOutStream; }); + process.__defineGetter__('stderr', function() { return stdErrStream; }); var fsWriteSyncString = function(fd, str, position, encoding) { // fs.writeSync(fd, string[, position[, encoding]]); @@ -81,14 +89,18 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A slicedBuffer = buffer.slice(off, off + len); } - stdOutStream.write(slicedBuffer); + if (fd === 1) { + stdOutStream.write(slicedBuffer); + } else { + stdErrStream.write(slicedBuffer); + } return slicedBuffer.length; }; // handle fs.writeSync(1, ...) var originalWriteSync = fs.writeSync; fs.writeSync = function(fd, data, position, encoding) { - if (fd !== 1) { + if (fd !== 1 || fd !== 2) { return originalWriteSync.apply(fs, arguments); } // usage: @@ -136,6 +148,7 @@ log('ATOM_SHELL_INTERNAL_RUN_AS_NODE: ' + process.env['ATOM_SHELL_INTERNAL_RUN_A // Unset the custom environmental variables that should not get inherited delete process.env['STDIN_PIPE_NAME']; delete process.env['STDOUT_PIPE_NAME']; + delete process.env['STDERR_PIPE_NAME']; delete process.env['ATOM_SHELL_INTERNAL_RUN_AS_NODE']; require(program);