Blob of Support/lib/ruby_amp/remote_debugger.rb (raw blob data)

1 require 'socket'
2 module RubyAMP
3 class RemoteDebugger
4 RUN_FILE = "/tmp/set_breakpoint.rb"
5
6 class << self
7 attr_reader :not_running
8 def socket(retries=1)
9 return @socket if @socket
10 tryCount = 0
11 return if @not_running
12
13 begin
14 @socket = TCPSocket.new('localhost', 8990)
15 rescue Errno::ECONNREFUSED
16 sleep(0.10) and retry if (tryCount+=1) < retries
17
18 puts "Debugger is not running."
19 @not_running = true
20 end
21 end
22
23 def connected?
24 @socket ? true : false
25 end
26
27 def disconnect
28 if connected?
29 socket.close
30 @socket = nil
31 end
32 true
33 end
34
35 def prepare_debug_wrapper(commands)
36 # create a file that will set our breakpoint for us
37 File.open(RUN_FILE, 'wb') do |f|
38 f.puts <<-EOF
39 require #{File.join(ENV['TM_BUNDLE_SUPPORT'], '/ext/debugger_extension.rb').inspect}
40 Debugger.start
41 Debugger.settings[:autoeval]=1
42 Debugger.settings[:autolist]=1
43 Debugger.add_breakpoint #{ENV['TM_FILEPATH'].to_s.inspect}, #{ENV['TM_LINE_NUMBER']}
44
45 Debugger.wait_for_connection
46 #{commands}
47 EOF
48 end
49 RUN_FILE
50 end
51 end
52
53 def initialize(retries = 1)
54 socket(retries)
55 end
56
57 def socket(retries = 1); self.class.socket(retries) end
58 def connected?; self.class.connected? end
59
60 def send_command(cmd, msg = nil)
61 return if self.class.not_running
62 begin
63 @first_output ||= socket.gets
64 socket.puts cmd
65 puts msg if msg
66 rescue Exception
67 puts "Error: #{$!.class}"
68 end
69 end
70
71 def read_output
72 return if self.class.not_running
73 result = ""
74 while line = socket.gets
75 break if line =~ /^PROMPT/
76 result << line
77 end
78 result
79 rescue Exception
80 puts "Error: #{$!.class}"
81 end
82
83 def command(cmd)
84 send_command(cmd)
85 read_output
86 end
87
88 def evaluate(cmd, binding = :current, format = :raw)
89 command("e require #{File.join(ENV['TM_BUNDLE_SUPPORT'], '/ext/debugger_extension.rb').inspect}")
90 o = command("e Debugger.evaluate(#{cmd.inspect}, :#{binding}, :#{format})")
91 eval(o)
92 rescue Exception
93 o
94 end
95
96 def current_frame
97 evaluate("::Debugger.current_frame", :control)
98 end
99
100 AUTO_LOAD = {
101 :BreakpointCommander => 'breakpoint_commander.rb',
102 :CommanderBase => 'commander_base.rb',
103 }
104
105 def self.const_missing(name)
106 @looked_for ||= {}
107 raise "Class not found: #{name}" if @looked_for[name]
108
109 return super unless AUTO_LOAD[name]
110 @looked_for[name] = true
111
112 require File.join(RUBYAMP_ROOT, "remote_debugger", AUTO_LOAD[name])
113 const_get(name)
114 end
115
116 def breakpoint
117 @breakpoint ||= BreakpointCommander.new(self)
118 end
119 end
120 end
121
122 at_exit { RubyAMP::RemoteDebugger.disconnect }