readapt 1.4.4 → 2.0.0
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/.github/workflows/rspec.yml +38 -0
- data/.gitignore +16 -16
- data/.rspec +2 -2
- data/.travis.yml +19 -19
- data/CHANGELOG.md +103 -100
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +37 -37
- data/Rakefile +14 -14
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/exe/readapt +5 -5
- data/ext/readapt/breakpoints.c +83 -83
- data/ext/readapt/breakpoints.h +11 -11
- data/ext/readapt/extconf.rb +0 -0
- data/ext/readapt/frame.c +137 -137
- data/ext/readapt/frame.h +17 -17
- data/ext/readapt/inspector.c +51 -51
- data/ext/readapt/inspector.h +8 -8
- data/ext/readapt/lookup_table.c +211 -211
- data/ext/readapt/lookup_table.h +30 -30
- data/ext/readapt/monitor.c +0 -0
- data/ext/readapt/monitor.h +0 -0
- data/ext/readapt/normalize.c +62 -62
- data/ext/readapt/normalize.h +7 -7
- data/ext/readapt/readapt.c +18 -18
- data/ext/readapt/stack.c +86 -86
- data/ext/readapt/stack.h +20 -20
- data/ext/readapt/threads.c +1 -1
- data/ext/readapt/threads.h +0 -0
- data/lib/readapt/adapter.rb +98 -98
- data/lib/readapt/breakpoint.rb +21 -21
- data/lib/readapt/data_reader.rb +62 -62
- data/lib/readapt/debugger.rb +227 -227
- data/lib/readapt/error.rb +63 -63
- data/lib/readapt/finder.rb +34 -34
- data/lib/readapt/frame.rb +40 -40
- data/lib/readapt/input.rb +7 -7
- data/lib/readapt/message/attach.rb +11 -11
- data/lib/readapt/message/base.rb +32 -32
- data/lib/readapt/message/configuration_done.rb +11 -11
- data/lib/readapt/message/continue.rb +15 -15
- data/lib/readapt/message/disconnect.rb +13 -13
- data/lib/readapt/message/evaluate.rb +19 -19
- data/lib/readapt/message/initialize.rb +21 -21
- data/lib/readapt/message/launch.rb +11 -11
- data/lib/readapt/message/next.rb +12 -12
- data/lib/readapt/message/pause.rb +11 -11
- data/lib/readapt/message/scopes.rb +26 -26
- data/lib/readapt/message/set_breakpoints.rb +25 -25
- data/lib/readapt/message/set_exception_breakpoints.rb +11 -11
- data/lib/readapt/message/stack_trace.rb +38 -38
- data/lib/readapt/message/step_in.rb +11 -11
- data/lib/readapt/message/step_out.rb +11 -11
- data/lib/readapt/message/threads.rb +18 -18
- data/lib/readapt/message/variables.rb +53 -53
- data/lib/readapt/message.rb +62 -62
- data/lib/readapt/monitor.rb +0 -0
- data/lib/readapt/output.rb +25 -25
- data/lib/readapt/references.rb +27 -27
- data/lib/readapt/server.rb +22 -22
- data/lib/readapt/shell.rb +104 -104
- data/lib/readapt/snapshot.rb +0 -0
- data/lib/readapt/thread.rb +20 -20
- data/lib/readapt/variable.rb +0 -0
- data/lib/readapt/version.rb +3 -3
- data/lib/readapt.rb +21 -21
- data/readapt.gemspec +39 -39
- metadata +8 -7
data/lib/readapt/debugger.rb
CHANGED
@@ -1,227 +1,227 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'backport'
|
4
|
-
require 'observer'
|
5
|
-
require 'set'
|
6
|
-
|
7
|
-
module Readapt
|
8
|
-
class Debugger
|
9
|
-
include Observable
|
10
|
-
include Finder
|
11
|
-
|
12
|
-
attr_reader :monitor
|
13
|
-
|
14
|
-
attr_reader :file
|
15
|
-
|
16
|
-
attr_writer :pause_on_raise
|
17
|
-
|
18
|
-
def initialize
|
19
|
-
@stack = []
|
20
|
-
@frames = {}
|
21
|
-
@running = false
|
22
|
-
@attached = false
|
23
|
-
@request = nil
|
24
|
-
@config = {}
|
25
|
-
@original_argv = ARGV.clone
|
26
|
-
@original_prog = $0
|
27
|
-
@breakpoints = {}
|
28
|
-
end
|
29
|
-
|
30
|
-
def config arguments, request
|
31
|
-
@file = Readapt.normalize_path(find(arguments['program']))
|
32
|
-
@config = arguments
|
33
|
-
@request = request
|
34
|
-
rescue LoadError => e
|
35
|
-
STDERR.puts e.message
|
36
|
-
end
|
37
|
-
|
38
|
-
def pause_on_raise?
|
39
|
-
@pause_on_raise ||= false
|
40
|
-
end
|
41
|
-
|
42
|
-
# @return [Readapt::Thread]
|
43
|
-
def thread id
|
44
|
-
Thread.find(id)
|
45
|
-
end
|
46
|
-
|
47
|
-
def threads
|
48
|
-
Thread.all
|
49
|
-
end
|
50
|
-
|
51
|
-
def frame id
|
52
|
-
@frames[id] || Frame::NULL_FRAME
|
53
|
-
end
|
54
|
-
|
55
|
-
def launched?
|
56
|
-
@request == :launch
|
57
|
-
end
|
58
|
-
|
59
|
-
def attached?
|
60
|
-
@request == :attach
|
61
|
-
end
|
62
|
-
|
63
|
-
def start
|
64
|
-
::Thread.new do
|
65
|
-
set_program_args
|
66
|
-
run { load @file }
|
67
|
-
set_original_args
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def run
|
72
|
-
# raise RuntimeError, 'Debugger is already running' if @running
|
73
|
-
@running = true
|
74
|
-
send_event('process', {
|
75
|
-
name: @file
|
76
|
-
})
|
77
|
-
Monitor.start @file do |snapshot|
|
78
|
-
debug snapshot
|
79
|
-
end
|
80
|
-
yield if block_given?
|
81
|
-
rescue StandardError => e
|
82
|
-
STDERR.puts "[#{e.class}] #{e.message}"
|
83
|
-
STDERR.puts e.backtrace.join("\n")
|
84
|
-
ensure
|
85
|
-
Monitor.stop
|
86
|
-
@running = false
|
87
|
-
STDOUT.flush #unless STDOUT.closed?
|
88
|
-
STDERR.flush #unless STDERR.closed?
|
89
|
-
changed
|
90
|
-
send_event 'terminated', nil
|
91
|
-
end
|
92
|
-
|
93
|
-
def output data, category = :console
|
94
|
-
send_event('output', {
|
95
|
-
output: data,
|
96
|
-
category: category
|
97
|
-
})
|
98
|
-
end
|
99
|
-
|
100
|
-
def get_breakpoint source, line
|
101
|
-
@breakpoints["#{source}:#{line}"] || Breakpoint.new(source, line, nil, 0)
|
102
|
-
end
|
103
|
-
|
104
|
-
def set_breakpoint source, line, condition, hitcount
|
105
|
-
@breakpoints["#{source}:#{line}"] = Breakpoint.new(source, line, condition, hitcount)
|
106
|
-
end
|
107
|
-
|
108
|
-
def clear_breakpoints source
|
109
|
-
@breakpoints.delete_if { |_key, value|
|
110
|
-
value.source == source
|
111
|
-
}
|
112
|
-
end
|
113
|
-
|
114
|
-
def disconnect
|
115
|
-
shutdown if launched?
|
116
|
-
@request = nil
|
117
|
-
end
|
118
|
-
|
119
|
-
def self.run &block
|
120
|
-
new.run &block
|
121
|
-
end
|
122
|
-
|
123
|
-
private
|
124
|
-
|
125
|
-
# @param [Snapshot]
|
126
|
-
# return [void]
|
127
|
-
def debug snapshot
|
128
|
-
References.clear
|
129
|
-
if snapshot.event == :thread_begin || snapshot.event == :entry
|
130
|
-
thr = Thread.find(snapshot.thread_id)
|
131
|
-
thr.control = :continue
|
132
|
-
send_event('thread', {
|
133
|
-
reason: 'started',
|
134
|
-
threadId: snapshot.thread_id
|
135
|
-
}, true)
|
136
|
-
snapshot.control = :continue
|
137
|
-
elsif snapshot.event == :thread_end
|
138
|
-
thr = thread(snapshot.thread_id)
|
139
|
-
thr.control = :continue
|
140
|
-
send_event('thread', {
|
141
|
-
reason: 'exited',
|
142
|
-
threadId: snapshot.thread_id
|
143
|
-
})
|
144
|
-
snapshot.control = :continue
|
145
|
-
else
|
146
|
-
confirmed_pause = true
|
147
|
-
thread = self.thread(snapshot.thread_id)
|
148
|
-
if snapshot.event == :breakpoint
|
149
|
-
bp = get_breakpoint(snapshot.file, snapshot.line)
|
150
|
-
unless bp.condition.nil? || bp.condition.empty?
|
151
|
-
# @type [Binding]
|
152
|
-
bnd = thread.frames.first.frame_binding
|
153
|
-
begin
|
154
|
-
unless bnd.eval(bp.condition)
|
155
|
-
confirmed_pause = false
|
156
|
-
end
|
157
|
-
rescue StandardError => e
|
158
|
-
STDERR.puts "Breakpoint condition raised an error"
|
159
|
-
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
160
|
-
STDERR.puts "[#{e.class}] #{e.message}"
|
161
|
-
confirmed_pause = false
|
162
|
-
end
|
163
|
-
end
|
164
|
-
unless !confirmed_pause || bp.hit_condition.nil? || bp.hit_condition.empty?
|
165
|
-
bp.hit_cursor += 1
|
166
|
-
bnd = thread.frames.first.frame_binding
|
167
|
-
begin
|
168
|
-
hit_count = bnd.eval(bp.hit_condition)
|
169
|
-
if bp.hit_cursor == hit_count
|
170
|
-
bp.hit_cursor = 0
|
171
|
-
else
|
172
|
-
confirmed_pause = false
|
173
|
-
end
|
174
|
-
rescue StandardError => e
|
175
|
-
STDERR.puts "Breakpoint condition raised an error"
|
176
|
-
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
177
|
-
STDERR.puts "[#{e.class}] #{e.message}"
|
178
|
-
confirmed_pause = false
|
179
|
-
end
|
180
|
-
end
|
181
|
-
elsif snapshot.event == :raise && !pause_on_raise?
|
182
|
-
confirmed_pause = false
|
183
|
-
end
|
184
|
-
if confirmed_pause
|
185
|
-
changed
|
186
|
-
thread.control = :pause
|
187
|
-
thread.frames.each do |frm|
|
188
|
-
@frames[frm.local_id] = frm
|
189
|
-
end
|
190
|
-
send_event('stopped', {
|
191
|
-
reason: snapshot.event,
|
192
|
-
threadId: thread.id
|
193
|
-
})
|
194
|
-
sleep 0.01 until thread.control != :pause || !Thread.include?(thread.id)
|
195
|
-
thread.frames.each do |frm|
|
196
|
-
@frames.delete frm.local_id
|
197
|
-
end
|
198
|
-
else
|
199
|
-
thread.control = :continue
|
200
|
-
end
|
201
|
-
snapshot.control = thread.control
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
def set_program_args
|
206
|
-
$0 = file
|
207
|
-
ARGV.clear
|
208
|
-
ARGV.replace(@config['programArgs'] || [])
|
209
|
-
end
|
210
|
-
|
211
|
-
def set_original_args
|
212
|
-
$0 = @original_prog
|
213
|
-
ARGV.clear
|
214
|
-
ARGV.replace @original_argv
|
215
|
-
end
|
216
|
-
|
217
|
-
def shutdown
|
218
|
-
exit
|
219
|
-
end
|
220
|
-
|
221
|
-
def send_event event, data, wait = false
|
222
|
-
changed
|
223
|
-
notify_observers event, data
|
224
|
-
sleep 0.01 if wait
|
225
|
-
end
|
226
|
-
end
|
227
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'backport'
|
4
|
+
require 'observer'
|
5
|
+
require 'set'
|
6
|
+
|
7
|
+
module Readapt
|
8
|
+
class Debugger
|
9
|
+
include Observable
|
10
|
+
include Finder
|
11
|
+
|
12
|
+
attr_reader :monitor
|
13
|
+
|
14
|
+
attr_reader :file
|
15
|
+
|
16
|
+
attr_writer :pause_on_raise
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
@stack = []
|
20
|
+
@frames = {}
|
21
|
+
@running = false
|
22
|
+
@attached = false
|
23
|
+
@request = nil
|
24
|
+
@config = {}
|
25
|
+
@original_argv = ARGV.clone
|
26
|
+
@original_prog = $0
|
27
|
+
@breakpoints = {}
|
28
|
+
end
|
29
|
+
|
30
|
+
def config arguments, request
|
31
|
+
@file = Readapt.normalize_path(find(arguments['program']))
|
32
|
+
@config = arguments
|
33
|
+
@request = request
|
34
|
+
rescue LoadError => e
|
35
|
+
STDERR.puts e.message
|
36
|
+
end
|
37
|
+
|
38
|
+
def pause_on_raise?
|
39
|
+
@pause_on_raise ||= false
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Readapt::Thread]
|
43
|
+
def thread id
|
44
|
+
Thread.find(id)
|
45
|
+
end
|
46
|
+
|
47
|
+
def threads
|
48
|
+
Thread.all
|
49
|
+
end
|
50
|
+
|
51
|
+
def frame id
|
52
|
+
@frames[id] || Frame::NULL_FRAME
|
53
|
+
end
|
54
|
+
|
55
|
+
def launched?
|
56
|
+
@request == :launch
|
57
|
+
end
|
58
|
+
|
59
|
+
def attached?
|
60
|
+
@request == :attach
|
61
|
+
end
|
62
|
+
|
63
|
+
def start
|
64
|
+
::Thread.new do
|
65
|
+
set_program_args
|
66
|
+
run { load @file }
|
67
|
+
set_original_args
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def run
|
72
|
+
# raise RuntimeError, 'Debugger is already running' if @running
|
73
|
+
@running = true
|
74
|
+
send_event('process', {
|
75
|
+
name: @file
|
76
|
+
})
|
77
|
+
Monitor.start @file do |snapshot|
|
78
|
+
debug snapshot
|
79
|
+
end
|
80
|
+
yield if block_given?
|
81
|
+
rescue StandardError => e
|
82
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
83
|
+
STDERR.puts e.backtrace.join("\n")
|
84
|
+
ensure
|
85
|
+
Monitor.stop
|
86
|
+
@running = false
|
87
|
+
STDOUT.flush #unless STDOUT.closed?
|
88
|
+
STDERR.flush #unless STDERR.closed?
|
89
|
+
changed
|
90
|
+
send_event 'terminated', nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def output data, category = :console
|
94
|
+
send_event('output', {
|
95
|
+
output: data,
|
96
|
+
category: category
|
97
|
+
})
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_breakpoint source, line
|
101
|
+
@breakpoints["#{source}:#{line}"] || Breakpoint.new(source, line, nil, 0)
|
102
|
+
end
|
103
|
+
|
104
|
+
def set_breakpoint source, line, condition, hitcount
|
105
|
+
@breakpoints["#{source}:#{line}"] = Breakpoint.new(source, line, condition, hitcount)
|
106
|
+
end
|
107
|
+
|
108
|
+
def clear_breakpoints source
|
109
|
+
@breakpoints.delete_if { |_key, value|
|
110
|
+
value.source == source
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def disconnect
|
115
|
+
shutdown if launched?
|
116
|
+
@request = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.run &block
|
120
|
+
new.run &block
|
121
|
+
end
|
122
|
+
|
123
|
+
private
|
124
|
+
|
125
|
+
# @param [Snapshot]
|
126
|
+
# return [void]
|
127
|
+
def debug snapshot
|
128
|
+
References.clear
|
129
|
+
if snapshot.event == :thread_begin || snapshot.event == :entry
|
130
|
+
thr = Thread.find(snapshot.thread_id)
|
131
|
+
thr.control = :continue
|
132
|
+
send_event('thread', {
|
133
|
+
reason: 'started',
|
134
|
+
threadId: snapshot.thread_id
|
135
|
+
}, true)
|
136
|
+
snapshot.control = :continue
|
137
|
+
elsif snapshot.event == :thread_end
|
138
|
+
thr = thread(snapshot.thread_id)
|
139
|
+
thr.control = :continue
|
140
|
+
send_event('thread', {
|
141
|
+
reason: 'exited',
|
142
|
+
threadId: snapshot.thread_id
|
143
|
+
})
|
144
|
+
snapshot.control = :continue
|
145
|
+
else
|
146
|
+
confirmed_pause = true
|
147
|
+
thread = self.thread(snapshot.thread_id)
|
148
|
+
if snapshot.event == :breakpoint
|
149
|
+
bp = get_breakpoint(snapshot.file, snapshot.line)
|
150
|
+
unless bp.condition.nil? || bp.condition.empty?
|
151
|
+
# @type [Binding]
|
152
|
+
bnd = thread.frames.first.frame_binding
|
153
|
+
begin
|
154
|
+
unless bnd.eval(bp.condition)
|
155
|
+
confirmed_pause = false
|
156
|
+
end
|
157
|
+
rescue StandardError => e
|
158
|
+
STDERR.puts "Breakpoint condition raised an error"
|
159
|
+
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
160
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
161
|
+
confirmed_pause = false
|
162
|
+
end
|
163
|
+
end
|
164
|
+
unless !confirmed_pause || bp.hit_condition.nil? || bp.hit_condition.empty?
|
165
|
+
bp.hit_cursor += 1
|
166
|
+
bnd = thread.frames.first.frame_binding
|
167
|
+
begin
|
168
|
+
hit_count = bnd.eval(bp.hit_condition)
|
169
|
+
if bp.hit_cursor == hit_count
|
170
|
+
bp.hit_cursor = 0
|
171
|
+
else
|
172
|
+
confirmed_pause = false
|
173
|
+
end
|
174
|
+
rescue StandardError => e
|
175
|
+
STDERR.puts "Breakpoint condition raised an error"
|
176
|
+
STDERR.puts "#{snapshot.file}:#{snapshot.line} - `#{bp.condition}`"
|
177
|
+
STDERR.puts "[#{e.class}] #{e.message}"
|
178
|
+
confirmed_pause = false
|
179
|
+
end
|
180
|
+
end
|
181
|
+
elsif snapshot.event == :raise && !pause_on_raise?
|
182
|
+
confirmed_pause = false
|
183
|
+
end
|
184
|
+
if confirmed_pause
|
185
|
+
changed
|
186
|
+
thread.control = :pause
|
187
|
+
thread.frames.each do |frm|
|
188
|
+
@frames[frm.local_id] = frm
|
189
|
+
end
|
190
|
+
send_event('stopped', {
|
191
|
+
reason: snapshot.event,
|
192
|
+
threadId: thread.id
|
193
|
+
})
|
194
|
+
sleep 0.01 until thread.control != :pause || !Thread.include?(thread.id)
|
195
|
+
thread.frames.each do |frm|
|
196
|
+
@frames.delete frm.local_id
|
197
|
+
end
|
198
|
+
else
|
199
|
+
thread.control = :continue
|
200
|
+
end
|
201
|
+
snapshot.control = thread.control
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
def set_program_args
|
206
|
+
$0 = file
|
207
|
+
ARGV.clear
|
208
|
+
ARGV.replace(@config['programArgs'] || [])
|
209
|
+
end
|
210
|
+
|
211
|
+
def set_original_args
|
212
|
+
$0 = @original_prog
|
213
|
+
ARGV.clear
|
214
|
+
ARGV.replace @original_argv
|
215
|
+
end
|
216
|
+
|
217
|
+
def shutdown
|
218
|
+
exit
|
219
|
+
end
|
220
|
+
|
221
|
+
def send_event event, data, wait = false
|
222
|
+
changed
|
223
|
+
notify_observers event, data
|
224
|
+
sleep 0.01 if wait
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
data/lib/readapt/error.rb
CHANGED
@@ -1,63 +1,63 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
|
-
module Readapt
|
4
|
-
module Error
|
5
|
-
class << self
|
6
|
-
attr_accessor :adapter
|
7
|
-
end
|
8
|
-
|
9
|
-
def opening
|
10
|
-
@buffer = ''
|
11
|
-
end
|
12
|
-
|
13
|
-
def receiving data
|
14
|
-
output = ''
|
15
|
-
data.each_char do |char|
|
16
|
-
@buffer += char
|
17
|
-
if open_message.start_with?(@buffer) || @buffer.start_with?(open_message)
|
18
|
-
if @buffer.end_with?(close_message)
|
19
|
-
msg = @buffer[open_message.length..-(close_message.length+1)]
|
20
|
-
exit if msg == '__TERMINATE__'
|
21
|
-
Error.adapter.write msg
|
22
|
-
@buffer.clear
|
23
|
-
end
|
24
|
-
else
|
25
|
-
output += @buffer
|
26
|
-
@buffer.clear
|
27
|
-
end
|
28
|
-
end
|
29
|
-
return if output.empty?
|
30
|
-
send_event('output', {
|
31
|
-
output: output,
|
32
|
-
category: 'stderr'
|
33
|
-
})
|
34
|
-
end
|
35
|
-
|
36
|
-
def send_event event, data
|
37
|
-
obj = {
|
38
|
-
type: 'event',
|
39
|
-
event: event
|
40
|
-
}
|
41
|
-
obj[:body] = data unless data.nil?
|
42
|
-
json = obj.to_json
|
43
|
-
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
44
|
-
Error.adapter.write envelope
|
45
|
-
end
|
46
|
-
|
47
|
-
def self.procid= pid
|
48
|
-
@@procid = pid
|
49
|
-
end
|
50
|
-
|
51
|
-
def procid
|
52
|
-
@@procid
|
53
|
-
end
|
54
|
-
|
55
|
-
def open_message
|
56
|
-
@@open_message ||= "<readapt-#{procid}>"
|
57
|
-
end
|
58
|
-
|
59
|
-
def close_message
|
60
|
-
@@close_message ||= "</readapt-#{procid}>"
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Readapt
|
4
|
+
module Error
|
5
|
+
class << self
|
6
|
+
attr_accessor :adapter
|
7
|
+
end
|
8
|
+
|
9
|
+
def opening
|
10
|
+
@buffer = ''
|
11
|
+
end
|
12
|
+
|
13
|
+
def receiving data
|
14
|
+
output = ''
|
15
|
+
data.each_char do |char|
|
16
|
+
@buffer += char
|
17
|
+
if open_message.start_with?(@buffer) || @buffer.start_with?(open_message)
|
18
|
+
if @buffer.end_with?(close_message)
|
19
|
+
msg = @buffer[open_message.length..-(close_message.length+1)]
|
20
|
+
exit if msg == '__TERMINATE__'
|
21
|
+
Error.adapter.write msg
|
22
|
+
@buffer.clear
|
23
|
+
end
|
24
|
+
else
|
25
|
+
output += @buffer
|
26
|
+
@buffer.clear
|
27
|
+
end
|
28
|
+
end
|
29
|
+
return if output.empty?
|
30
|
+
send_event('output', {
|
31
|
+
output: output,
|
32
|
+
category: 'stderr'
|
33
|
+
})
|
34
|
+
end
|
35
|
+
|
36
|
+
def send_event event, data
|
37
|
+
obj = {
|
38
|
+
type: 'event',
|
39
|
+
event: event
|
40
|
+
}
|
41
|
+
obj[:body] = data unless data.nil?
|
42
|
+
json = obj.to_json
|
43
|
+
envelope = "Content-Length: #{json.bytesize}\r\n\r\n#{json}"
|
44
|
+
Error.adapter.write envelope
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.procid= pid
|
48
|
+
@@procid = pid
|
49
|
+
end
|
50
|
+
|
51
|
+
def procid
|
52
|
+
@@procid
|
53
|
+
end
|
54
|
+
|
55
|
+
def open_message
|
56
|
+
@@open_message ||= "<readapt-#{procid}>"
|
57
|
+
end
|
58
|
+
|
59
|
+
def close_message
|
60
|
+
@@close_message ||= "</readapt-#{procid}>"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
data/lib/readapt/finder.rb
CHANGED
@@ -1,34 +1,34 @@
|
|
1
|
-
require 'pathname'
|
2
|
-
|
3
|
-
module Readapt
|
4
|
-
# Methods to find a program in the current directory or one of the
|
5
|
-
# environment paths.
|
6
|
-
#
|
7
|
-
module Finder
|
8
|
-
module_function
|
9
|
-
|
10
|
-
# Get the program's fully qualified path. Search first in the current
|
11
|
-
# directory, then the environment paths.
|
12
|
-
#
|
13
|
-
# @raise [LoadError] if the program was not found
|
14
|
-
#
|
15
|
-
# @param program [String] The name of the program
|
16
|
-
# @return [String] The fully qualified path
|
17
|
-
def find program
|
18
|
-
return program if File.exist?(program)
|
19
|
-
which(program) || raise(LoadError, "#{program} is not a valid Ruby file or program")
|
20
|
-
end
|
21
|
-
|
22
|
-
# Search the environment paths for the given program.
|
23
|
-
#
|
24
|
-
# @param program [String] The name of the program
|
25
|
-
# @return [String] The fully qualified path, or nil if it was not found
|
26
|
-
def which program
|
27
|
-
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
28
|
-
exe = File.join(path, program)
|
29
|
-
return exe if File.file?(exe)
|
30
|
-
end
|
31
|
-
nil
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
1
|
+
require 'pathname'
|
2
|
+
|
3
|
+
module Readapt
|
4
|
+
# Methods to find a program in the current directory or one of the
|
5
|
+
# environment paths.
|
6
|
+
#
|
7
|
+
module Finder
|
8
|
+
module_function
|
9
|
+
|
10
|
+
# Get the program's fully qualified path. Search first in the current
|
11
|
+
# directory, then the environment paths.
|
12
|
+
#
|
13
|
+
# @raise [LoadError] if the program was not found
|
14
|
+
#
|
15
|
+
# @param program [String] The name of the program
|
16
|
+
# @return [String] The fully qualified path
|
17
|
+
def find program
|
18
|
+
return program if File.exist?(program)
|
19
|
+
which(program) || raise(LoadError, "#{program} is not a valid Ruby file or program")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Search the environment paths for the given program.
|
23
|
+
#
|
24
|
+
# @param program [String] The name of the program
|
25
|
+
# @return [String] The fully qualified path, or nil if it was not found
|
26
|
+
def which program
|
27
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
28
|
+
exe = File.join(path, program)
|
29
|
+
return exe if File.file?(exe)
|
30
|
+
end
|
31
|
+
nil
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|