From 2e309ce15fa8c9639ae40b14bc44d2278a69a629 Mon Sep 17 00:00:00 2001 From: Tom Hicks Date: Mon, 7 Sep 2026 18:01:26 -0700 Subject: [PATCH] Upgrades java.sh to be more thorough and respect already configured environments. --- .rc.d/java.sh | 175 +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 158 insertions(+), 17 deletions(-) diff --git a/.rc.d/java.sh b/.rc.d/java.sh index 327de5a..695bb3e 100755 --- a/.rc.d/java.sh +++ b/.rc.d/java.sh @@ -1,18 +1,159 @@ -# TODO: Use find to get subdirs. Filter by vendor. Filter by version. Find the "best" version/vendor combo. -# Highest microsoft version, if not fallback to highest non-ms version -# Brew has graalvm (17,21), microsoft (11,17,21), oracle(17,21), sapmachine, semeru (8,11,17,21) -if [ -z "${JAVA_HOME}" -a -d "/Library/Java/JavaVirtualMachines/microsoft-21.jdk/Contents/Home" ]; then - JAVA_HOME=/Library/Java/JavaVirtualMachines/microsoft-21.jdk/Contents/Home -elif [ -z "${JAVA_HOME}" -a -d "/Library/Java/JavaVirtualMachines/microsoft-17.jdk/Contents/Home" ]; then - JAVA_HOME=/Library/Java/JavaVirtualMachines/microsoft-17.jdk/Contents/Home -elif [ -z "${JAVA_HOME}" -a -d "/Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home" ]; then - JAVA_HOME=/Library/Java/JavaVirtualMachines/microsoft-11.jdk/Contents/Home -elif [ -z "${JAVA_HOME}" -a -d "/Applications/Android\ Studio.app/Contents/jre/jdk/Contents/Home" ]; then - JAVA_HOME=/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home -fi +# Setup Java environment (JAVA_HOME, JDK_HOME, and PATH) +_setup_java() { + [ -n "$ZSH_VERSION" ] && setopt localoptions nonomatch nullglob -if [ -n "$JAVA_HOME" ]; then - path=("$JAVA_HOME/bin" $path) - export JAVA_HOME - export PATH -fi + _is_valid_jre() { + [ -n "$1" ] && [ -d "$1" ] && [ -x "$1/bin/java" ] + } + + _is_valid_jdk() { + _is_valid_jre "$1" && [ -x "$1/bin/javac" ] + } + + _add_to_path() { + [ -d "$1" ] || return 0 + case ":$PATH:" in + *":$1:"*) ;; + *) PATH="$1:$PATH"; export PATH ;; + esac + } + + # 1. If user already has a valid JAVA_HOME configured, respect it + _has_user_jre=0 + if _is_valid_jre "${JAVA_HOME:-}"; then + _has_user_jre=1 + _add_to_path "$JAVA_HOME/bin" + if _is_valid_jdk "$JAVA_HOME"; then + [ -z "$JDK_HOME" ] && export JDK_HOME="$JAVA_HOME" + fi + fi + + # If both a valid JRE (JAVA_HOME) and JDK (JDK_HOME) are already configured, we are done + if [ "$_has_user_jre" -eq 1 ] && [ -n "$JDK_HOME" ] && _is_valid_jdk "$JDK_HOME"; then + return 0 + fi + + # 2. Gather candidates across macOS and Linux + _candidates=() + + # macOS tool: /usr/libexec/java_home + if [ "$(uname -s 2>/dev/null)" = "Darwin" ] && [ -x "/usr/libexec/java_home" ]; then + _jh=$(/usr/libexec/java_home 2>/dev/null) + [ -n "$_jh" ] && _candidates+=("$_jh") + fi + + # Linux tools: update-java-alternatives (Debian/Ubuntu) and readlink on java command + if command -v update-java-alternatives >/dev/null 2>&1; then + for _alt_path in $(update-java-alternatives -l 2>/dev/null | awk '{print $NF}'); do + [ -d "$_alt_path" ] && _candidates+=("$_alt_path") + done + fi + + if command -v java >/dev/null 2>&1; then + _java_bin=$(command -v java 2>/dev/null) + if command -v readlink >/dev/null 2>&1; then + _real_java=$(readlink -f "$_java_bin" 2>/dev/null) + if [ -n "$_real_java" ] && [ -x "$_real_java" ]; then + _alt_home="$(dirname "$(dirname "$_real_java")")" + [ -n "$_alt_home" ] && _candidates+=("$_alt_home") + fi + fi + fi + + # Cross-platform user managers (SDKMAN) + [ -d "$HOME/.sdkman/candidates/java/current" ] && _candidates+=("$HOME/.sdkman/candidates/java/current") + + # macOS locations + if [ "$(uname -s 2>/dev/null)" = "Darwin" ]; then + # Homebrew OpenJDK + for _d in /opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home \ + /opt/homebrew/opt/openjdk@*/libexec/openjdk.jdk/Contents/Home \ + /usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home; do + [ -d "$_d" ] && _candidates+=("$_d") + done + + # Installed JVMs in /Library/Java/JavaVirtualMachines and ~/Library/... + # Version-sorted descending to prefer newer releases + for _d in $( + for _jvm in /Library/Java/JavaVirtualMachines/*/Contents/Home \ + "$HOME/Library/Java/JavaVirtualMachines"/*/Contents/Home; do + [ -d "$_jvm" ] && echo "$_jvm" + done | sort -V -r 2>/dev/null + ); do + _candidates+=("$_d") + done + + # Android Studio bundled JBR/JDK + for _d in \ + "/Applications/Android Studio.app/Contents/jbr/Contents/Home" \ + "/Applications/Android Studio.app/Contents/jre/Contents/Home" \ + "/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home" \ + "$HOME/Applications/Android Studio.app/Contents/jbr/Contents/Home" \ + "$HOME/Applications/Android Studio.app/Contents/jre/Contents/Home" + do + [ -d "$_d" ] && _candidates+=("$_d") + done + fi + + # Linux / WSL locations + if [ "$(uname -s 2>/dev/null)" = "Linux" ]; then + # Default java symlink on Debian/Ubuntu + [ -d "/usr/lib/jvm/default-java" ] && _candidates+=("/usr/lib/jvm/default-java") + + # Distribution JVMs in /usr/lib/jvm, version-sorted descending + for _d in $( + for _jvm in /usr/lib/jvm/*; do + [ -d "$_jvm" ] && echo "$_jvm" + done | sort -V -r 2>/dev/null + ); do + _candidates+=("$_d") + done + + for _d in \ + "/usr/java/latest" \ + "/usr/java/default" \ + "/opt/android-studio/jbr" \ + "/opt/android-studio/jre" \ + "$HOME/android-studio/jbr" \ + "$HOME/.local/share/JetBrains/Toolbox/apps/android-studio/jbr" + do + [ -d "$_d" ] && _candidates+=("$_d") + done + fi + + # 3. Evaluate candidates: find best JRE (preferring SDK JREs) and best JDK + _best_jdk="" + _best_jre="" + + for _cand in "${_candidates[@]}"; do + if [ -n "$_cand" ]; then + if _is_valid_jdk "$_cand"; then + [ -z "$_best_jdk" ] && _best_jdk="$_cand" + [ -z "$_best_jre" ] && _best_jre="$_cand" + elif _is_valid_jre "$_cand"; then + [ -z "$_best_jre" ] && _best_jre="$_cand" + fi + if [ -n "$_best_jdk" ] && [ -n "$_best_jre" ]; then + break + fi + fi + done + + # 4. If no valid JAVA_HOME was set by user, configure it with best JRE (preferring SDK) + if [ "$_has_user_jre" -eq 0 ] && [ -n "$_best_jre" ]; then + export JAVA_HOME="$_best_jre" + _add_to_path "$JAVA_HOME/bin" + fi + + # 5. If no SDK/JDK_HOME is set, configure it with best JDK + if [ -z "$JDK_HOME" ] || ! _is_valid_jdk "$JDK_HOME"; then + if _is_valid_jdk "${JAVA_HOME:-}"; then + export JDK_HOME="$JAVA_HOME" + elif [ -n "$_best_jdk" ]; then + export JDK_HOME="$_best_jdk" + _add_to_path "$_best_jdk/bin" + fi + fi +} +_setup_java +unset -f _setup_java _is_valid_jre _is_valid_jdk _add_to_path