Compare commits
2 Commits
Author | SHA1 | Date |
---|---|---|
TheThing | 15d1ba43f4 | |
TheThing | 8fad1b45b1 |
11
cli.mjs
11
cli.mjs
|
@ -27,15 +27,20 @@ function PrintHelp() {
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
function showErrorAndExit(message = '', err = null, code = 1) {
|
function showErrorAndExit(message = '', err = null, code = 1, clean = false) {
|
||||||
console.log('')
|
if (!clean) {
|
||||||
|
console.log('')
|
||||||
|
}
|
||||||
|
|
||||||
if (message) {
|
if (message) {
|
||||||
console.error(`\x1b[31m${message}\x1b[0m`)
|
console.error(`\x1b[31m${message}\x1b[0m`)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
printError(err)
|
printError(err, '', clean)
|
||||||
|
if (err.inner) {
|
||||||
|
return showErrorAndExit(null, err.inner, code, true)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
PrintHelp()
|
PrintHelp()
|
||||||
}
|
}
|
||||||
|
|
|
@ -440,9 +440,9 @@ export function getFilesFromTarget(files, match, insidePath, grabAll, insideStar
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function printError(err, msg) {
|
export function printError(err, msg, clean = false) {
|
||||||
let before = msg || ''
|
let before = msg || ''
|
||||||
console.error('')
|
if (!clean) console.error('')
|
||||||
console.error('\x1b[31m '
|
console.error('\x1b[31m '
|
||||||
+ before + err.toString()
|
+ before + err.toString()
|
||||||
+ '\x1b[0m\n \x1b[90m'
|
+ '\x1b[0m\n \x1b[90m'
|
||||||
|
|
52
lib/kill.mjs
52
lib/kill.mjs
|
@ -4,25 +4,41 @@ import { spawn, exec } from 'child_process'
|
||||||
const execPromise = promisify(exec)
|
const execPromise = promisify(exec)
|
||||||
|
|
||||||
export default function kill(pid, signal) {
|
export default function kill(pid, signal) {
|
||||||
let pids = new Set()
|
let pids = new Set([pid])
|
||||||
let getSpawn = null
|
let getSpawn = null
|
||||||
|
let getPids = null
|
||||||
|
|
||||||
switch (process.platform) {
|
switch (process.platform) {
|
||||||
case 'win32':
|
case 'win32':
|
||||||
return execPromise('taskkill /pid ' + pid + ' /T /F')
|
return execPromise('taskkill /pid ' + pid + ' /T /F').then(() => pids)
|
||||||
case 'darwin':
|
case 'darwin':
|
||||||
getSpawn = function(parentPid) {
|
getSpawn = function(parentPid) {
|
||||||
return spawn('pgrep', ['-P', parentPid])
|
return spawn('pgrep', ['-P', parentPid])
|
||||||
}
|
}
|
||||||
|
getPids = function(data) {
|
||||||
|
return data.match(/\d+/g).map(Number)
|
||||||
|
}
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
getSpawn = function (parentPid) {
|
getSpawn = function (parentPid) {
|
||||||
return spawn('ps', ['-o', 'pid', '--no-headers', '--ppid', parentPid])
|
return exec('ps -opid="" -oppid="" | grep ' + parentPid)
|
||||||
|
}
|
||||||
|
getPids = function(data, parentPid) {
|
||||||
|
let output = data.trim().split('\n')
|
||||||
|
return output.map(line => {
|
||||||
|
let [child, parent] = line.trim().split(/ +/)
|
||||||
|
|
||||||
|
if (Number(parent) === parentPid) {
|
||||||
|
return Number(child)
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}).filter(x => x)
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildTree(pids, getSpawn, pid)
|
return buildTree(pids, getSpawn, getPids, pid)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
for (let pid of pids) {
|
for (let pid of pids) {
|
||||||
try {
|
try {
|
||||||
|
@ -31,28 +47,38 @@ export default function kill(pid, signal) {
|
||||||
if (err.code !== 'ESRCH') throw err;
|
if (err.code !== 'ESRCH') throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return pids
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTree(allPids, spawnGetChildren, parentPid) {
|
function buildTree(allPids, spawnGetChildren, spawnGetPids, parentPid) {
|
||||||
allPids.set(parentPid)
|
allPids.add(parentPid)
|
||||||
|
|
||||||
let ps = spawnGetChildren(parentPid)
|
let ps = spawnGetChildren(parentPid)
|
||||||
let data = ''
|
let data = ''
|
||||||
|
let err = ''
|
||||||
ps.stdout.on('data', function(buf) {
|
ps.stdout.on('data', function(buf) {
|
||||||
data += buf.toString('ascii')
|
data += buf.toString('ascii')
|
||||||
})
|
})
|
||||||
|
ps.stderr.on('data', function(buf) {
|
||||||
|
err += buf.toString('ascii')
|
||||||
|
})
|
||||||
|
|
||||||
return new Promise(function(res) {
|
return new Promise(function(res, rej) {
|
||||||
ps.on('close', function(code) {
|
ps.on('close', function(code) {
|
||||||
// Check if we got error code (usually means empty results)
|
// Check if ps errored out
|
||||||
if (code !== 0) return res()
|
if (code !== 0 && err.trim()) {
|
||||||
|
return rej(new Error('Error running ps to kill processes:\n\t' + err))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we otherwise got an error code (usually means empty results)
|
||||||
|
if (code !== 0 || !data.trim()) return res()
|
||||||
|
|
||||||
|
let pids = spawnGetPids(data, parentPid)
|
||||||
|
|
||||||
res(Promise.all(
|
res(Promise.all(
|
||||||
allData.match(/\d+/g)
|
pids.filter(pid => pid && !allPids.has(pid))
|
||||||
.map(Number)
|
.map(buildTree.bind(this, allPids, spawnGetChildren, spawnGetPids))
|
||||||
.filter(pid => !bla.has(pid))
|
|
||||||
.map(buildTree.bind(this, allPids, spawnGetChildren))
|
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "eltro",
|
"name": "eltro",
|
||||||
"version": "1.4.3",
|
"version": "1.4.5",
|
||||||
"description": "Eltro is a tiny no-dependancy test framework for node",
|
"description": "Eltro is a tiny no-dependancy test framework for node",
|
||||||
"main": "index.mjs",
|
"main": "index.mjs",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|
|
@ -234,7 +234,6 @@ e.test('Eltro should support capturing unknown errors outside scope', async func
|
||||||
t.describe('', function() {
|
t.describe('', function() {
|
||||||
t.test('', function(cb) {
|
t.test('', function(cb) {
|
||||||
process.nextTick(function() {
|
process.nextTick(function() {
|
||||||
console.log('throw')
|
|
||||||
throw assertError
|
throw assertError
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
import { spawn } from 'child_process'
|
||||||
|
import t from '../../lib/eltro.mjs'
|
||||||
|
import assert from '../../lib/assert.mjs'
|
||||||
|
import kill from '../../lib/kill.mjs'
|
||||||
|
|
||||||
|
t.describe('kill', function() {
|
||||||
|
let worker
|
||||||
|
|
||||||
|
t.afterEach(function() {
|
||||||
|
if (worker?.pid && !worker.killed) {
|
||||||
|
worker.kill()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should kill process correctly', function(done) {
|
||||||
|
worker = spawn('node', ['./test/kill/runner.mjs'])
|
||||||
|
assert.ok(worker.pid)
|
||||||
|
|
||||||
|
worker.on('exit', done.finish(function(code, signal) {
|
||||||
|
assert.ok(code || signal)
|
||||||
|
}))
|
||||||
|
|
||||||
|
kill(worker.pid)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.test('should succeed in killing tree', async function() {
|
||||||
|
worker = spawn('node', ['./test/kill/runner.mjs'])
|
||||||
|
assert.ok(worker.pid)
|
||||||
|
|
||||||
|
// Give it some time to start
|
||||||
|
await new Promise(res => {
|
||||||
|
worker.stdout.on('data', function(data) {
|
||||||
|
if (data.toString().indexOf('secondary') >= 0) res()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
return kill(worker.pid).then(function(pids) {
|
||||||
|
assert.strictEqual(pids.size, 2)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { spawn } from 'child_process'
|
||||||
|
|
||||||
|
console.log('primary', process.pid)
|
||||||
|
|
||||||
|
let secondary = spawn('node', ['./test/kill/second_runner.mjs'])
|
||||||
|
|
||||||
|
secondary.stdout.on('data', function(data) {
|
||||||
|
process.stdout.write(data)
|
||||||
|
})
|
||||||
|
|
||||||
|
setInterval(function() { console.log('primary', process.pid) }, 100)
|
|
@ -0,0 +1,2 @@
|
||||||
|
console.log('secondary', process.pid)
|
||||||
|
setInterval(function() { console.log('secondary', process.pid) }, 100)
|
|
@ -28,7 +28,7 @@ t.afterEach(function(done) {
|
||||||
|
|
||||||
t.after(function() {
|
t.after(function() {
|
||||||
if (builder) {
|
if (builder) {
|
||||||
builder.cleanup()
|
return builder.cleanup()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -173,7 +173,7 @@ Builder.prototype.newRandomFiles = function(fpath, count) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder.prototype.cleanup = function() {
|
Builder.prototype.cleanup = function() {
|
||||||
return fs.rmdir(this.root)
|
return fs.rm(this.root, { recursive: true, force: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
Builder.prototype.getAllDirectories = function() {
|
Builder.prototype.getAllDirectories = function() {
|
||||||
|
|
Loading…
Reference in New Issue