diff --git a/source/src/commands/colours.cpp b/source/src/commands/colours.cpp new file mode 100644 index 0000000..4339c21 --- /dev/null +++ b/source/src/commands/colours.cpp @@ -0,0 +1,44 @@ +#include "command_registry.hpp" +#include "config.hpp" +#include "utils/output.hpp" +#include "utils/assert.hpp" + +namespace dropshell { + +void colours_autocomplete(const CommandContext& ctx) {} +int colours_handler(const CommandContext& ctx) +{ + info << "Colours:" << std::endl; + debug << "Debug Example: The quick brown fox jumps over the lazy dog." << std::endl; + info << "Info Example: The quick brown fox jumps over the lazy dog." << std::endl; + warning << "Warning Example: The quick brown fox jumps over the lazy dog." << std::endl; + error << "Error Example: The quick brown fox jumps over the lazy dog." << std::endl; + return 0; +} + +static std::vector colours_name_list={"colours","c","--colours","-c"}; + +// Static registration +struct ColoursCommandRegister { + ColoursCommandRegister() { + CommandRegistry::instance().register_command({ + colours_name_list, + colours_handler, + colours_autocomplete, + true, // hidden + false, // requires_config + false, // requires_install + 0, // min_args (after command) + 0, // max_args (after command) + "colours", + "Show the colours used by dropshell.", + // heredoc + R"( + Show the colours used by dropshell. + )" + }); + } +} colours_command_register; + + +} // namespace dropshell \ No newline at end of file diff --git a/source/src/commands/edit.cpp b/source/src/commands/edit.cpp index a452906..e20d236 100644 --- a/source/src/commands/edit.cpp +++ b/source/src/commands/edit.cpp @@ -66,13 +66,13 @@ bool edit_file(const std::string &file_path, bool has_bb64) // Check if stdin is connected to a terminal if EDITOR is not set editor_cmd = "nano -w " + quote(file_path); } else { - std::cerr << "Error: Standard input is not a terminal and EDITOR environment variable is not set." << std::endl; - std::cerr << "Try setting the EDITOR environment variable (e.g., export EDITOR=nano) or run in an interactive terminal." << std::endl; - std::cerr << "You can manually edit the file at: " << file_path << std::endl; + error << "Standard input is not a terminal and EDITOR environment variable is not set." << std::endl; + info << "Try setting the EDITOR environment variable (e.g., export EDITOR=nano) or run in an interactive terminal." << std::endl; + info << "You can manually edit the file at: " << file_path << std::endl; return false; } - std::cout << "Editing file: " << file_path << std::endl; + info << "Editing file: " << file_path << std::endl; if (has_bb64) { return execute_local_command("", editor_cmd, {}, nullptr, cMode::Interactive); @@ -119,14 +119,14 @@ int edit_server(const std::string &server_name) std::string config_file = localfile::server_json(server_name); if (!edit_file(config_file, true)) { - std::cerr << "Error: Failed to edit server config" << std::endl; - std::cerr << "You can manually edit this file at: " << config_file << std::endl; + error << "Failed to edit server config" << std::endl; + info << "You can manually edit this file at: " << config_file << std::endl; return 1; } - std::cout << "If you have changed DROPSHELL_DIR, you should manually move the files to the new location NOW." << std::endl - << "You can ssh in to the remote server with: dropshell ssh "<help_usage, 32); - std::cout << cmd_info->help_description << std::endl; + info << " "; + info << left_align(cmd_info->help_usage, 32); + info << cmd_info->help_description << std::endl; } extern const std::string VERSION; @@ -77,28 +77,26 @@ int show_command_help(const std::string& cmd) { const auto& cmd_info = CommandRegistry::instance().find_command(cmd); if (!cmd_info) { - std::cout << "Unknown command: " << cmd << std::endl; + error << "Unknown command: " << cmd << std::endl; return 1; } + info << "Command " << cmd << " usage:" << std::endl; + info << " "; + info << left_align(cmd_info->help_usage, 32); + info << cmd_info->help_description << std::endl; - std::cout << std::endl; - std::cout << "Usage: " << std::endl; - std::cout << " "; - print_left_aligned(cmd_info->help_usage, 30); - std::cout << cmd_info->help_description << std::endl; + info << std::endl; - std::cout << std::endl; - - std::cout << " Equivalent names: "; + info << " Equivalent names: "; bool first = true; for (const auto& name : cmd_info->names) { - if (!first) std::cout << ", "; - std::cout << name; + if (!first) info << ", "; + info << name; first = false; } - std::cout << std::endl << std::endl; + info << std::endl; - std::cout << cmd_info->full_help << std::endl << std::endl; + info << cmd_info->full_help << std::endl << std::endl; return 0; } @@ -108,12 +106,12 @@ int help_handler(const CommandContext& ctx) { if (ctx.args.size() > 0) return show_command_help(ctx.args[0]); - std::cout << std::endl; + info << std::endl; maketitle("DropShell version " + VERSION); - std::cout << std::endl; - std::cout << "A tool for managing remote servers, by " << AUTHOR << std::endl; - std::cout << std::endl; - std::cout << "dropshell ..." << std::endl; + info << std::endl; + info << "A tool for managing remote servers, by " << AUTHOR << std::endl; + info << std::endl; + info << "dropshell ..." << std::endl; show_command("help"); show_command("edit"); @@ -136,56 +134,6 @@ int help_handler(const CommandContext& ctx) { return 0; } -// void show_command(const std::string& cmd) { -// const auto& cmd_info = CommandRegistry::instance().find_command(cmd); -// if (cmd_info) { -// std::cout << " " << cmd_info->help_usage -// << std::string(' ', std::min(1,(int)(30-cmd_info->help_usage.length()))) -// << cmd_info->help_description << std::endl; -// } -// } - -// bool print_help() { -// std::cout << std::endl; -// maketitle("DropShell version " + VERSION); -// std::cout << std::endl; -// std::cout << "A tool for managing server configurations" << std::endl; -// std::cout << std::endl; -// std::cout << "dropshell ..." << std::endl; -// show_command("help"); -// show_command("edit"); - -// if (gConfig().is_config_set()) { -// std::cout << " templates List all available templates" << std::endl; -// std::cout << std::endl; -// std::cout << std::endl; -// std::cout << "Service commands: (if no service is specified, all services for the server are affected)" << std::endl; -// std::cout << " list [SERVER] [SERVICE] List status/details of all servers/server/service." << std::endl; -// std::cout << " edit [SERVER] [SERVICE] Edit the configuration of dropshell/server/service." << std::endl; -// std::cout << std::endl; -// std::cout << " install SERVER [SERVICE] Install/reinstall/update service(s). Safe/non-destructive." << std::endl; -// std::cout << " uninstall SERVER [SERVICE] Uninstalls the service on the remote server. Leaves data intact." << std::endl; -// std::cout << " nuke SERVER SERVICE Nuke the service, deleting ALL local and remote data." << std::endl; -// std::cout << std::endl; -// std::cout << " COMMAND SERVER [SERVICE] Run a command on service(s), e.g." << std::endl; -// std::cout << " backup, restore, start, stop, logs" << std::endl; -// std::cout << std::endl; -// std::cout << " ssh SERVER SERVICE Launch an interactive shell on a server or service" << std::endl; -// std::cout << std::endl; -// std::cout << "Creation commands: (apply to the first local config directory)"< servers = get_configured_servers(); for (const auto &server : servers) { - std::cout << server.name << std::endl; + rawout << server.name << std::endl; } } else if (ctx.args.size() == 1) @@ -32,7 +33,7 @@ namespace dropshell std::vector services = get_server_services_info(ctx.args[0]); for (const auto &service : services) { - std::cout << service.service_name << std::endl; + rawout << service.service_name << std::endl; } } } @@ -44,7 +45,7 @@ namespace dropshell { std_autocomplete(ctx); if (ctx.args.size() == 1) - std::cout << "all" << std::endl; + rawout << "all" << std::endl; } // ------------------------------------------------------------------------------------------------ @@ -88,7 +89,7 @@ namespace dropshell std::string p = remotepath::temp_files(server_env.get_server_name()) + "/" + random_alphanumeric_string(10); std::string mkdir_cmd = "mkdir -p " + quote(p); if (!execute_ssh_command(server_env.get_SSH_INFO(), sCommand("", mkdir_cmd, {}), cMode::Silent)) - std::cerr << "Failed to create temp directory on server" << std::endl; + error << "Failed to create temp directory on server" << std::endl; else mPath = p; } @@ -114,7 +115,7 @@ namespace dropshell server_env_manager env(server_name); if (!env.is_valid()) { - std::cerr << "Error: Invalid server environment" << std::endl; + error << "Invalid server environment" << std::endl; return status; } @@ -215,7 +216,7 @@ namespace dropshell server_env_manager env(server); if (!env.is_valid()) { - std::cerr << "Error: Server service not initialized" << std::endl; + error << "Server service not initialized" << std::endl; return HealthStatus::ERROR; } diff --git a/source/src/commands/ssh.cpp b/source/src/commands/ssh.cpp index 8445ddd..4793365 100644 --- a/source/src/commands/ssh.cpp +++ b/source/src/commands/ssh.cpp @@ -45,7 +45,7 @@ namespace dropshell server_env_manager server_env(server); if (!server_env.is_valid()) { - std::cerr << "Error: Server " << server << " is not valid" << std::endl; + error << "Server " << server << " is not valid" << std::endl; return false; } execute_ssh_command(server_env.get_SSH_INFO(), sCommand(remotepath::DROPSHELL_DIR(server), "ls --color && bash", {}), cMode::Interactive); @@ -57,26 +57,26 @@ namespace dropshell server_env_manager server_env(server); if (!server_env.is_valid()) { - std::cerr << "Error: Server " << server << " is not valid" << std::endl; + error << "Server " << server << " is not valid" << std::endl; return false; } LocalServiceInfo sinfo = get_service_info(server, service); if (!SIvalid(sinfo)) { - std::cerr << "Error: Service " << service << " is not valid" << std::endl; + error << "Service " << service << " is not valid" << std::endl; return false; } if (!gTemplateManager().has_template(sinfo.template_name)) { - std::cerr << "Error: Template " << sinfo.template_name << " is not valid" << std::endl; + error << "Template " << sinfo.template_name << " is not valid" << std::endl; return false; } if (!gTemplateManager().template_command_exists(sinfo.template_name, "ssh")) { - std::cerr << "Error: Template " << sinfo.template_name << " does not have an ssh command" << std::endl; + error << "Template " << sinfo.template_name << " does not have an ssh command" << std::endl; return false; } @@ -88,7 +88,7 @@ namespace dropshell { if (ctx.args.size() < 1) { - std::cerr << "Error: Server name is required" << std::endl; + error << "Server name is required" << std::endl; return 1; } diff --git a/source/src/commands/uninstall.cpp b/source/src/commands/uninstall.cpp index 3569b47..e899bf1 100644 --- a/source/src/commands/uninstall.cpp +++ b/source/src/commands/uninstall.cpp @@ -49,14 +49,14 @@ namespace dropshell server_env_manager server_env(server); if (!server_env.is_valid()) { - std::cerr << "Invalid server: " << server << std::endl; + error << "Invalid server: " << server << std::endl; return false; // should never hit this. } // 2. Check if service directory exists on server if (!server_env.check_remote_dir_exists(remotepath::service(server, service))) { - std::cerr << "Service is not installed: " << service << std::endl; + error << "Service is not installed: " << service << std::endl; return true; // Nothing to uninstall } @@ -64,20 +64,20 @@ namespace dropshell std::string uninstall_script = remotepath::service_template(server, service) + "/uninstall.sh"; if (!server_env.run_remote_template_command(service, "uninstall", {}, silent, {})) if (!silent) - std::cerr << "Warning: Uninstall script failed, but continuing with directory removal" << std::endl; + warning << "Uninstall script failed, but continuing with directory removal" << std::endl; // 4. Remove the service directory from the server, running in a docker container as root. if (server_env.remove_remote_dir(remotepath::service(server, service), silent)) { ASSERT(!server_env.check_remote_dir_exists(remotepath::service(server, service)), "Service directory still found on server after uninstall"); if (!silent) - std::cout << "Removed remote service directory " << remotepath::service(server, service) << std::endl; + info << "Removed remote service directory " << remotepath::service(server, service) << std::endl; } else if (!silent) - std::cerr << "Warning: Failed to remove remote service directory" << std::endl; + warning << "Failed to remove remote service directory" << std::endl; if (!silent) - std::cout << "Completed service " << service << " uninstall on " << server << std::endl; + info << "Completed service " << service << " uninstall on " << server << std::endl; return true; } @@ -85,7 +85,7 @@ namespace dropshell { if (ctx.args.size() < 1) { - std::cerr << "Error: uninstall requires a server and a service (or all)" << std::endl; + error << "uninstall requires a server and a service (or all)" << std::endl; return 1; } diff --git a/source/src/main.cpp b/source/src/main.cpp index de72de4..1198fe9 100644 --- a/source/src/main.cpp +++ b/source/src/main.cpp @@ -50,33 +50,33 @@ int main(int argc, char* argv[]) { return 0; } - const CommandInfo* info = CommandRegistry::instance().find_command(ctx.command); - if (!info) { - std::cerr << "Unknown command: " << ctx.command << std::endl; + const CommandInfo* cmdinfo = CommandRegistry::instance().find_command(ctx.command); + if (!cmdinfo) { + error << "Unknown command: " << ctx.command << std::endl; return 1; } - if (info->requires_config && !gConfig().is_config_set()) { - std::cerr << "Valid dropshell configuration required for command: " << ctx.command << std::endl; - std::cerr << "Please run 'dropshell edit' to set up the dropshell configuration." << std::endl; + if (cmdinfo->requires_config && !gConfig().is_config_set()) { + error << "Valid dropshell configuration required for command: " << ctx.command << std::endl; + info << "Please run 'dropshell edit' to set up the dropshell configuration." << std::endl; return 1; } - if (info->requires_install && !gConfig().is_agent_installed()) { - std::cerr << "Dropshell agent not installed for command: " << ctx.command << std::endl; - std::cerr << "Please run 'dropshell install' to install the local dropshell agent." << std::endl; + if (cmdinfo->requires_install && !gConfig().is_agent_installed()) { + error << "Dropshell agent not installed for command: " << ctx.command << std::endl; + info << "Please run 'dropshell install' to install the local dropshell agent." << std::endl; return 1; } int arg_count = ctx.args.size(); - if (arg_count < info->min_args || (info->max_args != -1 && arg_count > info->max_args)) { - std::cerr << "Invalid number of arguments for command: " << ctx.command << std::endl; - std::cerr << "(" << ctx.args.size() << " args provided, " << ctx.command << " requires " << (info->min_args) << " to " << (info->max_args) << " args)" << std::endl; - std::cerr << "Usage: " << std::endl; - std::cerr << " "; - print_left_aligned(info->help_usage,30); - std::cout << info->help_description << std::endl; + if (arg_count < cmdinfo->min_args || (cmdinfo->max_args != -1 && arg_count > cmdinfo->max_args)) { + error << "Invalid number of arguments for command: " << ctx.command << std::endl; + debug << "(" << ctx.args.size() << " args provided, " << ctx.command << " requires " << (cmdinfo->min_args) << " to " << (cmdinfo->max_args) << " args)" << std::endl; + info << "Usage: " << std::endl; + info << " "; + info << left_align(cmdinfo->help_usage,30); + info << cmdinfo->help_description << std::endl; return 1; } - return info->handler(ctx); + return cmdinfo->handler(ctx); } catch (const std::exception& e) { @@ -116,13 +116,6 @@ bool getCLIServices(const std::string & arg2, const std::string & arg3, return true; } -void printversion() { - maketitle("DropShell version " + VERSION); - std::cout << "Release date: " << RELEASE_DATE << std::endl; - std::cout << "Author: " << AUTHOR << std::endl; - std::cout << "License: " << LICENSE << std::endl; -} - auto command_match = [](const std::string& cmd_list, int argc, char* argv[]) -> bool { std::istringstream iss(cmd_list); std::string cmd_item; diff --git a/source/src/utils/output.cpp b/source/src/utils/output.cpp index bad2f4f..ab91a46 100644 --- a/source/src/utils/output.cpp +++ b/source/src/utils/output.cpp @@ -11,7 +11,8 @@ namespace dropshell constexpr const char *GREY = "\033[90m"; constexpr const char *RESET = "\033[0m"; constexpr const char *DEBUG_COLOUR = "\033[36m"; // Cyan - constexpr const char *INFO_COLOUR = "\033[32m"; // Green + // constexpr const char *INFO_COLOUR = "\033[32m"; // Green + constexpr const char *INFO_COLOUR = "\033[37m"; // White constexpr const char *WARNING_COLOUR = "\033[33m"; // Yellow constexpr const char *ERROR_COLOUR = "\033[31m"; // Red @@ -77,6 +78,9 @@ namespace dropshell std::ostream &warning = warning_stream; std::ostream &error = error_stream; + std::ostream &rawout = std::cout; + std::ostream &rawerr = std::cerr; + std::ostream &colourstream(sColour colour) { switch (colour) diff --git a/source/src/utils/output.hpp b/source/src/utils/output.hpp index 1f7e184..f2c66d5 100644 --- a/source/src/utils/output.hpp +++ b/source/src/utils/output.hpp @@ -56,6 +56,9 @@ extern std::ostream& info; extern std::ostream& warning; extern std::ostream& error; +extern std::ostream& rawout; +extern std::ostream& rawerr; + // Enum for colours enum class sColour { RESET, diff --git a/source/src/utils/utils.cpp b/source/src/utils/utils.cpp index 92d4a02..2a10e9b 100644 --- a/source/src/utils/utils.cpp +++ b/source/src/utils/utils.cpp @@ -334,20 +334,6 @@ std::string safearg(int argc, char *argv[], int index) return argv[index]; } - -void print_left_aligned(const std::string & str, int width) { - std::cout << left_align(str, width); -} - -void print_centered(const std::string & str, int width) { - std::cout << center_align(str, width); -} - -void print_right_aligned(const std::string & str, int width) { - std::cout << right_align(str, width); -} - - std::string left_align(const std::string & str, int width) { if (static_cast(str.size()) >= width) return str; diff --git a/source/src/utils/utils.hpp b/source/src/utils/utils.hpp index ee2dd49..4655238 100644 --- a/source/src/utils/utils.hpp +++ b/source/src/utils/utils.hpp @@ -47,10 +47,6 @@ int die(const std::string & msg); std::string safearg(int argc, char *argv[], int index); std::string safearg(const std::vector & args, int index); -void print_left_aligned(const std::string & str, int width); -void print_centered(const std::string & str, int width); -void print_right_aligned(const std::string & str, int width); - std::string left_align(const std::string & str, int width); std::string right_align(const std::string & str, int width); std::string center_align(const std::string & str, int width);