Skip to content

Commit c2d8f9e

Browse files
committed
fix: Allow user to set JAVA_HOME option
todo: Clean up Java version detection code
1 parent 1aa3e88 commit c2d8f9e

File tree

4 files changed

+139
-14
lines changed

4 files changed

+139
-14
lines changed

src/main/java/org/mcphackers/mcp/MCP.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
import org.mcphackers.mcp.tools.versions.json.Version;
3030

3131
public abstract class MCP {
32-
public static final String VERSION = "v1.1";
32+
public static final String VERSION = "v1.2";
3333
public static final String GITHUB_URL = "https://github.com/MCPHackers/RetroMCP-Java";
3434
public static final TranslatorUtil TRANSLATOR = new TranslatorUtil();
3535
private static final PluginManager pluginManager = new PluginManager();

src/main/java/org/mcphackers/mcp/tasks/TaskRecompile.java

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import javax.tools.*;
1010

11+
import java.io.BufferedWriter;
1112
import java.io.File;
1213
import java.io.IOException;
1314
import java.nio.charset.StandardCharsets;
@@ -44,7 +45,8 @@ public static List<Path> collectClassPath(MCP mcp, Side side) {
4445
@Override
4546
protected Stage[] setStages() {
4647
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
47-
if (compiler == null) {
48+
String javaHome = mcp.getOptions().getStringParameter(TaskParameter.JAVA_HOME);
49+
if (javaHome.isEmpty() && compiler == null) {
4850
throw new RuntimeException("Could not find compiling API. Please install or use a Java Development Kit to run this program.");
4951
}
5052
Path binPath = MCPPaths.get(mcp, BIN, side);
@@ -83,9 +85,10 @@ protected Stage[] setStages() {
8385
}
8486

8587
// Set --release flag for newer Java versions
86-
if (Util.getJavaVersion() > 9) {
88+
int javaVersion = Util.getJavaVersion(this.mcp);
89+
if (javaVersion > 9) {
8790
if (sourceVersion <= 0) {
88-
sourceVersion = Util.getJavaVersion();
91+
sourceVersion = javaVersion;
8992
}
9093
options.addAll(Arrays.asList("--release", Integer.toString(sourceVersion)));
9194
} else {
@@ -108,8 +111,12 @@ protected Stage[] setStages() {
108111

109112
setProgress(3);
110113

111-
DiagnosticCollector<JavaFileObject> ds = new DiagnosticCollector<>();
112-
recompile(compiler, ds, src, options);
114+
if (javaHome.isEmpty()) {
115+
DiagnosticCollector<JavaFileObject> ds = new DiagnosticCollector<>();
116+
recompile(compiler, ds, src, options);
117+
} else {
118+
recompile(mcp, side, javaHome, src, options);
119+
}
113120
}),
114121
stage(getLocalizedStage("copyres"), 50,
115122
() -> {
@@ -183,4 +190,41 @@ public void recompile(JavaCompiler compiler, DiagnosticCollector<JavaFileObject>
183190
}
184191
mgr.close();
185192
}
193+
194+
public void recompile(MCP mcp, Side side, String javaHome, Iterable<File> src, Iterable<String> recompileOptions) {
195+
Path sourcesTxt = MCPPaths.get(mcp, MCPPaths.PROJECT + "sources.txt", side);
196+
try (BufferedWriter writer = Files.newBufferedWriter(sourcesTxt)) {
197+
for (File srcFile : src) {
198+
writer.write(srcFile.getAbsolutePath() + System.lineSeparator());
199+
}
200+
} catch (IOException e) {
201+
e.printStackTrace();
202+
}
203+
204+
Path javac = Paths.get(javaHome).resolve("bin").resolve("javac");
205+
if (!Files.exists(javac)) {
206+
throw new RuntimeException("Failed to find javac in " + javaHome);
207+
}
208+
209+
Path binDir = MCPPaths.get(mcp, BIN, side);
210+
211+
List<String> cmd = new ArrayList<>();
212+
cmd.add(javac.toString());
213+
cmd.add("-d");
214+
cmd.add(binDir.toAbsolutePath().toString());
215+
cmd.add("@" + sourcesTxt.toAbsolutePath());
216+
217+
for (String recompileOption : recompileOptions) {
218+
cmd.add(recompileOption);
219+
}
220+
221+
try {
222+
int exitCode = Util.runCommand(cmd.toArray(new String[] {}), MCPPaths.get(mcp, PROJECT, side), true);
223+
if (exitCode != 0) {
224+
throw new RuntimeException("Failed to compile!");
225+
}
226+
} catch (IOException e) {
227+
throw new RuntimeException(e);
228+
}
229+
}
186230
}

src/main/java/org/mcphackers/mcp/tools/ClassUtils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package org.mcphackers.mcp.tools;
22

3+
import org.objectweb.asm.ClassReader;
4+
5+
import java.io.IOException;
36
import java.lang.reflect.Method;
47
import java.lang.reflect.Modifier;
58
import java.net.URL;
69
import java.net.URLClassLoader;
10+
import java.nio.file.Files;
711
import java.nio.file.Path;
812
import java.util.ArrayList;
913
import java.util.Enumeration;
@@ -58,4 +62,17 @@ public static int getSourceFromClassVersion(int classVersion) {
5862
}
5963
return -1;
6064
}
65+
66+
public static int getClassVersion(Path path) {
67+
try {
68+
byte[] classBytes = Files.readAllBytes(path);
69+
ClassReader cr = new ClassReader(classBytes);
70+
71+
return cr.readUnsignedShort(6);
72+
} catch (IOException ignored) {
73+
}
74+
75+
// Java 8 as a sane default
76+
return 52;
77+
}
6178
}

src/main/java/org/mcphackers/mcp/tools/Util.java

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
package org.mcphackers.mcp.tools;
22

3+
import org.mcphackers.mcp.MCP;
4+
import org.mcphackers.mcp.tasks.mode.TaskParameter;
5+
36
import java.awt.Desktop;
47
import java.awt.Toolkit;
58
import java.awt.datatransfer.StringSelection;
69
import java.io.BufferedInputStream;
710
import java.io.BufferedReader;
11+
import java.io.BufferedWriter;
812
import java.io.ByteArrayOutputStream;
913
import java.io.File;
1014
import java.io.IOException;
@@ -14,15 +18,21 @@
1418
import java.net.URISyntaxException;
1519
import java.nio.file.Files;
1620
import java.nio.file.Path;
21+
import java.nio.file.Paths;
1722
import java.security.MessageDigest;
1823
import java.security.NoSuchAlgorithmException;
24+
import java.util.ArrayList;
25+
import java.util.HashMap;
26+
import java.util.List;
27+
import java.util.Map;
1928
import java.util.Objects;
2029
import java.util.concurrent.ExecutorService;
2130
import java.util.concurrent.Executors;
2231
import java.util.concurrent.Future;
2332

2433
public abstract class Util {
2534
public static final ExecutorService SINGLE_THREAD_EXECUTOR = Executors.newSingleThreadExecutor();
35+
public static final Map<String, Integer> javaToJavaVersion = new HashMap<>();
2636

2737
public static int runCommand(String[] cmd, Path dir, boolean killOnShutdown) throws IOException {
2838
ProcessBuilder procBuilder = new ProcessBuilder(cmd);
@@ -204,16 +214,70 @@ public static String getJava() {
204214
return System.getProperties().getProperty("java.home") + File.separator + "bin" + File.separator + "java";
205215
}
206216

207-
public static int getJavaVersion() {
208-
String javaVersion = System.getProperty("java.version");
209-
String[] versionParts = javaVersion.split("\\.");
210-
int versionNumber = Integer.parseInt(versionParts[0]);
217+
public static int getJavaVersion(MCP mcp) {
218+
String javaHome = getJava();
219+
if (mcp == null) {
220+
String javaVersion = System.getProperty("java.version");
221+
String[] versionParts = javaVersion.split("\\.");
222+
int versionNumber = Integer.parseInt(versionParts[0]);
211223

212-
if (versionNumber < 9) {
213-
versionNumber = Integer.parseInt(versionParts[1]);
224+
if (versionNumber < 9) {
225+
versionNumber = Integer.parseInt(versionParts[1]);
226+
} else {
227+
versionNumber = Integer.parseInt(versionParts[0]);
228+
}
229+
javaToJavaVersion.put(javaHome, versionNumber);
230+
return versionNumber;
214231
} else {
215-
versionNumber = Integer.parseInt(versionParts[0]);
232+
// TODO: This is a hack
233+
// Please refactor.
234+
javaHome = mcp.getOptions().getStringParameter(TaskParameter.JAVA_HOME);
235+
Path javac = Paths.get(javaHome).resolve("bin").resolve("javac");
236+
int javaVersion;
237+
if (!Files.exists(javac)) {
238+
javaVersion = 6;
239+
javaToJavaVersion.put(javaHome, javaVersion);
240+
return javaVersion;
241+
}
242+
243+
String tempDirPath = System.getProperty("java.io.tmpdir");
244+
245+
// Write and compile a temporary Java file, then use ASM to read the default class file
246+
// version.
247+
try {
248+
Path tempJavaSrc = Files.createTempFile("retromcp-javac-check-", ".java");
249+
Path tempJavaOut = tempJavaSrc.getParent().resolve("Main.class");
250+
try (BufferedWriter writer = Files.newBufferedWriter(tempJavaSrc)) {
251+
writer.write("class Main { }\n");
252+
}
253+
254+
// Compile tempJavaSrc using the set javaHome
255+
List<String> cmd = new ArrayList<>();
256+
cmd.add(javac.toAbsolutePath().toString());
257+
cmd.add(tempJavaSrc.toAbsolutePath().toString());
258+
cmd.add("-d");
259+
cmd.add(tempDirPath);
260+
261+
int exitCode = Util.runCommand(cmd.toArray(new String[] {}), Paths.get(tempDirPath), true);
262+
if (exitCode != 0) {
263+
throw new RuntimeException("Failed to compile a test program with: " + javaHome);
264+
}
265+
266+
if (!Files.exists(tempJavaOut)) {
267+
throw new IllegalStateException("Test program could not be found at the location it was supposed to!");
268+
}
269+
270+
// Read class version from class
271+
int classVersion = ClassUtils.getClassVersion(tempJavaOut);
272+
return ClassUtils.getSourceFromClassVersion(classVersion);
273+
} catch (IOException ignored) {
274+
}
275+
276+
return 6;
216277
}
217-
return versionNumber;
278+
}
279+
280+
public static int getJavaVersion() {
281+
return getJavaVersion(null);
218282
}
219283
}

0 commit comments

Comments
 (0)