Added improved CLI structure.
This commit is contained in:
parent
ba4a0c16d6
commit
00cfcda9b8
|
@ -1 +1,2 @@
|
|||
build/
|
||||
cli*
|
|
@ -0,0 +1,39 @@
|
|||
#!/usr/bin/env rdmd
|
||||
/**
|
||||
* Run this script with `./build.d` to prepare the latest version of the CLI
|
||||
* for use. It compiles the CLI application, and copies a "cli" executable to
|
||||
* the project's root directory for use.
|
||||
*/
|
||||
module build;
|
||||
|
||||
import std.stdio;
|
||||
import std.process;
|
||||
import std.file;
|
||||
import std.path;
|
||||
|
||||
int main() {
|
||||
writeln("Building...");
|
||||
auto result = executeShell("dub build --build=release");
|
||||
if (result.status != 0) {
|
||||
stderr.writefln!"Build failed: %d"(result.status);
|
||||
stderr.writeln(result.output);
|
||||
return result.status;
|
||||
}
|
||||
string finalPath = buildPath("..", "cli");
|
||||
if (exists(finalPath)) std.file.remove(finalPath);
|
||||
version (Posix) {
|
||||
string sourceExecutable = "gymboard-cli";
|
||||
}
|
||||
version (Windows) {
|
||||
string sourceExecutable = "gymboard-cli.exe";
|
||||
}
|
||||
std.file.copy(sourceExecutable, finalPath);
|
||||
version (Posix) {
|
||||
result = executeShell("chmod +x " ~ finalPath);
|
||||
if (result.status != 0) {
|
||||
stderr.writefln!"Failed to enable executable permission: %d"(result.status);
|
||||
return result.status;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import std.stdio;
|
||||
|
||||
import cli;
|
||||
import command;
|
||||
import services;
|
||||
|
||||
import consolecolors;
|
||||
|
@ -9,11 +10,12 @@ void main() {
|
|||
ServiceManager serviceManager = new ServiceManager();
|
||||
CliHandler cliHandler = new CliHandler();
|
||||
cliHandler.register("service", new ServiceCommand(serviceManager));
|
||||
cwriteln("Gymboard CLI: Type <cyan>help</cyan> for more information. Type <red>exit</red> to exit the CLI.");
|
||||
while (!cliHandler.shouldExit) {
|
||||
cwriteln("\n<blue>Gymboard CLI</blue>: <grey>Command-line interface for managing Gymboard services.</grey>");
|
||||
cwriteln(" Type <cyan>help</cyan> for more information.\n Type <red>exit</red> to exit the CLI.\n");
|
||||
while (!cliHandler.isExitRequested) {
|
||||
cwrite("> ".blue);
|
||||
cliHandler.readAndHandleCommand();
|
||||
}
|
||||
serviceManager.stopAll();
|
||||
cwriteln("Goodbye!".green);
|
||||
cwriteln("Goodbye!".blue);
|
||||
}
|
||||
|
|
|
@ -7,45 +7,7 @@ import std.typecons;
|
|||
|
||||
import consolecolors;
|
||||
|
||||
interface CliCommand {
|
||||
void handle(string[] args);
|
||||
}
|
||||
|
||||
class CliHandler {
|
||||
private CliCommand[string] commands;
|
||||
public bool shouldExit = false;
|
||||
|
||||
public void register(string name, CliCommand command) {
|
||||
this.commands[name] = command;
|
||||
}
|
||||
|
||||
public void readAndHandleCommand() {
|
||||
string[] commandAndArgs = readln().strip().split!isWhite();
|
||||
if (commandAndArgs.length == 0) return;
|
||||
string command = commandAndArgs[0].toLower();
|
||||
if (command == "help") {
|
||||
showHelp();
|
||||
} else if (command == "exit") {
|
||||
shouldExit = true;
|
||||
} else if (command in commands) {
|
||||
commands[command].handle(commandAndArgs.length > 1 ? commandAndArgs[1 .. $] : []);
|
||||
} else {
|
||||
cwritefln("Unknown command: %s".red, command.orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void showHelp() {
|
||||
writeln(q"HELP
|
||||
Gymboard CLI: A tool for streamlining development.
|
||||
|
||||
Commands:
|
||||
|
||||
help Shows this message.
|
||||
exit Exits the CLI, stopping any running services.
|
||||
HELP");
|
||||
}
|
||||
|
||||
import command.base;
|
||||
import services;
|
||||
|
||||
class ServiceCommand : CliCommand {
|
||||
|
@ -86,6 +48,14 @@ class ServiceCommand : CliCommand {
|
|||
}
|
||||
}
|
||||
|
||||
string name() const {
|
||||
return "Service";
|
||||
}
|
||||
|
||||
string description() const {
|
||||
return "bleh";
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates that a service command contains as its second argument a valid
|
||||
* service name.
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
module command.base;
|
||||
|
||||
import consolecolors;
|
||||
import std.stdio;
|
||||
import std.string;
|
||||
import std.uni;
|
||||
|
||||
interface CliCommand {
|
||||
void handle(string[] args);
|
||||
string name() const;
|
||||
string description() const;
|
||||
}
|
||||
|
||||
class CliHandler {
|
||||
private CliCommand[string] commands;
|
||||
private bool exitRequested = false;
|
||||
|
||||
this() {
|
||||
commands["help"] = new HelpCommand(this);
|
||||
commands["exit"] = new ExitCommand(this);
|
||||
}
|
||||
|
||||
void register(string name, CliCommand command) {
|
||||
this.commands[name.strip().toLower()] = command;
|
||||
}
|
||||
|
||||
void readAndHandleCommand() {
|
||||
string[] commandAndArgs = readln().strip().split!isWhite();
|
||||
if (commandAndArgs.length == 0) return;
|
||||
string command = commandAndArgs[0].toLower();
|
||||
if (command in commands) {
|
||||
commands[command].handle(commandAndArgs.length > 1 ? commandAndArgs[1 .. $] : []);
|
||||
} else {
|
||||
cwritefln("Unknown command: %s".red, command.orange);
|
||||
}
|
||||
}
|
||||
|
||||
void setExitRequested() {
|
||||
this.exitRequested = true;
|
||||
}
|
||||
|
||||
bool isExitRequested() const {
|
||||
return this.exitRequested;
|
||||
}
|
||||
|
||||
CliCommand[string] getCommands() {
|
||||
return this.commands;
|
||||
}
|
||||
}
|
||||
|
||||
class HelpCommand : CliCommand {
|
||||
private CliHandler handler;
|
||||
|
||||
this(CliHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
void handle(string[] args) {
|
||||
import std.algorithm;
|
||||
|
||||
cwriteln("<blue>Gymboard CLI Help</blue>: <grey>Information about how to use this program.</grey>");
|
||||
|
||||
string[] commandNames = this.handler.getCommands().keys;
|
||||
sort(commandNames);
|
||||
uint longestCommandNameLength = commandNames.map!(n => cast(uint) n.length).maxElement;
|
||||
|
||||
foreach (name; commandNames) {
|
||||
CliCommand command = this.handler.getCommands()[name];
|
||||
|
||||
string formattedName = cyan(leftJustify(name, longestCommandNameLength + 1, ' '));
|
||||
cwriteln(formattedName, command.description().grey);
|
||||
}
|
||||
}
|
||||
|
||||
string name() const {
|
||||
return "help";
|
||||
}
|
||||
|
||||
string description() const {
|
||||
return "Shows help information.";
|
||||
}
|
||||
}
|
||||
|
||||
class ExitCommand : CliCommand {
|
||||
private CliHandler handler;
|
||||
|
||||
this(CliHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
void handle(string[] args) {
|
||||
this.handler.setExitRequested();
|
||||
}
|
||||
|
||||
string name() const {
|
||||
return "exit";
|
||||
}
|
||||
|
||||
string description() const {
|
||||
return "Exits the CLI, gracefully stopping any services or running jobs.";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
module command;
|
||||
|
||||
public import command.base;
|
Loading…
Reference in New Issue