byebug-dap 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +8 -0
- data/bin/byebug-dap +12 -5
- data/lib/byebug/dap.rb +1 -0
- data/lib/byebug/dap/child_spawned_event_body.rb +11 -0
- data/lib/byebug/dap/command_processor.rb +1 -3
- data/lib/byebug/dap/controller.rb +25 -20
- data/lib/byebug/dap/interface.rb +42 -4
- data/lib/byebug/dap/server.rb +21 -13
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cdcb974e222d9a64fea6f7f070e0352dc746dfd6f331d4b7230aad278ba563db
|
4
|
+
data.tar.gz: 91af303a92685b001c2fee3039f47cba119b67f3edefdeb11b9f28d54d6e2608
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c29328a148dc9e690452fdb09acbb5f63a6612a85f1e5c5cfa7a14b72ed5517b99d0fca4077ca3001d9d4cfbe0b25afa9f3475d65d21ee01369cb623af8462a4
|
7
|
+
data.tar.gz: 79f5f2dcfb469ab62250543620473f34c9dce69204eef8bb27cfeb1b636041716effb1f1486cd50ebb1c72e2770b627be5361112e2e64a6b97fd4d93fa9768d4
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# Change Log
|
2
|
+
|
3
|
+
## 0.1.2
|
4
|
+
|
5
|
+
- Fix possible failure when a breakpoint is hit but can't be resolved
|
6
|
+
- Fix possible failure when frame arguments can't be evaluated
|
7
|
+
- Exit on disconnect when started by 'launch'
|
8
|
+
- Expose `Server#wait_for_client` instead of passing a block
|
9
|
+
- Expose `Interface#stop!` to allow the debugee to stop
|
10
|
+
- Support specifying a start sequence with `--on-start CODE`
|
11
|
+
- Support for child processes
|
12
|
+
|
13
|
+
## 0.1.1
|
14
|
+
|
15
|
+
- Improve error handling in `Byebug::DAP::Controller`
|
16
|
+
|
17
|
+
## 0.1.0
|
18
|
+
|
19
|
+
- Initial release
|
data/README.md
CHANGED
@@ -2,3 +2,11 @@
|
|
2
2
|
|
3
3
|
This gem adds [Debug Adapter
|
4
4
|
Protocol](https://microsoft.github.io/debug-adapter-protocol) support to Byebug.
|
5
|
+
|
6
|
+
## TODO
|
7
|
+
|
8
|
+
- Multi-process support
|
9
|
+
- Stdout/stderr
|
10
|
+
- In STDIO mode, spawn with extra FDs and use those instead of 0/1?
|
11
|
+
- Many DAP features are already supported by Byebug and just need to be
|
12
|
+
implemented in DAP mode
|
data/bin/byebug-dap
CHANGED
@@ -26,6 +26,7 @@ OptionParser.new do |opts|
|
|
26
26
|
opts.on("-f", "--[no-]force", "When listening on a unix socket, delete the socket if it exists") { |v| options[:force] = v }
|
27
27
|
opts.on("--debug-protocol", "Debug DAP") { |v| Byebug::DAP::Debug.protocol = true if v }
|
28
28
|
opts.on("--debug-evaluate", "Debug variable evaluation") { |v| Byebug::DAP::Debug.evaluate = true if v }
|
29
|
+
opts.on("--on-start CODE", "Code to print once the debugger is available") { |v| options[:start_code] = v }
|
29
30
|
end.parse!
|
30
31
|
|
31
32
|
program = next_arg
|
@@ -59,16 +60,22 @@ else
|
|
59
60
|
end
|
60
61
|
|
61
62
|
begin
|
62
|
-
STDERR.
|
63
|
+
STDERR.print "Starting DAP... " unless options[:start_code]
|
64
|
+
|
65
|
+
server = Byebug.start_dap(host, port)
|
66
|
+
|
67
|
+
STDERR.puts options[:start_code] if options[:start_code]
|
63
68
|
STDERR.flush
|
64
69
|
|
65
70
|
if options[:wait]
|
66
|
-
|
67
|
-
|
68
|
-
Byebug.start_dap(host, port)
|
69
|
-
require File.realpath(program)
|
71
|
+
STDERR.print "waiting for debugger... " unless options[:start_code]
|
72
|
+
server.wait_for_client
|
70
73
|
end
|
71
74
|
|
75
|
+
STDERR.puts "ok" unless options[:start_code]
|
76
|
+
|
77
|
+
require File.realpath(program)
|
78
|
+
|
72
79
|
ensure
|
73
80
|
File.delete(port) if File.exist?(port) if host == :unix
|
74
81
|
end
|
data/lib/byebug/dap.rb
CHANGED
@@ -103,12 +103,10 @@ module Byebug
|
|
103
103
|
def stopped!
|
104
104
|
case context.stop_reason
|
105
105
|
when :breakpoint
|
106
|
-
number = Byebug.breakpoints.index(@at_breakpoint) + 1
|
107
|
-
|
108
106
|
args = {
|
109
107
|
reason: 'breakpoint',
|
110
108
|
description: 'Hit breakpoint',
|
111
|
-
text: "Stopped by breakpoint
|
109
|
+
text: "Stopped by breakpoint at #{context.frame.file}:#{context.frame.line}",
|
112
110
|
}
|
113
111
|
|
114
112
|
when :catchpoint
|
@@ -1,11 +1,9 @@
|
|
1
1
|
module Byebug
|
2
2
|
module DAP
|
3
3
|
class Controller
|
4
|
-
|
5
|
-
|
6
|
-
def initialize(interface, signal_start = nil)
|
4
|
+
def initialize(interface, &block)
|
7
5
|
@interface = interface
|
8
|
-
@
|
6
|
+
@on_configured = block
|
9
7
|
|
10
8
|
@trace = TracePoint.new(:thread_begin, :thread_end) { |t| process_trace t }
|
11
9
|
end
|
@@ -13,16 +11,17 @@ module Byebug
|
|
13
11
|
def run
|
14
12
|
loop do
|
15
13
|
@request = @interface.receive
|
16
|
-
process_command @request
|
14
|
+
result = process_command @request
|
15
|
+
return if result == :stop
|
17
16
|
end
|
18
17
|
|
19
|
-
rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
|
18
|
+
rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
|
20
19
|
STDERR.puts "\nClient disconnected"
|
21
20
|
|
22
21
|
ensure
|
23
|
-
|
24
|
-
|
25
|
-
@interface.
|
22
|
+
exit if @exit_on_disconnect
|
23
|
+
|
24
|
+
@interface.stop!
|
26
25
|
@trace.disable
|
27
26
|
end
|
28
27
|
|
@@ -45,6 +44,19 @@ module Byebug
|
|
45
44
|
end
|
46
45
|
|
47
46
|
def process_command(request)
|
47
|
+
case request.command
|
48
|
+
when 'attach', 'launch'
|
49
|
+
if Byebug.started?
|
50
|
+
respond! success: false, message: "Cannot #{request.command} - debugger is already running"
|
51
|
+
return
|
52
|
+
end
|
53
|
+
when 'pause', 'next', 'stepIn', 'stepOut', 'continue', 'evaluate', 'variables', 'scopes', 'threads', 'stackTrace'
|
54
|
+
unless Byebug.started?
|
55
|
+
respond! success: false, message: "Cannot #{request.command} - debugger is not running"
|
56
|
+
return
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
48
60
|
case request.command
|
49
61
|
when 'initialize'
|
50
62
|
# "The ‘initialize’ request is sent as the first request from the client to the debug adapter
|
@@ -67,7 +79,7 @@ module Byebug
|
|
67
79
|
# "This behavior can be controlled with the ‘terminateDebuggee’ argument (if supported by the debug adapter).
|
68
80
|
|
69
81
|
respond!
|
70
|
-
|
82
|
+
return :stop
|
71
83
|
|
72
84
|
when 'attach'
|
73
85
|
# "The attach request is sent from the client to the debug adapter to attach to a debuggee that is already running.
|
@@ -76,8 +88,6 @@ module Byebug
|
|
76
88
|
Byebug.start
|
77
89
|
@trace.enable
|
78
90
|
|
79
|
-
@signal_start.call(:attach) if @signal_start
|
80
|
-
|
81
91
|
respond!
|
82
92
|
return
|
83
93
|
|
@@ -90,7 +100,7 @@ module Byebug
|
|
90
100
|
@trace.enable
|
91
101
|
end
|
92
102
|
|
93
|
-
@
|
103
|
+
@exit_on_disconnect = true
|
94
104
|
|
95
105
|
respond!
|
96
106
|
return
|
@@ -98,16 +108,11 @@ module Byebug
|
|
98
108
|
when 'configurationDone'
|
99
109
|
# "This optional request indicates that the client has finished initialization of the debug adapter.
|
100
110
|
|
101
|
-
respond!
|
102
|
-
return
|
103
|
-
end
|
104
111
|
|
105
|
-
|
106
|
-
respond!
|
112
|
+
@on_configured&.call
|
113
|
+
respond!
|
107
114
|
return
|
108
|
-
end
|
109
115
|
|
110
|
-
case request.command
|
111
116
|
when 'pause', 'next', 'stepIn', 'stepOut', 'continue'
|
112
117
|
ctx = @interface.find_thread(request.arguments.threadId)
|
113
118
|
ctx.interrupt if request.command == 'pause'
|
data/lib/byebug/dap/interface.rb
CHANGED
@@ -3,26 +3,58 @@ module Byebug
|
|
3
3
|
class Interface
|
4
4
|
include SafeHelpers
|
5
5
|
|
6
|
+
@@children = []
|
7
|
+
|
8
|
+
def self.child_spawned(name, pid, socket)
|
9
|
+
child = ChildSpawnedEventBody.new(name: name, pid: pid, socket: socket)
|
10
|
+
@@children << child
|
11
|
+
|
12
|
+
interface = Context.interface
|
13
|
+
interface.event! child if interface.is_a?(Byebug::DAP::Interface)
|
14
|
+
|
15
|
+
return true
|
16
|
+
|
17
|
+
rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
6
21
|
attr_reader :socket
|
7
22
|
|
8
23
|
def initialize(socket)
|
9
24
|
@socket = socket
|
25
|
+
|
26
|
+
begin
|
27
|
+
@@children.each { |c| event! c }
|
28
|
+
rescue IOError, Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNABORTED
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def stop!
|
33
|
+
Byebug.mode = :off
|
34
|
+
Byebug.stop
|
35
|
+
socket.close
|
10
36
|
end
|
11
37
|
|
12
38
|
def <<(message)
|
13
|
-
STDERR.puts "> #{message.to_wire}" if Debug.protocol
|
39
|
+
STDERR.puts "#{Process.pid} > #{message.to_wire}" if Debug.protocol
|
14
40
|
message.validate!
|
15
41
|
socket.write ::DAP::Encoding.encode(message)
|
16
42
|
end
|
17
43
|
|
18
44
|
def event!(event, **values)
|
19
|
-
|
45
|
+
if (cls = event.class.name.split('::').last) && cls.end_with?('EventBody')
|
46
|
+
body, event = event, cls[0].downcase + cls[1...-9]
|
47
|
+
|
48
|
+
elsif event.is_a?(String) && !values.empty?
|
49
|
+
body = ::DAP.const_get("#{event[0].upcase}#{event[1..]}EventBody").new(values)
|
50
|
+
end
|
51
|
+
|
20
52
|
self << ::DAP::Event.new(event: event, body: body)
|
21
53
|
end
|
22
54
|
|
23
55
|
def receive
|
24
56
|
m = ::DAP::Encoding.decode(socket)
|
25
|
-
STDERR.puts "< #{m.to_wire}" if Debug.protocol
|
57
|
+
STDERR.puts "#{Process.pid} < #{m.to_wire}" if Debug.protocol
|
26
58
|
m
|
27
59
|
end
|
28
60
|
|
@@ -78,7 +110,7 @@ module Byebug
|
|
78
110
|
frame = ::Byebug::Frame.new(ctx, i)
|
79
111
|
::DAP::StackFrame.new(
|
80
112
|
id: frame_ids << [ctx.thnum, i],
|
81
|
-
name: frame
|
113
|
+
name: frame_name(frame),
|
82
114
|
source: ::DAP::Source.new(
|
83
115
|
name: File.basename(frame.file),
|
84
116
|
path: File.expand_path(frame.file)),
|
@@ -194,6 +226,12 @@ module Byebug
|
|
194
226
|
|
195
227
|
private
|
196
228
|
|
229
|
+
def frame_name(frame)
|
230
|
+
frame.deco_call
|
231
|
+
rescue
|
232
|
+
frame.deco_block + frame.deco_class + frame.deco_method + "(?)"
|
233
|
+
end
|
234
|
+
|
197
235
|
def describe_thread(context)
|
198
236
|
if context.thread.name
|
199
237
|
"##{context.thnum} (#{context.thread.name})"
|
data/lib/byebug/dap/server.rb
CHANGED
@@ -20,13 +20,11 @@ module Byebug
|
|
20
20
|
public :<<, :bytes, :chars, :close_read, :close_write, :codepoints, :each, :each_byte, :each_char, :each_codepoint, :each_line, :getbyte, :getc, :gets, :lines, :pread, :print, :printf, :putc, :puts, :pwrite, :read, :read_nonblock, :readbyte, :readchar, :readline, :readlines, :readpartial, :sysread, :syswrite, :ungetbyte, :ungetc, :write, :write_nonblock
|
21
21
|
end
|
22
22
|
|
23
|
-
def initialize
|
23
|
+
def initialize
|
24
24
|
@started = false
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@cond = ConditionVariable.new
|
29
|
-
end
|
25
|
+
@mu = Mutex.new
|
26
|
+
@cond = ConditionVariable.new
|
27
|
+
@configured = false
|
30
28
|
end
|
31
29
|
|
32
30
|
def start(host, port = 0)
|
@@ -61,6 +59,16 @@ module Byebug
|
|
61
59
|
launch STDIO.new
|
62
60
|
end
|
63
61
|
|
62
|
+
def wait_for_client
|
63
|
+
@mu.synchronize do
|
64
|
+
loop do
|
65
|
+
return if @configured
|
66
|
+
|
67
|
+
@cond.wait(@mu)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
64
72
|
private
|
65
73
|
|
66
74
|
def launch(server)
|
@@ -74,19 +82,19 @@ module Byebug
|
|
74
82
|
end
|
75
83
|
end
|
76
84
|
|
77
|
-
|
78
|
-
|
79
|
-
@mu.synchronize { @cond.wait(@mu) }
|
80
|
-
|
81
|
-
@on_start.call
|
85
|
+
self
|
82
86
|
end
|
83
87
|
|
84
88
|
def debug(session)
|
85
89
|
Context.interface = Byebug::DAP::Interface.new(session)
|
86
90
|
Context.processor = Byebug::DAP::CommandProcessor
|
87
91
|
|
88
|
-
|
89
|
-
|
92
|
+
Byebug::DAP::Controller.new(Context.interface) do
|
93
|
+
@mu.synchronize do
|
94
|
+
@configured = true
|
95
|
+
@cond.broadcast
|
96
|
+
end
|
97
|
+
end.run
|
90
98
|
end
|
91
99
|
end
|
92
100
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: byebug-dap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ethan Reesor
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-10-
|
11
|
+
date: 2020-10-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.1.
|
33
|
+
version: 0.1.2
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.1.
|
40
|
+
version: 0.1.2
|
41
41
|
description: Implements a Debug Adapter Protocol interface for Byebug
|
42
42
|
email: ethan.reesor@gmail.com
|
43
43
|
executables:
|
@@ -46,11 +46,13 @@ extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
48
|
- AUTHORS
|
49
|
+
- CHANGELOG.md
|
49
50
|
- LICENSE
|
50
51
|
- README.md
|
51
52
|
- bin/byebug-dap
|
52
53
|
- lib/byebug/dap.rb
|
53
54
|
- lib/byebug/dap/channel.rb
|
55
|
+
- lib/byebug/dap/child_spawned_event_body.rb
|
54
56
|
- lib/byebug/dap/command_processor.rb
|
55
57
|
- lib/byebug/dap/controller.rb
|
56
58
|
- lib/byebug/dap/handles.rb
|