mirror of
https://github.com/HMCL-dev/HMCL.git
synced 2025-09-13 13:56:55 -04:00
Fix 2338 自定义命令问题 (#2339)
* Fix 2338 * Fix: Now HMCL could read Post exit command from config file. * Invoke processListener.onExit before invoking exit command. Remove 'throw new RuntimeException'.
This commit is contained in:
parent
372b6376fc
commit
c74ef3eca8
@ -844,6 +844,7 @@ public final class VersionSetting implements Cloneable {
|
|||||||
vs.setHeight(Optional.ofNullable(obj.get("height")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
vs.setHeight(Optional.ofNullable(obj.get("height")).map(JsonElement::getAsJsonPrimitive).map(this::parseJsonPrimitive).orElse(0));
|
||||||
vs.setJavaDir(Optional.ofNullable(obj.get("javaDir")).map(JsonElement::getAsString).orElse(""));
|
vs.setJavaDir(Optional.ofNullable(obj.get("javaDir")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setPreLaunchCommand(Optional.ofNullable(obj.get("precalledCommand")).map(JsonElement::getAsString).orElse(""));
|
vs.setPreLaunchCommand(Optional.ofNullable(obj.get("precalledCommand")).map(JsonElement::getAsString).orElse(""));
|
||||||
|
vs.setPostExitCommand(Optional.ofNullable(obj.get("postExitCommand")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setServerIp(Optional.ofNullable(obj.get("serverIp")).map(JsonElement::getAsString).orElse(""));
|
vs.setServerIp(Optional.ofNullable(obj.get("serverIp")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setJava(Optional.ofNullable(obj.get("java")).map(JsonElement::getAsString).orElse(""));
|
vs.setJava(Optional.ofNullable(obj.get("java")).map(JsonElement::getAsString).orElse(""));
|
||||||
vs.setWrapper(Optional.ofNullable(obj.get("wrapper")).map(JsonElement::getAsString).orElse(""));
|
vs.setWrapper(Optional.ofNullable(obj.get("wrapper")).map(JsonElement::getAsString).orElse(""));
|
||||||
|
@ -217,6 +217,7 @@ public final class AdvancedVersionSettingPage extends StackPane implements Decor
|
|||||||
FXUtils.bindString(txtEnvironmentVariables, versionSetting.environmentVariablesProperty());
|
FXUtils.bindString(txtEnvironmentVariables, versionSetting.environmentVariablesProperty());
|
||||||
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
FXUtils.bindString(txtWrapper, versionSetting.wrapperProperty());
|
||||||
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
|
FXUtils.bindString(txtPreLaunchCommand, versionSetting.preLaunchCommandProperty());
|
||||||
|
FXUtils.bindString(txtPostExitCommand, versionSetting.postExitCommandProperty());
|
||||||
FXUtils.bindEnum(cboRenderer, versionSetting.rendererProperty());
|
FXUtils.bindEnum(cboRenderer, versionSetting.rendererProperty());
|
||||||
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
|
noGameCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckGameProperty());
|
||||||
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
|
noJVMCheckPane.selectedProperty().bindBidirectional(versionSetting.notCheckJVMProperty());
|
||||||
|
@ -419,6 +419,9 @@ public class DefaultLauncher extends Launcher {
|
|||||||
|
|
||||||
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
|
// To guarantee that when failed to generate launch command line, we will not call pre-launch command
|
||||||
List<String> rawCommandLine = command.commandLine.asList();
|
List<String> rawCommandLine = command.commandLine.asList();
|
||||||
|
if (StringUtils.isNotBlank(options.getWrapper())) {
|
||||||
|
rawCommandLine.addAll(0, StringUtils.parseCommand(options.getWrapper(), getEnvVars()));
|
||||||
|
}
|
||||||
|
|
||||||
if (command.tempNativeFolder != null) {
|
if (command.tempNativeFolder != null) {
|
||||||
Files.deleteIfExists(command.tempNativeFolder);
|
Files.deleteIfExists(command.tempNativeFolder);
|
||||||
@ -439,7 +442,7 @@ public class DefaultLauncher extends Launcher {
|
|||||||
File runDirectory = repository.getRunDirectory(version.getId());
|
File runDirectory = repository.getRunDirectory(version.getId());
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
|
if (StringUtils.isNotBlank(options.getPreLaunchCommand())) {
|
||||||
ProcessBuilder builder = new ProcessBuilder(StringUtils.tokenize(options.getPreLaunchCommand())).directory(runDirectory);
|
ProcessBuilder builder = new ProcessBuilder(StringUtils.parseCommand(options.getPreLaunchCommand(), getEnvVars())).directory(runDirectory);
|
||||||
builder.environment().putAll(getEnvVars());
|
builder.environment().putAll(getEnvVars());
|
||||||
SystemUtils.callExternalProcess(builder);
|
SystemUtils.callExternalProcess(builder);
|
||||||
}
|
}
|
||||||
@ -649,7 +652,7 @@ public class DefaultLauncher extends Launcher {
|
|||||||
throw new ExecutionPolicyLimitException();
|
throw new ExecutionPolicyLimitException();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, Charset encoding, boolean isDaemon) {
|
private void startMonitors(ManagedProcess managedProcess, ProcessListener processListener, Charset encoding, boolean isDaemon) {
|
||||||
processListener.setProcess(managedProcess);
|
processListener.setProcess(managedProcess);
|
||||||
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
|
Thread stdout = Lang.thread(new StreamPump(managedProcess.getProcess().getInputStream(), it -> {
|
||||||
processListener.onLog(it, false);
|
processListener.onLog(it, false);
|
||||||
@ -661,7 +664,19 @@ public class DefaultLauncher extends Launcher {
|
|||||||
managedProcess.addLine(it);
|
managedProcess.addLine(it);
|
||||||
}, encoding), "stderr-pump", isDaemon);
|
}, encoding), "stderr-pump", isDaemon);
|
||||||
managedProcess.addRelatedThread(stderr);
|
managedProcess.addRelatedThread(stderr);
|
||||||
managedProcess.addRelatedThread(Lang.thread(new ExitWaiter(managedProcess, Arrays.asList(stdout, stderr), processListener::onExit), "exit-waiter", isDaemon));
|
managedProcess.addRelatedThread(Lang.thread(new ExitWaiter(managedProcess, Arrays.asList(stdout, stderr), (exitCode, exitType) -> {
|
||||||
|
processListener.onExit(exitCode, exitType);
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(options.getPostExitCommand())) {
|
||||||
|
try {
|
||||||
|
ProcessBuilder builder = new ProcessBuilder(StringUtils.parseCommand(options.getPostExitCommand(), getEnvVars())).directory(options.getGameDir());
|
||||||
|
builder.environment().putAll(getEnvVars());
|
||||||
|
SystemUtils.callExternalProcess(builder);
|
||||||
|
} catch (Throwable e) {
|
||||||
|
LOG.log(Level.WARNING, "An Exception happened while running exit command.", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}), "exit-waiter", isDaemon));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class Command {
|
private static final class Command {
|
||||||
|
@ -210,19 +210,58 @@ public final class StringUtils {
|
|||||||
public static List<String> tokenize(String str) {
|
public static List<String> tokenize(String str) {
|
||||||
if (str == null)
|
if (str == null)
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
else
|
else {
|
||||||
return tokenize(str, " \t\n\r\f");
|
// Split the string with ' or " and space cleverly.
|
||||||
|
|
||||||
|
final char groupSplit;
|
||||||
|
if (OperatingSystem.CURRENT_OS == OperatingSystem.WINDOWS) {
|
||||||
|
groupSplit = '"';
|
||||||
|
} else {
|
||||||
|
groupSplit = '\'';
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<String> parts = new ArrayList<>();
|
||||||
|
|
||||||
|
{
|
||||||
|
boolean inside = false;
|
||||||
|
StringBuilder current = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < str.length(); i++) {
|
||||||
|
char c = str.charAt(i);
|
||||||
|
if (c == groupSplit) {
|
||||||
|
inside = !inside;
|
||||||
|
} else if (!inside && c == ' ') {
|
||||||
|
parts.add(current.toString());
|
||||||
|
current.setLength(0);
|
||||||
|
} else {
|
||||||
|
current.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current.length() != 0) {
|
||||||
|
parts.add(current.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parts;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<String> tokenize(String str, String delim) {
|
public static List<String> parseCommand(String command, Map<String, String> env) {
|
||||||
ArrayList<String> result = new ArrayList<>();
|
StringBuilder stringBuilder = new StringBuilder(command);
|
||||||
StringTokenizer tokenizer = new StringTokenizer(str, delim);
|
env.forEach((key, value) -> {
|
||||||
while (tokenizer.hasMoreTokens()) {
|
key = "$" + key;
|
||||||
delim = tokenizer.nextToken();
|
int i = 0;
|
||||||
result.add(delim);
|
while (true) {
|
||||||
}
|
i = stringBuilder.indexOf(key, i);
|
||||||
|
if (i == -1) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
stringBuilder.replace(i, i + key.length(), value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return result;
|
return tokenize(stringBuilder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String parseColorEscapes(String original) {
|
public static String parseColorEscapes(String original) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user