Browse files

another ruby-debug-cli file

  • Loading branch information...
1 parent a4f236c commit 526545f6641bd72342606bd254aad35cb6395d9d @mark-moseley committed Oct 2, 2009
Showing with 398 additions and 0 deletions.
  1. +398 −0 bin/rdebug
View
398 bin/rdebug
@@ -0,0 +1,398 @@
+#!/usr/bin/env ruby
+
+#=== Summary
+#
+#A command-line front-end to the Ruby debugger, <tt>ruby-debug</tt>, the
+#Fast Ruby Debugger.
+#
+#Command invocation:
+#
+# rdebug [options] [--] [script-options] ruby-script-to-debug
+# rdebug [options] [script-options] [--client]
+# rdebug [--version | --help]
+#
+#=== Options
+#
+#<tt>-A | --annotate</tt> <i>level</i>::
+# Set gdb-style annotation to <i>level</i>, a number. Additional
+# information is output automatically when program state is
+# changed. This can be used by front-ends such as GNU Emacs to post
+# this updated information without having to poll for it.
+#
+#<tt>--client</tt>::
+# Connect to a remote debugger. Used with another rdebug invocation
+# using <tt>--server</tt>. See also <tt>--host</tt> and
+# <tt>--cport</tt> options
+#
+#<tt>--cport=</tt><i>port</i>::
+# Use port <i>port</i> for access to debugger control.
+#
+#<tt>-d | --debug</tt>::
+# Set $DEBUG true.
+#
+#<tt>--emacs</tt>::
+# Activates full GNU Emacs mode. Is the equivalent of setting the
+# options <tt>--emacs-basic --annotate=3 --no-stop --no-control
+# --post-mortem</tt>.
+#
+#<tt>--emacs-basic</tt>::
+# Activates GNU Emacs mode. Debugger prompts are prefaced with two
+# octal 032 characters.
+#
+#<tt>-h | --host=</tt><i>host</i>::
+# Use host name <i>host</i> for remote debugging.
+#
+#<tt>-I | --include</tt> <i>path</i>
+# Add <i>path</i> to <tt>$LOAD_PATH</tt>
+#
+#<tt>-m | --post-mortem</tt>::
+# Activate post-mortem mode.
+#
+#<tt>--no-control</tt>::
+# Do not automatically start control thread.
+#
+#<tt>--no-stop</tt>::
+# Do not stop when script is loaded.
+#
+#<tt>-p | --port=PORT</tt>::
+# Host name used for remote debugging.
+#
+#<tt>-r | --require</tt><i>script</i>::
+# Require the library, before executing your script.
+#
+#<tt>--script</tt> <i>file</i>::
+# Run debugger script file <i>file</i>
+#
+#<tt>-x | --trace</tt>::
+# Show lines before executing them.
+#
+#<tt>--no-quit</tt>::
+# Do not quit when script terminates. Instead rerun the
+# program.
+#
+#<tt>--version</tt>::
+# Show the version number and exit.
+#
+#<tt>--verbose</tt>::
+# Turn on verbose mode.
+#
+#<tt>--v</tt>::
+# Print the version number, then turn on verbose mode if
+# a script name is given. If no script name is given
+# just exit after printing the version number.
+#
+#<tt>--nx</tt>::
+# Don’t execute commands found in any initialization
+# files, e.g. <tt>.rdebugrc</tt>.
+#
+#<tt>--keep-frame-binding</tt>::
+# Keep frame bindings.
+#
+#<tt>--script=</tt><i>file</i>::
+# Name of the script file to run
+#
+#<tt>-s | --server</tt>::
+# Listen for remote connections. Another rdebug session
+# accesses using the <tt>--client</tt> option. See also the
+# <tt>--host</tt>, <tt>--port</tt> and <tt>--cport</tt> options
+#
+#<tt>-w | --wait</tt>::
+# Wait for a client connection; implies <tt>-s</tt> option.
+#
+#<tt>--help</tt>::
+# Show invocation help and exit.
+
+require 'rubygems'
+require 'optparse'
+require 'ostruct'
+require_relative '../cli/ruby-debug'
+
+def debug_program(options)
+ # Make sure Ruby script syntax checks okay.
+ # Otherwise we get a load message that looks like rdebug has
+ # a problem.
+ output = `ruby -c "#{Debugger::PROG_SCRIPT}" 2>&1`
+ if $?.exitstatus != 0 and RUBY_PLATFORM !~ /mswin/
+ puts output
+ exit $?.exitstatus
+ end
+ print "\032\032starting\n" if Debugger.annotate and Debugger.annotate > 2
+
+ # Record where we are we can know if the call stack has been
+ # truncated or not.
+ Debugger.start_sentinal=caller(0)[1]
+
+ bt = Debugger.debug_load(Debugger::PROG_SCRIPT, options.stop, false)
+ if bt
+ print bt.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
+ print "Uncaught exception: #{bt}\n"
+ end
+end
+
+# Do a shell-like path lookup for prog_script and return the results.
+# If we can't find anything return prog_script.
+def whence_file(prog_script)
+ if prog_script.index(File::SEPARATOR)
+ # Don't search since this name has path separator components
+ return prog_script
+ end
+ for dirname in ENV['PATH'].split(File::PATH_SEPARATOR) do
+ prog_script_try = File.join(dirname, prog_script)
+ return prog_script_try if File.exist?(prog_script_try)
+ end
+ # Failure
+ return prog_script
+end
+
+options = OpenStruct.new(
+ 'annotate' => Debugger.annotate,
+ 'client' => false,
+ 'control' => true,
+ 'cport' => Debugger::PORT + 1,
+ 'host' => nil,
+ 'quit' => true,
+ 'no_rewrite_program' => false,
+ 'stop' => true,
+ 'nx' => false,
+ 'port' => Debugger::PORT,
+ 'restart_script' => nil,
+ 'script' => nil,
+ 'server' => false,
+ 'tracing' => false,
+ 'verbose_long' => false,
+ 'wait' => false
+)
+
+def process_options(options)
+ program = File.basename($0)
+ opts = OptionParser.new do |opts|
+ opts.banner = <<EOB
+#{program} #{Debugger::VERSION}
+Usage: #{program} [options] <script.rb> -- <script.rb parameters>
+EOB
+ opts.separator ""
+ opts.separator "Options:"
+ opts.on("-A", "--annotate LEVEL", Integer, "Set annotation level") do
+ |annotate|
+ Debugger.annotate = annotate
+ end
+ opts.on("-c", "--client", "Connect to remote debugger") do
+ options.client = true
+ end
+ opts.on("--cport PORT", Integer, "Port used for control commands") do
+ |cport|
+ options.cport = cport
+ end
+ opts.on("-d", "--debug", "Set $DEBUG=true") {$DEBUG = true}
+ opts.on("--emacs LEVEL", Integer,
+ "Activates full Emacs support at annotation level LEVEL") do
+ |level|
+ Debugger.annotate = level.to_i
+ ENV['EMACS'] = '1'
+ ENV['COLUMNS'] = '120' if ENV['COLUMNS'].to_i < 120
+ options.control = false
+ options.quit = false
+ end
+ opts.on('--emacs-basic', 'Activates basic Emacs mode') do
+ ENV['EMACS'] = '1'
+ end
+ opts.on('-h', '--host HOST', 'Host name used for remote debugging') do
+ |host|
+ options.host = host
+ end
+ opts.on('-I', '--include PATH', String, 'Add PATH to $LOAD_PATH') do |path|
+ $LOAD_PATH.unshift(path)
+ end
+ opts.on('--no-control', 'Do not automatically start control thread') do
+ options.control = false
+ end
+ opts.on('--no-quit', 'Do not quit when script finishes') do
+ options.quit = false
+ end
+ opts.on('--no-rewrite-program',
+ 'Do not set $0 to the program being debugged') do
+ options.no_rewrite_program = true
+ end
+ opts.on('--no-stop', 'Do not stop when script is loaded') do
+ options.stop = false
+ end
+ opts.on('-nx', 'Not run debugger initialization files (e.g. .rdebugrc') do
+ options.nx = true
+ end
+ opts.on('-p', '--port PORT', Integer, 'Port used for remote debugging') do
+ |port|
+ options.port = port
+ end
+ opts.on('-r', '--require SCRIPT', String,
+ 'Require the library, before executing your script') do |name|
+ if name == 'debug'
+ puts "ruby-debug is not compatible with Ruby's 'debug' library. This option is ignored."
+ else
+ require name
+ end
+ end
+ opts.on('--restart-script FILE', String,
+ 'Name of the script file to run. Erased after read') do
+ |restart_script|
+ options.restart_script = restart_script
+ unless File.exists?(options.restart_script)
+ puts "Script file '#{options.restart_script}' is not found"
+ exit
+ end
+ end
+ opts.on('--script FILE', String, 'Name of the script file to run') do
+ |script|
+ options.script = script
+ unless File.exists?(options.script)
+ puts "Script file '#{options.script}' is not found"
+ exit
+ end
+ end
+ opts.on('-s', '--server', 'Listen for remote connections') do
+ options.server = true
+ end
+ opts.on('-w', '--wait', 'Wait for a client connection, implies -s option') do
+ options.wait = true
+ end
+ opts.on('-x', '--trace', 'Turn on line tracing') {options.tracing = true}
+ opts.separator ''
+ opts.separator 'Common options:'
+ opts.on_tail('--help', 'Show this message') do
+ puts opts
+ exit
+ end
+ opts.on_tail('--version',
+ 'Print the version') do
+ puts "ruby-debug #{Debugger::VERSION}"
+ exit
+ end
+ opts.on('--verbose', 'Turn on verbose mode') do
+ $VERBOSE = true
+ options.verbose_long = true
+ end
+ opts.on_tail('-v',
+ 'Print version number, then turn on verbose mode') do
+ puts "ruby-debug #{Debugger::VERSION}"
+ $VERBOSE = true
+ end
+ end
+ return opts
+end
+
+# What file is used for debugger startup commands.
+unless defined?(OPTS_INITFILE)
+ if RUBY_PLATFORM =~ /mswin/
+ # Of course MS Windows has to be different
+ OPTS_INITFILE = 'rdbopt.ini'
+ HOME_DIR = (ENV['HOME'] ||
+ ENV['HOMEDRIVE'].to_s + ENV['HOMEPATH'].to_s).to_s
+ else
+ OPTS_INITFILE = '.rdboptrc'
+ HOME_DIR = ENV['HOME'].to_s
+ end
+end
+begin
+ initfile = File.join(HOME_DIR, OPTS_INITFILE)
+ eval(File.read(initfile)) if
+ File.exist?(initfile)
+rescue
+end
+
+opts = process_options(options)
+begin
+ if not defined? Debugger::ARGV
+ Debugger::ARGV = ARGV.clone
+ end
+ rdebug_path = File.expand_path($0)
+ if RUBY_PLATFORM =~ /mswin/
+ rdebug_path += '.cmd' unless rdebug_path =~ /\.cmd$/i
+ end
+ Debugger::RDEBUG_SCRIPT = rdebug_path
+ Debugger::RDEBUG_FILE = __FILE__
+ Debugger::INITIAL_DIR = Dir.pwd
+ opts.parse! ARGV
+rescue StandardError => e
+ puts opts
+ puts
+ puts e.message
+ exit(-1)
+end
+
+if options.client
+ Debugger.start_client(options.host, options.port)
+else
+ if ARGV.empty?
+ exit if $VERBOSE and not options.verbose_long
+ puts opts
+ puts
+ puts 'Must specify a script to run'
+ exit(-1)
+ end
+
+ # save script name
+ prog_script = ARGV.shift
+ prog_script = whence_file(prog_script) unless File.exist?(prog_script)
+ Debugger::PROG_SCRIPT = File.expand_path prog_script
+
+ # install interruption handler
+ trap('INT') { Debugger.interrupt_last }
+
+ # set options
+ Debugger.wait_connection = options.wait
+
+ if options.server
+ # start remote mode
+ Debugger.start_remote(options.host, [options.port, options.cport]) do
+ # load initrc script
+ Debugger.run_init_script(StringIO.new) unless options.nx
+ end
+ debug_program(options)
+ else
+ # Set up trace hook for debugger
+ Debugger.start
+ # start control thread
+ Debugger.start_control(options.host, options.cport) if options.control
+
+ # load initrc script (e.g. .rdebugrc)
+ Debugger.run_init_script(StringIO.new) unless options.nx
+
+ # run restore-settings startup script if specified
+ if options.restart_script
+ require 'fileutils'
+ Debugger.run_script(options.restart_script)
+ FileUtils.rm(options.restart_script)
+ end
+
+ # run startup script if specified
+ if options.script
+ Debugger.run_script(options.script)
+ end
+
+ options.stop = false if options.tracing
+ Debugger.tracing = options.tracing
+
+ if !options.quit
+ if Debugger.started?
+ until Debugger.stop do end
+ end
+ begin
+ debug_program(options)
+ rescue SyntaxError
+ puts $!.backtrace.map{|l| "\t#{l}"}.join("\n")
+ puts "Uncaught Syntax Error\n"
+ rescue
+ print $!.backtrace.map{|l| "\t#{l}"}.join("\n"), "\n"
+ print "Uncaught exception: #{$!}\n"
+ end
+ print "The program finished.\n" unless
+ Debugger.annotate.to_i > 1 # annotate has its own way
+ interface = Debugger::LocalInterface.new
+ # Not sure if ControlCommandProcessor is really the right
+ # thing to use. CommandProcessor requires a state.
+ processor = Debugger::ControlCommandProcessor.new(interface)
+ processor.process_commands
+ else
+ debug_program(options)
+ end
+ end
+end

0 comments on commit 526545f

Please sign in to comment.