update files

This commit is contained in:
nuintun 2016-01-14 09:33:15 +08:00
parent 47a857cd5b
commit bf76db01b9
3 changed files with 175 additions and 45 deletions

View File

@ -4,7 +4,8 @@
'use strict';
var spawn = require('child_process').spawn;
var spawn = require('./spawn');
var threadKill = require('./thread-kill');
/**
* Emulator
@ -17,7 +18,7 @@ function Emulator(task){
Emulator.prototype = {
start: function (){
this.thread = this.exec(this.task.command, {
this.thread = spawn(this.task.command, {
env: this.task.env,
cwd: this.task.cwd
});
@ -26,53 +27,17 @@ Emulator.prototype = {
},
stop: function (){
if (this.thread) {
this.exec('taskkill /t /f /pid ' + this.thread.pid);
var context = this;
['stdin', 'stdout', 'stderr'].forEach(function (stream){
this.thread[stream].removeAllListeners();
}, this);
threadKill(this.thread.pid, function (){
['stdin', 'stdout', 'stderr'].forEach(function (stream){
context.thread[stream].removeAllListeners();
});
this.thread = null;
context.thread = null;
});
}
},
exec: function (){
var parsed = normalizeExecArgs.apply(null, arguments);
return spawn(parsed.shell, parsed.args, parsed.options);
}
};
/**
* normalize exec args
* @param command
* @param options
* @returns {{cmd: *, shell: *, args: *, options: *}}
*/
function normalizeExecArgs(command, options){
var shell, args;
// Make a shallow copy before patching so we don't clobber the user's
// options object.
options = options || {};
if (process.platform === 'win32') {
shell = process.env.comspec || 'cmd.exe';
args = ['/s', '/c', '"' + command + '"'];
options.windowsVerbatimArguments = true;
} else {
shell = '/bin/sh';
args = ['-c', command];
}
if (options.shell) {
shell = options.shell;
}
return {
shell: shell,
args: args,
options: options
};
}
module.exports = Emulator;

49
bin/spawn.js Normal file
View File

@ -0,0 +1,49 @@
/**
* Created by nuintun on 2016/1/14.
*/
'use strict';
var spawn = require('child_process').spawn;
/**
* normalize exec args
* @param command
* @param options
* @returns {{cmd: *, shell: *, args: *, options: *}}
*/
function normalizeExecArgs(command, options){
var shell, args;
// Make a shallow copy before patching so we don't clobber the user's
// options object.
options = options || {};
if (process.platform === 'win32') {
shell = process.env.comspec || 'cmd.exe';
args = ['/s', '/c', '"' + command + '"'];
options.windowsVerbatimArguments = true;
} else {
shell = '/bin/sh';
args = ['-c', command];
}
if (options.shell) {
shell = options.shell;
}
return {
shell: shell,
args: args,
options: options
};
}
/**
* exec thread
*/
module.exports = function (){
var parsed = normalizeExecArgs.apply(null, arguments);
return spawn(parsed.shell, parsed.args, parsed.options);
};

116
bin/thread-kill.js Normal file
View File

@ -0,0 +1,116 @@
/**
* Created by nuintun on 2016/1/14.
*/
var spawn = require('./spawn');
var exec = require('child_process').exec;
/**
*
* @param pid
* @param signal
* @param callback
*/
module.exports = function (pid, signal, callback){
var tree = {};
var pidsToProcess = {};
tree[pid] = [];
pidsToProcess[pid] = 1;
if (typeof signal === 'function') {
signal = 'SIGKILL';
callback = signal;
}
switch (process.platform) {
// win32
case 'win32':
exec('taskkill /pid ' + pid + ' /T /F', callback);
break;
// darwin
case 'darwin':
buildProcessTree(pid, tree, pidsToProcess, function (parentPid){
return spawn('pgrep', ['-P', parentPid]);
}, function (){
killAll(tree, signal, callback);
});
break;
// linux
default:
buildProcessTree(pid, tree, pidsToProcess, function (parentPid){
return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid]);
}, function (){
killAll(tree, signal, callback);
});
break;
}
};
function killAll(tree, signal, callback){
var killed = {};
try {
Object.keys(tree).forEach(function (pid){
tree[pid].forEach(function (pidpid){
if (!killed[pidpid]) {
killPid(pidpid, signal);
killed[pidpid] = 1;
}
});
if (!killed[pid]) {
killPid(pid, signal);
killed[pid] = 1;
}
});
} catch (error) {
if (callback) {
return callback(error);
} else {
throw error;
}
}
if (callback) {
return callback();
}
}
function killPid(pid, signal){
try {
process.kill(parseInt(pid, 10), signal);
}
catch (error) {
if (error.code !== 'ESRCH') throw error;
}
}
function buildProcessTree(parentPid, tree, pidsToProcess, spawnChildProcessesList, callback){
var allData = '';
var ps = spawnChildProcessesList(parentPid);
ps.stdout.on('data', function (data){
allData += data.toString('ascii');
});
var onClose = function (code){
delete pidsToProcess[parentPid];
if (code != 0) {
// no more parent processes
if (Object.keys(pidsToProcess).length == 0) {
callback();
}
return;
}
allData.match(/\d+/g).forEach(function (pid){
pid = parseInt(pid, 10);
tree[parentPid].push(pid);
tree[pid] = [];
pidsToProcess[pid] = 1;
buildProcessTree(pid, tree, pidsToProcess, spawnChildProcessesList, callback);
});
};
ps.on('close', onClose);
}