diff --git a/.gitignore b/.gitignore index 13abef4..59d842b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,28 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- node_modules -node_modules/* -npm_debug.log + +# Users Environment Variables +.lock-wscript diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..20fd86b --- /dev/null +++ b/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.10 diff --git a/bin/ps-tree.js b/bin/ps-tree.js new file mode 100644 index 0000000..1a008a4 --- /dev/null +++ b/bin/ps-tree.js @@ -0,0 +1,5 @@ +#!/usr/bin/env node +'use strict'; +require('../')(process.argv[2] || 1, function (err, data) { + console.log(data) +}); diff --git a/index.js b/index.js old mode 100644 new mode 100755 index 3203103..b6f4eca --- a/index.js +++ b/index.js @@ -1,4 +1,4 @@ -var spawn = require('child_process').spawn, +var spawn = require('child_process').spawn, es = require('event-stream'); module.exports = childrenOfPid @@ -6,11 +6,15 @@ module.exports = childrenOfPid function childrenOfPid( pid, callback) { var headers = null; - if('function' !== typeof callback) + if('function' !== typeof callback) throw new Error('childrenOfPid(pid, callback) expects callback') - if('number' == typeof pid) + if('number' == typeof pid) { pid = pid.toString() - + } + else { + pid = parseInt(pid, 10).toString(); // force string + } + es.connect( spawn('ps', ['-A', '-o', 'ppid,pid,stat,comm']).stdout, es.split(), @@ -20,14 +24,14 @@ function childrenOfPid( pid, callback) { headers = columns else { var row = {} - //for each header, + //for each header, var h = headers.slice() while (h.length) { row[h.shift()] = h.length ? columns.shift() : columns.join(' ') } return cb(null, row) } - return cb() + return cb(); }), es.writeArray(function (err, ps) { var parents = [pid], children = [] @@ -37,13 +41,7 @@ function childrenOfPid( pid, callback) { children.push(proc) } }) - callback(null, children) + callback(null, children) }) ).on('error', callback) } - -if(!module.parent) { - childrenOfPid(process.argv[2] || 1, function (err, data) { - console.log(data) - }) -} \ No newline at end of file diff --git a/package.json b/package.json index 834d90e..7d160f1 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,39 @@ { "name": "ps-tree" -, "version": "0.0.3" -, "description": "get all children of a pid" +, "version": "0.0.4" +, "description": "Get all children of a pid" , "homepage": "http://github.com/indexzero/ps-tree" -, "repository": +, "repository": { "type": "git" - , "url": "https://github.com/indexzero/ps-tree.git" } +, "url": "https://github.com/indexzero/ps-tree.git" } , "dependencies": { - "event-stream": "~0.5" + "event-stream": "~3.3.0" } , "author": "Charlie Robbins" -} \ No newline at end of file +, "directories": { + "test": "test" + } +, "scripts": { + "quick": "./node_modules/tape/bin/tape ./test/*.js" +, "test": "./node_modules/.bin/istanbul cover ./node_modules/tape/bin/tape ./test/*.js" +, "direct": "./node_modules/.bin/istanbul cover ./node_modules/tape/bin/tape ./test/direct.js" +, "coverage": "./node_modules/.bin/istanbul cover ./node_modules/tape/bin/tape ./test/*.js && ./node_modules/.bin/istanbul check-coverage --statements 100 --functions 100 --lines 100 --branches 100" +, "jshint": "./node_modules/jshint/bin/jshint -c .jshintrc --exclude-path .gitignore ." +, "codeclimate": "CODECLIMATE_REPO_TOKEN=84436b4f13c70ace9c62e7f04928bf23c234eb212c0232d39d7fb1535beb2da5 ./node_modules/codeclimate-test-reporter/bin/codeclimate.js < ./coverage/lcov.info" + } +, "devDependencies": { + "chalk": "^1.0.0" +, "codeclimate-test-reporter": "0.0.4" +, "ignored": "^2.0.2" +, "istanbul": "^0.3.4" +, "jshint": "^2.5.10" +, "mkdirp": "^0.5.0" +, "pre-commit": "0.0.9" +, "tape": "^3.0.3" + } +, "pre-commit": [ + "coverage" + ] +, "engines": { + "node": ">=0.10" + } +} diff --git a/readme.markdown b/readme.markdown index c4edc51..088a211 100644 --- a/readme.markdown +++ b/readme.markdown @@ -11,7 +11,7 @@ solution: use `ps-tree` to get all processes that a child_process may have start ``` js var cp = require('child_process'), psTree = require('ps-tree') - + var child = cp.exec("node -e 'while (true);'",function () {...}) child.kill() //this will not actually kill the child it will kill the `sh` process. @@ -38,11 +38,25 @@ used ps tree like this: var cp = require('child_process'), psTree = require('ps-tree') - + var child = cp.exec("node -e 'while (true);'",function () {...}) psTree(child.pid, function (err, children) { cp.spawn('kill', ['-9'].concat(children.map(function (p) {return p.PID}))) }) -``` \ No newline at end of file +``` + +If you prefer to run **psTree** from the command line, +use: `node ./bin/ps-tree.js` + + +
+[![Build Status](https://travis-ci.org/nelsonic/ps-tree.svg)](https://travis-ci.org/nelsonic/ps-tree) +[![Code Climate](https://codeclimate.com/github/nelsonic/ps-tree/badges/gpa.svg)](https://codeclimate.com/github/nelsonic/ps-tree) +[![Test Coverage](https://codeclimate.com/github/nelsonic/ps-tree/badges/coverage.svg)](https://codeclimate.com/github/nelsonic/ps-tree) +[![npm version](https://badge.fury.io/js/ps-tree.svg)](http://badge.fury.io/js/ps-tree) +[![Node.js Version][node-version-image]][node-version-url] +[![Dependency Status](https://david-dm.org/nelsonic/ps-tree.svg)](https://david-dm.org/nelsonic/ps-tree) +[node-version-image]: https://img.shields.io/node/v/listdirs.svg?style=flat +[node-version-url]: http://nodejs.org/download/ diff --git a/test/direct.js b/test/direct.js new file mode 100644 index 0000000..4263332 --- /dev/null +++ b/test/direct.js @@ -0,0 +1,20 @@ +var test = require('tape'); +var chalk = require('chalk'); +var red = chalk.red, green = chalk.green, cyan = chalk.cyan; + +var cp = require('child_process'); +// var fs = require('fs'); +// fs.chmodSync('./index.js', 777); + +test(cyan('Directly Execute bin/ps-tree.js'), function (t) { + var first = cp.exec("node -v", function(error, stdout, stderr) { + }) + var child = cp.exec("node ./bin/ps-tree.js", function(error, data) { + // console.log('data: ' + data.length); + if (error !== null) { + console.log(red('exec error: ' + error)); + } + }) + t.true(child.pid, green("✓ Called ./bin/ps-tree.js directly. worked as expected")); + t.end(); +}); diff --git a/test/exec/child.js b/test/exec/child.js new file mode 100644 index 0000000..8be694a --- /dev/null +++ b/test/exec/child.js @@ -0,0 +1,9 @@ +// a basic node http server +var port = Math.floor(Math.random() * 60000) + 1000; +// require('http').createServer(function (req, res) { +// res.writeHead(200, {"Content-Type": "text/html"}); +// res.end('Hai'); +// }).listen(port); +console.log("Visit: http://127.0.0.1:"+port); +console.log("process.id: "+process.pid); +console.log(" - - - - - - - - - - - - - - - - - - - - - - - "); diff --git a/test/exec/parent.js b/test/exec/parent.js new file mode 100644 index 0000000..bc657fa --- /dev/null +++ b/test/exec/parent.js @@ -0,0 +1,15 @@ +var cp = require('child_process'); +var chalk = require('chalk'); +var red = chalk.red, green = chalk.green, cyan = chalk.cyan; +var count = 0; +while(count < 10) { + var child = cp.exec("node ./test/exec/child.js", function(error, stdout, stderr) { + console.log('stdout: ' + stdout); + console.log(red('stderr: ' + stderr)); + if (error !== null) { + console.log(red('exec error: ' + error)); + } + }) + console.log("child pid: "+child.pid + " | count: "+count); + count++ +} diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..85a9eea --- /dev/null +++ b/test/test.js @@ -0,0 +1,66 @@ +var test = require('tape'); +var chalk = require('chalk'); +var red = chalk.red, green = chalk.green, cyan = chalk.cyan; + +var cp = require('child_process'), + psTree = require('../') + +test(cyan('Spawn a Parent process which has a Two Child Processes'), function (t) { + var parent = cp.exec("node ./test/exec/parent.js", function(error, stdout, stderr) { + }) + setTimeout(function(){ + psTree(parent.pid, function (err, children) { + if(err){ + console.log(err); + } + console.log(red("Children: "), children, '\n'); + t.true(children.length > 0, green("✓ There are "+children.length+" active child processes")); + cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID }))) + }) + setTimeout(function(){ + psTree(parent.pid, function (err, children) { + if(err){ + console.log(err); + } + // console.log("Children: ", children, '\n'); + // console.log(' ') + t.equal(children.length, 0, green("✓ No more active child processes (we killed them)")); + t.end(); + }) + },1000); // give psTree time to kill the processes + },200); // give the child process time to spawn +}); + +test(cyan('FORCE ERROR by calling psTree without supplying a Callback'), function (t) { + var errmsg = "Error: childrenOfPid(pid, callback) expects callback" + try { + psTree(1234); // attempt to call psTree without a callback + } + catch(e){ + // console.log(red(e)); + t.equal(e.toString(), errmsg, green("✓ Fails when no callback supplied (as expected)")) + } + t.end(); +}); + + +test(cyan('Spawn a Child Process and psTree with a String as pid'), function (t) { + var child = cp.exec("node ./test/exec/child.js", function(error, stdout, stderr) { }); + setTimeout(function(){ + psTree(child.pid.toString(), function (err, children) { + if(err){ + console.log(err); + } + cp.spawn('kill', ['-9'].concat(children.map(function (p) { return p.PID }))) + }) + setTimeout(function() { + psTree(child.pid.toString(), function (err, children) { + if(err){ + console.log(err); + } + t.equal(children.length, 0, green("✓ No more active child processes")); + t.end(); + }); + },1000); // give psTree time to kill the processes + },200); // give the child process time to spawn +});