Add module that about java runtime management to core_lib.

This commit is contained in:
2026-07-13 22:06:39 +08:00
parent 648cde6e33
commit bd5a1e8974
11 changed files with 1034 additions and 189 deletions
+151
View File
@@ -0,0 +1,151 @@
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]:
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) -> list[dict]:
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,
"executable": converted_path,
}
)
installations.sort(key=lambda item: item["major"], reverse=True)
return installations