put new cli parser to use in CLIAppBase

This commit is contained in:
Niklas Kapelle 2024-05-08 16:08:35 +02:00
parent 5f42941d76
commit f95c262c57
Signed by: niklas
GPG Key ID: 4EB651B36D841D16
11 changed files with 114 additions and 219 deletions

View File

@ -1,5 +1,6 @@
package bin;
import kernel.peripherals.Drive;
import lib.CLIAppBase;
import kernel.peripherals.Peripherals.Peripheral;
@ -30,37 +31,17 @@ class Disk extends CLIAppBase {
});
registerSyncSubcommand("play", (args) -> {
if (args.length < 1) {
handle.writeLine("Missing drive address");
return false;
}
return audioDiskPlayPause(args[0], true);
}, "<drive>");
return audioDiskPlayPause(args.getString("addr"), true);
}, [Peripheral("addr", Drive.TYPE_NAME)]);
registerSyncSubcommand("stop", (args) -> {
if (args.length < 1) {
handle.writeLine("Missing drive address");
return false;
}
return audioDiskPlayPause(args[0], false);
}, "<drive>");
return audioDiskPlayPause(args.getString("addr"), false);
}, [Peripheral("addr", Drive.TYPE_NAME)]);
registerSyncSubcommand("eject", (args) -> {
if (args.length < 1) {
handle.writeLine("Missing drive address");
return false;
}
var driveAddr = args[0];
var driveAddr = args.getString("addr");
var drive = Peripheral.getDrive(driveAddr);
if (drive == null) {
handle.writeLine("Drive not found: " + driveAddr);
return false;
}
if (!drive.isDiskPresent()) {
handle.writeLine("No disk in drive: " + driveAddr);
return false;
@ -68,21 +49,12 @@ class Disk extends CLIAppBase {
drive.ejectDisk();
return true;
}, "<drive>");
}, [Peripheral("addr", Drive.TYPE_NAME)]);
registerSyncSubcommand("lable", (args) -> {
if (args.length < 1) {
handle.writeLine("Missing drive address");
return false;
}
var driveAddr = args[0];
registerSyncSubcommand("label", (args) -> {
var driveAddr = args.getString("addr");
var drive = Peripheral.getDrive(driveAddr);
var label:String = args[1];
if (drive == null) {
handle.writeLine("Drive not found: " + driveAddr);
}
var label:Null<String> = args.getString("label");
if (!drive.isDiskPresent()) {
handle.writeLine("No disk in drive: " + driveAddr);
@ -99,7 +71,7 @@ class Disk extends CLIAppBase {
}
return true;
}, "<drive> [label]");
}, [Peripheral("addr", Drive.TYPE_NAME), Optional(String("label"))]);
}
private function audioDiskPlayPause(driveAddr:String, play:Bool):Bool {

View File

@ -11,16 +11,16 @@ using tink.CoreApi;
class GPS extends CLIAppBase {
public function new() {
registerSyncSubcommand("set", (args) -> {
var x:Float = Std.parseFloat(args[0]);
var y:Float = Std.parseFloat(args[1]);
var z:Float = Std.parseFloat(args[2]);
var x:Float = args.getFloat("x");
var y:Float = args.getFloat("y");
var z:Float = args.getFloat("z");
var pos:Pos3 = new Vec3<Float>(x, y, z);
kernel.gps.GPS.setManualPosition(pos);
return true;
}, "<x> <y> <z>");
}, [Float("x"), Float("y"), Float("z")]);
registerSyncSubcommand("status", (args) -> {
var pos = kernel.gps.GPS.getPosition();

View File

@ -7,12 +7,7 @@ import lib.CLIAppBase;
class KSettings extends CLIAppBase {
public function new() {
registerSyncSubcommand("get", (args) -> {
var key = args[0];
if (key == null) {
handle.writeLine("Key not specified");
return false;
}
var key = args.getString("key");
var value = switch (key) {
case "hostname":
@ -30,17 +25,17 @@ class KSettings extends CLIAppBase {
handle.writeLine(value);
return true;
}, " <key>");
}, [String("key")]);
registerSyncSubcommand("set", (args) -> {
var key = args[0];
var key = args.getString("key");
if (key == null) {
handle.writeLine("Key not specified");
return false;
}
var value = args[1];
var value = args.getString("value");
if (value == null) {
handle.writeLine("Value not specified");
@ -57,7 +52,7 @@ class KSettings extends CLIAppBase {
return false;
}
return true;
}, " <key> <value>");
}, [String("key"), String("value")]);
registerSyncSubcommand("list", (args) -> {
handle.writeLine("hostname");

View File

@ -40,16 +40,7 @@ class Net extends CLIAppBase {
});
registerAsyncSubcommand("ping", (args) -> {
if (args.length < 1) {
return Future.sync(false);
}
var toID:Null<Int> = Std.parseInt(args[0]);
if (toID == null) {
handle.write("Invalid ID");
return Future.sync(false);
}
var toID:Int = args.getInt("id");
return kernel.net.Net.ping(toID).map(result -> {
switch (result) {
@ -61,6 +52,6 @@ class Net extends CLIAppBase {
return true;
});
}, "<id>");
}, [Int("id")]);
}
}

View File

@ -7,15 +7,8 @@ import lib.CLIAppBase;
class Perf extends CLIAppBase {
public function new() {
registerSyncSubcommand("inspect", (args) -> {
if (args.length < 1)
return false;
var result = Peripheral.inspect(args[0]);
if (result == null) {
handle.writeLine("No peripheral found on side " + args[0]);
return true;
}
var addr = args.getString("addr");
var result = Peripheral.inspect(addr);
handle.writeLine("Types:");
for (type in result.types) {
@ -28,7 +21,7 @@ class Perf extends CLIAppBase {
}
return true;
}, "<side>");
}, [Addr("addr")]);
registerSyncSubcommand("list", (args) -> {
for (addr in Peripheral.getAllAddresses()) {

View File

@ -9,19 +9,19 @@ using tink.CoreApi;
class Redstone extends CLIAppBase {
public function new() {
registerSyncSubcommand("on", (args) -> {
Peripheral.getRedstone(args[0]).setOutput(true);
Peripheral.getRedstone(args.getString("side")).setOutput(true);
return true;
}, "<side>");
}, [Side("side")]);
registerSyncSubcommand("off", (args) -> {
Peripheral.getRedstone(args[0]).setOutput(false);
Peripheral.getRedstone(args.getString("side")).setOutput(false);
return true;
}, "<side>");
}, [Side("side")]);
registerSyncSubcommand("get", (args) -> {
var value = Peripheral.getRedstone(args[0]).getAnalogInput();
var value = Peripheral.getRedstone(args.getString("side")).getAnalogInput();
handle.write("Analog input: " + value);
return true;
}, "<side>");
}, [Side("side")]);
}
}

View File

@ -9,50 +9,28 @@ using tink.CoreApi;
class Service extends CLIAppBase {
public function new() {
registerSyncSubcommand("start", (args) -> {
if (args.length < 1) {
return false;
}
var name = args[0];
var result = ServiceManager.start(name);
var result = ServiceManager.start(args.getString("name"));
return handleResult(result);
}, "<name>");
}, [String("name")]);
registerSyncSubcommand("stop", (args) -> {
if (args.length < 1) {
return false;
}
var name = args[0];
var result = ServiceManager.stop(name);
var result = ServiceManager.stop(args.getString("name"));
return handleResult(result);
}, "<name>");
}, [String("name")]);
registerSyncSubcommand("register", (args) -> {
if (args.length < 2) {
return false;
}
var name = args[0];
var binName = args[1];
var rest = args.slice(2);
var name = args.getString("name");
var binName = args.getString("binary");
var rest = args.getRest();
var result = ServiceManager.register(name, binName, rest);
return handleResult(result);
}, "<name> <binary> [args...]");
}, [String("name"), String("binary"), Rest("args")]);
registerSyncSubcommand("unregister", (args) -> {
if (args.length < 2) {
return false;
}
var name = args[0];
var result = ServiceManager.unregister(name);
var result = ServiceManager.unregister(args.getString("name"));
return handleResult(result);
}, "<name>");
}, [String("name")]);
registerSyncSubcommand("list", (args) -> {
var list = ServiceManager.listRunning();
@ -65,13 +43,9 @@ class Service extends CLIAppBase {
});
registerSyncSubcommand("enable", (args) -> {
if (args.length < 1) {
return false;
}
ServiceManager.enable(args[0]);
ServiceManager.enable(args.getString("name"));
return true;
}, "<name>");
}, [String("name")]);
}
private function handleResult(res:Outcome<Noise, String>):Bool {

View File

@ -9,33 +9,16 @@ using tink.CoreApi;
class Speaker extends CLIAppBase {
public function new() {
registerSyncSubcommand("note", (args) -> {
if (args.length < 2) {
handle.writeLine("Not enough args");
return false;
}
var sp = Peripheral.getSpeaker(args.getString("addr"));
var sp = Peripheral.getSpeaker(args[0]);
var note = args[1];
var note = args.getString("note");
var r;
if (args.length > 3) {
var volume = Std.parseFloat(args[2]);
if (volume == null) {
handle.writeLine("Failed to parse volume");
return false;
}
if (args.length > 4) {
var pitch = Std.parseInt(args[3]);
if (pitch == null) {
handle.writeLine("Failed to parse pitch");
return false;
}
r = sp.playNote(note, volume, pitch);
if (args.hasArg("pitch")) {
if (args.hasArg("volume")) {
r = sp.playNote(note, args.getFloat("volume"), args.getInt("pitch"));
} else {
r = sp.playNote(note, volume);
r = sp.playNote(note, args.getFloat("volume"));
}
} else {
r = sp.playNote(note);
@ -48,36 +31,24 @@ class Speaker extends CLIAppBase {
case Success(_):
return true;
}
}, "<addr> <note> [pitch] [volume]");
}, [
Peripheral("addr", kernel.peripherals.Speaker.TYPE_NAME),
String("note"),
Optional(Int("pitch")),
Optional(Float("volume"))
]);
registerSyncSubcommand("sound", (args) -> {
if (args.length < 2) {
handle.writeLine("Not enough args");
return false;
}
var sp = Peripheral.getSpeaker(args.getString("addr"));
var sp = Peripheral.getSpeaker(args[0]);
var sound = args[1];
var sound = args.getString("sound");
var r;
if (args.length > 3) {
var volume = Std.parseFloat(args[2]);
if (volume == null) {
handle.writeLine("Failed to parse volume");
return false;
}
if (args.length > 4) {
var pitch = Std.parseFloat(args[3]);
if (pitch == null) {
handle.writeLine("Failed to parse pitch");
return false;
}
r = sp.playSound(sound, volume, pitch);
if (args.hasArg("volume")) {
if (args.hasArg("pitch")) {
r = sp.playSound(sound, args.getFloat("volume"), args.getFloat("pitch"));
} else {
r = sp.playSound(sound, volume);
r = sp.playSound(sound, args.getFloat("volume"));
}
} else {
r = sp.playSound(sound);
@ -90,6 +61,11 @@ class Speaker extends CLIAppBase {
case Success(_):
return true;
}
}, "<addr> <sound> [volume] [pitch]");
}, [
Peripheral("addr", kernel.peripherals.Speaker.TYPE_NAME),
String("sound"),
Optional(Float("pitch")),
Optional(Float("volume"))
]);
}
}

View File

@ -11,28 +11,28 @@ using tink.CoreApi;
class TurtleCtl extends CLIAppBase {
public function new() {
registerAsyncSubcommand("f", (args) -> {
return asynPerform(Turtle.forward, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.forward, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("b", (args) -> {
return asynPerform(Turtle.back, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.back, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("l", (args) -> {
return asynPerform(Turtle.turnLeft, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.turnLeft, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("r", (args) -> {
return asynPerform(Turtle.turnRight, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.turnRight, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("u", (args) -> {
return asynPerform(Turtle.up, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.up, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("d", (args) -> {
return asynPerform(Turtle.down, parseTimes(args));
}, "<times>");
return asynPerform(Turtle.down, args.getInt("times"));
}, [Int("times")]);
registerAsyncSubcommand("defrag", (args) -> {
return asynPerform(() -> {
@ -63,8 +63,9 @@ class TurtleCtl extends CLIAppBase {
registerAsyncSubcommand("refuel", (args) -> {
var refuelTo = Turtle.getFuelLimit();
if (args.length > 0) {
var split = args[0].split("%");
var arg = args.getString("to");
if (arg != null) {
var split = arg.split("%");
if (split.length > 1) {
// Is percentage
@ -78,7 +79,7 @@ class TurtleCtl extends CLIAppBase {
refuelTo = Math.round(refuelTo * (parsed / 100));
} else {
// Is absolute
var parsed = Std.parseInt(args[0]);
var parsed = Std.parseInt(arg);
if (parsed == null) {
handle.writeLine("Failed to parse ammount");
@ -94,7 +95,7 @@ class TurtleCtl extends CLIAppBase {
return Success(null);
}, 1);
}, "<to|to%>");
}, [Optional(String("to"))]);
}
private function asynPerform(op:Void->Outcome<Noise, String>, times:Int):Future<Bool> {

View File

@ -8,13 +8,9 @@ using tink.CoreApi;
class NameSystemCLI extends CLIAppBase {
public function new() {
registerAsyncSubcommand("get", (args) -> {
if (args.length < 1) {
return Future.sync(false);
}
var ns = NameSystemRPC.getDefault();
return ns.getIDRecord(args[0]).map((r) -> {
return ns.getIDRecord(args.getString("name")).map((r) -> {
switch r {
case Success(data):
handle.writeLine('Resolved: $data');
@ -24,23 +20,13 @@ class NameSystemCLI extends CLIAppBase {
return true;
});
}, "<name>");
}, [String("name")]);
registerAsyncSubcommand("register", (args) -> {
if (args.length < 2) {
return Future.sync(false);
}
var id = Std.parseInt(args[1]);
if (id == null) {
handle.writeLine("Not a valid id");
return Future.sync(false);
}
var id = args.getInt("id");
var ns = NameSystemRPC.getDefault();
return ns.setIDRecord(args[0], id).map((r) -> {
return ns.setIDRecord(args.getString("name"), id).map((r) -> {
switch r {
case Success(_):
handle.writeLine('Set');
@ -50,7 +36,7 @@ class NameSystemCLI extends CLIAppBase {
return true;
});
}, "<name> <id>");
}, [String("name"), Int("id")]);
registerAsyncSubcommand("list", (args) -> {
var ns = NameSystemRPC.getDefault();
@ -68,13 +54,9 @@ class NameSystemCLI extends CLIAppBase {
});
registerAsyncSubcommand("unregister", (args) -> {
if (args.length < 1) {
return Future.sync(false);
}
var ns = NameSystemRPC.getDefault();
return ns.removeIDRecord(args[0]).map((r) -> {
return ns.removeIDRecord(args.getString("name")).map((r) -> {
switch r {
case Success(_):
handle.writeLine('Unregisterd');
@ -84,6 +66,6 @@ class NameSystemCLI extends CLIAppBase {
return true;
});
}, "<name>");
}, [String("name")]);
}
}

View File

@ -1,5 +1,7 @@
package lib;
import lib.args.CLIArgs;
import lib.args.ArgType;
import kernel.ps.IProcess;
import kernel.ps.ProcessHandle;
@ -8,9 +10,9 @@ using tink.CoreApi;
abstract class CLIAppBase implements IProcess {
private var handle:ProcessHandle;
private final _subcommandsSync:Map<String, (Array<String>) -> Bool> = [];
private final _subcommandsAsync:Map<String, (Array<String>) -> Future<Bool>> = [];
private final _subcommandsSynopsis:Array<String> = [];
private final _subcommandsSync:Map<String, (CLIArgs) -> Bool> = [];
private final _subcommandsAsync:Map<String, (CLIArgs) -> Future<Bool>> = [];
private final _subcommandsArgs:Map<String, Array<ArgType>> = [];
public final function run(handle:ProcessHandle) {
this.handle = handle;
@ -26,10 +28,19 @@ abstract class CLIAppBase implements IProcess {
var args = handle.args.slice(1);
if (_subcommandsSync.exists(subcommand)) {
var result = _subcommandsSync[subcommand](args);
return handle.close(result);
var argParser = new CLIArgs(_subcommandsArgs.get(subcommand));
if (!argParser.parse(args)) {
handle.writeLine(argParser.getError());
return handle.close(false);
}
return handle.close(_subcommandsSync[subcommand](argParser));
} else if (_subcommandsAsync.exists(subcommand)) {
_subcommandsAsync[subcommand](args).handle(handle.close);
var argParser = new CLIArgs(_subcommandsArgs.get(subcommand));
if (!argParser.parse(args)) {
handle.writeLine(argParser.getError());
return handle.close(false);
}
_subcommandsAsync[subcommand](argParser).handle(handle.close);
} else {
handle.writeLine("Unknown subcommand: " + subcommand);
printHelp();
@ -37,21 +48,21 @@ abstract class CLIAppBase implements IProcess {
}
}
private function registerSyncSubcommand(command:String, callback:(Array<String>) -> Bool, synopsis:String = null) {
private function registerSyncSubcommand(command:String, callback:(CLIArgs) -> Bool, args:Array<ArgType> = null) {
_subcommandsSync.set(command, callback);
_subcommandsSynopsis.push(command + " " + (synopsis ?? ""));
_subcommandsArgs.set(command, args ?? []);
}
private function registerAsyncSubcommand(command:String, callback:(Array<String>) -> Future<Bool>, synopsis:String = null) {
private function registerAsyncSubcommand(command:String, callback:(CLIArgs) -> Future<Bool>, args:Array<ArgType> = null) {
_subcommandsAsync.set(command, callback);
_subcommandsSynopsis.push(command + " " + (synopsis ?? ""));
_subcommandsArgs.set(command, args ?? []);
}
private function printHelp() {
handle.writeLine("Usage: <subcommand> [args]");
handle.writeLine("Subcommands:");
for (subcommand in _subcommandsSynopsis) {
handle.writeLine(" " + subcommand);
for (k => v in this._subcommandsArgs) {
handle.writeLine(' $k ${CLIArgs.getSynopsis(v)}');
}
}
}