diff --git a/doc/api/debugger.markdown b/doc/api/debugger.markdown index 2c68c1d49e5..f4f989072d9 100644 --- a/doc/api/debugger.markdown +++ b/doc/api/debugger.markdown @@ -109,6 +109,30 @@ functions body script.js * `clearBreakpoint`, `cb(...)` - Clear breakpoint +It is also possible to set a breakpoint in a file (module) that +isn't loaded yet: + + % ./node debug test/fixtures/break-in-module/main.js + < debugger listening on port 5858 + connecting to port 5858... ok + break in test/fixtures/break-in-module/main.js:1 + 1 var mod = require('./mod.js'); + 2 mod.hello(); + 3 mod.hello(); + debug> setBreakpoint('mod.js', 23) + Warning: script 'mod.js' was not loaded yet. + 1 var mod = require('./mod.js'); + 2 mod.hello(); + 3 mod.hello(); + debug> c + break in test/fixtures/break-in-module/mod.js:23 + 21 + 22 exports.hello = function() { + 23 return 'hello from module'; + 24 }; + 25 + debug> + ### Info * `backtrace`, `bt` - Print backtrace of current execution frame diff --git a/lib/_debugger.js b/lib/_debugger.js index 106e55cb555..170f5e7e6e1 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -1385,16 +1385,28 @@ Interface.prototype.setBreakpoint = function(script, line, scriptId = script; } - if (!scriptId) return this.error('Script : ' + script + ' not found'); if (ambiguous) return this.error('Script name is ambiguous'); if (line <= 0) return this.error('Line should be a positive value'); - var req = { - type: 'scriptId', - target: scriptId, - line: line - 1, - condition: condition - }; + var req; + if (scriptId) { + req = { + type: 'scriptId', + target: scriptId, + line: line - 1, + condition: condition + }; + } else { + this.print('Warning: script \'' + script + '\' was not loaded yet.'); + var normalizedPath = script.replace('([/.?*])', '\\$1'); + var scriptPathRegex = '^(.*[\\/\\\\])?' + normalizedPath + '$'; + req = { + type: 'scriptRegExp', + target: scriptPathRegex, + line: line - 1, + condition: condition + }; + } } self.pause(); @@ -1411,20 +1423,18 @@ Interface.prototype.setBreakpoint = function(script, line, // Try load scriptId and line from response if (!scriptId) { scriptId = res.script_id; - line = res.line; - } - - // If we finally have one - remember this breakpoint - if (scriptId) { - self.client.breakpoints.push({ - id: res.breakpoint, - scriptId: scriptId, - script: (self.client.scripts[scriptId] || {}).name, - line: line, - condition: condition - }); + line = res.line + 1; } + // Remember this breakpoint even if scriptId is not resolved yet + self.client.breakpoints.push({ + id: res.breakpoint, + scriptId: scriptId, + script: (self.client.scripts[scriptId] || {}).name, + line: line, + condition: condition, + scriptReq: script + }); } self.resume(); }); @@ -1439,7 +1449,9 @@ Interface.prototype.clearBreakpoint = function(script, line) { index; this.client.breakpoints.some(function(bp, i) { - if (bp.scriptId === script || bp.script.indexOf(script) !== -1) { + if (bp.scriptId === script || + bp.scriptReq === script || + (bp.script && bp.script.indexOf(script) !== -1)) { if (index !== undefined) { ambiguous = true; } @@ -1657,7 +1669,8 @@ Interface.prototype.trySpawn = function(cb) { // Restore breakpoints breakpoints.forEach(function(bp) { - self.setBreakpoint(bp.scriptId, bp.line, bp.condition, true); + self.print('Restoring breakpoint ' + bp.scriptReq + ':' + bp.line); + self.setBreakpoint(bp.scriptReq, bp.line, bp.condition, true); }); client.on('close', function() { diff --git a/test/fixtures/break-in-module/main.js b/test/fixtures/break-in-module/main.js new file mode 100644 index 00000000000..cb7074ed2a3 --- /dev/null +++ b/test/fixtures/break-in-module/main.js @@ -0,0 +1,4 @@ +var mod = require('./mod.js'); +mod.hello(); +mod.hello(); +debugger; diff --git a/test/fixtures/break-in-module/mod.js b/test/fixtures/break-in-module/mod.js new file mode 100644 index 00000000000..57bf58bb31a --- /dev/null +++ b/test/fixtures/break-in-module/mod.js @@ -0,0 +1,24 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +exports.hello = function() { + return 'hello from module'; +}; diff --git a/test/simple/helper-debugger-repl.js b/test/simple/helper-debugger-repl.js index 2ef3ea35a63..9a39bbb9f20 100644 --- a/test/simple/helper-debugger-repl.js +++ b/test/simple/helper-debugger-repl.js @@ -126,16 +126,23 @@ function addTest(input, output) { expected.push({input: input, lines: output, callback: next}); } -var initialLines = [ +var handshakeLines = [ /listening on port \d+/, - /connecting.* ok/, + /connecting.* ok/ +]; + +var initialBreakLines = [ /break in .*:1/, /1/, /2/, /3/ ]; +var initialLines = handshakeLines.concat(initialBreakLines); + // Process initial lines addTest(null, initialLines); exports.startDebugger = startDebugger; exports.addTest = addTest; exports.initialLines = initialLines; +exports.handshakeLines = handshakeLines; +exports.initialBreakLines = initialBreakLines; diff --git a/test/simple/test-debugger-repl-break-in-module.js b/test/simple/test-debugger-repl-break-in-module.js new file mode 100644 index 00000000000..ddf17f8ee18 --- /dev/null +++ b/test/simple/test-debugger-repl-break-in-module.js @@ -0,0 +1,72 @@ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +var repl = require('./helper-debugger-repl.js'); + +repl.startDebugger('break-in-module/main.js'); + +// -- SET BREAKPOINT -- + +// Set breakpoint by file name + line number where the file is not loaded yet +repl.addTest('sb("mod.js", 23)', [ + /Warning: script 'mod\.js' was not loaded yet\./, + /1/, /2/, /3/, /4/, /5/, /6/ +]); + +// continue - the breakpoint should be triggered +repl.addTest('c', [ + /break in .*[\\\/]mod\.js:23/, + /21/, /22/, /23/, /24/, /25/ +]); + +// -- RESTORE BREAKPOINT ON RESTART -- + +// Restart the application - breakpoint should be restored +repl.addTest('restart', [].concat( + [ + /terminated/ + ], + repl.handshakeLines, + [ + /Restoring breakpoint mod.js:23/, + /Warning: script 'mod\.js' was not loaded yet\./ + ], + repl.initialBreakLines)); + +// continue - the breakpoint should be triggered +repl.addTest('c', [ + /break in .*[\\\/]mod\.js:23/, + /21/, /22/, /23/, /24/, /25/ +]); + +// -- CLEAR BREAKPOINT SET IN MODULE TO BE LOADED -- + +repl.addTest('cb("mod.js", 23)', [ + /18/, /./, /./, /./, /./, /./, /./, /./, /26/ +]); + +repl.addTest('c', [ + /break in .*[\\\/]main\.js:4/, + /2/, /3/, /4/, /5/, /6/ +]); + +// -- (END) -- +repl.addTest('quit', []);