From b9ec22677ebc9a8e7cbb5557252e11e946bf954d Mon Sep 17 00:00:00 2001 From: Mingye Wang Date: Mon, 23 May 2022 23:17:32 +0800 Subject: [PATCH] chore(javaversion): refactor searchPotentialJavaExecutables (#1485) * chore(javaversion): refactor searchPotentialJavaExecutables This is a very draft quality PR. I don't even have JDK installed to build it, that's how draft it is. 1. Refactor function to share common steps of the code: system locations, Minecraft launcher runtimes, PATH/HMCL_JRES 2. Modify Minecraft launcher runtimes to include java-runtime-beta * Update HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java * Make optional happy * correct stream-of paren; add macOS bundle exploration * who needs exploreBundle? * fix a stupid typo; add debugging tools. It works! --- .../hmcl/util/platform/JavaVersion.java | 120 +++++++++++------- 1 file changed, 73 insertions(+), 47 deletions(-) diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java index 821e2fa79..23526eecb 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/JavaVersion.java @@ -32,6 +32,7 @@ import java.util.concurrent.*; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; +import java.util.stream.Collectors; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; @@ -64,6 +65,10 @@ public final class JavaVersion { } } + public String toString() { + return "JavaVersion {" + binary + ", " + longVersion + "(" + version + ")" + ", " + platform + "}"; + } + public Path getBinary() { return binary; } @@ -295,9 +300,20 @@ public final class JavaVersion { } private static Stream searchPotentialJavaExecutables() throws IOException { + // Add order: + // 1. System-defined locations + // 2. Minecraft-installed locations + // 3. PATH List> javaExecutables = new ArrayList<>(); - switch (OperatingSystem.CURRENT_OS) { + // Can be not present -- we check at the last part + List> runtimeDirs = new ArrayList<>(); + // Is this necessary? Can't we just do listDirectory(...).map(x -> x.resolve(...))? + // lookupJavas() should take care of it... + List runtimeOSArch = new ArrayList<>(); + String pathSep = System.getProperty("path.separator"); + String javaExec = OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS ? "java.exe" : "java"; + switch (OperatingSystem.CURRENT_OS) { case WINDOWS: javaExecutables.add(queryJavaHomesInRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Runtime Environment\\").stream().map(JavaVersion::getExecutable)); javaExecutables.add(queryJavaHomesInRegistryKey("HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\").stream().map(JavaVersion::getExecutable)); @@ -309,56 +325,33 @@ public final class JavaVersion { FileUtils.tryGetPath(Optional.ofNullable(System.getenv("ProgramFiles(x86)")).orElse("C:\\Program Files (x86)")), FileUtils.tryGetPath(Optional.ofNullable(System.getenv("ProgramFiles(ARM)")).orElse("C:\\Program Files (ARM)")) )) { - if (programFiles.isPresent()) { - javaExecutables.add(listDirectory(programFiles.get().resolve("Java")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("BellSoft")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("AdoptOpenJDK")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("Zulu")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("Microsoft")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("Eclipse Foundation")).map(JavaVersion::getExecutable)); - javaExecutables.add(listDirectory(programFiles.get().resolve("Semeru")).map(JavaVersion::getExecutable)); + if (!programFiles.isPresent()) + continue; + + for (String vendor : new String[]{"Java", "BellSoft", "AdoptOpenJDK", "Zulu", "Microsoft", "Eclipse Foundation", "Semeru"}) { + javaExecutables.add(listDirectory(programFiles.get().resolve(vendor)).map(JavaVersion::getExecutable)); } } - final Optional programFilesX86 = FileUtils.tryGetPath(Optional.ofNullable(System.getenv("ProgramFiles(x86)")).orElse("C:\\Program Files (x86)")); - if (programFilesX86.isPresent()) { - final Path runtimeDir = programFilesX86.get().resolve("Minecraft Launcher").resolve("runtime"); - javaExecutables.add(Stream.of( - runtimeDir.resolve("jre-legacy").resolve("windows-x64").resolve("jre-legacy"), - runtimeDir.resolve("jre-legacy").resolve("windows-x86").resolve("jre-legacy"), - runtimeDir.resolve("java-runtime-alpha").resolve("windows-x64").resolve("java-runtime-alpha"), - runtimeDir.resolve("java-runtime-alpha").resolve("windows-x86").resolve("java-runtime-alpha") - ).map(JavaVersion::getExecutable)); - } + runtimeDirs.add(FileUtils.tryGetPath(System.getenv("localappdata"), + "Packages\\Microsoft.4297127D64EC6_8wekyb3d8bbwe\\LocalCache\\Local\\runtime")); + runtimeDirs.add(FileUtils.tryGetPath( + Optional.ofNullable(System.getenv("ProgramFiles(x86)")).orElse("C:\\Program Files (x86)"), + "Minecraft Launcher\\runtime")); - if (System.getenv("PATH") != null) { - javaExecutables.add(Arrays.stream(System.getenv("PATH").split(";")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "java.exe")))); - } - if (System.getenv("HMCL_JRES") != null) { - javaExecutables.add(Arrays.stream(System.getenv("HMCL_JRES").split(";")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "bin", "java.exe")))); - } + runtimeOSArch.add("windows-x64"); + runtimeOSArch.add("windows-x86"); break; case LINUX: javaExecutables.add(listDirectory(Paths.get("/usr/java")).map(JavaVersion::getExecutable)); // Oracle RPMs javaExecutables.add(listDirectory(Paths.get("/usr/lib/jvm")).map(JavaVersion::getExecutable)); // General locations javaExecutables.add(listDirectory(Paths.get("/usr/lib32/jvm")).map(JavaVersion::getExecutable)); // General locations - if (System.getenv("PATH") != null) { - javaExecutables.add(Arrays.stream(System.getenv("PATH").split(":")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "java")))); - } - if (System.getenv("HMCL_JRES") != null) { - javaExecutables.add(Arrays.stream(System.getenv("HMCL_JRES").split(":")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "bin", "java")))); - } - final Optional home = FileUtils.tryGetPath(System.getProperty("user.home", "")); - if (home.isPresent()) { - final Path runtimeDir = home.get().resolve(".minecraft").resolve("runtime"); - javaExecutables.add(Stream.of( - runtimeDir.resolve("jre-legacy").resolve("linux").resolve("jre-legacy"), - runtimeDir.resolve("java-runtime-alpha").resolve("linux").resolve("java-runtime-alpha") - ).map(JavaVersion::getExecutable)); - } + runtimeDirs.add(FileUtils.tryGetPath(System.getProperty("user.home", ".minecraft/runtime"))); + runtimeOSArch.add("linux"); break; + case OSX: javaExecutables.add(listDirectory(Paths.get("/Library/Java/JavaVirtualMachines")) @@ -369,18 +362,41 @@ public final class JavaVersion { .map(JavaVersion::getExecutable)); javaExecutables.add(Stream.of(Paths.get("/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"))); javaExecutables.add(Stream.of(Paths.get("/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/bin/java"))); - javaExecutables.add(Stream.of(Paths.get("/Library/Application Support/minecraft/runtime/jre-x64/jre.bundle/Contents/Home/bin/java"))); - if (System.getenv("PATH") != null) { - javaExecutables.add(Arrays.stream(System.getenv("PATH").split(":")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "java")))); - } - if (System.getenv("HMCL_JRES") != null) { - javaExecutables.add(Arrays.stream(System.getenv("HMCL_JRES").split(":")).flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "bin", "java")))); - } - break; + runtimeDirs.add(FileUtils.tryGetPath("/Library/Application Support/minecraft/runtime")); + runtimeDirs.add(FileUtils.tryGetPath(System.getProperty("user.home"), "/Library/Application Support/minecraft/runtime")); + + runtimeOSArch.add("mac-os"); + break; + default: break; } + + // Do MC runtimes, given the OS-specific info we have. + for (Optional runtimeDir : runtimeDirs) { + if (!runtimeDir.isPresent()) + continue; + + for (String osArch : runtimeOSArch) { + javaExecutables.add(Stream.of( + runtimeDir.get().resolve("jre-legacy").resolve(osArch).resolve("jre-legacy"), + runtimeDir.get().resolve("java-runtime-alpha").resolve(osArch).resolve("java-runtime-alpha"), + runtimeDir.get().resolve("java-runtime-beta").resolve(osArch).resolve("java-runtime-beta")) + .map(x -> OperatingSystem.CURRENT_OS == OperatingSystem.OSX ? x.resolve("jre.bundle/Contents/Home") : x) + .map(JavaVersion::getExecutable)); + } + } + + // Do PATH. + if (System.getenv("PATH") != null) { + javaExecutables.add(Arrays.stream(System.getenv("PATH").split(pathSep)) + .flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, javaExec)))); + } + if (System.getenv("HMCL_JRES") != null) { + javaExecutables.add(Arrays.stream(System.getenv("HMCL_JRES").split(pathSep)) + .flatMap(path -> Lang.toStream(FileUtils.tryGetPath(path, "bin", javaExec)))); + } return javaExecutables.parallelStream().flatMap(stream -> stream); } @@ -456,4 +472,14 @@ public final class JavaVersion { return null; } // ==== + + public static void main(String[] args) { + try { + LOG.setLevel(Level.ALL); + initialize(); + LOG.info(JAVAS.toString()); + } catch (Throwable e) { + LOG.log(Level.WARNING, "Oops:", e); + } + } }