forked from enviPath/enviPy
Current Dev State
This commit is contained in:
295
static/js/ketcher2/node_modules/shelljs/src/exec.js
generated
vendored
Normal file
295
static/js/ketcher2/node_modules/shelljs/src/exec.js
generated
vendored
Normal file
@ -0,0 +1,295 @@
|
||||
var common = require('./common');
|
||||
var _tempDir = require('./tempdir');
|
||||
var _pwd = require('./pwd');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
var child = require('child_process');
|
||||
|
||||
var DEFAULT_MAXBUFFER_SIZE = 20 * 1024 * 1024;
|
||||
|
||||
common.register('exec', _exec, {
|
||||
unix: false,
|
||||
canReceivePipe: true,
|
||||
wrapOutput: false,
|
||||
});
|
||||
|
||||
// Hack to run child_process.exec() synchronously (sync avoids callback hell)
|
||||
// Uses a custom wait loop that checks for a flag file, created when the child process is done.
|
||||
// (Can't do a wait loop that checks for internal Node variables/messages as
|
||||
// Node is single-threaded; callbacks and other internal state changes are done in the
|
||||
// event loop).
|
||||
function execSync(cmd, opts, pipe) {
|
||||
if (!common.config.execPath) {
|
||||
common.error('Unable to find a path to the node binary. Please manually set config.execPath');
|
||||
}
|
||||
|
||||
var tempDir = _tempDir();
|
||||
var stdoutFile = path.resolve(tempDir + '/' + common.randomFileName());
|
||||
var stderrFile = path.resolve(tempDir + '/' + common.randomFileName());
|
||||
var codeFile = path.resolve(tempDir + '/' + common.randomFileName());
|
||||
var scriptFile = path.resolve(tempDir + '/' + common.randomFileName());
|
||||
var sleepFile = path.resolve(tempDir + '/' + common.randomFileName());
|
||||
|
||||
opts = common.extend({
|
||||
silent: common.config.silent,
|
||||
cwd: _pwd().toString(),
|
||||
env: process.env,
|
||||
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
|
||||
}, opts);
|
||||
|
||||
var previousStdoutContent = '';
|
||||
var previousStderrContent = '';
|
||||
// Echoes stdout and stderr changes from running process, if not silent
|
||||
function updateStream(streamFile) {
|
||||
if (opts.silent || !fs.existsSync(streamFile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var previousStreamContent;
|
||||
var procStream;
|
||||
if (streamFile === stdoutFile) {
|
||||
previousStreamContent = previousStdoutContent;
|
||||
procStream = process.stdout;
|
||||
} else { // assume stderr
|
||||
previousStreamContent = previousStderrContent;
|
||||
procStream = process.stderr;
|
||||
}
|
||||
|
||||
var streamContent = fs.readFileSync(streamFile, 'utf8');
|
||||
// No changes since last time?
|
||||
if (streamContent.length <= previousStreamContent.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
procStream.write(streamContent.substr(previousStreamContent.length));
|
||||
previousStreamContent = streamContent;
|
||||
}
|
||||
|
||||
if (fs.existsSync(scriptFile)) common.unlinkSync(scriptFile);
|
||||
if (fs.existsSync(stdoutFile)) common.unlinkSync(stdoutFile);
|
||||
if (fs.existsSync(stderrFile)) common.unlinkSync(stderrFile);
|
||||
if (fs.existsSync(codeFile)) common.unlinkSync(codeFile);
|
||||
|
||||
var execCommand = JSON.stringify(common.config.execPath) + ' ' + JSON.stringify(scriptFile);
|
||||
var script;
|
||||
|
||||
opts.cwd = path.resolve(opts.cwd);
|
||||
var optString = JSON.stringify(opts);
|
||||
|
||||
if (typeof child.execSync === 'function') {
|
||||
script = [
|
||||
"var child = require('child_process')",
|
||||
" , fs = require('fs');",
|
||||
'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {',
|
||||
' var fname = ' + JSON.stringify(codeFile) + ';',
|
||||
' if (!err) {',
|
||||
' fs.writeFileSync(fname, "0");',
|
||||
' } else if (err.code === undefined) {',
|
||||
' fs.writeFileSync(fname, "1");',
|
||||
' } else {',
|
||||
' fs.writeFileSync(fname, err.code.toString());',
|
||||
' }',
|
||||
'});',
|
||||
'var stdoutStream = fs.createWriteStream(' + JSON.stringify(stdoutFile) + ');',
|
||||
'var stderrStream = fs.createWriteStream(' + JSON.stringify(stderrFile) + ');',
|
||||
'childProcess.stdout.pipe(stdoutStream, {end: false});',
|
||||
'childProcess.stderr.pipe(stderrStream, {end: false});',
|
||||
'childProcess.stdout.pipe(process.stdout);',
|
||||
'childProcess.stderr.pipe(process.stderr);',
|
||||
].join('\n') +
|
||||
(pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n') +
|
||||
[
|
||||
'var stdoutEnded = false, stderrEnded = false;',
|
||||
'function tryClosingStdout(){ if(stdoutEnded){ stdoutStream.end(); } }',
|
||||
'function tryClosingStderr(){ if(stderrEnded){ stderrStream.end(); } }',
|
||||
"childProcess.stdout.on('end', function(){ stdoutEnded = true; tryClosingStdout(); });",
|
||||
"childProcess.stderr.on('end', function(){ stderrEnded = true; tryClosingStderr(); });",
|
||||
].join('\n');
|
||||
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
|
||||
if (opts.silent) {
|
||||
opts.stdio = 'ignore';
|
||||
} else {
|
||||
opts.stdio = [0, 1, 2];
|
||||
}
|
||||
|
||||
// Welcome to the future
|
||||
try {
|
||||
child.execSync(execCommand, opts);
|
||||
} catch (e) {
|
||||
// Clean up immediately if we have an exception
|
||||
try { common.unlinkSync(scriptFile); } catch (e2) {}
|
||||
try { common.unlinkSync(stdoutFile); } catch (e2) {}
|
||||
try { common.unlinkSync(stderrFile); } catch (e2) {}
|
||||
try { common.unlinkSync(codeFile); } catch (e2) {}
|
||||
throw e;
|
||||
}
|
||||
} else {
|
||||
cmd += ' > ' + stdoutFile + ' 2> ' + stderrFile; // works on both win/unix
|
||||
|
||||
script = [
|
||||
"var child = require('child_process')",
|
||||
" , fs = require('fs');",
|
||||
'var childProcess = child.exec(' + JSON.stringify(cmd) + ', ' + optString + ', function(err) {',
|
||||
' var fname = ' + JSON.stringify(codeFile) + ';',
|
||||
' if (!err) {',
|
||||
' fs.writeFileSync(fname, "0");',
|
||||
' } else if (err.code === undefined) {',
|
||||
' fs.writeFileSync(fname, "1");',
|
||||
' } else {',
|
||||
' fs.writeFileSync(fname, err.code.toString());',
|
||||
' }',
|
||||
'});',
|
||||
].join('\n') +
|
||||
(pipe ? '\nchildProcess.stdin.end(' + JSON.stringify(pipe) + ');\n' : '\n');
|
||||
|
||||
fs.writeFileSync(scriptFile, script);
|
||||
|
||||
child.exec(execCommand, opts);
|
||||
|
||||
// The wait loop
|
||||
// sleepFile is used as a dummy I/O op to mitigate unnecessary CPU usage
|
||||
// (tried many I/O sync ops, writeFileSync() seems to be only one that is effective in reducing
|
||||
// CPU usage, though apparently not so much on Windows)
|
||||
while (!fs.existsSync(codeFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); }
|
||||
while (!fs.existsSync(stdoutFile)) { updateStream(stdoutFile); fs.writeFileSync(sleepFile, 'a'); }
|
||||
while (!fs.existsSync(stderrFile)) { updateStream(stderrFile); fs.writeFileSync(sleepFile, 'a'); }
|
||||
try { common.unlinkSync(sleepFile); } catch (e) {}
|
||||
}
|
||||
|
||||
// At this point codeFile exists, but it's not necessarily flushed yet.
|
||||
// Keep reading it until it is.
|
||||
var code = parseInt('', 10);
|
||||
while (isNaN(code)) {
|
||||
code = parseInt(fs.readFileSync(codeFile, 'utf8'), 10);
|
||||
}
|
||||
|
||||
var stdout = fs.readFileSync(stdoutFile, 'utf8');
|
||||
var stderr = fs.readFileSync(stderrFile, 'utf8');
|
||||
|
||||
// No biggie if we can't erase the files now -- they're in a temp dir anyway
|
||||
try { common.unlinkSync(scriptFile); } catch (e) {}
|
||||
try { common.unlinkSync(stdoutFile); } catch (e) {}
|
||||
try { common.unlinkSync(stderrFile); } catch (e) {}
|
||||
try { common.unlinkSync(codeFile); } catch (e) {}
|
||||
|
||||
if (code !== 0) {
|
||||
common.error('', code, { continue: true });
|
||||
}
|
||||
var obj = common.ShellString(stdout, stderr, code);
|
||||
return obj;
|
||||
} // execSync()
|
||||
|
||||
// Wrapper around exec() to enable echoing output to console in real time
|
||||
function execAsync(cmd, opts, pipe, callback) {
|
||||
var stdout = '';
|
||||
var stderr = '';
|
||||
|
||||
opts = common.extend({
|
||||
silent: common.config.silent,
|
||||
cwd: _pwd().toString(),
|
||||
env: process.env,
|
||||
maxBuffer: DEFAULT_MAXBUFFER_SIZE,
|
||||
}, opts);
|
||||
|
||||
var c = child.exec(cmd, opts, function (err) {
|
||||
if (callback) {
|
||||
if (!err) {
|
||||
callback(0, stdout, stderr);
|
||||
} else if (err.code === undefined) {
|
||||
// See issue #536
|
||||
callback(1, stdout, stderr);
|
||||
} else {
|
||||
callback(err.code, stdout, stderr);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (pipe) c.stdin.end(pipe);
|
||||
|
||||
c.stdout.on('data', function (data) {
|
||||
stdout += data;
|
||||
if (!opts.silent) process.stdout.write(data);
|
||||
});
|
||||
|
||||
c.stderr.on('data', function (data) {
|
||||
stderr += data;
|
||||
if (!opts.silent) process.stderr.write(data);
|
||||
});
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
//@
|
||||
//@ ### exec(command [, options] [, callback])
|
||||
//@ Available options (all `false` by default):
|
||||
//@
|
||||
//@ + `async`: Asynchronous execution. If a callback is provided, it will be set to
|
||||
//@ `true`, regardless of the passed value.
|
||||
//@ + `silent`: Do not echo program output to console.
|
||||
//@ + and any option available to Node.js's
|
||||
//@ [child_process.exec()](https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback)
|
||||
//@
|
||||
//@ Examples:
|
||||
//@
|
||||
//@ ```javascript
|
||||
//@ var version = exec('node --version', {silent:true}).stdout;
|
||||
//@
|
||||
//@ var child = exec('some_long_running_process', {async:true});
|
||||
//@ child.stdout.on('data', function(data) {
|
||||
//@ /* ... do something with data ... */
|
||||
//@ });
|
||||
//@
|
||||
//@ exec('some_long_running_process', function(code, stdout, stderr) {
|
||||
//@ console.log('Exit code:', code);
|
||||
//@ console.log('Program output:', stdout);
|
||||
//@ console.log('Program stderr:', stderr);
|
||||
//@ });
|
||||
//@ ```
|
||||
//@
|
||||
//@ Executes the given `command` _synchronously_, unless otherwise specified. When in synchronous
|
||||
//@ mode, this returns a ShellString (compatible with ShellJS v0.6.x, which returns an object
|
||||
//@ of the form `{ code:..., stdout:... , stderr:... }`). Otherwise, this returns the child process
|
||||
//@ object, and the `callback` gets the arguments `(code, stdout, stderr)`.
|
||||
//@
|
||||
//@ Not seeing the behavior you want? `exec()` runs everything through `sh`
|
||||
//@ by default (or `cmd.exe` on Windows), which differs from `bash`. If you
|
||||
//@ need bash-specific behavior, try out the `{shell: 'path/to/bash'}` option.
|
||||
//@
|
||||
//@ **Note:** For long-lived processes, it's best to run `exec()` asynchronously as
|
||||
//@ the current synchronous implementation uses a lot of CPU. This should be getting
|
||||
//@ fixed soon.
|
||||
function _exec(command, options, callback) {
|
||||
options = options || {};
|
||||
if (!command) common.error('must specify command');
|
||||
|
||||
var pipe = common.readFromPipe();
|
||||
|
||||
// Callback is defined instead of options.
|
||||
if (typeof options === 'function') {
|
||||
callback = options;
|
||||
options = { async: true };
|
||||
}
|
||||
|
||||
// Callback is defined with options.
|
||||
if (typeof options === 'object' && typeof callback === 'function') {
|
||||
options.async = true;
|
||||
}
|
||||
|
||||
options = common.extend({
|
||||
silent: common.config.silent,
|
||||
async: false,
|
||||
}, options);
|
||||
|
||||
try {
|
||||
if (options.async) {
|
||||
return execAsync(command, options, pipe, callback);
|
||||
} else {
|
||||
return execSync(command, options, pipe);
|
||||
}
|
||||
} catch (e) {
|
||||
common.error('internal error');
|
||||
}
|
||||
}
|
||||
module.exports = _exec;
|
||||
Reference in New Issue
Block a user