"batch" command to allow scripting
This commit is contained in:
parent
4b90821036
commit
a7f5931730
|
@ -2,10 +2,9 @@ package io.gitlab.jfronny.inceptum;
|
|||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import io.gitlab.jfronny.inceptum.cli.*;
|
||||
import io.gitlab.jfronny.inceptum.cli.InvokedCommandDescription;
|
||||
import io.gitlab.jfronny.inceptum.gson.*;
|
||||
import io.gitlab.jfronny.inceptum.model.ComparableVersion;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.Config;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.source.ModSource;
|
||||
import io.gitlab.jfronny.inceptum.model.microsoft.OauthTokenResponse;
|
||||
|
@ -22,7 +21,6 @@ import java.io.IOException;
|
|||
import java.lang.reflect.Modifier;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
//TODO allow instance sync through metadata
|
||||
public class Inceptum {
|
||||
|
@ -34,7 +32,6 @@ public class Inceptum {
|
|||
private static final Path CONFIG_PATH = MetaHolder.BASE_PATH.resolve("glaunch2.json");
|
||||
public static final Path ACCOUNTS_PATH = MetaHolder.BASE_PATH.resolve("accounts.json");
|
||||
public static final Path FORCE_LOAD_PATH = NATIVES_DIR.resolve("forceload");
|
||||
public static final Set<Command> COMMANDS = Set.of(new HelpCommand(), new GuiCommand(), new LaunchCommand(), new UpdateCheckCommand(), new JvmStateCommand());
|
||||
public static final Logger LOGGER = LoggerFactory.getLogger("Inceptum");
|
||||
public static final Gson GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(MinecraftArgument.class, new MinecraftArgumentDeserializer())
|
||||
|
@ -52,20 +49,9 @@ public class Inceptum {
|
|||
public static Config CONFIG;
|
||||
public static boolean IS_GUI;
|
||||
|
||||
public static void main(String[] _args) throws IOException {
|
||||
CommandArguments arg = new CommandArguments(_args);
|
||||
Command cmd = null;
|
||||
for (Command command : COMMANDS) {
|
||||
if (command.isAlias(arg.command)) {
|
||||
cmd = command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cmd == null) {
|
||||
System.out.println("Command not found: " + arg.command);
|
||||
return;
|
||||
}
|
||||
if (cmd.enableLog()) {
|
||||
public static void main(String[] _args) throws Exception {
|
||||
InvokedCommandDescription arg = new InvokedCommandDescription(_args);
|
||||
if (arg.command.enableLog()) {
|
||||
LOGGER.info("Launching Inceptum v" + MetaHolder.VERSION.version + " (" + MetaHolder.VERSION.flavor + ")");
|
||||
LOGGER.info("Loading from " + MetaHolder.BASE_PATH);
|
||||
}
|
||||
|
@ -91,7 +77,7 @@ public class Inceptum {
|
|||
});
|
||||
}
|
||||
|
||||
cmd.invoke(arg);
|
||||
arg.command.invoke(arg);
|
||||
}
|
||||
|
||||
public static void saveConfig() {
|
||||
|
|
|
@ -5,7 +5,7 @@ import imgui.ImGuiIO;
|
|||
import imgui.flag.ImGuiConfigFlags;
|
||||
import imgui.gl3.ImGuiImplGl3;
|
||||
import imgui.glfw.ImGuiImplGlfw;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.cli.InvokedCommandDescription;
|
||||
import io.gitlab.jfronny.inceptum.util.api.account.AccountManager;
|
||||
import io.gitlab.jfronny.inceptum.windows.Window;
|
||||
import org.lwjgl.glfw.Callbacks;
|
||||
|
@ -34,7 +34,7 @@ public class InceptumGui {
|
|||
protected static long handle;
|
||||
private static String glslVersion = null;
|
||||
|
||||
public static void main(CommandArguments args, Runnable exec) {
|
||||
public static void main(InvokedCommandDescription args, Runnable exec) {
|
||||
AccountManager.loadAccounts();
|
||||
Inceptum.LOGGER.info("Initializing UI");
|
||||
init();
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import io.gitlab.jfronny.inceptum.util.ArgumentTokenizer;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class BatchCommand extends Command {
|
||||
public BatchCommand() {
|
||||
super("Executes several commands specified in a text file in one setting", "batch");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
if (args.length == 0) {
|
||||
Inceptum.LOGGER.error("Could not start batch execution: No source file specified");
|
||||
return;
|
||||
}
|
||||
Set<InvokedCommandDescription> argsSet = new LinkedHashSet<>();
|
||||
for (String arg : args) {
|
||||
Path p = Path.of(arg);
|
||||
if (!Files.exists(p)) {
|
||||
Inceptum.LOGGER.error("Could not find " + p);
|
||||
return;
|
||||
}
|
||||
if (Files.isDirectory(p)) {
|
||||
Inceptum.LOGGER.error("Path is a directory: " + p);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
for (String line : Files.readAllLines(p)) {
|
||||
argsSet.add(new InvokedCommandDescription(ArgumentTokenizer.tokenize(line).toArray(String[]::new)));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Inceptum.LOGGER.error("Could not read file", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
for (InvokedCommandDescription commandDescription : argsSet) {
|
||||
commandDescription.command.invoke(commandDescription);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean enableLog() {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
@ -31,5 +29,5 @@ public abstract class Command {
|
|||
return false;
|
||||
}
|
||||
|
||||
public abstract void invoke(CommandArguments args);
|
||||
public abstract void invoke(InvokedCommandDescription args);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package io.gitlab.jfronny.inceptum.cli;
|
|||
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import io.gitlab.jfronny.inceptum.InceptumGui;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.inceptum.util.Utils;
|
||||
import io.gitlab.jfronny.inceptum.windows.MainWindow;
|
||||
|
@ -17,7 +16,7 @@ public class GuiCommand extends Command {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void invoke(CommandArguments args) {
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
Inceptum.IS_GUI = true;
|
||||
UpdateInfo update = UpdateCheckCommand.getUpdate();
|
||||
InceptumGui.main(args, () -> {
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.util.MetaHolder;
|
||||
|
||||
public class HelpCommand extends Command {
|
||||
|
@ -9,9 +7,9 @@ public class HelpCommand extends Command {
|
|||
super("Displays this screen", "help");
|
||||
}
|
||||
@Override
|
||||
public void invoke(CommandArguments args) {
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
System.out.println("Inceptum v" + MetaHolder.VERSION.version + " (" + MetaHolder.VERSION.flavor + ")\n\nCommands:");
|
||||
for (Command command : Inceptum.COMMANDS) {
|
||||
for (Command command : InvokedCommandDescription.COMMANDS) {
|
||||
System.out.println(" " + command.getName() + " - " + command.getHelp());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class InvokedCommandDescription implements Iterable<String> {
|
||||
public static final Set<Command> COMMANDS = Set.of(new HelpCommand(), new GuiCommand(), new LaunchCommand(), new UpdateCheckCommand(), new JvmStateCommand(), new BatchCommand());
|
||||
private final List<String> args;
|
||||
public final int length;
|
||||
public final boolean wrapped;
|
||||
public final Command command;
|
||||
public InvokedCommandDescription(String[] args) throws Exception {
|
||||
if (args.length == 0) args = new String[]{"gui"};
|
||||
wrapped = args[0].equals("wrapper");
|
||||
if (wrapped && args.length == 1) args = new String[] {"wrapper", "gui"};
|
||||
{
|
||||
String cmdSel = wrapped ? args[1] : args[0];
|
||||
Command cmd = null;
|
||||
for (Command command : COMMANDS) {
|
||||
if (command.isAlias(cmdSel)) {
|
||||
cmd = command;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (cmd == null) {
|
||||
throw new Exception("Command not found: " + cmdSel);
|
||||
}
|
||||
command = cmd;
|
||||
}
|
||||
this.args = Arrays.asList(args).subList(wrapped ? 2 : 1, args.length);
|
||||
this.length = args.length;
|
||||
}
|
||||
|
||||
public boolean contains(String param) {
|
||||
return args.contains(param.replaceAll("^[-/]*", "").toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
public String last() {
|
||||
return args.get(args.size() - 1);
|
||||
}
|
||||
|
||||
public String get(int index) {
|
||||
return args.get(index);
|
||||
}
|
||||
|
||||
public List<String> after(String param) {
|
||||
List<String> yes = null;
|
||||
for (String arg : args) {
|
||||
if (yes != null)
|
||||
yes.add(arg);
|
||||
else if (arg.equals(param.replaceAll("^[-/]*", "").toLowerCase(Locale.ROOT)))
|
||||
yes = new ArrayList<>();
|
||||
}
|
||||
return yes;
|
||||
}
|
||||
|
||||
public List<String> after(int index) {
|
||||
return index + 2 < length ? args.subList(index + 1, length) : new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<String> iterator() {
|
||||
return args.iterator();
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -11,7 +9,7 @@ public class JvmStateCommand extends Command {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void invoke(CommandArguments args) {
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
System.out.println(System.getProperty("java.class.path"));
|
||||
dumpClasspath(JvmStateCommand.class.getClassLoader());
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.InstanceMeta;
|
||||
import io.gitlab.jfronny.inceptum.util.ClientLauncher;
|
||||
import io.gitlab.jfronny.inceptum.util.ProcessUtils;
|
||||
|
@ -15,11 +14,11 @@ import java.util.ArrayList;
|
|||
|
||||
public class LaunchCommand extends Command {
|
||||
public LaunchCommand() {
|
||||
super("Launches the game. Optionally specify \"server\" or \"client\"", "run", "launch", "start");
|
||||
super("Launches the game. Optionally specify \"server\" or \"client\". Non-blocking (batch commands will continue if this is ran)", "run", "launch", "start");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(CommandArguments args) {
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
if (args.length == 0) {
|
||||
Inceptum.LOGGER.error("You must provide an instance name or path");
|
||||
return;
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.inceptum.cli;
|
||||
|
||||
import io.gitlab.jfronny.inceptum.Inceptum;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.CommandArguments;
|
||||
import io.gitlab.jfronny.inceptum.model.inceptum.UpdateInfo;
|
||||
import io.gitlab.jfronny.inceptum.util.*;
|
||||
|
||||
|
@ -16,7 +15,7 @@ public class UpdateCheckCommand extends Command {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void invoke(CommandArguments args) {
|
||||
public void invoke(InvokedCommandDescription args) {
|
||||
if (args.contains("install") && !args.wrapped) {
|
||||
System.err.println("Automatic updates are not supported without the wrapper");
|
||||
return;
|
||||
|
|
|
@ -1,44 +0,0 @@
|
|||
package io.gitlab.jfronny.inceptum.model.inceptum;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class CommandArguments {
|
||||
private final List<String> args;
|
||||
public final int length;
|
||||
public final boolean wrapped;
|
||||
public final String command;
|
||||
public CommandArguments(String[] args) {
|
||||
if (args.length == 0) args = new String[]{"gui"};
|
||||
wrapped = args[0].equals("wrapper");
|
||||
if (wrapped && args.length == 1) args = new String[] {"wrapper", "gui"};
|
||||
command = wrapped ? args[1] : args[0];
|
||||
this.args = Arrays.asList(args).subList(wrapped ? 2 : 1, args.length);
|
||||
this.length = args.length;
|
||||
}
|
||||
|
||||
public boolean contains(String param) {
|
||||
return args.contains(param.replaceAll("^[-/]*", "").toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
public String last() {
|
||||
return args.get(args.size() - 1);
|
||||
}
|
||||
|
||||
public List<String> after(String param) {
|
||||
List<String> yes = null;
|
||||
for (String arg : args) {
|
||||
if (yes != null)
|
||||
yes.add(arg);
|
||||
else if (arg.equals(param.replaceAll("^[-/]*", "").toLowerCase(Locale.ROOT)))
|
||||
yes = new ArrayList<>();
|
||||
}
|
||||
return yes;
|
||||
}
|
||||
|
||||
public List<String> after(int index) {
|
||||
return index + 1 < length ? args.subList(index + 1, length) : new ArrayList<>();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
package io.gitlab.jfronny.inceptum.util;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public class ArgumentTokenizer {
|
||||
private static final int NO_TOKEN_STATE = 0;
|
||||
private static final int NORMAL_TOKEN_STATE = 1;
|
||||
private static final int SINGLE_QUOTE_STATE = 2;
|
||||
private static final int DOUBLE_QUOTE_STATE = 3;
|
||||
|
||||
/** Tokenizes the given String into String tokens
|
||||
* @param arguments A String containing one or more command-line style arguments to be tokenized.
|
||||
* @return A list of parsed and properly escaped arguments.
|
||||
*/
|
||||
public static List<String> tokenize(String arguments) {
|
||||
return tokenize(arguments, false);
|
||||
}
|
||||
|
||||
/** Tokenizes the given String into String tokens.
|
||||
* @param arguments A String containing one or more command-line style arguments to be tokenized.
|
||||
* @param stringify whether to include escape special characters
|
||||
* @return A list of parsed and properly escaped arguments.
|
||||
*/
|
||||
public static List<String> tokenize(String arguments, boolean stringify) {
|
||||
List<String> argList = new LinkedList<>();
|
||||
StringBuilder currArg = new StringBuilder();
|
||||
boolean escaped = false;
|
||||
int state = NO_TOKEN_STATE; // start in the NO_TOKEN_STATE
|
||||
int len = arguments.length();
|
||||
|
||||
// Loop over each character in the string
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = arguments.charAt(i);
|
||||
if (escaped) {
|
||||
// Escaped state: just append the next character to the current arg.
|
||||
escaped = false;
|
||||
currArg.append(c);
|
||||
}
|
||||
else {
|
||||
switch(state) {
|
||||
case SINGLE_QUOTE_STATE:
|
||||
if (c == '\'') {
|
||||
// Seen the close quote; continue this arg until whitespace is seen
|
||||
state = NORMAL_TOKEN_STATE;
|
||||
}
|
||||
else {
|
||||
currArg.append(c);
|
||||
}
|
||||
break;
|
||||
case DOUBLE_QUOTE_STATE:
|
||||
if (c == '"') {
|
||||
// Seen the close quote; continue this arg until whitespace is seen
|
||||
state = NORMAL_TOKEN_STATE;
|
||||
}
|
||||
else if (c == '\\') {
|
||||
// Look ahead, and only escape quotes or backslashes
|
||||
i++;
|
||||
char next = arguments.charAt(i);
|
||||
if (next == '"' || next == '\\') {
|
||||
currArg.append(next);
|
||||
}
|
||||
else {
|
||||
currArg.append(c);
|
||||
currArg.append(next);
|
||||
}
|
||||
}
|
||||
else {
|
||||
currArg.append(c);
|
||||
}
|
||||
break;
|
||||
// case NORMAL_TOKEN_STATE:
|
||||
// if (Character.isWhitespace(c)) {
|
||||
// // Whitespace ends the token; start a new one
|
||||
// argList.add(currArg.toString());
|
||||
// currArg = new StringBuffer();
|
||||
// state = NO_TOKEN_STATE;
|
||||
// }
|
||||
// else if (c == '\\') {
|
||||
// // Backslash in a normal token: escape the next character
|
||||
// escaped = true;
|
||||
// }
|
||||
// else if (c == '\'') {
|
||||
// state = SINGLE_QUOTE_STATE;
|
||||
// }
|
||||
// else if (c == '"') {
|
||||
// state = DOUBLE_QUOTE_STATE;
|
||||
// }
|
||||
// else {
|
||||
// currArg.append(c);
|
||||
// }
|
||||
// break;
|
||||
case NO_TOKEN_STATE:
|
||||
case NORMAL_TOKEN_STATE:
|
||||
switch(c) {
|
||||
case '\\':
|
||||
escaped = true;
|
||||
state = NORMAL_TOKEN_STATE;
|
||||
break;
|
||||
case '\'':
|
||||
state = SINGLE_QUOTE_STATE;
|
||||
break;
|
||||
case '"':
|
||||
state = DOUBLE_QUOTE_STATE;
|
||||
break;
|
||||
default:
|
||||
if (!Character.isWhitespace(c)) {
|
||||
currArg.append(c);
|
||||
state = NORMAL_TOKEN_STATE;
|
||||
}
|
||||
else if (state == NORMAL_TOKEN_STATE) {
|
||||
// Whitespace ends the token; start a new one
|
||||
argList.add(currArg.toString());
|
||||
currArg = new StringBuilder();
|
||||
state = NO_TOKEN_STATE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("ArgumentTokenizer state " + state + " is invalid!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we're still escaped, put in the backslash
|
||||
if (escaped) {
|
||||
currArg.append('\\');
|
||||
argList.add(currArg.toString());
|
||||
}
|
||||
// Close the last argument if we haven't yet
|
||||
else if (state != NO_TOKEN_STATE) {
|
||||
argList.add(currArg.toString());
|
||||
}
|
||||
// Format each argument if we've been told to stringify them
|
||||
if (stringify) {
|
||||
for (int i = 0; i < argList.size(); i++) {
|
||||
argList.set(i, "\"" + _escapeQuotesAndBackslashes(argList.get(i)) + "\"");
|
||||
}
|
||||
}
|
||||
return argList;
|
||||
}
|
||||
|
||||
/** Inserts backslashes before any occurrences of a backslash or
|
||||
* quote in the given string. Also converts any special characters
|
||||
* appropriately.
|
||||
*/
|
||||
protected static String _escapeQuotesAndBackslashes(String s) {
|
||||
final StringBuilder buf = new StringBuilder(s);
|
||||
|
||||
// Walk backwards, looking for quotes or backslashes.
|
||||
// If we see any, insert an extra backslash into the buffer at
|
||||
// the same index. (By walking backwards, the index into the buffer
|
||||
// will remain correct as we change the buffer.)
|
||||
for (int i = s.length()-1; i >= 0; i--) {
|
||||
char c = s.charAt(i);
|
||||
if ((c == '\\') || (c == '"')) {
|
||||
buf.insert(i, '\\');
|
||||
}
|
||||
// Replace any special characters with escaped versions
|
||||
else if (c == '\n') {
|
||||
buf.deleteCharAt(i);
|
||||
buf.insert(i, "\\n");
|
||||
}
|
||||
else if (c == '\t') {
|
||||
buf.deleteCharAt(i);
|
||||
buf.insert(i, "\\t");
|
||||
}
|
||||
else if (c == '\r') {
|
||||
buf.deleteCharAt(i);
|
||||
buf.insert(i, "\\r");
|
||||
}
|
||||
else if (c == '\b') {
|
||||
buf.deleteCharAt(i);
|
||||
buf.insert(i, "\\b");
|
||||
}
|
||||
else if (c == '\f') {
|
||||
buf.deleteCharAt(i);
|
||||
buf.insert(i, "\\f");
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue