Improve 'Architecture' and 'JavaVersion'

This commit is contained in:
Glavo 2021-10-13 20:45:22 +08:00 committed by Yuhui Huang
parent dd8da57cfb
commit 0a54037460
13 changed files with 254 additions and 155 deletions

View File

@ -432,7 +432,7 @@ public final class LauncherHelper {
}
}
if (javaVersion.getBits() != Architecture.SYSTEM.getBits()) {
if (javaVersion.getBits() != Architecture.SYSTEM_ARCH.getBits()) {
Controllers.dialog(i18n("launch.advice.different_platform"), i18n("message.warning"), MessageType.ERROR, continueAction);
suggested = true;
}

View File

@ -26,9 +26,9 @@ import org.jackhuang.hmcl.task.Schedulers;
import org.jackhuang.hmcl.task.Task;
import org.jackhuang.hmcl.util.Lang;
import org.jackhuang.hmcl.util.StringUtils;
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 org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.IOException;
@ -608,7 +608,7 @@ public final class VersionSetting implements Cloneable {
if (checkJava)
return JavaVersion.fromExecutable(Paths.get(getJavaDir()));
else
return new JavaVersion(Paths.get(getJavaDir()), "", Architecture.SYSTEM.getBits());
return new JavaVersion(Paths.get(getJavaDir()), "", Platform.SYSTEM_PLATFORM);
} catch (IOException | InvalidPathException e) {
return null; // Custom Java Directory not found,
}

View File

@ -70,7 +70,7 @@ public class GameCrashWindow extends Stage {
private final String java;
private final LibraryAnalyzer analyzer;
private final StringProperty os = new SimpleStringProperty(System.getProperty("os.name"));
private final StringProperty arch = new SimpleStringProperty(Architecture.SYSTEM_ARCHITECTURE);
private final StringProperty arch = new SimpleStringProperty(Architecture.CURRENT_ARCH_NAME);
private final StringProperty reason = new SimpleStringProperty(i18n("game.crash.reason.unknown"));
private final BooleanProperty loading = new SimpleBooleanProperty();
private final Label feedbackLabel = new Label(i18n("game.crash.feedback"));

View File

@ -228,23 +228,23 @@ public final class MultiplayerManager {
public static String getCatoPath() {
switch (OperatingSystem.CURRENT_OS) {
case WINDOWS:
if (Architecture.SYSTEM == Architecture.X86_64) {
if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return "cato/cato/" + MultiplayerManager.CATO_VERSION + "/cato-windows-amd64.exe";
} else {
return "";
}
case OSX:
if (Architecture.SYSTEM == Architecture.X86_64) {
if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return "cato/cato/" + MultiplayerManager.CATO_VERSION + "/cato-darwin-amd64";
} else if (Architecture.SYSTEM == Architecture.ARM64) {
} else if (Architecture.SYSTEM_ARCH == Architecture.ARM64) {
return "cato/cato/" + MultiplayerManager.CATO_VERSION + "/cato-darwin-arm64";
} else {
return "";
}
case LINUX:
if (Architecture.SYSTEM == Architecture.X86_64) {
if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return "cato/cato/" + MultiplayerManager.CATO_VERSION + "/cato-linux-amd64";
} else if (Architecture.SYSTEM == Architecture.ARM || Architecture.SYSTEM == Architecture.ARM64) {
} else if (Architecture.SYSTEM_ARCH == Architecture.ARM32 || Architecture.SYSTEM_ARCH == Architecture.ARM64) {
return "cato/cato/" + MultiplayerManager.CATO_VERSION + "/cato-linux-arm7";
} else {
return "";

View File

@ -84,23 +84,23 @@ public final class SelfDependencyPatcher {
private static String currentArchClassifier() {
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
switch (Architecture.JDK) {
switch (Architecture.CURRENT_ARCH) {
case X86_64:
return "linux";
case ARM:
case ARM32:
return "linux-arm32-monocle";
case ARM64:
return "linux-aarch64";
}
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
switch (Architecture.JDK) {
switch (Architecture.CURRENT_ARCH) {
case X86_64:
return "mac";
case ARM64:
return "mac-aarch64";
}
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
switch (Architecture.JDK) {
switch (Architecture.CURRENT_ARCH) {
case X86_64:
return "win";
case X86:

View File

@ -62,19 +62,19 @@ public final class JavaRepository {
public static Optional<String> getCurrentJavaPlatform() {
if (OperatingSystem.CURRENT_OS == OperatingSystem.LINUX) {
if (Architecture.SYSTEM == Architecture.X86) {
if (Architecture.SYSTEM_ARCH == Architecture.X86) {
return Optional.of("linux-i386");
} else if (Architecture.SYSTEM == Architecture.X86_64) {
} else if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return Optional.of("linux");
}
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.OSX) {
if (Architecture.SYSTEM == Architecture.X86_64) {
if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return Optional.of("mac-os");
}
} else if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
if (Architecture.SYSTEM == Architecture.X86) {
if (Architecture.SYSTEM_ARCH == Architecture.X86) {
return Optional.of("windows-x86");
} else if (Architecture.SYSTEM == Architecture.X86_64) {
} else if (Architecture.SYSTEM_ARCH == Architecture.X86_64) {
return Optional.of("windows-x64");
}
}

View File

@ -82,7 +82,7 @@ public enum JavaVersionConstraint {
VANILLA_LINUX_JAVA_8(JavaVersionConstraint.RULE_MANDATORY, versionRange("0", "1.12.999"), versionRange(JavaVersionConstraint.MIN, "1.8.999")) {
@Override
public boolean appliesToVersion(@Nullable VersionNumber gameVersion, @Nullable Version version) {
return OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM == Architecture.X86_64;
return OperatingSystem.CURRENT_OS == OperatingSystem.LINUX && Architecture.SYSTEM_ARCH == Architecture.X86_64;
}
}
;

View File

@ -94,7 +94,7 @@ public class Library implements Comparable<Library>, Validation {
public String getClassifier() {
if (artifact.getClassifier() == null)
if (natives != null && natives.containsKey(OperatingSystem.CURRENT_OS))
return natives.get(OperatingSystem.CURRENT_OS).replace("${arch}", Architecture.SYSTEM.getBits().getBit());
return natives.get(OperatingSystem.CURRENT_OS).replace("${arch}", Architecture.SYSTEM_ARCH.getBits().getBit());
else
return null;
else

View File

@ -72,7 +72,7 @@ public final class OSRestriction {
return false;
if (arch != null)
return !Lang.test(() -> !Pattern.compile(arch).matcher(Architecture.SYSTEM_ARCHITECTURE).matches());
return !Lang.test(() -> !Pattern.compile(arch).matcher(Architecture.CURRENT_ARCH_NAME).matches());
return true;
}

View File

@ -17,39 +17,56 @@
*/
package org.jackhuang.hmcl.util.platform;
import org.jackhuang.hmcl.util.StringUtils;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Locale;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import static org.jackhuang.hmcl.util.platform.Bits.BIT_32;
import static org.jackhuang.hmcl.util.platform.Bits.BIT_64;
public enum Architecture {
X86(BIT_32),
X86_64(BIT_64),
IA32(BIT_32),
IA64(BIT_64),
SPARC32(BIT_32),
SPARC64(BIT_64),
ARM(BIT_32),
X86(BIT_32, "x86"),
X86_64(BIT_64, "x86-64"),
IA32(BIT_32, "IA-32"),
IA64(BIT_64, "IA-64"),
SPARC(BIT_32),
SPARCV9(BIT_64, "SPARC V9"),
ARM32(BIT_32),
ARM64(BIT_64),
MIPS(BIT_32),
MIPS64(BIT_64),
MIPSEL32(BIT_32),
MIPSEL64(BIT_64),
PPC(BIT_32),
PPC64(BIT_64),
PPCLE(BIT_32),
PPCLE64(BIT_64),
MIPSEL(BIT_32, "MIPSel"),
MIPS64EL(BIT_64, "MIPS64el"),
PPC(BIT_32, "PowerPC"),
PPC64(BIT_64, "PowerPC-64"),
PPCLE(BIT_32, "PowerPC (Little-Endian)"),
PPC64LE(BIT_64, "PowerPC-64 (Little-Endian)"),
S390(BIT_32),
S390X(BIT_64),
RISCV(BIT_64),
UNKNOWN(Bits.UNKNOWN);
S390X(BIT_64, "S390x"),
RISCV(BIT_64, "RISC-V"),
UNKNOWN(Bits.UNKNOWN, "Unknown");
private final String checkedName;
private final String displayName;
private final Bits bits;
Architecture(Bits bits) {
this.checkedName = this.toString().toLowerCase(Locale.ROOT);
this.displayName = this.toString();
this.bits = bits;
}
Architecture(Bits bits, String displayName) {
this.checkedName = this.toString().toLowerCase(Locale.ROOT);
this.displayName = displayName;
this.bits = bits;
}
Architecture(Bits bits, String displayName, String identifier) {
this.checkedName = identifier;
this.displayName = displayName;
this.bits = bits;
}
@ -57,102 +74,113 @@ public enum Architecture {
return bits;
}
public static final String SYSTEM_ARCHITECTURE;
public static final Architecture JDK;
public static final Architecture SYSTEM;
private static Architecture normalizeArch(String value) {
value = normalize(value);
if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
return X86_64;
}
if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
return X86;
}
if (value.matches("^(ia64w?|itanium64)$")) {
return IA64;
}
if ("ia64n".equals(value)) {
return IA32;
}
if (value.matches("^(sparc|sparc32)$")) {
return SPARC32;
}
if (value.matches("^(sparcv9|sparc64)$")) {
return SPARC64;
}
if (value.matches("^(arm|arm32)$")) {
return ARM;
}
if ("aarch64".equals(value)) {
return ARM64;
}
if (value.matches("^(mips|mips32)$")) {
return MIPS;
}
if (value.matches("^(mipsel|mips32el)$")) {
return MIPSEL32;
}
if ("mips64".equals(value)) {
return MIPS64;
}
if ("mips64el".equals(value)) {
return MIPSEL64;
}
if (value.matches("^(ppc|ppc32)$")) {
return PPC;
}
if (value.matches("^(ppcle|ppc32le)$")) {
return PPCLE;
}
if ("ppc64".equals(value)) {
return PPC64;
}
if ("ppc64le".equals(value)) {
return PPCLE64;
}
if ("s390".equals(value)) {
return S390;
}
if ("s390x".equals(value)) {
return S390X;
}
if ("riscv".equals(value)) {
return RISCV;
}
return UNKNOWN;
public String getCheckedName() {
return checkedName;
}
private static Architecture normalizeProcessorArchitecture() {
String processorArchitecture = System.getenv("PROCESSOR_ARCHITECTURE");
if (StringUtils.isBlank(processorArchitecture)) return null;
switch (processorArchitecture) {
case "AMD64":
case "EM64T":
return X86_64;
case "IA64":
return IA64;
case "ARM64":
return ARM64;
case "X86":
return X86;
default:
return null;
}
public String getDisplayName() {
return displayName;
}
private static String normalize(String value) {
public static final String CURRENT_ARCH_NAME;
public static final Architecture CURRENT_ARCH;
public static final Architecture SYSTEM_ARCH;
private static final Pattern NORMALIZER = Pattern.compile("[^a-z0-9]+");
public static Architecture parseArchName(String value) {
if (value == null) {
return "";
return UNKNOWN;
}
value = NORMALIZER.matcher(value.toLowerCase(Locale.ROOT).trim()).replaceAll("");
switch (value) {
case "x8664":
case "amd64":
case "ia32e":
case "em64t":
case "x64":
return X86_64;
case "x8632":
case "x86":
case "i386":
case "i486":
case "i586":
case "i686":
case "ia32":
case "x32":
return X86;
case "aarch64":
return ARM64;
case "arm":
case "arm32":
return ARM32;
case "mips64":
return MIPS64;
case "mips64el":
return MIPS64EL;
case "mips":
case "mips32":
return MIPS;
case "mipsel":
case "mips32el":
return MIPSEL;
case "riscv":
return RISCV;
case "ia64":
case "ia64w":
case "itanium64":
return IA64;
case "ia64n":
return IA32;
case "sparcv9":
case "sparc64":
return SPARCV9;
case "sparc":
case "sparc32":
return SPARC;
case "ppc64":
return PPC64;
case "ppc64le":
return PPC64LE;
case "ppc":
case "ppc32":
return PPC;
case "ppcle":
case "ppc32le":
return PPCLE;
case "s390":
return S390;
case "s390x":
return S390X;
default:
return UNKNOWN;
}
return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
}
static {
SYSTEM_ARCHITECTURE = System.getProperty("os.arch");
CURRENT_ARCH_NAME = System.getProperty("os.arch");
JDK = normalizeArch(SYSTEM_ARCHITECTURE);
SYSTEM = Optional.ofNullable(normalizeProcessorArchitecture()).orElse(JDK);
CURRENT_ARCH = parseArchName(CURRENT_ARCH_NAME);
Architecture sysArch = UNKNOWN;
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
sysArch = parseArchName(System.getenv("PROCESSOR_ARCHITECTURE"));
} else {
try {
Process process = Runtime.getRuntime().exec("/usr/bin/arch");
if (process.waitFor(1, TimeUnit.SECONDS)) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
sysArch = parseArchName(reader.readLine());
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (Throwable ignored) {
}
}
SYSTEM_ARCH = sysArch == UNKNOWN ? CURRENT_ARCH : sysArch;
}
}

View File

@ -46,10 +46,10 @@ public final class JavaVersion {
private final Path binary;
private final String longVersion;
private final Bits platform;
private final Platform platform;
private final int version;
public JavaVersion(Path binary, String longVersion, Bits platform) {
public JavaVersion(Path binary, String longVersion, Platform platform) {
this.binary = binary;
this.longVersion = longVersion;
this.platform = platform;
@ -64,10 +64,14 @@ public final class JavaVersion {
return longVersion;
}
public Bits getBits() {
public Platform getPlatform() {
return platform;
}
public Bits getBits() {
return platform.getBits();
}
public VersionNumber getVersionNumber() {
return VersionNumber.asVersion(longVersion);
}
@ -87,7 +91,12 @@ public final class JavaVersion {
private static final Pattern REGEX = Pattern.compile("version \"(?<version>(.*?))\"");
private static final Pattern VERSION = Pattern.compile("^(?<version>[0-9]+)");
private static final Pattern OS_NAME = Pattern.compile("os\\.name = (?<name>.*)");
private static final Pattern OS_ARCH = Pattern.compile("os\\.arch = (?<arch>.*)");
private static final Pattern JAVA_VERSION = Pattern.compile("java\\.version = (?<version>.*)");
public static final int UNKNOWN = -1;
public static final int JAVA_6 = 6;
public static final int JAVA_7 = 7;
public static final int JAVA_8 = 8;
public static final int JAVA_9 = 9;
@ -103,6 +112,8 @@ public final class JavaVersion {
return JAVA_8;
else if (version.contains("1.7"))
return JAVA_7;
else if (version.contains("1.6"))
return JAVA_6;
else
return UNKNOWN;
}
@ -115,26 +126,75 @@ public final class JavaVersion {
if (cachedJavaVersion != null)
return cachedJavaVersion;
Bits platform = Bits.BIT_32;
String osName = null;
String osArch = null;
String version = null;
Process process = new ProcessBuilder(executable.toString(), "-version").start();
Platform platform = null;
Process process = new ProcessBuilder(executable.toString(), "-XshowSettings:properties", "-version").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
for (String line; (line = reader.readLine()) != null;) {
Matcher m = REGEX.matcher(line);
if (m.find())
for (String line; (line = reader.readLine()) != null; ) {
Matcher m;
m = OS_NAME.matcher(line);
if (m.find()) {
osName = m.group("name");
if (osArch != null && version != null) {
break;
} else {
continue;
}
}
m = OS_ARCH.matcher(line);
if (m.find()) {
osArch = m.group("arch");
if (osName != null && version != null) {
break;
} else {
continue;
}
}
m = JAVA_VERSION.matcher(line);
if (m.find()) {
version = m.group("version");
if (line.contains("64-Bit"))
platform = Bits.BIT_64;
if (osName != null && osArch != null) {
break;
} else {
//noinspection UnnecessaryContinue
continue;
}
}
}
}
if (version == null)
throw new IOException("No Java version is matched");
if (osName != null && osArch != null) {
platform = Platform.getPlatform(OperatingSystem.parseOSName(osName), Architecture.parseArchName(osArch));
}
if (version == null) {
boolean is64Bit = false;
process = new ProcessBuilder(executable.toString(), "-version").start();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getErrorStream()))) {
for (String line; (line = reader.readLine()) != null; ) {
Matcher m = REGEX.matcher(line);
if (m.find())
version = m.group("version");
if (line.contains("64-Bit"))
is64Bit = true;
}
}
if (platform == null) {
platform = Platform.getPlatform(OperatingSystem.CURRENT_OS, is64Bit ? Architecture.X86_64 : Architecture.X86);
}
}
if (parseVersion(version) == UNKNOWN)
throw new IOException("Unrecognized Java version " + version);
JavaVersion javaVersion = new JavaVersion(executable, version, platform);
if (javaVersion.getParsedVersion() == UNKNOWN)
throw new IOException("Unrecognized Java version " + version);
fromExecutableCache.put(executable, javaVersion);
return javaVersion;
}
@ -163,7 +223,8 @@ public final class JavaVersion {
CURRENT_JAVA = new JavaVersion(
currentExecutable,
System.getProperty("java.version"),
Architecture.JDK.getBits());
Platform.CURRENT_PLATFORM
);
}
private static Collection<JavaVersion> JAVAS;

View File

@ -98,15 +98,7 @@ public enum OperatingSystem {
private static final Pattern MEMINFO_PATTERN = Pattern.compile("^(?<key>.*?):\\s+(?<value>\\d+) kB?$");
static {
String name = System.getProperty("os.name").toLowerCase(Locale.US);
if (name.contains("win"))
CURRENT_OS = WINDOWS;
else if (name.contains("mac"))
CURRENT_OS = OSX;
else if (name.contains("solaris") || name.contains("linux") || name.contains("unix") || name.contains("sunos"))
CURRENT_OS = LINUX;
else
CURRENT_OS = UNKNOWN;
CURRENT_OS = parseOSName(System.getProperty("os.name"));
TOTAL_MEMORY = getPhysicalMemoryStatus()
.map(PhysicalMemoryStatus::getTotal)
@ -134,6 +126,23 @@ public enum OperatingSystem {
}
}
public static OperatingSystem parseOSName(String name) {
if (name == null) {
return UNKNOWN;
}
name = name.trim().toLowerCase(Locale.ROOT);
if (name.contains("win"))
return WINDOWS;
else if (name.contains("mac"))
return OSX;
else if (name.contains("solaris") || name.contains("linux") || name.contains("unix") || name.contains("sunos"))
return LINUX;
else
return UNKNOWN;
}
public static Optional<PhysicalMemoryStatus> getPhysicalMemoryStatus() {
if (CURRENT_OS == LINUX) {
try {
@ -202,7 +211,7 @@ public enum OperatingSystem {
if (name.isEmpty())
return false;
// . and .. have special meaning on all platforms
if (name.isEmpty() || name.equals("."))
if (name.equals("."))
return false;
// \0 and / are forbidden on all platforms
if (name.indexOf('/') != -1 || name.indexOf('\0') != -1)

View File

@ -4,7 +4,8 @@ import java.util.Objects;
public final class Platform {
public static final Platform UNKNOWN = new Platform(OperatingSystem.UNKNOWN, Architecture.UNKNOWN);
public static final Platform CURRENT = new Platform(OperatingSystem.CURRENT_OS, Architecture.JDK);
public static final Platform CURRENT_PLATFORM = new Platform(OperatingSystem.CURRENT_OS, Architecture.CURRENT_ARCH);
public static final Platform SYSTEM_PLATFORM = new Platform(OperatingSystem.CURRENT_OS, Architecture.SYSTEM_ARCH);
public static final Platform WINDOWS_X86_64 = new Platform(OperatingSystem.WINDOWS, Architecture.X86_64);
public static final Platform OSX_X86_64 = new Platform(OperatingSystem.OSX, Architecture.X86_64);
@ -19,7 +20,7 @@ public final class Platform {
}
public static Platform getPlatform() {
return CURRENT;
return CURRENT_PLATFORM;
}
public static Platform getPlatform(OperatingSystem os, Architecture arch) {
@ -68,6 +69,6 @@ public final class Platform {
@Override
public String toString() {
return os.getCheckedName() + "-" + arch; // TODO: getCheckedName()
return os.getCheckedName() + "-" + arch.getCheckedName();
}
}