Files
2026-08-09 20:12:05 +07:00

64 lines
2.3 KiB
Python

"""Optional Java runtime detection.
``opendataloader-pdf`` (structured PDF→JSON extraction, see chat_agent.py) is a
Python wrapper around a JAVA CLI tool — the first Java dependency anywhere in
this app. Same optional-native-binary shape as doc_extract.py::find_soffice:
env override → PATH → common install directories → ``None`` if not found.
Callers must degrade gracefully — a missing JVM just means that one capability
isn't available on this machine, not an error.
"""
from __future__ import annotations
import os
import re
import shutil
from pathlib import Path
_EXE = "java.exe" if os.name == "nt" else "java"
# Common JDK/JRE install roots, newest-version subfolder picked first.
_COMMON_ROOTS = (
r"C:\Program Files\Java",
r"C:\Program Files\Eclipse Adoptium",
r"C:\Program Files (x86)\Java",
"/Library/Java/JavaVirtualMachines",
"/usr/lib/jvm",
)
def _version_key(path: Path) -> tuple:
"""Natural-sort key so "jdk-17..." ranks above "jdk-8..." — a plain string
sort ranks '8' > '1' and would pick the OLDER JDK when major-version digit
counts differ (e.g. Eclipse Adoptium installs several majors side by side
under one root)."""
return tuple(int(n) for n in re.findall(r"\d+", path.name))
def find_java() -> str | None:
"""Locate a Java launcher (``JAVA_HOME`` → PATH → common install dirs)."""
env = os.environ.get("JAVA_HOME")
if env:
candidate = Path(env) / "bin" / _EXE
if candidate.exists():
return str(candidate)
found = shutil.which("java")
if found:
return found
for base in _COMMON_ROOTS:
base_path = Path(base)
if not base_path.is_dir():
continue
try:
subdirs = sorted(base_path.iterdir(), key=_version_key, reverse=True)
except OSError:
continue # unreadable dir (permissions/AV) — not fatal, just try the next root
for sub in subdirs:
candidate = sub / "bin" / _EXE
if candidate.exists():
return str(candidate)
# macOS JDK bundles nest an extra Contents/Home.
mac_candidate = sub / "Contents" / "Home" / "bin" / _EXE
if mac_candidate.exists():
return str(mac_candidate)
return None