You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ni...@apache.org on 2026/10/06 15:46:01 UTC
(hbase) branch branch-3 updated: HBASE-30419 Add .jsh/.java single-file script dispatch to bin/hbase (#8703)
This is an automated email from the ASF dual-hosted git repository.
NihalJain 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 d71e275c50f HBASE-30419 Add .jsh/.java single-file script dispatch to bin/hbase (#8703)
d71e275c50f is described below
commit d71e275c50fec47a1ecbd509a32eab3764bc488c
Author: Aman Poonia <am...@gmail.com>
AuthorDate: Tue Oct 6 21:05:22 2026 +0530
HBASE-30419 Add .jsh/.java single-file script dispatch to bin/hbase (#8703)
Signed-off-by: Andrew Purtell <ap...@apache.org>
Signed-off-by: Nihal Jain <ni...@apache.org>
(cherry picked from commit 8813918aa98b3e3313529af48fbd5a2679cf83fe)
---
bin/hbase | 143 +++++++++++++++++++++++++++++++++++++++++++++++---
bin/hbase_startup.jsh | 13 +++++
conf/hbase-env.sh | 4 +-
3 files changed, 153 insertions(+), 7 deletions(-)
diff --git a/bin/hbase b/bin/hbase
index 045b6171fa6..72c53081823 100755
--- a/bin/hbase
+++ b/bin/hbase
@@ -54,8 +54,21 @@
# HBASE_SHELL_OPTS Extra options passed to the hbase shell.
# Empty by default.
#
-# HBASE_JSHELL_ARGS Additional arguments passed to the jshell.
-# Defaults to `--startup DEFAULT --startup PRINTING --startup hbase_startup.jsh`
+# HBASE_JSHELL_ARGS Additional arguments passed to jshell (interactive `jshell`
+# and `*.jsh` script dispatch). When unset, defaults to
+# `--startup DEFAULT --startup PRINTING` plus
+# `--startup ${HBASE_HOME}/bin/hbase_startup.jsh` when that
+# file exists, and `--execution local` unless --execution is
+# already set here (so System.exit in scripts propagates).
+# Split on whitespace like HBASE_OPTS -- individual argument
+# values (e.g. a --startup file path) cannot contain spaces.
+#
+# HBASE_JSH_ARG_N / HBASE_JSH_ARG_COUNT
+# Positional args for `hbase path/to/script.jsh [args...]`.
+# JShell script mode has no String[] args, so bin/hbase
+# exports HBASE_JSH_ARG_0..HBASE_JSH_ARG_{N-1} and
+# HBASE_JSH_ARG_COUNT=N for the script to read (see
+# hbase_startup.jsh for an example).
#
# HBASE_HBCK_OPTS Extra options passed to hbck.
# Defaults to HBASE_SERVER_JAAS_OPTS if specified, or HBASE_REGIONSERVER_OPTS.
@@ -111,6 +124,8 @@ show_usage() {
echo " credential Run the Hadoop Credential Shell"
echo " copyreppeers Run CopyReplicationPeers tool"
echo " CLASSNAME Run the class named CLASSNAME"
+ echo " <path>.jsh Run <path> as a JShell script non-interactively (args via HBASE_JSH_ARG_N)"
+ echo " <path>.java Run <path> as a single-file .java source (JEP 330) with HBase on the classpath"
}
if [ "--help" = "$1" ] || [ "-h" = "$1" ]; then
@@ -173,6 +188,50 @@ add_size_suffix() {
fi
}
+# Resolve a script under bin/: keep paths that already contain a slash, otherwise
+# look in HBASE_HOME/bin. Sets RESOLVED_BIN_SCRIPT or exits.
+resolve_bin_script() {
+ local name="$1"
+ local kind="$2"
+ if [[ "$name" == */* ]]; then
+ RESOLVED_BIN_SCRIPT="$name"
+ else
+ RESOLVED_BIN_SCRIPT="${HBASE_HOME}/bin/${name}"
+ fi
+ if [ ! -f "$RESOLVED_BIN_SCRIPT" ]; then
+ echo "${kind} not found: $RESOLVED_BIN_SCRIPT"
+ exit 1
+ fi
+}
+
+# Populate JSHELL_ARGS for both interactive `jshell` and `*.jsh` script dispatch.
+# Shared so the two paths cannot drift. Honors HBASE_JSHELL_ARGS when set; otherwise
+# DEFAULT + PRINTING + optional hbase_startup.jsh. Defaults to --execution local
+# unless the user already passed --execution / --execution=<spec>.
+init_jshell_args() {
+ if [ -n "${HBASE_JSHELL_ARGS}" ]; then
+ read -r -a JSHELL_ARGS <<< "${HBASE_JSHELL_ARGS}"
+ else
+ JSHELL_ARGS=(--startup DEFAULT --startup PRINTING)
+ if [ -f "${HBASE_HOME}/bin/hbase_startup.jsh" ]; then
+ JSHELL_ARGS+=(--startup "${HBASE_HOME}/bin/hbase_startup.jsh")
+ fi
+ fi
+ # --execution local runs snippets in-process so System.exit() propagates as the
+ # process exit code (JDI remote mode only kills the forked VM).
+ local has_execution=false
+ local arg
+ for arg in "${JSHELL_ARGS[@]}"; do
+ if [ "$arg" = "--execution" ] || [[ "$arg" == --execution=* ]]; then
+ has_execution=true
+ break
+ fi
+ done
+ if [ "$has_execution" = false ]; then
+ JSHELL_ARGS+=(--execution local)
+ fi
+}
+
if [[ -n "$HBASE_HEAPSIZE" ]]; then
JAVA_HEAP_MAX="-Xmx$(add_size_suffix $HBASE_HEAPSIZE)"
fi
@@ -578,8 +637,7 @@ if [ "$COMMAND" = "shell" ] ; then
HBASE_OPTS="$HBASE_OPTS $HBASE_SHELL_OPTS"
elif [ "$COMMAND" = 'jshell' ] ; then
CLASS='jdk.internal.jshell.tool.JShellToolProvider'
- # set default values for HBASE_JSHELL_ARGS
- read -r -a JSHELL_ARGS <<< "${HBASE_JSHELL_ARGS:-"--startup DEFAULT --startup PRINTING --startup ${HBASE_HOME}/bin/hbase_startup.jsh"}"
+ init_jshell_args
HBASE_OPTS="$HBASE_OPTS $HBASE_JSHELL_OPTS"
elif [ "$COMMAND" = "hbck" ] ; then
# Look for the -j /path/to/HBCK2.jar parameter. Else pass through to hbck.
@@ -778,6 +836,54 @@ elif [ "$COMMAND" = "credential" ] ; then
CLASS='org.apache.hadoop.security.alias.CredentialShell'
elif [ "$COMMAND" = "copyreppeers" ] ; then
CLASS='org.apache.hadoop.hbase.replication.CopyReplicationPeers'
+elif [[ "$COMMAND" == *.jsh ]] ; then
+ # No JDK version guard here: hbase-config.sh already requires JDK 17+.
+ resolve_bin_script "$COMMAND" "jshell script"
+ JSH_SCRIPT="$RESOLVED_BIN_SCRIPT"
+ # pass positional args to the script via env vars: jshell script mode has no
+ # String[] args equivalent, and re-joining/re-splitting args into one string
+ # breaks on embedded spaces, so each arg gets its own env var instead.
+ # See HBASE_JSH_ARG_N / HBASE_JSH_ARG_COUNT in the header and hbase_startup.jsh.
+ i=0
+ for a in "$@"; do
+ export HBASE_JSH_ARG_$i="$a"
+ i=$((i+1))
+ done
+ export HBASE_JSH_ARG_COUNT=$i
+ set --
+ CLASS='jdk.internal.jshell.tool.JShellToolProvider'
+ init_jshell_args
+ # Default to -q (concise feedback) for non-interactive scripts, but jshell
+ # allows only one feedback option (--feedback / -q / -s / -v); honor any the
+ # user already set via HBASE_JSHELL_ARGS.
+ has_feedback=false
+ for arg in "${JSHELL_ARGS[@]}"; do
+ if [ "$arg" = "--feedback" ] || [[ "$arg" == --feedback=* ]] \
+ || [ "$arg" = "-q" ] || [ "$arg" = "-s" ] || [ "$arg" = "-v" ]; then
+ has_feedback=true
+ break
+ fi
+ done
+ if [ "$has_feedback" = false ]; then
+ JSHELL_ARGS+=(-q)
+ fi
+ JSHELL_ARGS+=("$JSH_SCRIPT")
+ HBASE_OPTS="$HBASE_OPTS $HBASE_JSHELL_OPTS"
+ # run the script and exit rather than dropping into an interactive REPL
+ HBASE_JSH_SCRIPT_MODE=true
+elif [[ "$COMMAND" == *.java ]] ; then
+ # JEP 330 single-file source launch: java forwards the remaining args
+ # directly to main(String[] args), so no env-var passthrough is needed here
+ # (unlike the .jsh case above). No JDK version guard: hbase-config.sh already
+ # requires JDK 17+, which covers JEP 330 (JDK 11+).
+ #
+ # Keep the source path out of $CLASS: the java invocation expands $CLASS
+ # unquoted (so multi-token CLASS values like the JRuby shell launcher still
+ # word-split), which would break paths containing spaces. Prepend the path
+ # onto "$@" instead; it is then carried via the quoted "${CMD_ARGS[@]}" array.
+ resolve_bin_script "$COMMAND" "java source script"
+ set -- "$RESOLVED_BIN_SCRIPT" "$@"
+ CLASS=
else
CLASS=$COMMAND
fi
@@ -838,9 +944,34 @@ if [ "${#JSHELL_ARGS[@]}" -gt 0 ] ; then
CMD_ARGS=("${JSHELL_ARGS[@]}" "${CMD_ARGS[@]}")
fi
+# Keep -Dproc_* as a plain keyword even when COMMAND is a .jsh/.java path.
+case "$COMMAND" in
+ *.jsh) HBASE_PROC_NAME=jsh ;;
+ *.java) HBASE_PROC_NAME=java ;;
+ *) HBASE_PROC_NAME="$COMMAND" ;;
+esac
+
+# JShell script mode: detach stdin so an interactive tty does not keep jshell
+# open after the script finishes. Do this once here rather than duplicating the
+# java invocation for the redirect.
+if [ "${HBASE_JSH_SCRIPT_MODE}" = "true" ]; then
+ exec < /dev/null
+fi
+
+# $CLASS is left unquoted historically so multi-token values (rare) still
+# word-split, but for .java JEP 330 we keep CLASS empty and put the source
+# path in CMD_ARGS (quoted). Build the trailing argv so an empty CLASS does
+# not become a spurious "" argument the way quoting "$CLASS" would.
+JAVA_MAIN=()
+if [ -n "$CLASS" ]; then
+ # shellcheck disable=SC2206
+ JAVA_MAIN+=($CLASS)
+fi
+JAVA_MAIN+=("${CMD_ARGS[@]}")
+
if [ "${HBASE_NOEXEC}" != "" ]; then
- "$JAVA" -Dproc_$COMMAND -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS $CLASS "${CMD_ARGS[@]}"
+ "$JAVA" "-Dproc_${HBASE_PROC_NAME}" -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS "${JAVA_MAIN[@]}"
else
export JVM_PID="$$"
- exec "$JAVA" -Dproc_$COMMAND -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS $CLASS "${CMD_ARGS[@]}"
+ exec "$JAVA" "-Dproc_${HBASE_PROC_NAME}" -XX:OnOutOfMemoryError="kill -9 %p" $HEAP_SETTINGS $HBASE_OPTS "${JAVA_MAIN[@]}"
fi
diff --git a/bin/hbase_startup.jsh b/bin/hbase_startup.jsh
index 0f5dd9c25bb..794f230eb3a 100644
--- a/bin/hbase_startup.jsh
+++ b/bin/hbase_startup.jsh
@@ -18,3 +18,16 @@
import org.apache.hadoop.hbase.*;
import org.apache.hadoop.hbase.client.*;
+
+/*
+ * Positional args for non-interactive scripts launched as:
+ * hbase path/to/script.jsh arg0 arg1 ...
+ *
+ * JShell has no String[] args equivalent, so bin/hbase exports:
+ * HBASE_JSH_ARG_COUNT - number of args (decimal string)
+ * HBASE_JSH_ARG_0 .. HBASE_JSH_ARG_{N-1} - each positional arg
+ *
+ * Example in a .jsh script:
+ * int n = Integer.parseInt(System.getenv().getOrDefault("HBASE_JSH_ARG_COUNT", "0"));
+ * String first = System.getenv("HBASE_JSH_ARG_0");
+ */
diff --git a/conf/hbase-env.sh b/conf/hbase-env.sh
index d80bfaeeddb..c69421b61f2 100644
--- a/conf/hbase-env.sh
+++ b/conf/hbase-env.sh
@@ -208,5 +208,7 @@
#
# JDK11+ JShell
#
-# Additional arguments passed to jshell invocation
+# Additional arguments passed to jshell (interactive and *.jsh script dispatch).
+# When unset, bin/hbase uses DEFAULT + PRINTING (+ hbase_startup.jsh when present)
+# and --execution local unless --execution is already set here.
# export HBASE_JSHELL_ARGS="--startup DEFAULT --startup PRINTING --startup hbase_startup.jsh"