diff --git a/hbase-shell/src/main/ruby/irb/hirb.rb b/hbase-shell/src/main/ruby/irb/hirb.rb index 713cb848c764..73b0ee91a11d 100644 --- a/hbase-shell/src/main/ruby/irb/hirb.rb +++ b/hbase-shell/src/main/ruby/irb/hirb.rb @@ -53,18 +53,21 @@ def initialize(workspace = nil, interactive = true, input_method = nil) $stdout = STDOUT end - def output_value + def output_value(omit = false) # Suppress output if last_value is 'nil' # Otherwise, when user types help, get ugly 'nil' # after all output. - super unless @context.last_value.nil? + super(omit) unless @context.last_value.nil? end - # Copied from irb.rb and overrides the rescue Exception block so the + # Copied from https://github.com/ruby/irb/blob/v1.4.2/lib/irb.rb + # We override the rescue Exception block so the # Shell::exception_handler can deal with the exceptions. def eval_input + exc = nil + @scanner.set_prompt do - |ltype, indent, continue, line_no| + |ltype, indent, continue, line_no| if ltype f = @context.prompt_s elsif continue @@ -80,17 +83,19 @@ def eval_input else @context.io.prompt = p = "" end - if @context.auto_indent_mode + if @context.auto_indent_mode and !@context.io.respond_to?(:auto_indent) unless ltype - ind = prompt(@context.prompt_i, ltype, indent, line_no)[/.*\z/].size + + prompt_i = @context.prompt_i.nil? ? "" : @context.prompt_i + ind = prompt(prompt_i, ltype, indent, line_no)[/.*\z/].size + indent * 2 - p.size ind += 2 if continue @context.io.prompt = p + " " * ind if ind > 0 end end + @context.io.prompt end - @scanner.set_input(@context.io) do + @scanner.set_input(@context.io, context: @context) do signal_status(:IN_INPUT) do if l = @context.io.gets print l if @context.verbose? @@ -101,24 +106,51 @@ def eval_input printf "Use \"exit\" to leave %s\n", @context.ap_name end else - print "\n" + print "\n" if @context.prompting? end end l end end + @scanner.set_auto_indent(@context) if @context.auto_indent_mode + @scanner.each_top_level_statement do |line, line_no| signal_status(:IN_EVAL) do begin - line.untaint - @context.evaluate(line, line_no) - output_value if @context.echo? - exc = nil + line.untaint if RUBY_VERSION < '2.7' + if IRB.conf[:MEASURE] && IRB.conf[:MEASURE_CALLBACKS].empty? + IRB.set_measure_callback + end + if IRB.conf[:MEASURE] && !IRB.conf[:MEASURE_CALLBACKS].empty? + result = nil + last_proc = proc{ result = @context.evaluate(line, line_no, exception: exc) } + IRB.conf[:MEASURE_CALLBACKS].inject(last_proc) { |chain, item| + _name, callback, arg = item + proc { + callback.(@context, line, line_no, arg, exception: exc) do + chain.call + end + } + }.call + @context.set_last_value(result) + else + @context.evaluate(line, line_no, exception: exc) + end + if @context.echo? + if assignment_expression?(line) + if @context.echo_on_assignment? + output_value(@context.echo_on_assignment? == :truncate) + end + else + output_value + end + end rescue Interrupt => exc rescue SystemExit, SignalException raise rescue SyntaxError => exc + # HBASE-27726: Ignore SyntaxError to prevent exiting Shell on unexpected syntax. raise exc unless @interactive rescue NameError => exc raise exc unless @interactive @@ -128,43 +160,13 @@ def eval_input # This modifies this copied method from JRuby so that the HBase shell can # manage the exception and set a proper exit code on the process. raise exc + else + exc = nil + next end - if exc - if exc.backtrace && exc.backtrace[0] =~ /irb(2)?(\/.*|-.*|\.rb)?:/ && exc.class.to_s !~ /^IRB/ && - !(SyntaxError === exc) - irb_bug = true - else - irb_bug = false - end - - messages = [] - lasts = [] - levels = 0 - if exc.backtrace - count = 0 - exc.backtrace.each do |m| - m = @context.workspace.filter_backtrace(m) or next unless irb_bug - m = sprintf("%9d: from %s", (count += 1), m) - if messages.size < @context.back_trace_limit - messages.push(m) - elsif lasts.size < @context.back_trace_limit - lasts.push(m).shift - levels += 1 - end - end - end - attr = STDOUT.tty? ? ATTR_TTY : ATTR_PLAIN - print "#{attr[1]}Traceback#{attr[]} (most recent call last):\n" - unless lasts.empty? - puts lasts.reverse - printf "... %d levels...\n", levels if levels > 0 - end - puts messages.reverse - messages = exc.to_s.split(/\n/) - print "#{attr[1]}#{exc.class} (#{attr[4]}#{messages.shift}#{attr[0, 1]})#{attr[]}\n" - puts messages.map {|s| "#{attr[1]}#{s}#{attr[]}\n"} - print "Maybe IRB bug!\n" if irb_bug - end + handle_exception(exc) + @context.workspace.local_variable_set(:_, exc) + exc = nil end end end diff --git a/hbase-shell/src/main/ruby/jar-bootstrap.rb b/hbase-shell/src/main/ruby/jar-bootstrap.rb index 63cb0a755449..e9844cfb223f 100644 --- a/hbase-shell/src/main/ruby/jar-bootstrap.rb +++ b/hbase-shell/src/main/ruby/jar-bootstrap.rb @@ -68,6 +68,8 @@ -h | --help This help. -n | --noninteractive Do not run within an IRB session and exit with non-zero status on first error. + -c | --colorize Enable colorized output. + -a | --autocomplete Enable auto-completion. --top-level-defs Compatibility flag to export HBase shell commands onto Ruby's main object -Dkey=value Pass hbase-*.xml Configuration overrides. For example, to @@ -105,6 +107,8 @@ def add_to_configuration(c, arg) ['--help', '-h', GetoptLong::NO_ARGUMENT], ['--debug', '-d', GetoptLong::NO_ARGUMENT], ['--noninteractive', '-n', GetoptLong::NO_ARGUMENT], + ['--colorize', '-c', GetoptLong::NO_ARGUMENT], + ['--autocomplete', '-a', GetoptLong::NO_ARGUMENT], ['--top-level-defs', GetoptLong::NO_ARGUMENT], ['-D', GetoptLong::REQUIRED_ARGUMENT], ['--return-values', '-r', GetoptLong::NO_ARGUMENT] @@ -115,6 +119,8 @@ def add_to_configuration(c, arg) log_level = 'ERROR' @shell_debug = false interactive = true +colorize = false +autocomplete = false full_backtrace = false top_level_definitions = false @@ -132,6 +138,10 @@ def add_to_configuration(c, arg) puts 'Setting DEBUG log level...' when '--noninteractive' interactive = false + when '--colorize' + colorize = true + when '--autocomplete' + autocomplete = true when '--return-values' warn '[INFO] the -r | --return-values option is ignored. we always behave '\ 'as though it was given.' @@ -213,6 +223,8 @@ def debug? IRB.conf[:AP_NAME] = 'hbase' IRB.conf[:PROMPT_MODE] = :CUSTOM IRB.conf[:BACK_TRACE_LIMIT] = 0 unless full_backtrace +IRB.conf[:USE_AUTOCOMPLETE] = autocomplete +IRB.conf[:USE_COLORIZE] = colorize # Create a workspace we'll use across sessions. workspace = @shell.get_workspace diff --git a/pom.xml b/pom.xml index d055c74f9989..9d35eb71e6a8 100644 --- a/pom.xml +++ b/pom.xml @@ -841,7 +841,7 @@ 2.1.1 2.3.2 3.0.1-b08 - 9.3.13.0 + 9.4.8.0 4.13.2 1.3 1.15.0