修复遗留问题 (#1875)

* Check the sha1 file of java in the minecraft runtime dir

* Fix download Java on macOS

* misc

* Verify Java at startup

* Find the Java installed by official launcher on osx-arm64

* Extract the downloaded file to a temporary file

* Rollback JavaRepository.getSystemJavaPlatform
This commit is contained in:
Glavo 2022-11-26 21:43:35 +08:00 committed by GitHub
parent a96fe298b8
commit d11e22026c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 65 additions and 21 deletions

View File

@ -822,7 +822,7 @@ public final class LauncherHelper {
if (exitType != ExitType.NORMAL) {
ArrayList<Pair<String, Log4jLevel>> pairs = new ArrayList<>(logs.size());
Lang.forEachZipped(logs, levels,
(log, l) -> pairs.add(pair(log, l instanceof Log4jLevel ? ((Log4jLevel) l) : Log4jLevel.guessLevel(log))));
(log, l) -> pairs.add(pair(log, l instanceof Log4jLevel ? ((Log4jLevel) l) : Optional.ofNullable(Log4jLevel.guessLevel(log)).orElse(Log4jLevel.INFO))));
repository.markVersionLaunchedAbnormally(version.getId());
Platform.runLater(() -> new GameCrashWindow(process, exitType, repository, version, launchOptions, pairs).show());
}

View File

@ -120,12 +120,15 @@ public class JavaDownloadTask extends Task<Void> {
FileDownloadTask task = new FileDownloadTask(NetworkUtils.toURL(downloadProvider.injectURL(download.getUrl())), tempFile, new FileDownloadTask.IntegrityCheck("SHA-1", download.getSha1()));
task.setName(entry.getKey());
dependencies.add(task.thenRunAsync(() -> {
Path decompressed = jvmDir.resolve(entry.getKey() + ".tmp");
try (LZMAInputStream input = new LZMAInputStream(new FileInputStream(tempFile))) {
Files.copy(input, dest, StandardCopyOption.REPLACE_EXISTING);
Files.copy(input, decompressed, StandardCopyOption.REPLACE_EXISTING);
} catch (IOException e) {
throw new ArtifactMalformedException("File " + entry.getKey() + " is malformed", e);
}
tempFile.delete();
Files.move(decompressed, dest, StandardCopyOption.REPLACE_EXISTING);
if (file.isExecutable()) {
dest.toFile().setExecutable(true);
}

View File

@ -8,14 +8,15 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.platform.Architecture;
import org.jackhuang.hmcl.util.platform.JavaVersion;
import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.platform.Platform;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.logging.Level;
import java.util.stream.Stream;
@ -58,8 +59,7 @@ public final class JavaRepository {
case LINUX:
return Stream.of(FileUtils.tryGetPath(System.getProperty("user.home", ".minecraft/runtime")));
case OSX:
return Stream.of(FileUtils.tryGetPath("/Library/Application Support/minecraft/runtime"),
FileUtils.tryGetPath(System.getProperty("user.home"), "Library/Application Support/minecraft/runtime"));
return Stream.of(FileUtils.tryGetPath(System.getProperty("user.home"), "Library/Application Support/minecraft/runtime"));
default:
return Stream.empty();
}
@ -71,25 +71,63 @@ public final class JavaRepository {
// Examples:
// $HOME/Library/Application Support/minecraft/runtime/java-runtime-beta/mac-os/java-runtime-beta/jre.bundle/Contents/Home
// $HOME/.minecraft/runtime/java-runtime-beta/linux/java-runtime-beta
Optional<String> platformOptional = getSystemJavaPlatform();
if (!platformOptional.isPresent()) return Stream.empty();
String platform = platformOptional.get();
List<Path> javaHomes = new ArrayList<>();
try (DirectoryStream<Path> dir = Files.newDirectoryStream(runtimeDir)) {
// component can be jre-legacy, java-runtime-alpha, java-runtime-beta, java-runtime-gamma or any other being added in the future.
for (Path component : dir) {
Path javaHome = component.resolve(platform).resolve(component.getFileName());
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
javaHomes.add(javaHome.resolve("jre.bundle/Contents/Home"));
Consumer<String> action = platform -> {
try (DirectoryStream<Path> dir = Files.newDirectoryStream(runtimeDir)) {
// component can be jre-legacy, java-runtime-alpha, java-runtime-beta, java-runtime-gamma or any other being added in the future.
for (Path component : dir) {
findJavaHomeInComponentDir(platform, component).ifPresent(javaHomes::add);
}
javaHomes.add(javaHome);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to list java-runtime directory " + runtimeDir, e);
}
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to list java-runtime directory " + runtimeDir, e);
}
};
getSystemJavaPlatform().ifPresent(action);
// Workaround, which will be removed in the future
if (Platform.SYSTEM_PLATFORM == Platform.OSX_ARM64)
action.accept("mac-os-arm64");
return javaHomes.stream();
}
private static Optional<Path> findJavaHomeInComponentDir(String platform, Path component) {
Path sha1File = component.resolve(platform).resolve(component.getFileName() + ".sha1");
if (!Files.isRegularFile(sha1File))
return Optional.empty();
Path dir = component.resolve(platform).resolve(component.getFileName());
try (BufferedReader reader = Files.newBufferedReader(sha1File)) {
String line;
while ((line = reader.readLine()) != null) {
if (line.isEmpty()) continue;
int idx = line.indexOf(" /#//");
if (idx <= 0)
throw new IOException("Illegal line: " + line);
Path file = dir.resolve(line.substring(0, idx));
// Should we check the sha1 of files? This will take a lot of time.
if (Files.notExists(file))
throw new NoSuchFileException(file.toAbsolutePath().toString());
}
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
Path macPath = dir.resolve("jre.bundle/Contents/Home");
if (Files.exists(macPath))
return Optional.of(macPath);
else
LOG.warning("The Java is not in 'jre.bundle/Contents/Home'");
}
return Optional.of(dir);
} catch (IOException e) {
LOG.log(Level.WARNING, "Failed to verify Java in " + component, e);
return Optional.empty();
}
}
public static Optional<String> getSystemJavaPlatform() {
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
if (Architecture.SYSTEM_ARCH == Architecture.X86) {
@ -122,6 +160,9 @@ public final class JavaRepository {
}
public static Path getJavaHome(GameJavaVersion javaVersion, String platform) {
return getJavaStoragePath().resolve(javaVersion.getComponent()).resolve(platform).resolve(javaVersion.getComponent());
Path javaHome = getJavaStoragePath().resolve(javaVersion.getComponent()).resolve(platform).resolve(javaVersion.getComponent());
if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX)
javaHome = javaHome.resolve("jre.bundle/Contents/Home");
return javaHome;
}
}