#!/usr/bin/env ruby # $LOAD_PATH.unshift(File.expand_path('../../lib', __FILE__)) require 'optparse' require 'ostruct' require 'debugger' require 'debugger/xml' $stdout.sync = true class RdebugIde def initialize check_argv! @proxy = DebuggerXml::DebuggerProxy.new @proxy.set_argv(ARGV.clone) @proxy.set_rdebug_script(rdebug_path) @proxy.set_prog_script(ARGV.shift) if options.int_handler install_interruption_handler end @proxy.tracing = options.tracing @proxy.printer = Printers::Xml.new @proxy.wait_connection = true DebuggerXml.wait_for_start = options.wait_for_start Debugger::Xml.logger = if options.debug_mode Debugger::Xml::Ide::Logger.new else Debugger::Xml::FakeLogger.new end init_multi_process_debug(options) if options.dispatcher_port end def run Debugger.start_remote_ide(options.host, options.port) bt = Debugger.debug_load(Debugger::PROG_SCRIPT, false, false) if bt print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n" print "Uncaught exception: #{bt}\n" end end private def init_multi_process_debug(options) ENV['IDE_PROCESS_DISPATCHER'] = options.dispatcher_port.to_s ENV['DEBUGGER_HOST'] = options.host.to_s ENV['DEBUGGER_DEBUG_MODE'] = options.debug_mode.to_s ENV['DEBUGGER_STORED_RUBYLIB'] = $LOAD_PATH.join(File::PATH_SEPARATOR) old_opts = ENV['RUBYOPT'] ENV['RUBYOPT'] = "-r#{File.expand_path(File.dirname(__FILE__))}/../lib/debugger/xml/multiprocess/starter" ENV['RUBYOPT'] += " #{old_opts}" if old_opts end def check_argv! if ARGV.empty? puts opts puts puts "Must specify a script to run" exit(1) end end def install_interruption_handler trap('INT') { @proxy.interrupt_last } end def rdebug_path File.expand_path($0).tap do |path| if RUBY_PLATFORM =~ /mswin/ rdebug_path << ".cmd" unless rdebug_path =~ /\.cmd$/i end end end def options opts @options end def opts @opts ||= begin @options = OpenStruct.new( host: "127.0.0.1", port: 12345, stop: false, tracing: false, wait_for_start: true, int_handler: true, debug_mode: false, dispatcher_port: nil ) opts = OptionParser.new do |opts| opts.banner = %{ Using rdebug-ide Usage: rdebug-ide is supposed to be called from RDT, NetBeans, RubyMine or vim-ruby-debugger. The command line interface to 'debugger' is rdebug. }.gsub(/^\s*/, '') opts.separator "" opts.separator "Options:" opts.on("-h", "--host HOST", "Host name used for remote debugging") { |host| @options.host = host } opts.on("-p", "--port PORT", Integer, "Port used for remote debugging") { |port| @options.port = port } opts.on('--dispatcher-port PORT', Integer, 'Port used for multi-process debugging dispatcher') do |dp| @options.dispatcher_port = dp end opts.on("-d", "--debug", "Enable debug mode") { |host| @options.debug_mode = true } opts.on("--wait", String, "Wait for 'start' command") do |bool| @options.wait_for_start = (bool == "false" ? false : true) end opts.on('--stop', 'stop when the script is loaded') { @options.stop = true } opts.on("-x", "--trace", "turn on line tracing") { @options.tracing = true } opts.on("-I", "--include PATH", String, "Add PATH to $LOAD_PATH") { |path| $LOAD_PATH.unshift(path) } opts.on('--disable-int-handler', 'Disables interrupt signal handler') { @options.int_handler = false } end opts.parse! opts end end end RdebugIde.new.run