You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ju...@apache.org on 2026/09/09 23:45:48 UTC

(hbase) branch branch-3 updated: HBASE-30370 Fix shell exiting on errors other than NameError and SyntaxError (#8629)

This is an automated email from the ASF dual-hosted git repository.

junegunn pushed a commit to branch branch-3
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-3 by this push:
     new 6e2657b68f8 HBASE-30370 Fix shell exiting on errors other than NameError and SyntaxError (#8629)
6e2657b68f8 is described below

commit 6e2657b68f85eaa3afd4a6069eb8e29d600bab9e
Author: Junegunn Choi <ju...@apache.org>
AuthorDate: Thu Sep 10 08:36:15 2026 +0900

    HBASE-30370 Fix shell exiting on errors other than NameError and SyntaxError (#8629)
    
    HBASE-26741 made eval_input re-raise every exception to set an exit code,
    which also ended interactive sessions. Worked around since for NameError
    (HBASE-26880) and SyntaxError (HBASE-27726); every other error still killed
    the prompt.
    
    Re-raise only when the exit code is used: a script run, or -n. Everything
    else falls through to handle_exception, as before HBASE-26741.
    
    A script given as an argument runs with interactive still true, so detect it
    by the FileInputMethod that HBaseLoader.file_for_load returns rather than by
    @interactive alone.
    
    Signed-off-by: Peng Lu <lu...@apache.org>
---
 hbase-shell/src/main/ruby/irb/hirb.rb              | 12 +++++-------
 .../src/test/ruby/shell/general_test_cluster.rb    | 22 ++++++++++++++++++++++
 2 files changed, 27 insertions(+), 7 deletions(-)

diff --git a/hbase-shell/src/main/ruby/irb/hirb.rb b/hbase-shell/src/main/ruby/irb/hirb.rb
index ae534f6f00b..87a62551281 100644
--- a/hbase-shell/src/main/ruby/irb/hirb.rb
+++ b/hbase-shell/src/main/ruby/irb/hirb.rb
@@ -51,6 +51,8 @@ module IRB
         `stty icrnl <&2`
       end
       @interactive = interactive
+      # Errors must abort a script run to set the exit code, but not a live prompt
+      @exit_on_error = !interactive || input_method.is_a?(::IRB::FileInputMethod)
       super(workspace, input_method)
     ensure
       f.close
@@ -161,17 +163,13 @@ module IRB
           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
-            # HBASE-26880: Ignore NameError to prevent exiting Shell on mistyped commands.
           rescue Exception => exc
             # HBASE-26741: Raise exception so Shell::exception_handler can catch it.
             # 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
+            # Otherwise keep the session alive and report the error, as the shell did before
+            # HBASE-26741. Supersedes HBASE-26880 (NameError) and HBASE-27726 (SyntaxError).
+            raise if @exit_on_error
           else
             exc = nil
             next
diff --git a/hbase-shell/src/test/ruby/shell/general_test_cluster.rb b/hbase-shell/src/test/ruby/shell/general_test_cluster.rb
index 8c1687dea01..4c3195d00c3 100644
--- a/hbase-shell/src/test/ruby/shell/general_test_cluster.rb
+++ b/hbase-shell/src/test/ruby/shell/general_test_cluster.rb
@@ -21,6 +21,7 @@ require 'hbase_constants'
 require 'hbase_shell'
 require 'irb/hirb'
 require 'stringio'
+require 'tempfile'
 
 class ShellTest < Test::Unit::TestCase
   include Hbase::TestHelpers
@@ -226,4 +227,25 @@ class ShellTest < Test::Unit::TestCase
     assert_match(/WARN: 'scan' is a reserved HBase command/, err_output)
     assert_match(/WARN: 'processlist' is a reserved HBase command/, err_output)
   end
+
+  def new_hirb(input_method)
+    IRB.setup(__FILE__) unless IRB.conf[:IRB_NAME]
+    IRB::HIRB.new(@shell.workspace, true, input_method)
+  end
+
+  define_test 'Shell::Shell should keep an interactive session alive on any error' do
+    hirb = new_hirb(MockInputMethod.new(["1 + '2'\n", "my_var = 5\n"]))
+    capture_stdout { hirb.eval_input }
+    assert_equal(5, hirb.context.workspace.binding.local_variable_get(:my_var))
+  end
+
+  define_test 'Shell::Shell should abort a script on error even when interactive' do
+    Tempfile.create(['hirb_test', '.rb']) do |file|
+      file.write("1 + '2'\n")
+      file.close
+      # interactive is true, as it is for `hbase shell script.rb` without -n
+      hirb = new_hirb(IRB::HBaseLoader.file_for_load(file.path))
+      assert_raise(TypeError) { capture_stdout { hirb.eval_input } }
+    end
+  end
 end