Files
Launcher/core_lib/runtime/java.py
T

163 lines
4.7 KiB
Python

import glob
import logging
import os
import platform
import re
import shutil
import subprocess
import sys
from pathlib import Path
from core_lib.common.exception import JavaRuntimeException, JavaRuntimeParseException
logger = logging.getLogger("Launcher.CoreLib")
def get_java_version(java_executable_path: str | Path) -> tuple[int, str]:
"""
Get java version by executing `java -version`
:param java_executable_path:
:return:
"""
if isinstance(java_executable_path, Path):
java_executable_path = java_executable_path.as_posix()
try:
process = subprocess.run(
[java_executable_path, "-version"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
encoding="utf-8",
errors="replace",
timeout=10,
)
except subprocess.TimeoutExpired:
raise JavaRuntimeException(
"Java runtime timed out.",
)
except subprocess.CalledProcessError as e:
raise JavaRuntimeException(
"Unable to run Java runtime: {}".format(e.stderr),
)
except Exception as e:
raise JavaRuntimeException(
"An error occurred while executing Java runtime: {}".format(e),
)
output = (process.stderr or "") + "\n" + (process.stdout or "")
match = re.search(r'version "([^"]+)"', output)
if not match:
raise JavaRuntimeParseException(
f"Unable to parse Java version:\n{output}"
)
raw_version = match.group(1)
if raw_version.startswith("1."):
major = int(raw_version.split(".")[1])
else:
major = int(raw_version.split(".")[0])
return major, raw_version
def find_java_installations(extra_install_patterns: list | None=None) -> tuple[list[dict], list[Path]]:
"""
Find Java installations
:param extra_install_patterns:
:return:
installations: List[dict]
errors: List[Path]
"""
candidates_paths = []
installations = []
java_executable_name = "java.exe" if sys.platform == "win32" else "java"
# Check (system) environment
path_java = shutil.which("java")
if path_java:
candidates_paths.append(Path(path_java))
java_home = os.environ.get("JAVA_HOME")
if java_home:
candidates_paths.append(Path(java_home) / "bin" / java_executable_name)
system = platform.system().lower()
if system == "windows":
patterns = [
r"C:\Program Files\Java\*\bin\java.exe",
r"C:\Program Files\Eclipse Adoptium\*\bin\java.exe",
r"C:\Program Files\Microsoft\jdk-*\bin\java.exe",
r"C:\Program Files (x86)\Java\*\bin\java.exe",
]
elif system == "darwin":
patterns = [
"/Library/Java/JavaVirtualMachines/*/Contents/Home/bin/java",
"/System/Library/Java/JavaVirtualMachines/*/Contents/Home/bin/java",
"/opt/homebrew/opt/openjdk*/bin/java",
"/usr/local/opt/openjdk*/bin/java",
"/Applications/*/Contents/jbr/Contents/Home/bin/java",
]
else:
patterns = [
"/usr/bin/java",
"/bin/java",
"/usr/local/bin/java",
"/usr/lib/jvm/*/bin/java",
"/opt/java/*/bin/java",
"/opt/jdk*/bin/java",
"/snap/*/current/bin/java",
]
if isinstance(extra_install_patterns, list):
patterns.extend(extra_install_patterns)
for pattern in patterns:
candidates_paths.extend(Path(p) for p in glob.glob(pattern))
seen = set()
errors = []
for candidate_path in candidates_paths:
try:
converted_path = candidate_path.resolve().absolute()
except OSError:
continue
if converted_path in seen:
continue
ver = None
raw = None
try:
ver, raw = get_java_version(converted_path)
except JavaRuntimeParseException:
logger.debug(f"Unable to parse java version: {converted_path}")
except JavaRuntimeException:
logger.debug(f"Unable to run java executable: {converted_path}")
except Exception as e:
logger.exception(f"Unhandled exception: {e} (For path: {converted_path})")
finally:
if not ver:
errors.append(converted_path)
continue
logger.debug(f"Detected java version {ver} for path: {converted_path}")
installations.append(
{
"major": ver,
"raw": raw,
"homeDir": converted_path.parent.parent.as_posix(),
"executable": converted_path.as_posix(),
}
)
installations.sort(key=lambda item: item["major"], reverse=True)
return installations, errors