Support the Synchronous Process Execution of Node v0.12(v0.11).
This commit is contained in:
parent
995f22b4bf
commit
ab94a1ea2b
3 changed files with 76 additions and 60 deletions
|
@ -191,8 +191,7 @@ grunt.initConfig({
|
|||
|
||||
### Platforms
|
||||
|
||||
The your Node and OS may not support interactively reading from stdin. The stdin interfaces are different by platforms.
|
||||
If in those platforms, an error is thrown.
|
||||
The stdin interfaces are different by platforms. If the platform doesn't support interactively reading from stdin, an error is thrown.
|
||||
|
||||
```js
|
||||
try {
|
||||
|
@ -205,18 +204,16 @@ try {
|
|||
|
||||
### Reading by shell
|
||||
|
||||
readlineSync tries reading from stdin by shell if it is needed. And, it use "piping via files" for synchronous running.
|
||||
readlineSync tries reading from stdin by shell if it is needed. And if the running Node doesn't support the [Synchronous Process Execution](http://nodejs.org/api/child_process.html#child_process_synchronous_process_creation) (i.e. Node v0.10-), it use "piping via files" for synchronous running.
|
||||
As everyone knows, "piping via files" is no good. It blocks event loop and a process. It may make your script be slow.
|
||||
|
||||
Why did I choose it? :
|
||||
|
||||
+ The best solution is [child_process.execSync](https://github.com/joyent/node/blob/master/doc/api/child_process.markdown#child_processexecsynccommand-options) in core modules of Node. But it is not supported by current version.
|
||||
+ The good modules (native addon) for synchronous execution exist. But node-gyp can't compile those in some platforms or Node versions.
|
||||
+ I think that the security is important more than the speed. Some modules have problem about security. (Those don't protect data.) I think that the speed is not needed usually, because readlineSync is used while user types keys.
|
||||
|
||||
Someday, I may rewrite readlineSync to use child_process.execSync, or safety module.
|
||||
|
||||
## Release History
|
||||
* 2015-02-12 v0.5.5 Support the Synchronous Process Execution of Node v0.12(v0.11).
|
||||
* 2015-01-27 v0.5.0 Add `options.noTrim`.
|
||||
* 2014-07-12 v0.4.0 Add `options.noEchoBack`.
|
||||
* 2014-07-12 v0.3.0 Add `setPrint()`.
|
||||
|
|
|
@ -10,6 +10,9 @@
|
|||
|
||||
var
|
||||
BUF_SIZE = 256,
|
||||
IS_WIN = process.platform === 'win32',
|
||||
SHELL_PATH = IS_WIN ? 'cmd.exe' : '/bin/sh',
|
||||
|
||||
ALGORITHM_CIPHER = 'aes-256-cbc',
|
||||
ALGORITHM_HASH = 'sha256',
|
||||
|
||||
|
@ -79,14 +82,63 @@ function _readlineSync(display, options) {
|
|||
}
|
||||
|
||||
function _readlineShell(noEchoBack) {
|
||||
// piping via files instead of execSync (node v0.12+)
|
||||
// https://github.com/joyent/node/blob/master/doc/api/child_process.markdown#child_processexecsynccommand-options
|
||||
// see README > Note
|
||||
var shellPath, args, shellStdout,
|
||||
var shellStdout, command,
|
||||
options = {
|
||||
env: process.env,
|
||||
stdio: [stdin], // ScriptPW needs piped stdin
|
||||
encoding: encoding
|
||||
},
|
||||
optEchoBack = noEchoBack ? ' noechoback' : '';
|
||||
|
||||
if (IS_WIN) {
|
||||
// The quote (") is escaped by node before parsed by shell. Then use ENV{Q}.
|
||||
process.env.Q = '"';
|
||||
command = '%Q%' + __dirname + '\\read.bat%Q%' + optEchoBack;
|
||||
} else {
|
||||
command = '"' + __dirname + '/read.sh"' + optEchoBack;
|
||||
}
|
||||
|
||||
stdin.pause(); // re-start in child process
|
||||
if (childProc.execFileSync) {
|
||||
shellStdout = childProc.execFileSync(SHELL_PATH,
|
||||
IS_WIN ? ['/S', '/C', command] : ['-c', command], options);
|
||||
shellStdout = shellStdout.replace(/^'|'$/g, '');
|
||||
} else {
|
||||
shellStdout = _execSyncByFile(command, options);
|
||||
}
|
||||
|
||||
return shellStdout;
|
||||
}
|
||||
|
||||
// piping via files (node v0.10-)
|
||||
function _execSyncByFile(command, options) {
|
||||
|
||||
function getTempfile(name) {
|
||||
var path = require('path'), filepath, suffix = '', fd;
|
||||
tempdir = tempdir || require('os').tmpdir();
|
||||
|
||||
while (true) {
|
||||
filepath = path.join(tempdir, name + suffix);
|
||||
try {
|
||||
fd = fs.openSync(filepath, 'wx');
|
||||
} catch (e) {
|
||||
if (e.code === 'EEXIST') {
|
||||
suffix++;
|
||||
continue;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
fs.closeSync(fd);
|
||||
break;
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
|
||||
var shellStdout,
|
||||
pathStdout = getTempfile('readline-sync.stdout'),
|
||||
pathStatus = getTempfile('readline-sync.status'),
|
||||
pathDone = getTempfile('readline-sync.done'),
|
||||
optEchoBack = noEchoBack ? ' noechoback' : '',
|
||||
crypto = require('crypto'), shasum, decipher, password;
|
||||
|
||||
shasum = crypto.createHash(ALGORITHM_HASH);
|
||||
|
@ -94,32 +146,20 @@ function _readlineShell(noEchoBack) {
|
|||
password = shasum.digest('hex');
|
||||
decipher = crypto.createDecipher(ALGORITHM_CIPHER, password);
|
||||
|
||||
if (process.platform === 'win32') {
|
||||
// The quote (") is escaped by node before parsed by shell. Then use ENV{Q}.
|
||||
shellPath = 'cmd.exe';
|
||||
args = ['/V:ON', '/S', '/C',
|
||||
'%Q%' + __dirname + '\\read.bat%Q%' + optEchoBack +
|
||||
' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' +
|
||||
' %Q%' + ALGORITHM_CIPHER + '%Q% %Q%' + password + '%Q%' +
|
||||
' >%Q%' + pathStdout + '%Q%' +
|
||||
' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%'];
|
||||
process.env.Q = '"';
|
||||
} else {
|
||||
shellPath = '/bin/sh';
|
||||
args = ['-c',
|
||||
'DATA=`(' + shellPath + ' "' + __dirname + '/read.sh"' + optEchoBack + ')`; RTN=$?;' +
|
||||
' if [ $RTN -eq 0 ]; then (printf \'%s\' "$DATA" |' +
|
||||
'"' + process.execPath + '" "' + __dirname + '/encrypt.js"' +
|
||||
' "' + ALGORITHM_CIPHER + '" "' + password + '"' +
|
||||
' >"' + pathStdout + '") fi;' +
|
||||
' expr $RTN + $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"'];
|
||||
}
|
||||
|
||||
stdin.pause(); // re-start in child process
|
||||
childProc.spawn(shellPath, args, {
|
||||
env: process.env,
|
||||
stdio: [stdin] // ScriptPW needs piped stdin
|
||||
});
|
||||
childProc.spawn(SHELL_PATH,
|
||||
IS_WIN ? ['/V:ON', '/S', '/C',
|
||||
command + ' |%Q%' + process.execPath + '%Q% %Q%' + __dirname + '\\encrypt.js%Q%' +
|
||||
' %Q%' + ALGORITHM_CIPHER + '%Q% %Q%' + password + '%Q%' +
|
||||
' >%Q%' + pathStdout + '%Q%' +
|
||||
' & (echo !ERRORLEVEL!)>%Q%' + pathStatus + '%Q% & (echo 1)>%Q%' + pathDone + '%Q%'] :
|
||||
['-c',
|
||||
'DATA=`(' + SHELL_PATH + ' ' + command + ')`; RTN=$?;' +
|
||||
' if [ $RTN -eq 0 ]; then (printf \'%s\' "$DATA" |' +
|
||||
'"' + process.execPath + '" "' + __dirname + '/encrypt.js"' +
|
||||
' "' + ALGORITHM_CIPHER + '" "' + password + '"' +
|
||||
' >"' + pathStdout + '") fi;' +
|
||||
' expr $RTN + $? >"' + pathStatus + '"; echo 1 >"' + pathDone + '"'],
|
||||
options);
|
||||
|
||||
while (fs.readFileSync(pathDone, {encoding: encoding}).trim() !== '1') {}
|
||||
if (fs.readFileSync(pathStatus, {encoding: encoding}).trim() === '0') {
|
||||
|
@ -132,31 +172,10 @@ function _readlineShell(noEchoBack) {
|
|||
fs.unlinkSync(pathStdout);
|
||||
fs.unlinkSync(pathStatus);
|
||||
fs.unlinkSync(pathDone);
|
||||
|
||||
return shellStdout;
|
||||
}
|
||||
|
||||
function getTempfile(name) {
|
||||
var path = require('path'), filepath, suffix = '', fd;
|
||||
tempdir = tempdir || require('os').tmpdir();
|
||||
|
||||
while (true) {
|
||||
filepath = path.join(tempdir, name + suffix);
|
||||
try {
|
||||
fd = fs.openSync(filepath, 'wx');
|
||||
} catch (e) {
|
||||
if (e.code === 'EEXIST') {
|
||||
suffix++;
|
||||
continue;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
fs.closeSync(fd);
|
||||
break;
|
||||
}
|
||||
return filepath;
|
||||
}
|
||||
|
||||
// for dev
|
||||
exports.useShellSet = function(use) { useShell = use; };
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "readline-sync",
|
||||
"version": "0.5.4",
|
||||
"version": "0.5.5",
|
||||
"title": "readlineSync",
|
||||
"description": "Synchronous Readline",
|
||||
"keywords": [
|
||||
|
|
Loading…
Reference in a new issue