mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-06-18 23:01:03 +00:00
argument parsing
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
package com.dfsek.terra.api.command;
|
package com.dfsek.terra.api.command;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.command.exception.CommandException;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public interface CommandManager {
|
public interface CommandManager {
|
||||||
void execute(String command, List<String> args);
|
void execute(String command, List<String> args) throws CommandException;
|
||||||
|
|
||||||
void register(String name, Class<? extends CommandTemplate> clazz);
|
void register(String name, Class<? extends CommandTemplate> clazz);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,24 @@ package com.dfsek.terra.api.command;
|
|||||||
import com.dfsek.terra.api.command.annotation.Argument;
|
import com.dfsek.terra.api.command.annotation.Argument;
|
||||||
import com.dfsek.terra.api.command.annotation.Command;
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
import com.dfsek.terra.api.command.annotation.Subcommand;
|
import com.dfsek.terra.api.command.annotation.Subcommand;
|
||||||
|
import com.dfsek.terra.api.command.exception.CommandException;
|
||||||
|
import com.dfsek.terra.api.command.exception.InvalidArgumentsException;
|
||||||
|
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public class TerraCommandManager implements CommandManager {
|
public class TerraCommandManager implements CommandManager {
|
||||||
Map<String, CommandHolder> commands = new HashMap<>();
|
private final Map<String, CommandHolder> commands = new HashMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(String commandName, List<String> args) {
|
public void execute(String commandName, List<String> argsIn) throws CommandException {
|
||||||
|
|
||||||
|
List<String> args = new ArrayList<>(argsIn);
|
||||||
ExecutionState state = new ExecutionState();
|
ExecutionState state = new ExecutionState();
|
||||||
|
|
||||||
CommandHolder commandHolder = commands.get(commandName);
|
CommandHolder commandHolder = commands.get(commandName);
|
||||||
@@ -29,34 +34,45 @@ public class TerraCommandManager implements CommandManager {
|
|||||||
|
|
||||||
if(command.arguments().length == 0 && command.subcommands().length == 0) {
|
if(command.arguments().length == 0 && command.subcommands().length == 0) {
|
||||||
if(args.isEmpty()) invoke(commandClass, state);
|
if(args.isEmpty()) invoke(commandClass, state);
|
||||||
else throw new IllegalArgumentException("Expected 0 arguments, found " + args.size());
|
else throw new InvalidArgumentsException("Expected 0 arguments, found " + args.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(commandHolder.subcommands.containsKey(args.get(0))) {
|
if(commandHolder.subcommands.containsKey(args.get(0))) {
|
||||||
invoke(commandClass, state);
|
invoke(commandHolder.subcommands.get(args.get(0)).clazz(), state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boolean req = true;
|
boolean req = true;
|
||||||
for(Argument argument : command.arguments()) {
|
for(Argument argument : command.arguments()) {
|
||||||
if(!req && argument.required())
|
if(!req && argument.required())
|
||||||
throw new IllegalStateException("Required arguments must come first! Arguments: " + Arrays.toString(command.arguments()));
|
throw new MalformedCommandException("Required arguments must come first! Arguments: " + Arrays.toString(command.arguments()));
|
||||||
req = argument.required();
|
req = argument.required();
|
||||||
|
|
||||||
|
if(args.isEmpty()) {
|
||||||
|
if(req) throw new InvalidArgumentsException("Invalid arguments: " + command.usage());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
String arg = args.get(0);
|
String arg = args.get(0);
|
||||||
|
|
||||||
if(arg.startsWith("-")) { // flags have started.
|
if(arg.startsWith("-")) { // flags have started.
|
||||||
|
if(req) throw new InvalidArgumentsException("Flags must come after arguments.");
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
state.addArgument(argument.value(), args.remove(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void invoke(Class<? extends CommandTemplate> clazz, ExecutionState state) {
|
|
||||||
|
invoke(commandClass, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void invoke(Class<? extends CommandTemplate> clazz, ExecutionState state) throws MalformedCommandException {
|
||||||
try {
|
try {
|
||||||
|
System.out.println("invocation");
|
||||||
clazz.getConstructor().newInstance().execute(state);
|
clazz.getConstructor().newInstance().execute(state);
|
||||||
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
} catch(InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
|
||||||
e.printStackTrace();
|
throw new MalformedCommandException("Unable to reflectively instantiate command: ", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ public @interface Command {
|
|||||||
Flag[] flags() default {};
|
Flag[] flags() default {};
|
||||||
|
|
||||||
Subcommand[] subcommands() default {};
|
Subcommand[] subcommands() default {};
|
||||||
|
|
||||||
|
String usage() default "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.dfsek.terra.api.command.exception;
|
||||||
|
|
||||||
|
public abstract class CommandException extends Exception {
|
||||||
|
private static final long serialVersionUID = -2955328495045879822L;
|
||||||
|
|
||||||
|
public CommandException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CommandException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
+13
@@ -0,0 +1,13 @@
|
|||||||
|
package com.dfsek.terra.api.command.exception;
|
||||||
|
|
||||||
|
public class InvalidArgumentsException extends CommandException {
|
||||||
|
private static final long serialVersionUID = 7563619667472569824L;
|
||||||
|
|
||||||
|
public InvalidArgumentsException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public InvalidArgumentsException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
package com.dfsek.terra.api.command.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thrown when command is incorrectly defined.
|
||||||
|
*/
|
||||||
|
public class MalformedCommandException extends CommandException {
|
||||||
|
private static final long serialVersionUID = -5417760860407895496L;
|
||||||
|
|
||||||
|
public MalformedCommandException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MalformedCommandException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,6 +8,6 @@ import com.dfsek.terra.api.command.annotation.Command;
|
|||||||
public class StructureExportCommand implements CommandTemplate {
|
public class StructureExportCommand implements CommandTemplate {
|
||||||
@Override
|
@Override
|
||||||
public void execute(ExecutionState state) {
|
public void execute(ExecutionState state) {
|
||||||
|
System.out.println("export command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package command;
|
||||||
|
|
||||||
|
import com.dfsek.terra.api.command.CommandManager;
|
||||||
|
import com.dfsek.terra.api.command.CommandTemplate;
|
||||||
|
import com.dfsek.terra.api.command.ExecutionState;
|
||||||
|
import com.dfsek.terra.api.command.TerraCommandManager;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Argument;
|
||||||
|
import com.dfsek.terra.api.command.annotation.Command;
|
||||||
|
import com.dfsek.terra.api.command.exception.CommandException;
|
||||||
|
import com.dfsek.terra.api.command.exception.MalformedCommandException;
|
||||||
|
import com.dfsek.terra.commands.StructureCommand;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
public class CommandTest {
|
||||||
|
@Test
|
||||||
|
public void subcommand() throws CommandException {
|
||||||
|
CommandManager manager = new TerraCommandManager();
|
||||||
|
manager.register("structure", StructureCommand.class);
|
||||||
|
|
||||||
|
manager.execute("structure", Arrays.asList("export"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void args() throws CommandException {
|
||||||
|
CommandManager manager = new TerraCommandManager();
|
||||||
|
manager.register("test", DemoCommand.class);
|
||||||
|
|
||||||
|
manager.execute("test", Arrays.asList("first", "2"));
|
||||||
|
manager.execute("test", Arrays.asList("first", "2", "3.4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void requiredArgsFirst() throws CommandException {
|
||||||
|
CommandManager manager = new TerraCommandManager();
|
||||||
|
manager.register("test", DemoInvalidCommand.class);
|
||||||
|
|
||||||
|
try {
|
||||||
|
manager.execute("test", Arrays.asList("first", "2"));
|
||||||
|
fail();
|
||||||
|
} catch(MalformedCommandException ignore) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(arguments = {
|
||||||
|
@Argument(value = "arg0"),
|
||||||
|
@Argument(value = "arg1", type = int.class),
|
||||||
|
@Argument(value = "arg2", type = double.class, required = false)
|
||||||
|
})
|
||||||
|
public static final class DemoCommand implements CommandTemplate {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ExecutionState state) {
|
||||||
|
System.out.println(state.getArgument("arg0", String.class));
|
||||||
|
System.out.println(state.getArgument("arg1", String.class));
|
||||||
|
try {
|
||||||
|
System.out.println(state.getArgument("arg2", String.class));
|
||||||
|
} catch(IllegalArgumentException e) {
|
||||||
|
System.out.println("arg2 undefined.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Command(arguments = {
|
||||||
|
@Argument(value = "arg0"),
|
||||||
|
@Argument(value = "arg2", type = double.class, required = false), // optional arguments must be last. this command is invalid.
|
||||||
|
@Argument(value = "arg1", type = int.class)
|
||||||
|
})
|
||||||
|
public static final class DemoInvalidCommand implements CommandTemplate {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void execute(ExecutionState state) {
|
||||||
|
throw new Error("this should never be reached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user