From 8fc1ec7bb8c75f9e9eaa7a0adc9db746f075dfba Mon Sep 17 00:00:00 2001 From: Glavo Date: Sat, 10 Jul 2021 22:44:13 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=BF=E6=8D=A2=E5=AF=B9=20JDK=20=E5=86=85?= =?UTF-8?q?=E7=BD=AE=20Pack200=20=E7=9A=84=E4=BE=9D=E8=B5=96=EF=BC=8C?= =?UTF-8?q?=E5=85=81=E8=AE=B8=E5=9C=A8=20JDK14=20=E5=8F=8A=E6=9B=B4?= =?UTF-8?q?=E9=AB=98=E7=89=88=E6=9C=AC=E4=B8=8A=E6=9E=84=E5=BB=BA=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=20(#904)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Pack200 has been removed * Automatically add pack200 to class path * add license header to Pack200Utils.java --- HMCL/build.gradle | 16 ++- .../hmcl/upgrade/HMCLDownloadTask.java | 4 +- .../jackhuang/hmcl/upgrade/RemoteVersion.java | 4 +- .../download/game/LibraryDownloadTask.java | 10 +- .../org/jackhuang/hmcl/util/Pack200Utils.java | 123 ++++++++++++++++++ .../hmcl/util/platform/SystemUtils.java | 4 - README.md | 2 +- build.gradle | 4 + 8 files changed, 149 insertions(+), 18 deletions(-) create mode 100644 HMCLCore/src/main/java/org/jackhuang/hmcl/util/Pack200Utils.java diff --git a/HMCL/build.gradle b/HMCL/build.gradle index 3ae9ee9c8..c86ca1602 100644 --- a/HMCL/build.gradle +++ b/HMCL/build.gradle @@ -1,9 +1,11 @@ buildscript { repositories { gradlePluginPortal() + maven { url 'https://jitpack.io' } } dependencies { classpath 'org.tukaani:xz:1.8' + classpath 'org.glavo:pack200:0.3.0' } } @@ -19,13 +21,13 @@ import java.security.Signature import java.security.spec.PKCS8EncodedKeySpec import java.util.jar.JarFile import java.util.jar.JarOutputStream -import java.util.jar.Pack200 import java.util.zip.GZIPOutputStream import java.util.zip.ZipFile import java.nio.file.Files import org.tukaani.xz.LZMA2Options import org.tukaani.xz.XZOutputStream +import org.glavo.pack200.Pack200 def dev = null def shortcommit = System.getenv("GITHUB_SHA")?.toLowerCase()?.substring(0, 7) ?: null @@ -99,8 +101,10 @@ sourceSets { } compileJava11Java { - javaCompiler = javaToolchains.compilerFor { - languageVersion = JavaLanguageVersion.of(11) + if(JavaVersion.current() < JavaVersion.VERSION_11) { + javaCompiler = javaToolchains.compilerFor { + languageVersion = JavaLanguageVersion.of(11) + } } options.compilerArgs.add('--add-exports=java.base/jdk.internal.loader=ALL-UNNAMED') sourceCompatibility = 11 @@ -120,6 +124,7 @@ shadowJar { 'Main-Class': mainClassName, 'Multi-Release': 'true', 'Implementation-Version': version, + 'Class-Path': 'pack200.jar', 'Add-Opens': [ 'java.base/java.lang', 'java.base/java.lang.reflect', @@ -164,8 +169,9 @@ processResources { def cssFile = new File(this.projectDir, "src/main/resources/" + resource) def bssFile = new File(this.projectDir, "build/compiled-resources/" + resource[0..-4] + "bss") bssFile.parentFile.mkdirs() - exec { - commandLine 'javapackager', '-createbss', '-outdir', bssFile.parent, '-srcfiles', cssFile.path + javaexec { + main = "com.sun.javafx.css.parser.Css2Bin" + args = [cssFile, bssFile] } } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java index 163d09362..8b6fdc06c 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.upgrade; import org.jackhuang.hmcl.task.FileDownloadTask; +import org.jackhuang.hmcl.util.Pack200Utils; import org.jackhuang.hmcl.util.io.NetworkUtils; import org.tukaani.xz.XZInputStream; @@ -26,7 +27,6 @@ import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.util.jar.JarOutputStream; -import java.util.jar.Pack200; class HMCLDownloadTask extends FileDownloadTask { @@ -52,7 +52,7 @@ class HMCLDownloadTask extends FileDownloadTask { byte[] raw = Files.readAllBytes(target); try (InputStream in = new XZInputStream(new ByteArrayInputStream(raw)); JarOutputStream out = new JarOutputStream(Files.newOutputStream(target))) { - Pack200.newUnpacker().unpack(in, out); + Pack200Utils.unpack(in, out); } break; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java index 82142b8ef..e0ec48171 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java @@ -21,9 +21,9 @@ import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; +import org.jackhuang.hmcl.util.Pack200Utils; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; -import org.jackhuang.hmcl.util.platform.SystemUtils; import java.io.IOException; import java.util.Optional; @@ -38,7 +38,7 @@ public class RemoteVersion { String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null); String packXZUrl = Optional.ofNullable(response.get("packxz")).map(JsonElement::getAsString).orElse(null); String packXZHash = Optional.ofNullable(response.get("packxzsha1")).map(JsonElement::getAsString).orElse(null); - if (SystemUtils.JRE_CAPABILITY_PACK200 && packXZUrl != null && packXZHash != null) { + if (Pack200Utils.isSupported() && packXZUrl != null && packXZHash != null) { return new RemoteVersion(version, packXZUrl, Type.PACK_XZ, new IntegrityCheck("SHA-1", packXZHash)); } else if (jarUrl != null && jarHash != null) { return new RemoteVersion(version, jarUrl, Type.JAR, new IntegrityCheck("SHA-1", jarHash)); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java index b3d16bde9..b694c617d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/LibraryDownloadTask.java @@ -25,10 +25,10 @@ import org.jackhuang.hmcl.task.DownloadException; import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.FileDownloadTask.IntegrityCheck; import org.jackhuang.hmcl.task.Task; +import org.jackhuang.hmcl.util.Pack200Utils; import org.jackhuang.hmcl.util.io.FileUtils; import org.jackhuang.hmcl.util.io.IOUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; -import org.jackhuang.hmcl.util.platform.SystemUtils; import org.tukaani.xz.XZInputStream; import java.io.*; @@ -38,7 +38,9 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.*; import java.util.concurrent.CancellationException; -import java.util.jar.*; +import java.util.jar.JarEntry; +import java.util.jar.JarInputStream; +import java.util.jar.JarOutputStream; import java.util.logging.Level; import static org.jackhuang.hmcl.util.DigestUtils.digest; @@ -129,7 +131,7 @@ public class LibraryDownloadTask extends Task { } } - if (SystemUtils.JRE_CAPABILITY_PACK200 && testURLExistence(url)) { + if (Pack200Utils.isSupported() && testURLExistence(url)) { List urls = dependencyManager.getDownloadProvider().injectURLWithCandidates(url + ".pack.xz"); task = new FileDownloadTask(urls, xzFile, null); task.setCacheRepository(cacheRepository); @@ -264,7 +266,7 @@ public class LibraryDownloadTask extends Task { } try (FileOutputStream jarBytes = new FileOutputStream(dest); JarOutputStream jos = new JarOutputStream(jarBytes)) { - Pack200.newUnpacker().unpack(temp.toFile(), jos); + Pack200Utils.unpack(temp.toFile(), jos); JarEntry checksumsFile = new JarEntry("checksums.sha1"); checksumsFile.setTime(0L); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Pack200Utils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Pack200Utils.java new file mode 100644 index 000000000..16aa2c10d --- /dev/null +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/Pack200Utils.java @@ -0,0 +1,123 @@ +/* + * Hello Minecraft! Launcher + * Copyright (C) 2021 huangyuhui and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.jackhuang.hmcl.util; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.util.jar.JarOutputStream; +import java.util.logging.Level; + +import static org.jackhuang.hmcl.util.Logging.LOG; + +/** + * @author Glavo + */ +public final class Pack200Utils { + private Pack200Utils() { + } + + private static final String[] IMPL_NAMES = { + "java.util.jar.Pack200", + "org.glavo.pack200.Pack200", + "io.pack200.Pack200" + }; + + private static final MethodHandle newUnpackerHandle; + private static final MethodHandle unpackHandle; + private static final MethodHandle unpackFileHandle; + + static { + Class pack200Class = null; + Class unpackerClass = null; + + for (String implName : IMPL_NAMES) { + try { + pack200Class = Class.forName(implName); + unpackerClass = Class.forName(implName + "$Unpacker"); + break; + } catch (ClassNotFoundException ignored) { + } + } + + if (pack200Class == null) { + LOG.warning("Pack200 not found"); + newUnpackerHandle = null; + unpackHandle = null; + unpackFileHandle = null; + } else { + final MethodHandles.Lookup lookup = MethodHandles.publicLookup(); + MethodHandle newUnpacker = null; + MethodHandle unpack = null; + MethodHandle unpackFile = null; + try { + newUnpacker = lookup.findStatic(pack200Class, "newUnpacker", MethodType.methodType(unpackerClass)); + unpack = lookup.findVirtual(unpackerClass, "unpack", MethodType.methodType(void.class, InputStream.class, JarOutputStream.class)); + unpackFile = lookup.findVirtual(unpackerClass, "unpack", MethodType.methodType(void.class, File.class, JarOutputStream.class)); + } catch (Throwable e) { + LOG.log(Level.WARNING, "Failed to find pack200 methods", e); + } + + if (newUnpacker != null) { + newUnpackerHandle = newUnpacker; + unpackHandle = unpack; + unpackFileHandle = unpackFile; + } else { + newUnpackerHandle = null; + unpackHandle = null; + unpackFileHandle = null; + } + } + + } + + public static boolean isSupported() { + return newUnpackerHandle != null; + } + + public static void unpack(InputStream in, JarOutputStream out) throws IOException { + if (newUnpackerHandle == null) { + throw new UnsupportedOperationException("Pack200"); + } + + try { + unpackHandle.invoke(newUnpackerHandle.invoke(), in, out); + } catch (IOException | RuntimeException | Error e) { + throw e; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + public static void unpack(File in, JarOutputStream out) throws IOException { + if (newUnpackerHandle == null) { + throw new UnsupportedOperationException("Pack200"); + } + + try { + unpackFileHandle.invoke(newUnpackerHandle.invoke(), in, out); + } catch (IOException | RuntimeException | Error e) { + throw e; + } catch (Throwable e) { + throw new RuntimeException(e); + } + } +} diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java index b1dd73bfb..ec4766eb9 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/platform/SystemUtils.java @@ -17,8 +17,6 @@ */ package org.jackhuang.hmcl.util.platform; -import org.jackhuang.hmcl.util.Lang; - import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -28,8 +26,6 @@ import java.util.List; public final class SystemUtils { private SystemUtils() {} - public static final boolean JRE_CAPABILITY_PACK200 = Lang.test(() -> Class.forName("java.util.jar.Pack200")); - public static int callExternalProcess(String... command) throws IOException, InterruptedException { return callExternalProcess(Arrays.asList(command)); } diff --git a/README.md b/README.md index 3e9f61d2e..90b4d15cc 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ Simply execute following command: ```bash ./gradlew clean build ``` -Make sure you have Java installed with Pack200 and JavaFX 8 at least. Liberica full JDK 8~11 is recommended. +Make sure you have Java installed with JavaFX 8 at least. Liberica full JDK 8~16 is recommended. ## JVM Options (for debugging) |Parameter|Description| diff --git a/build.gradle b/build.gradle index ae43a9793..1e1e5d52b 100644 --- a/build.gradle +++ b/build.gradle @@ -25,6 +25,10 @@ subprojects { maven { url 'https://jitpack.io' } } + checkstyle { + sourceSets = [] + } + sourceCompatibility = 1.8 compileJava.options.encoding = "UTF-8" compileTestJava.options.encoding = "UTF-8"