Prefer venv Python and normalize venv extraction
This commit is contained in:
parent
9064d3ea10
commit
b5baaa38c3
|
|
@ -298,6 +298,7 @@ public class ResourceExtractor {
|
|||
Files.createDirectories(targetDir);
|
||||
copyDirectoryFromClasspath("python-runtime/venv-offline", targetDir);
|
||||
}
|
||||
normalizeVenvDir(targetDir.getParent(), targetDir);
|
||||
makeExecutable(targetDir.resolve("bin/python3.10"));
|
||||
makeExecutable(targetDir.resolve("bin/python3"));
|
||||
log.info(" Done");
|
||||
|
|
@ -468,4 +469,28 @@ public class ResourceExtractor {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void normalizeVenvDir(Path parentDir, Path expectedDir) throws IOException {
|
||||
if (Files.isDirectory(expectedDir)) {
|
||||
return;
|
||||
}
|
||||
Path altLinux = parentDir.resolve("venv-linux-offline");
|
||||
if (Files.isDirectory(altLinux)) {
|
||||
log.info(" Renaming venv directory: {} -> {}", altLinux.getFileName(), expectedDir.getFileName());
|
||||
Files.move(altLinux, expectedDir, StandardCopyOption.REPLACE_EXISTING);
|
||||
return;
|
||||
}
|
||||
Path altVenv = parentDir.resolve("venv");
|
||||
if (Files.isDirectory(altVenv)) {
|
||||
log.info(" Renaming venv directory: {} -> {}", altVenv.getFileName(), expectedDir.getFileName());
|
||||
Files.move(altVenv, expectedDir, StandardCopyOption.REPLACE_EXISTING);
|
||||
return;
|
||||
}
|
||||
Path altOff = parentDir.resolve("venv-offline");
|
||||
if (Files.isDirectory(altOff)) {
|
||||
// already present under expected name in parent, but expectedDir path differs
|
||||
return;
|
||||
}
|
||||
log.warn(" Venv directory not found after extraction under {}", parentDir);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -153,10 +153,20 @@ public class FlaskProcessManager implements ApplicationListener<ContextRefreshed
|
|||
if (libPath != null) {
|
||||
env.put("PYTHONPATH", libPath.toString());
|
||||
}
|
||||
// Prefer embedded Python home when using standalone runtime
|
||||
Path pythonHome = resolveEmbeddedPythonHome();
|
||||
if (pythonHome != null) {
|
||||
env.put("PYTHONHOME", pythonHome.toString());
|
||||
Path venvRoot = resolveEmbeddedVenvRoot();
|
||||
boolean usingVenv = venvRoot != null && embeddedPython != null &&
|
||||
embeddedPython.toAbsolutePath().startsWith(venvRoot.toAbsolutePath());
|
||||
if (usingVenv) {
|
||||
Path venvBin = venvRoot.resolve(isWindows() ? "Scripts" : "bin");
|
||||
env.put("VIRTUAL_ENV", venvRoot.toString());
|
||||
String oldPath = env.getOrDefault("PATH", "");
|
||||
env.put("PATH", venvBin.toString() + File.pathSeparator + oldPath);
|
||||
} else {
|
||||
// Prefer embedded Python home when using standalone runtime
|
||||
Path pythonHome = resolveEmbeddedPythonHome();
|
||||
if (pythonHome != null) {
|
||||
env.put("PYTHONHOME", pythonHome.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Use bundled models
|
||||
|
|
@ -338,7 +348,40 @@ public class FlaskProcessManager implements ApplicationListener<ContextRefreshed
|
|||
}
|
||||
|
||||
private Path resolveEmbeddedPython() {
|
||||
// Prefer embedded standalone runtime first
|
||||
// Prefer venv interpreter first (ensures Flask and deps are available)
|
||||
Path venvRoot = resolveEmbeddedVenvRoot();
|
||||
if (venvRoot != null) {
|
||||
Path linuxPython310 = venvRoot.resolve("bin/python3.10");
|
||||
if (Files.exists(linuxPython310)) {
|
||||
return linuxPython310;
|
||||
}
|
||||
Path linuxPython311 = venvRoot.resolve("bin/python3.11");
|
||||
if (Files.exists(linuxPython311)) {
|
||||
return linuxPython311;
|
||||
}
|
||||
Path linuxPython39 = venvRoot.resolve("bin/python3.9");
|
||||
if (Files.exists(linuxPython39)) {
|
||||
return linuxPython39;
|
||||
}
|
||||
Path linuxPython38 = venvRoot.resolve("bin/python3.8");
|
||||
if (Files.exists(linuxPython38)) {
|
||||
return linuxPython38;
|
||||
}
|
||||
Path linuxPythonVenv = venvRoot.resolve("bin/python3");
|
||||
if (Files.exists(linuxPythonVenv)) {
|
||||
return linuxPythonVenv;
|
||||
}
|
||||
Path linuxPythonAlt = venvRoot.resolve("bin/python");
|
||||
if (Files.exists(linuxPythonAlt)) {
|
||||
return linuxPythonAlt;
|
||||
}
|
||||
Path windowsPython = venvRoot.resolve("Scripts/python.exe");
|
||||
if (Files.exists(windowsPython)) {
|
||||
return windowsPython;
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to embedded standalone runtime
|
||||
Path linuxPython310 = Paths.get(resourceDir, "python-runtime/python/bin/python3.10");
|
||||
if (Files.exists(linuxPython310)) {
|
||||
return linuxPython310;
|
||||
|
|
@ -351,35 +394,6 @@ public class FlaskProcessManager implements ApplicationListener<ContextRefreshed
|
|||
if (Files.exists(linuxPython)) {
|
||||
return linuxPython;
|
||||
}
|
||||
// Fallback to venv interpreter if bundled (still embedded)
|
||||
linuxPython310 = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python3.10");
|
||||
if (Files.exists(linuxPython310)) {
|
||||
return linuxPython310;
|
||||
}
|
||||
Path linuxPython311 = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python3.11");
|
||||
if (Files.exists(linuxPython311)) {
|
||||
return linuxPython311;
|
||||
}
|
||||
Path linuxPython39 = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python3.9");
|
||||
if (Files.exists(linuxPython39)) {
|
||||
return linuxPython39;
|
||||
}
|
||||
Path linuxPython38 = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python3.8");
|
||||
if (Files.exists(linuxPython38)) {
|
||||
return linuxPython38;
|
||||
}
|
||||
Path linuxPythonVenv = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python3");
|
||||
if (Files.exists(linuxPythonVenv)) {
|
||||
return linuxPythonVenv;
|
||||
}
|
||||
Path linuxPythonAlt = Paths.get(resourceDir, "python-runtime/venv-offline/bin/python");
|
||||
if (Files.exists(linuxPythonAlt)) {
|
||||
return linuxPythonAlt;
|
||||
}
|
||||
Path windowsPython = Paths.get(resourceDir, "python-runtime/venv-offline/Scripts/python.exe");
|
||||
if (Files.exists(windowsPython)) {
|
||||
return windowsPython;
|
||||
}
|
||||
Path windowsPythonAlt = Paths.get(resourceDir, "python-runtime/python.exe");
|
||||
if (Files.exists(windowsPythonAlt)) {
|
||||
return windowsPythonAlt;
|
||||
|
|
@ -397,7 +411,8 @@ public class FlaskProcessManager implements ApplicationListener<ContextRefreshed
|
|||
|
||||
private Path resolveEmbeddedSitePackages() {
|
||||
// Linux venvs use lib/pythonX.Y/site-packages
|
||||
Path libRoot = Paths.get(resourceDir, "python-runtime/venv-offline/lib");
|
||||
Path venvRoot = resolveEmbeddedVenvRoot();
|
||||
Path libRoot = venvRoot != null ? venvRoot.resolve("lib") : Paths.get(resourceDir, "python-runtime/venv-offline/lib");
|
||||
if (Files.isDirectory(libRoot)) {
|
||||
try {
|
||||
try (java.nio.file.DirectoryStream<Path> stream = Files.newDirectoryStream(libRoot)) {
|
||||
|
|
@ -415,10 +430,28 @@ public class FlaskProcessManager implements ApplicationListener<ContextRefreshed
|
|||
}
|
||||
}
|
||||
// Windows venvs
|
||||
Path venvLibWin = Paths.get(resourceDir, "python-runtime/venv-offline/Lib/site-packages");
|
||||
Path venvLibWin = venvRoot != null ? venvRoot.resolve("Lib/site-packages") :
|
||||
Paths.get(resourceDir, "python-runtime/venv-offline/Lib/site-packages");
|
||||
if (Files.exists(venvLibWin)) {
|
||||
return venvLibWin;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Path resolveEmbeddedVenvRoot() {
|
||||
Path venv = Paths.get(resourceDir, "python-runtime/venv-offline");
|
||||
if (Files.isDirectory(venv)) {
|
||||
return venv;
|
||||
}
|
||||
Path alt = Paths.get(resourceDir, "python-runtime/venv-linux-offline");
|
||||
if (Files.isDirectory(alt)) {
|
||||
return alt;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isWindows() {
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
return os.contains("windows");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue