Skip to content
This repository has been archived by the owner on Feb 1, 2022. It is now read-only.

Support for debugging a pid #37

Merged
merged 1 commit into from
Apr 4, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 69 additions & 52 deletions lib/_inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,52 +53,6 @@ function getDefaultPort() {
return 9229;
}

function runScript(script, scriptArgs, inspectPort, childPrint) {
return new Promise((resolve) => {
const args = [
`--inspect-brk=${inspectPort}`,
].concat([script], scriptArgs);
const child = spawn(process.execPath, args);
child.stdout.setEncoding('utf8');
child.stderr.setEncoding('utf8');
child.stdout.on('data', childPrint);
child.stderr.on('data', childPrint);

let output = '';
function waitForListenHint(text) {
output += text;
if (/^Debugger listening on/.test(output)) {
child.stderr.removeListener('data', waitForListenHint);
resolve(child);
}
}

child.stderr.on('data', waitForListenHint);
});
}

function createAgentProxy(domain, client) {
const agent = new EventEmitter();
agent.then = (...args) => {
// TODO: potentially fetch the protocol and pretty-print it here.
const descriptor = {
[util.inspect.custom](depth, { stylize }) {
return stylize(`[Agent ${domain}]`, 'special');
},
};
return Promise.resolve(descriptor).then(...args);
};

return new Proxy(agent, {
get(target, name) {
if (name in target) return target[name];
return function callVirtualMethod(params) {
return client.callMethod(`${domain}.${name}`, params);
};
},
});
}

function portIsFree(host, port, timeout = 2000) {
const retryDelay = 150;
let didTimeOut = false;
Expand Down Expand Up @@ -138,6 +92,56 @@ function portIsFree(host, port, timeout = 2000) {
});
}

function runScript(script, scriptArgs, inspectHost, inspectPort, childPrint) {
return portIsFree(inspectHost, inspectPort)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving the port check here so it's skipped for remote debugging. Waiting or the the port to be available doesn't make sense for node inspect <host>:<port>/node inspect -p <pid>.

.then(() => {
return new Promise((resolve) => {
const args = [
'--inspect',
`--debug-brk=${inspectPort}`,
].concat([script], scriptArgs);
const child = spawn(process.execPath, args);
child.stdout.setEncoding('utf8');
child.stderr.setEncoding('utf8');
child.stdout.on('data', childPrint);
child.stderr.on('data', childPrint);

let output = '';
function waitForListenHint(text) {
output += text;
if (/chrome-devtools:\/\//.test(output)) {
child.stderr.removeListener('data', waitForListenHint);
resolve(child);
}
}

child.stderr.on('data', waitForListenHint);
});
});
}

function createAgentProxy(domain, client) {
const agent = new EventEmitter();
agent.then = (...args) => {
// TODO: potentially fetch the protocol and pretty-print it here.
const descriptor = {
[util.inspect.custom](depth, { stylize }) {
return stylize(`[Agent ${domain}]`, 'special');
},
};
return Promise.resolve(descriptor).then(...args);
};

return new Proxy(agent, {
get(target, name) {
if (name in target) return target[name];
return function callVirtualMethod(params) {
return client.callMethod(`${domain}.${name}`, params);
};
},
});
}

class NodeInspector {
constructor(options, stdin, stdout) {
this.options = options;
Expand All @@ -151,6 +155,7 @@ class NodeInspector {
this._runScript = runScript.bind(null,
options.script,
options.scriptArgs,
options.host,
options.port,
this.childPrint.bind(this));
} else {
Expand Down Expand Up @@ -219,12 +224,7 @@ class NodeInspector {
this.killChild();
const { host, port } = this.options;

const runOncePortIsFree = () => {
return portIsFree(host, port)
.then(() => this._runScript());
};

return runOncePortIsFree().then((child) => {
return this._runScript().then((child) => {
this.child = child;

let connectionAttempts = 0;
Expand Down Expand Up @@ -308,6 +308,22 @@ function parseArgv([target, ...args]) {
port = parseInt(portMatch[1], 10);
script = args[0];
scriptArgs = args.slice(1);
} else if (args.length === 1 && /^\d+$/.test(args[0]) && target === '-p') {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pretty much 1:1 copy of the existing _debugger.js code.

// Start debugger against a given pid
const pid = parseInt(args[0], 10);
try {
process._debugProcess(pid);
} catch (e) {
if (e.code === 'ESRCH') {
/* eslint-disable no-console */
console.error(`Target process: ${pid} doesn't exist.`);
/* eslint-enable no-console */
process.exit(1);
}
throw e;
}
script = null;
isRemote = true;
}

return {
Expand All @@ -326,6 +342,7 @@ function startInspect(argv = process.argv.slice(2),

console.error(`Usage: ${invokedAs} script.js`);
console.error(` ${invokedAs} <host>:<port>`);
console.error(` ${invokedAs} -p <pid>`);
process.exit(1);
}

Expand Down
2 changes: 1 addition & 1 deletion test/cli/launch.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ test('examples/three-lines.js', (t) => {
t.match(cli.output, 'debug>', 'prints a prompt');
t.match(
cli.output,
new RegExp(`< Debugger listening on [^\n]*9229`),
/< Debugger listening on [^\n]*9229/,
'forwards child output');
})
.then(() => cli.command('["hello", "world"].join(" ")'))
Expand Down
52 changes: 52 additions & 0 deletions test/cli/pid.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use strict';
const { spawn } = require('child_process');
const Path = require('path');

const { test } = require('tap');

const startCLI = require('./start-cli');

function launchTarget(...args) {
const childProc = spawn(process.execPath, args);
return Promise.resolve(childProc);
}

// process.debugPort is our proxy for "the version of node used to run this
// test suite doesn't support SIGUSR1 for enabling --inspect for a process".
const defaultsToOldProtocol = process.debugPort === 5858;

test('examples/alive.js', { skip: defaultsToOldProtocol }, (t) => {
const script = Path.join('examples', 'alive.js');
let cli = null;
let target = null;

function cleanup(error) {
if (cli) {
cli.quit();
cli = null;
}
if (target) {
target.kill();
target = null;
}
if (error) throw error;
}

return launchTarget(script)
.then((childProc) => {
target = childProc;
cli = startCLI(['-p', `${target.pid}`]);
return cli.waitForPrompt();
})
.then(() => cli.command('sb("alive.js", 3)'))
.then(() => cli.waitFor(/break/))
.then(() => cli.waitForPrompt())
.then(() => {
t.match(
cli.output,
'> 3 ++x;',
'marks the 3rd line');
})
.then(() => cleanup())
.then(null, cleanup);
});