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

Commit 6052946

Browse files
authored
Merge pull request #34 from nodejs/jk-delay-run
Delay run until breakpoints are restored
2 parents d54a448 + 8b101bf commit 6052946

15 files changed

+143
-49
lines changed

examples/alive.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use strict';
21
let x = 0;
32
function heartbeat() {
43
++x;

examples/backtrace.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use strict';
21
const { exports: moduleScoped } = module;
32

43
function topFn(a, b = false) {

examples/cjs/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
'use strict';
1+
const fourty = 40;
22
const { add } = require('./other');
33

4-
const sum = add(40, 2);
4+
const sum = add(fourty, 2);
55
module.exports = sum;

examples/cjs/other.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use strict';
21
exports.add = function add(a, b) {
32
return a + b;
43
};

examples/exceptions.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use strict';
21
let error = null;
32
try {
43
throw new Error('Caught');

examples/three-lines.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
'use strict';
21
let x = 1;
32
x = x + 1;
43
module.exports = x;

examples/use-strict.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
'use strict';
2+
console.log('first real line');

lib/_inspect.js

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
'use strict';
2323
const { spawn } = require('child_process');
2424
const { EventEmitter } = require('events');
25+
const net = require('net');
2526
const util = require('util');
2627

2728
const runAsStandalone = typeof __dirname !== 'undefined';
@@ -99,6 +100,45 @@ function createAgentProxy(domain, client) {
99100
});
100101
}
101102

103+
function portIsFree(host, port, timeout = 2000) {
104+
const retryDelay = 150;
105+
let didTimeOut = false;
106+
107+
return new Promise((resolve, reject) => {
108+
setTimeout(() => {
109+
didTimeOut = true;
110+
reject(new Error(
111+
`Timeout (${timeout}) waiting for ${host}:${port} to be free`));
112+
}, timeout);
113+
114+
function pingPort() {
115+
if (didTimeOut) return;
116+
117+
const socket = net.connect(port, host);
118+
let didRetry = false;
119+
function retry() {
120+
if (!didRetry && !didTimeOut) {
121+
didRetry = true;
122+
setTimeout(pingPort, retryDelay);
123+
}
124+
}
125+
126+
socket.on('error', (error) => {
127+
if (error.code === 'ECONNREFUSED') {
128+
resolve();
129+
} else {
130+
retry();
131+
}
132+
});
133+
socket.on('connect', () => {
134+
socket.destroy();
135+
retry();
136+
});
137+
}
138+
pingPort();
139+
});
140+
}
141+
102142
class NodeInspector {
103143
constructor(options, stdin, stdout) {
104144
this.options = options;
@@ -139,8 +179,9 @@ class NodeInspector {
139179
process.once('SIGHUP', process.exit.bind(process, 0));
140180

141181
this.run()
142-
.then(() => {
143-
this.repl = startRepl();
182+
.then(() => startRepl())
183+
.then((repl) => {
184+
this.repl = repl;
144185
this.repl.on('exit', () => {
145186
process.exit(0);
146187
});
@@ -150,15 +191,19 @@ class NodeInspector {
150191
}
151192

152193
suspendReplWhile(fn) {
153-
this.repl.rli.pause();
194+
if (this.repl) {
195+
this.repl.rli.pause();
196+
}
154197
this.stdin.pause();
155198
this.paused = true;
156199
return new Promise((resolve) => {
157200
resolve(fn());
158201
}).then(() => {
159202
this.paused = false;
160-
this.repl.rli.resume();
161-
this.repl.displayPrompt();
203+
if (this.repl) {
204+
this.repl.rli.resume();
205+
this.repl.displayPrompt();
206+
}
162207
this.stdin.resume();
163208
}).then(null, (error) => process.nextTick(() => { throw error; }));
164209
}
@@ -173,7 +218,14 @@ class NodeInspector {
173218

174219
run() {
175220
this.killChild();
176-
return this._runScript().then((child) => {
221+
const { host, port } = this.options;
222+
223+
const runOncePortIsFree = () => {
224+
return portIsFree(host, port)
225+
.then(() => this._runScript());
226+
};
227+
228+
return runOncePortIsFree().then((child) => {
177229
this.child = child;
178230

179231
let connectionAttempts = 0;
@@ -198,7 +250,6 @@ class NodeInspector {
198250
});
199251
};
200252

201-
const { host, port } = this.options;
202253
this.print(`connecting to ${host}:${port} ..`, true);
203254
return attemptConnect();
204255
});

lib/internal/inspect_client.js

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -334,20 +334,7 @@ class Client extends EventEmitter {
334334
this.emit('close');
335335
});
336336

337-
Promise.all([
338-
this.callMethod('Runtime.enable'),
339-
this.callMethod('Debugger.enable'),
340-
this.callMethod('Debugger.setPauseOnExceptions', { state: 'none' }),
341-
this.callMethod('Debugger.setAsyncCallStackDepth', { maxDepth: 0 }),
342-
this.callMethod('Profiler.enable'),
343-
this.callMethod('Profiler.setSamplingInterval', { interval: 100 }),
344-
this.callMethod('Debugger.setBlackboxPatterns', { patterns: [] }),
345-
this.callMethod('Runtime.runIfWaitingForDebugger'),
346-
]).then(() => {
347-
this.emit('ready');
348-
}, (error) => {
349-
this.emit('error', error);
350-
});
337+
this.emit('ready');
351338
};
352339

353340
return new Promise((resolve, reject) => {

lib/internal/inspect_repl.js

Lines changed: 34 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -748,8 +748,8 @@ function createRepl(inspector) {
748748
.filter(({ location }) => !!location.scriptUrl)
749749
.map(({ location }) =>
750750
setBreakpoint(location.scriptUrl, location.lineNumber + 1));
751-
if (!newBreakpoints.length) return;
752-
Promise.all(newBreakpoints).then((results) => {
751+
if (!newBreakpoints.length) return Promise.resolve();
752+
return Promise.all(newBreakpoints).then((results) => {
753753
print(`${results.length} breakpoints restored.`);
754754
});
755755
}
@@ -770,16 +770,19 @@ function createRepl(inspector) {
770770
const breakType = reason === 'other' ? 'break' : reason;
771771
const script = knownScripts[scriptId];
772772
const scriptUrl = script ? getRelativePath(script.url) : '[unknown]';
773-
print(`${breakType} in ${scriptUrl}:${lineNumber + 1}`);
773+
774+
const header = `${breakType} in ${scriptUrl}:${lineNumber + 1}`;
774775

775776
inspector.suspendReplWhile(() =>
776777
Promise.all([formatWatchers(true), selectedFrame.list(2)])
777778
.then(([watcherList, context]) => {
778779
if (watcherList) {
779780
return `${watcherList}\n${inspect(context)}`;
780781
}
781-
return context;
782-
}).then(print));
782+
return inspect(context);
783+
}).then((breakContext) => {
784+
print(`${header}\n${breakContext}`);
785+
}));
783786
});
784787

785788
function handleResumed() {
@@ -1026,7 +1029,30 @@ function createRepl(inspector) {
10261029
aliasProperties(context, SHORTCUTS);
10271030
}
10281031

1032+
function initAfterStart() {
1033+
const setupTasks = [
1034+
Runtime.enable(),
1035+
Profiler.enable(),
1036+
Profiler.setSamplingInterval({ interval: 100 }),
1037+
Debugger.enable(),
1038+
Debugger.setPauseOnExceptions({ state: 'none' }),
1039+
Debugger.setAsyncCallStackDepth({ maxDepth: 0 }),
1040+
Debugger.setBlackboxPatterns({ patterns: [] }),
1041+
Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }),
1042+
restoreBreakpoints(),
1043+
Runtime.runIfWaitingForDebugger(),
1044+
];
1045+
return Promise.all(setupTasks);
1046+
}
1047+
10291048
return function startRepl() {
1049+
inspector.client.on('close', () => {
1050+
resetOnStart();
1051+
});
1052+
inspector.client.on('ready', () => {
1053+
initAfterStart();
1054+
});
1055+
10301056
const replOptions = {
10311057
prompt: 'debug> ',
10321058
input: inspector.stdin,
@@ -1035,6 +1061,7 @@ function createRepl(inspector) {
10351061
useGlobal: false,
10361062
ignoreUndefined: true,
10371063
};
1064+
10381065
repl = Repl.start(replOptions); // eslint-disable-line prefer-const
10391066
initializeContext(repl.context);
10401067
repl.on('reset', initializeContext);
@@ -1044,14 +1071,8 @@ function createRepl(inspector) {
10441071
repl.rli.emit('SIGINT');
10451072
});
10461073

1047-
inspector.client.on('close', () => {
1048-
resetOnStart();
1049-
});
1050-
1051-
inspector.client.on('ready', () => {
1052-
restoreBreakpoints();
1053-
Debugger.setPauseOnExceptions({ state: pauseOnExceptionState });
1054-
});
1074+
// Init once for the initial connection
1075+
initAfterStart();
10551076

10561077
return repl;
10571078
};

0 commit comments

Comments
 (0)