diff --git a/src/bin/Disk.hx b/src/bin/Disk.hx index 6118de6..8e6cd0d 100644 --- a/src/bin/Disk.hx +++ b/src/bin/Disk.hx @@ -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); - }, ""); + 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); - }, ""); + 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; - }, ""); + }, [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 = args.getString("label"); if (!drive.isDiskPresent()) { handle.writeLine("No disk in drive: " + driveAddr); @@ -99,7 +71,7 @@ class Disk extends CLIAppBase { } return true; - }, " [label]"); + }, [Peripheral("addr", Drive.TYPE_NAME), Optional(String("label"))]); } private function audioDiskPlayPause(driveAddr:String, play:Bool):Bool { diff --git a/src/bin/GPS.hx b/src/bin/GPS.hx index 4ca1dde..21a49ca 100644 --- a/src/bin/GPS.hx +++ b/src/bin/GPS.hx @@ -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(x, y, z); kernel.gps.GPS.setManualPosition(pos); return true; - }, " "); + }, [Float("x"), Float("y"), Float("z")]); registerSyncSubcommand("status", (args) -> { var pos = kernel.gps.GPS.getPosition(); diff --git a/src/bin/KSettings.hx b/src/bin/KSettings.hx index 423d125..61722d0 100644 --- a/src/bin/KSettings.hx +++ b/src/bin/KSettings.hx @@ -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; - }, " "); + }, [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; - }, " "); + }, [String("key"), String("value")]); registerSyncSubcommand("list", (args) -> { handle.writeLine("hostname"); diff --git a/src/bin/Net.hx b/src/bin/Net.hx index b6a8bec..eaac9b2 100644 --- a/src/bin/Net.hx +++ b/src/bin/Net.hx @@ -40,16 +40,7 @@ class Net extends CLIAppBase { }); registerAsyncSubcommand("ping", (args) -> { - if (args.length < 1) { - return Future.sync(false); - } - - var toID:Null = 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; }); - }, ""); + }, [Int("id")]); } } diff --git a/src/bin/Perf.hx b/src/bin/Perf.hx index e4e4ac0..3083cb9 100644 --- a/src/bin/Perf.hx +++ b/src/bin/Perf.hx @@ -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; - }, ""); + }, [Addr("addr")]); registerSyncSubcommand("list", (args) -> { for (addr in Peripheral.getAllAddresses()) { diff --git a/src/bin/Redstone.hx b/src/bin/Redstone.hx index 020fec5..4141c6b 100644 --- a/src/bin/Redstone.hx +++ b/src/bin/Redstone.hx @@ -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")]); registerSyncSubcommand("off", (args) -> { - Peripheral.getRedstone(args[0]).setOutput(false); + Peripheral.getRedstone(args.getString("side")).setOutput(false); return true; - }, ""); + }, [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")]); } } diff --git a/src/bin/Service.hx b/src/bin/Service.hx index fd92bfe..45dc4fb 100644 --- a/src/bin/Service.hx +++ b/src/bin/Service.hx @@ -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); - }, ""); + }, [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); - }, ""); + }, [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); - }, " [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); - }, ""); + }, [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; - }, ""); + }, [String("name")]); } private function handleResult(res:Outcome):Bool { diff --git a/src/bin/Speaker.hx b/src/bin/Speaker.hx index d8289be..6228efe 100644 --- a/src/bin/Speaker.hx +++ b/src/bin/Speaker.hx @@ -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; } - }, " [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; } - }, " [volume] [pitch]"); + }, [ + Peripheral("addr", kernel.peripherals.Speaker.TYPE_NAME), + String("sound"), + Optional(Float("pitch")), + Optional(Float("volume")) + ]); } } diff --git a/src/bin/TurtleCtl.hx b/src/bin/TurtleCtl.hx index cf612e9..46b30da 100644 --- a/src/bin/TurtleCtl.hx +++ b/src/bin/TurtleCtl.hx @@ -11,28 +11,28 @@ using tink.CoreApi; class TurtleCtl extends CLIAppBase { public function new() { registerAsyncSubcommand("f", (args) -> { - return asynPerform(Turtle.forward, parseTimes(args)); - }, ""); + return asynPerform(Turtle.forward, args.getInt("times")); + }, [Int("times")]); registerAsyncSubcommand("b", (args) -> { - return asynPerform(Turtle.back, parseTimes(args)); - }, ""); + return asynPerform(Turtle.back, args.getInt("times")); + }, [Int("times")]); registerAsyncSubcommand("l", (args) -> { - return asynPerform(Turtle.turnLeft, parseTimes(args)); - }, ""); + return asynPerform(Turtle.turnLeft, args.getInt("times")); + }, [Int("times")]); registerAsyncSubcommand("r", (args) -> { - return asynPerform(Turtle.turnRight, parseTimes(args)); - }, ""); + return asynPerform(Turtle.turnRight, args.getInt("times")); + }, [Int("times")]); registerAsyncSubcommand("u", (args) -> { - return asynPerform(Turtle.up, parseTimes(args)); - }, ""); + return asynPerform(Turtle.up, args.getInt("times")); + }, [Int("times")]); registerAsyncSubcommand("d", (args) -> { - return asynPerform(Turtle.down, parseTimes(args)); - }, ""); + 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); - }, ""); + }, [Optional(String("to"))]); } private function asynPerform(op:Void->Outcome, times:Int):Future { diff --git a/src/bin/ns/NameSystemCLI.hx b/src/bin/ns/NameSystemCLI.hx index 4b2452b..9d620ef 100644 --- a/src/bin/ns/NameSystemCLI.hx +++ b/src/bin/ns/NameSystemCLI.hx @@ -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; }); - }, ""); + }, [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; }); - }, " "); + }, [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; }); - }, ""); + }, [String("name")]); } } diff --git a/src/lib/CLIAppBase.hx b/src/lib/CLIAppBase.hx index f5afd32..fb34028 100644 --- a/src/lib/CLIAppBase.hx +++ b/src/lib/CLIAppBase.hx @@ -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) -> Bool> = []; - private final _subcommandsAsync:Map) -> Future> = []; - private final _subcommandsSynopsis:Array = []; + private final _subcommandsSync:Map Bool> = []; + private final _subcommandsAsync:Map Future> = []; + private final _subcommandsArgs:Map> = []; 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) -> Bool, synopsis:String = null) { + private function registerSyncSubcommand(command:String, callback:(CLIArgs) -> Bool, args:Array = null) { _subcommandsSync.set(command, callback); - _subcommandsSynopsis.push(command + " " + (synopsis ?? "")); + _subcommandsArgs.set(command, args ?? []); } - private function registerAsyncSubcommand(command:String, callback:(Array) -> Future, synopsis:String = null) { + private function registerAsyncSubcommand(command:String, callback:(CLIArgs) -> Future, args:Array = null) { _subcommandsAsync.set(command, callback); - _subcommandsSynopsis.push(command + " " + (synopsis ?? "")); + _subcommandsArgs.set(command, args ?? []); } private function printHelp() { handle.writeLine("Usage: [args]"); handle.writeLine("Subcommands:"); - for (subcommand in _subcommandsSynopsis) { - handle.writeLine(" " + subcommand); + for (k => v in this._subcommandsArgs) { + handle.writeLine(' $k ${CLIArgs.getSynopsis(v)}'); } } }