File: runner.rb

package info (click to toggle)
ruby-byebug 12.0.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,304 kB
  • sloc: ruby: 9,013; ansic: 1,678; sh: 5; makefile: 4
file content (198 lines) | stat: -rw-r--r-- 4,205 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# frozen_string_literal: true

require "optparse"
require "English"
require_relative "core"
require_relative "version"
require_relative "helpers/bin"
require_relative "helpers/parse"
require_relative "helpers/string"
require_relative "option_setter"
require_relative "processors/control_processor"

module Byebug
  #
  # Responsible for starting the debugger when started from the command line.
  #
  class Runner
    include Helpers::BinHelper
    include Helpers::ParseHelper
    include Helpers::StringHelper

    #
    # Special working modes that don't actually start the debugger.
    #
    attr_reader :help, :version, :remote

    #
    # Signals that we should exit after the debugged program is finished.
    #
    attr_accessor :quit

    #
    # Signals that we should stop before program starts
    #
    attr_accessor :stop

    #
    # Signals that we should run rc scripts before program starts
    #
    attr_writer :init_script

    #
    # @param stop [Boolean] Whether the runner should stop right before
    # starting the program.
    #
    # @param quit [Boolean] Whether the runner should quit right after
    # finishing the program.
    #
    def initialize(stop = true, quit = true)
      @stop = stop
      @quit = quit
    end

    def help=(text)
      @help ||= text

      interface.puts("#{text}\n")
    end

    def version=(number)
      @version ||= number

      interface.puts prettify <<-VERSION
        Running byebug #{number}
      VERSION
    end

    def remote=(host_and_port)
      @remote ||= Byebug.parse_host_and_port(host_and_port)

      Byebug.start_client(*@remote)
    end

    def init_script
      defined?(@init_script) ? @init_script : true
    end

    #
    # Usage banner.
    #
    def banner
      prettify <<-BANNER
        byebug #{Byebug::VERSION}

        Usage: byebug [options] <script.rb> -- <script.rb parameters>
      BANNER
    end

    #
    # Starts byebug to debug a program.
    #
    def run
      Byebug.mode = :standalone

      option_parser.order!($ARGV)
      return if non_script_option? || error_in_script?

      $PROGRAM_NAME = program

      Byebug.run_init_script if init_script

      loop do
        debug_program

        break if quit

        ControlProcessor.new(nil, interface).process_commands
      end
    end

    def interface
      @interface ||= Context.interface
    end

    #
    # Processes options passed from the command line.
    #
    def option_parser
      @option_parser ||= OptionParser.new(banner, 25) do |opts|
        opts.banner = banner

        OptionSetter.new(self, opts).setup
      end
    end

    def program
      @program ||= begin
                     candidate = which($ARGV.shift)

                     if [which("ruby"), RbConfig.ruby].include?(candidate)
                       which($ARGV.shift)
                     else
                       candidate
                     end
                   end
    end

    #
    # An option that doesn't need a script specified was given
    #
    def non_script_option?
      version || help || remote
    end

    #
    # There is an error with the specified script
    #
    def error_in_script?
      no_script? || non_existing_script? || invalid_script?
    end

    #
    # No script to debug specified
    #
    def no_script?
      return false unless $ARGV.empty?

      print_error("You must specify a program to debug")
      true
    end

    #
    # Extracts debugged program from command line args.
    #
    def non_existing_script?
      return false if program

      print_error("The script doesn't exist")
      true
    end

    #
    # Checks the debugged script has correct syntax
    #
    def invalid_script?
      return false if syntax_valid?(File.read(program))

      print_error("The script has incorrect syntax")
      true
    end

    #
    # Debugs a script only if syntax checks okay.
    #
    def debug_program
      error = Byebug.debug_load(program, stop)
      puts "#{error}\n#{error.backtrace}" if error
    end

    #
    # Prints an error message and a help string
    #
    def print_error(msg)
      interface.errmsg(msg)
      interface.puts(option_parser.help)
    end
  end
end