diff --git a/source/agent/_allservicesstatus.sh b/source/agent/_allservicesstatus.sh index 0c96da2..5895129 100755 --- a/source/agent/_allservicesstatus.sh +++ b/source/agent/_allservicesstatus.sh @@ -73,6 +73,7 @@ function run_command() { # update the main variables. CONFIG_PATH="${service_path}/config" SERVICE="${SERVICE_NAME}" + DOCKER_CLI_HINTS=false set +a @@ -99,6 +100,10 @@ function command_exists() { } +if [ ! -d "${SERVICES_PATH}" ]; then + echo "Services path does not exist: ${SERVICES_PATH}" + exit 0 +fi # Get all service names SERVICE_NAMES=$(ls "${SERVICES_PATH}") diff --git a/source/src/autogen/_agent.cpp b/source/src/autogen/_agent.cpp index 7109976..7f95082 100644 --- a/source/src/autogen/_agent.cpp +++ b/source/src/autogen/_agent.cpp @@ -281,36 +281,39 @@ bool recreate_tree(std::string destination_folder) { "YXRofS9jb25maWcvc2VydmljZS5lbnYiCiAgICAgICAgbG9hZF9kb3RlbnYgIiR7c2VydmljZV9w"\ "YXRofS9jb25maWcvLnRlbXBsYXRlX2luZm8uZW52IgoKICAgICAgICAjIHVwZGF0ZSB0aGUgbWFp"\ "biB2YXJpYWJsZXMuCiAgICAgICAgQ09ORklHX1BBVEg9IiR7c2VydmljZV9wYXRofS9jb25maWci"\ - "CiAgICAgICAgU0VSVklDRT0iJHtTRVJWSUNFX05BTUV9IgoKICAgICAgICBzZXQgK2EKCiAgICAg"\ - "ICAgX2NoZWNrX3JlcXVpcmVkX2Vudl92YXJzX2FsbHNlcnZpY2Vzc3RhdHVzICJDT05GSUdfUEFU"\ - "SCIgIlNFUlZFUiIgIlNFUlZJQ0UiICJBR0VOVF9QQVRIIiAiSE9TVF9OQU1FIiAiVEVNUExBVEUi"\ - "CgogICAgICAgIGlmIFsgIiRjYXB0dXJlX291dHB1dCIgPSAidHJ1ZSIgXTsgdGhlbgogICAgICAg"\ - "ICAgICAjIENhcHR1cmUgYW5kIHJldHVybiBvdXRwdXQKICAgICAgICAgICAgYmFzaCAiJHtzZXJ2"\ - "aWNlX3BhdGh9L3RlbXBsYXRlLyR7Y29tbWFuZH0uc2giIDI+JjEKICAgICAgICBlbHNlCiAgICAg"\ - "ICAgICAgICMgUnVuIHNpbGVudGx5IGFuZCByZXR1cm4gZXhpdCBjb2RlCiAgICAgICAgICAgIGJh"\ - "c2ggIiR7c2VydmljZV9wYXRofS90ZW1wbGF0ZS8ke2NvbW1hbmR9LnNoIiA+IC9kZXYvbnVsbCAy"\ - "PiYxCiAgICAgICAgZmkKICAgICkKICAgIENVUlJFTlRfRVhJVF9DT0RFPSQ/Cn0KCmZ1bmN0aW9u"\ - "IGNvbW1hbmRfZXhpc3RzKCkgewogICAgbG9jYWwgc2VydmljZV9wYXRoPSQxCiAgICBsb2NhbCBj"\ - "b21tYW5kPSQyCiAgICBpZiBbICEgLWYgIiR7c2VydmljZV9wYXRofS90ZW1wbGF0ZS8ke2NvbW1h"\ - "bmR9LnNoIiBdOyB0aGVuCiAgICAgICAgcmV0dXJuIDEKICAgIGZpCiAgICByZXR1cm4gMAp9CgoK"\ - "CiMgR2V0IGFsbCBzZXJ2aWNlIG5hbWVzClNFUlZJQ0VfTkFNRVM9JChscyAiJHtTRVJWSUNFU19Q"\ - "QVRIfSIpCgojIEl0ZXJhdGUgb3ZlciBhbGwgc2VydmljZSBuYW1lcwpmb3IgU0VSVklDRV9OQU1F"\ - "IGluICR7U0VSVklDRV9OQU1FU307IGRvCgogICAgU0VSVklDRV9QQVRIPSQocmVhbHBhdGggIiR7"\ - "U0VSVklDRVNfUEFUSH0vJHtTRVJWSUNFX05BTUV9IikKCiAgICAjLS0tLS0tLS0tLS0tLS0tLS0t"\ - "LS0tLS0tLS0tLS0tLS0KICAgICMgR2V0IHRoZSBzZXJ2aWNlIGhlYWx0aAogICAgaWYgISBjb21t"\ - "YW5kX2V4aXN0cyAiJHtTRVJWSUNFX1BBVEh9IiAic3RhdHVzIjsgdGhlbgogICAgICAgIFNFUlZJ"\ - "Q0VfSEVBTFRIPSJ1bmtub3duIgogICAgZWxzZQogICAgICAgIHJ1bl9jb21tYW5kICIke1NFUlZJ"\ - "Q0VfUEFUSH0iICJzdGF0dXMiICJmYWxzZSIKICAgICAgICBpZiBbICIke0NVUlJFTlRfRVhJVF9D"\ - "T0RFfSIgLWVxIDAgXTsgdGhlbgogICAgICAgICAgICBTRVJWSUNFX0hFQUxUSD0iaGVhbHRoeSIK"\ - "ICAgICAgICBlbHNlCiAgICAgICAgICAgIFNFUlZJQ0VfSEVBTFRIPSJ1bmhlYWx0aHkiCiAgICAg"\ - "ICAgZmkKICAgIGZpCgogICAgIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAj"\ - "IEdldCB0aGUgc2VydmljZSBwb3J0cwogICAgaWYgISBjb21tYW5kX2V4aXN0cyAiJHtTRVJWSUNF"\ - "X1BBVEh9IiAicG9ydHMiOyB0aGVuCiAgICAgICAgU0VSVklDRV9QT1JUUz0iIgogICAgZWxzZQog"\ - "ICAgICAgIHJ1bl9jb21tYW5kICIke1NFUlZJQ0VfUEFUSH0iICJwb3J0cyIgInRydWUiCiAgICAg"\ - "ICAgU0VSVklDRV9QT1JUUz0iJHtDVVJSRU5UX09VVFBVVH0iCiAgICBmaQoKICAgICMtLS0tLS0t"\ - "LS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgIyByZXR1cm4gdGhlIGhlYWx0aCBhbmQgcG9y"\ - "dHMKICAgIGVjaG8gIiR7U0VSVklDRV9OQU1FfV9IRUFMVEg9JHtTRVJWSUNFX0hFQUxUSH0iCiAg"\ - "ICBlY2hvICIke1NFUlZJQ0VfTkFNRX1fUE9SVFM9JHtTRVJWSUNFX1BPUlRTfSIKZG9uZQo="; + "CiAgICAgICAgU0VSVklDRT0iJHtTRVJWSUNFX05BTUV9IgogICAgICAgIERPQ0tFUl9DTElfSElO"\ + "VFM9ZmFsc2UKCiAgICAgICAgc2V0ICthCgogICAgICAgIF9jaGVja19yZXF1aXJlZF9lbnZfdmFy"\ + "c19hbGxzZXJ2aWNlc3N0YXR1cyAiQ09ORklHX1BBVEgiICJTRVJWRVIiICJTRVJWSUNFIiAiQUdF"\ + "TlRfUEFUSCIgIkhPU1RfTkFNRSIgIlRFTVBMQVRFIgoKICAgICAgICBpZiBbICIkY2FwdHVyZV9v"\ + "dXRwdXQiID0gInRydWUiIF07IHRoZW4KICAgICAgICAgICAgIyBDYXB0dXJlIGFuZCByZXR1cm4g"\ + "b3V0cHV0CiAgICAgICAgICAgIGJhc2ggIiR7c2VydmljZV9wYXRofS90ZW1wbGF0ZS8ke2NvbW1h"\ + "bmR9LnNoIiAyPiYxCiAgICAgICAgZWxzZQogICAgICAgICAgICAjIFJ1biBzaWxlbnRseSBhbmQg"\ + "cmV0dXJuIGV4aXQgY29kZQogICAgICAgICAgICBiYXNoICIke3NlcnZpY2VfcGF0aH0vdGVtcGxh"\ + "dGUvJHtjb21tYW5kfS5zaCIgPiAvZGV2L251bGwgMj4mMQogICAgICAgIGZpCiAgICApCiAgICBD"\ + "VVJSRU5UX0VYSVRfQ09ERT0kPwp9CgpmdW5jdGlvbiBjb21tYW5kX2V4aXN0cygpIHsKICAgIGxv"\ + "Y2FsIHNlcnZpY2VfcGF0aD0kMQogICAgbG9jYWwgY29tbWFuZD0kMgogICAgaWYgWyAhIC1mICIk"\ + "e3NlcnZpY2VfcGF0aH0vdGVtcGxhdGUvJHtjb21tYW5kfS5zaCIgXTsgdGhlbgogICAgICAgIHJl"\ + "dHVybiAxCiAgICBmaQogICAgcmV0dXJuIDAKfQoKCmlmIFsgISAtZCAiJHtTRVJWSUNFU19QQVRI"\ + "fSIgXTsgdGhlbgogICAgZWNobyAiU2VydmljZXMgcGF0aCBkb2VzIG5vdCBleGlzdDogJHtTRVJW"\ + "SUNFU19QQVRIfSIKICAgIGV4aXQgMApmaQoKIyBHZXQgYWxsIHNlcnZpY2UgbmFtZXMKU0VSVklD"\ + "RV9OQU1FUz0kKGxzICIke1NFUlZJQ0VTX1BBVEh9IikKCiMgSXRlcmF0ZSBvdmVyIGFsbCBzZXJ2"\ + "aWNlIG5hbWVzCmZvciBTRVJWSUNFX05BTUUgaW4gJHtTRVJWSUNFX05BTUVTfTsgZG8KCiAgICBT"\ + "RVJWSUNFX1BBVEg9JChyZWFscGF0aCAiJHtTRVJWSUNFU19QQVRIfS8ke1NFUlZJQ0VfTkFNRX0i"\ + "KQoKICAgICMtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQogICAgIyBHZXQgdGhlIHNl"\ + "cnZpY2UgaGVhbHRoCiAgICBpZiAhIGNvbW1hbmRfZXhpc3RzICIke1NFUlZJQ0VfUEFUSH0iICJz"\ + "dGF0dXMiOyB0aGVuCiAgICAgICAgU0VSVklDRV9IRUFMVEg9InVua25vd24iCiAgICBlbHNlCiAg"\ + "ICAgICAgcnVuX2NvbW1hbmQgIiR7U0VSVklDRV9QQVRIfSIgInN0YXR1cyIgImZhbHNlIgogICAg"\ + "ICAgIGlmIFsgIiR7Q1VSUkVOVF9FWElUX0NPREV9IiAtZXEgMCBdOyB0aGVuCiAgICAgICAgICAg"\ + "IFNFUlZJQ0VfSEVBTFRIPSJoZWFsdGh5IgogICAgICAgIGVsc2UKICAgICAgICAgICAgU0VSVklD"\ + "RV9IRUFMVEg9InVuaGVhbHRoeSIKICAgICAgICBmaQogICAgZmkKCiAgICAjLS0tLS0tLS0tLS0t"\ + "LS0tLS0tLS0tLS0tLS0tLS0tLS0KICAgICMgR2V0IHRoZSBzZXJ2aWNlIHBvcnRzCiAgICBpZiAh"\ + "IGNvbW1hbmRfZXhpc3RzICIke1NFUlZJQ0VfUEFUSH0iICJwb3J0cyI7IHRoZW4KICAgICAgICBT"\ + "RVJWSUNFX1BPUlRTPSIiCiAgICBlbHNlCiAgICAgICAgcnVuX2NvbW1hbmQgIiR7U0VSVklDRV9Q"\ + "QVRIfSIgInBvcnRzIiAidHJ1ZSIKICAgICAgICBTRVJWSUNFX1BPUlRTPSIke0NVUlJFTlRfT1VU"\ + "UFVUfSIKICAgIGZpCgogICAgIy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tCiAgICAj"\ + "IHJldHVybiB0aGUgaGVhbHRoIGFuZCBwb3J0cwogICAgZWNobyAiJHtTRVJWSUNFX05BTUV9X0hF"\ + "QUxUSD0ke1NFUlZJQ0VfSEVBTFRIfSIKICAgIGVjaG8gIiR7U0VSVklDRV9OQU1FfV9QT1JUUz0k"\ + "e1NFUlZJQ0VfUE9SVFN9Igpkb25lCg=="; // Decode Base64 data size_t decoded_size = (strlen(filedata_base64) * 3) / 4; @@ -318,7 +321,7 @@ bool recreate_tree(std::string destination_folder) { size_t actual_size; base64_decode(filedata_base64, strlen(filedata_base64), decoded_data, &actual_size); - bool file_written = _recreate_file_(outpath, 4383289270743338040ULL, std::filesystem::perms(493), decoded_data, actual_size); + bool file_written = _recreate_file_(outpath, 4669115953916396805ULL, std::filesystem::perms(493), decoded_data, actual_size); delete[] decoded_data; any_written = any_written || file_written; } diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index 75ace8a..093a9f0 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -7,6 +7,7 @@ #include "utils/hash.hpp" #include "autogen/_agent.hpp" #include "services.hpp" +#include "utils/output.hpp" #include #include @@ -100,7 +101,7 @@ namespace dropshell } // Copy template files - std::cout << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl + debug << "Copying: [LOCAL] " << tinfo.local_template_path() << std::endl << std::string(8, ' ') << "[REMOTE] " << remotepath::service_template(server, service) << "/" << std::endl; if (!shared_commands::rsync_tree_to_remote(tinfo.local_template_path().string(), remotepath::service_template(server, service), server_env, silent)) @@ -110,7 +111,7 @@ namespace dropshell } // Copy service files - std::cout << "Copying: [LOCAL] " << localpath::service(server, service) << std::endl + debug << "Copying: [LOCAL] " << localpath::service(server, service) << std::endl << std::string(8, ' ') << "[REMOTE] " << remotepath::service_config(server, service) << std::endl; if (!shared_commands::rsync_tree_to_remote(localpath::service(server, service), remotepath::service_config(server, service), server_env, silent)) @@ -121,12 +122,12 @@ namespace dropshell // Run install script { - std::cout << "Running " << service_info.template_name << " install script on " << server << "..." << std::endl; + info << "Running " << service_info.template_name << " install script on " << server << "..." << std::endl; server_env.run_remote_template_command(service, "install", {}, silent, {}); } // print health tick - std::cout << "Health: " << shared_commands::healthtick(server, service) << std::endl; + info << "Health: " << shared_commands::healthtick(server, service) << std::endl; return true; } @@ -281,30 +282,30 @@ namespace dropshell int install_server(const std::string &server) { // install the dropshell agent on the given server. - std::cout << "Installing dropshell agent on " << server << std::endl; + maketitle("Installing dropshell agent on " + server, sColour::INFO); std::string agent_path = remotepath::agent(server); if (agent_path.empty()) { - std::cerr << "Failed to get agent path for " << server << std::endl; + error << "Failed to get agent path for " << server << std::endl; return 1; } server_env_manager server_env(server); if (!server_env.is_valid()) { - std::cerr << "Invalid server environment for " << server << std::endl; + error << "Invalid server environment for " << server << std::endl; return 1; } // now create the agent. // copy across from the local agent files. - std::cout << "Copying local agent files to remote server... " << std::flush; + info << "Copying local agent files to remote server... " << std::flush; shared_commands::rsync_tree_to_remote(localpath::files_for_remote_agent(), agent_path, server_env, false); - std::cout << "done." << std::endl; + info << "done." << std::endl; // add in bb64. We can't use execute_remote_command() here, as that relies on bb64 which we're installing! - std::cout << "Installing bb64 on " << server << "..." << std::endl << std::flush; + info << "Installing bb64 on " << server << "..." << std::endl << std::flush; std::string remote_cmd = "ssh -p " + server_env.get_SSH_INFO().port + " " + server_env.get_SSH_INFO().user + "@" + server_env.get_SSH_INFO().host + @@ -313,23 +314,19 @@ namespace dropshell //std::cout << "Executing: " << remote_cmd << std::endl; if (!execute_local_command("", remote_cmd, {}, nullptr, cMode::Silent)) - std::cerr << "Failed to download bb64 to " << agent_path << " on remote server." << std::endl; + error << "Failed to download bb64 to " << agent_path << " on remote server." << std::endl; else - std::cout << "Downloaded bb64 to " << agent_path << " on remote server." << std::endl; - - // just test all is ok + debug << "Downloaded bb64 to " << agent_path << " on remote server." << std::endl; // run the self-test. - std::string output; - bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "./selftest.sh", {}), cMode::Defaults, &output); + bool okay = execute_ssh_command(server_env.get_SSH_INFO(), sCommand(agent_path, "./selftest.sh", {}), cMode::Defaults, nullptr); if (!okay) { - std::cerr << "ERROR: Failed to install remote agent on " << server << std::endl; - std::cerr << "ERROR: Output: " << output << std::endl; + error << "ERROR: Failed to install remote agent on " << server << std::endl; return 1; } - std::cout << output << std::endl; + info << "Installation on " << server << " complete." << std::endl; return 0; } @@ -345,7 +342,7 @@ namespace dropshell if (!gConfig().is_config_set()) { - std::cerr << "Error: Dropshell is not configured. Please run 'dropshell edit' to configure it." << std::endl; + error << "Dropshell is not configured. Please run 'dropshell edit' to configure it." << std::endl; return 1; } diff --git a/source/src/commands/list.cpp b/source/src/commands/list.cpp index 0d829be..cf9ab28 100644 --- a/source/src/commands/list.cpp +++ b/source/src/commands/list.cpp @@ -63,7 +63,7 @@ int list_handler(const CommandContext& ctx) { return 0; } - std::cout << "List handler called with " << ctx.args.size() << " args\n"; + debug << "List handler called with " << ctx.args.size() << " args\n"; return 0; } @@ -74,16 +74,16 @@ void list_servers() { auto servers = get_configured_servers(); if (servers.empty()) { - std::cout << "No servers found" << std::endl; - std::cout << "Please run 'dropshell edit' to set up dropshell." << std::endl; - std::cout << "Then run 'dropshell create-server' to create a server." << std::endl; + error << "No servers found" << std::endl; + info << "Please run 'dropshell edit' to set up dropshell." << std::endl; + info << "Then run 'dropshell create-server' to create a server." << std::endl; return; } tableprint tp("All DropShell Servers"); tp.add_row({"Name", "User", "Address", "Health", "Ports"}); - std::cout << "Checking "<wait(); - std::cout << std::endl << std::endl; + info << std::endl << std::endl; tp.print(); } @@ -116,7 +116,7 @@ void list_servers() { void show_server_details(const std::string& server_name) { server_env_manager env(server_name); if (!env.is_valid()) { - std::cerr << "Error: Invalid server environment file: " << server_name << std::endl; + error << "Error: Invalid server environment file: " << server_name << std::endl; return; } @@ -126,14 +126,14 @@ void show_server_details(const std::string& server_name) { std::string ssh_user = env.get_SSH_USER(); std::string ssh_port = env.get_SSH_PORT(); if (!ssh_address.empty()) { - std::cout << std::endl << "Server Status:" << std::endl; - std::cout << std::string(40, '-') << std::endl; + info << std::endl << "Server Status:" << std::endl; + info << std::string(40, '-') << std::endl; // Try to connect to the server std::string cmd = "ssh -o ConnectTimeout=5 " + ssh_user + "@" + ssh_address + " -p " + ssh_port + " 'echo connected' 2>/dev/null"; int result = system(cmd.c_str()); if (result == 0) { - std::cout << "Status: Online" << std::endl; + info << "Status: Online" << std::endl; // // Get uptime if possible // cmd = "ssh " + ssh_address + " 'uptime' 2>/dev/null"; @@ -142,10 +142,10 @@ void show_server_details(const std::string& server_name) { // std::cout << "Error: Failed to get uptime" << std::endl; // } } else { - std::cout << "Status: Offline" << std::endl; + warning << "Status: Offline" << std::endl; } } - std::cout << std::endl; + info << std::endl; //--------------------- { diff --git a/source/src/commands/shared_commands.cpp b/source/src/commands/shared_commands.cpp index 68aefae..10ded1f 100644 --- a/source/src/commands/shared_commands.cpp +++ b/source/src/commands/shared_commands.cpp @@ -119,7 +119,11 @@ namespace dropshell } std::string output; - if (!execute_ssh_command(env.get_SSH_INFO(), sCommand(remotepath::agent(server_name), "./_allservicesstatus.sh", {{"HOST_NAME", server_name}, {"SERVER", server_name}, {"AGENT_PATH", remotepath::agent(server_name)}}), cMode::CaptureOutput, &output)) + if (!execute_ssh_command(env.get_SSH_INFO(), sCommand(remotepath::agent(server_name), + "./_allservicesstatus.sh", + {{"HOST_NAME", server_name}, {"SERVER", server_name}, {"AGENT_PATH", remotepath::agent(server_name)}}), + cMode::CaptureOutput | cMode::Silent, + &output)) return status; std::stringstream ss(output); diff --git a/source/src/services.cpp b/source/src/services.cpp index 11caccf..7cd62f2 100644 --- a/source/src/services.cpp +++ b/source/src/services.cpp @@ -176,6 +176,7 @@ bool get_all_service_env_vars(const std::string &server_name, const std::string all_env_vars["SERVICE"] = service_name; all_env_vars["AGENT_PATH"] = remotepath::agent(server_name); all_env_vars["HOST_NAME"] = server_info.ssh_host; + all_env_vars["DOCKER_CLI_HINTS"] = "false"; // turn off docker junk. // Lambda function to load environment variables from a file auto load_env_file = [&all_env_vars](const std::string& file) { diff --git a/source/src/utils/assert.hpp b/source/src/utils/assert.hpp index 385362a..c32a292 100644 --- a/source/src/utils/assert.hpp +++ b/source/src/utils/assert.hpp @@ -1,10 +1,11 @@ #ifndef ASSERT_HPP #define ASSERT_HPP +#include "output.hpp" #define ASSERT(condition, message) \ if (!(condition)) { \ - std::cerr << "Assertion failed: " << message << std::endl; \ + dropshell::error << "Assertion failed: " << message << std::endl; \ std::exit(1); \ } diff --git a/source/src/utils/execute.cpp b/source/src/utils/execute.cpp index 1cfa2f7..f9b5602 100644 --- a/source/src/utils/execute.cpp +++ b/source/src/utils/execute.cpp @@ -60,6 +60,56 @@ namespace dropshell // execute_local_command // ---------------------------------------------------------------------------------------------------------- + class fancypinter + { + public: + fancypinter(sColour startColour) : startColour_(startColour), currentColour_(startColour) {} + + void print_chunk(std::string chunk) + { + if (chunk.empty()) + return; + + if (newline_) + { + // sniff the mode... if the string starts with warning or warning: then set mode to WARNING. etc. + if (chunk.find("warning") == 0) + currentColour_ = sColour::WARNING; + else if (chunk.find("error") == 0) + currentColour_ = sColour::ERROR; + else if (chunk.find("debug") == 0) + currentColour_ = sColour::DEBUG; + else if (chunk.find("info") == 0) + currentColour_ = sColour::INFO; + else + currentColour_ = startColour_; + } + colourstream(currentColour_) << chunk; + newline_ = (chunk[chunk.size()-1] == '\n'); + } + + void print(const std::string& buffer) { + size_t start = 0; + while (start < buffer.size()) { + size_t newline_pos = buffer.find('\n', start); + if (newline_pos == std::string::npos) { + if (start < buffer.size()) { + print_chunk(buffer.substr(start)); + } + break; + } + print_chunk(buffer.substr(start, newline_pos - start + 1)); // include the newline + start = newline_pos + 1; + } + } + + private: + bool newline_ = true; + sColour startColour_; + sColour currentColour_; + }; + + bool execute_local_command(std::string directory_to_run_in, std::string command_to_run, const std::map &env_vars, std::string *output, cMode mode) { sCommand command(directory_to_run_in, command_to_run, env_vars); @@ -86,15 +136,14 @@ namespace dropshell return false; } char buffer[128]; + fancypinter fancyprint(sColour::DEBUG); while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { if (output != nullptr) (*output) += buffer; if (!silent) - { - std::cerr << buffer; - } + fancyprint.print(buffer); } int ret = pclose(pipe); return EXITSTATUSCHECK(ret); diff --git a/source/src/utils/output.cpp b/source/src/utils/output.cpp index 9d7cd13..bad2f4f 100644 --- a/source/src/utils/output.cpp +++ b/source/src/utils/output.cpp @@ -2,56 +2,63 @@ #include #include -namespace { +namespace dropshell +{ // Mutex to synchronize output std::mutex output_mutex; // ANSI colour codes - 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* WARNING_COLOUR = "\033[33m"; // Yellow - constexpr const char* ERROR_COLOUR = "\033[31m"; // Red + 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 *WARNING_COLOUR = "\033[33m"; // Yellow + constexpr const char *ERROR_COLOUR = "\033[31m"; // Red // Tag and colour for each stream - struct StreamInfo { - const char* tag; - const char* colour; + struct StreamInfo + { + const char *tag; + const char *colour; }; const StreamInfo stream_infos[] = { {"[DBG]", DEBUG_COLOUR}, {"[INF]", INFO_COLOUR}, {"[WRN]", WARNING_COLOUR}, - {"[ERR]", ERROR_COLOUR} - }; + {"[ERR]", ERROR_COLOUR}}; // Custom streambuf to prefix and colour each line - class PrefixStreambuf : public std::streambuf { + class PrefixStreambuf : public std::streambuf + { public: - PrefixStreambuf(std::ostream& dest, const char* tag, const char* colour) + PrefixStreambuf(std::ostream &dest, const char *tag, const char *colour) : dest_(dest), tag_(tag), colour_(colour), at_line_start_(true) {} protected: - int overflow(int c) override { + int overflow(int c) override + { std::lock_guard lock(output_mutex); - if (c == EOF) return !EOF; - if (at_line_start_ && c != '\n') { + if (c == EOF) + return !EOF; + if (at_line_start_ && c != '\n') + { dest_ << GREY << tag_ << RESET << ' ' << colour_; at_line_start_ = false; } dest_.put(static_cast(c)); - if (c == '\n') { + if (c == '\n') + { dest_ << RESET; at_line_start_ = true; } return c; } + private: - std::ostream& dest_; - const char* tag_; - const char* colour_; + std::ostream &dest_; + const char *tag_; + const char *colour_; bool at_line_start_; }; @@ -64,15 +71,33 @@ namespace { std::ostream info_stream(&info_buf); std::ostream warning_stream(&warning_buf); std::ostream error_stream(&error_buf); -} -std::ostream& debug = debug_stream; -std::ostream& info = info_stream; -std::ostream& warning = warning_stream; -std::ostream& error = error_stream; + std::ostream &debug = debug_stream; + std::ostream &info = info_stream; + std::ostream &warning = warning_stream; + std::ostream &error = error_stream; -void SetColour(sColour colour, std::ostream& os) { - switch (colour) { + std::ostream &colourstream(sColour colour) + { + switch (colour) + { + case sColour::DEBUG: + return debug_stream; + case sColour::INFO: + return info_stream; + case sColour::WARNING: + return warning_stream; + case sColour::ERROR: + return error_stream; + default: + return info_stream; + } + } + + void SetColour(sColour colour, std::ostream &os) + { + switch (colour) + { case sColour::RESET: os << RESET; break; @@ -88,32 +113,17 @@ void SetColour(sColour colour, std::ostream& os) { case sColour::ERROR: os << ERROR_COLOUR; break; + } } -} -void PrintDebug(const std::string& msg) { - std::lock_guard lock(output_mutex); - debug << msg << '\n'; -} -void PrintInfo(const std::string& msg) { - std::lock_guard lock(output_mutex); - info << msg << '\n'; -} -void PrintWarning(const std::string& msg) { - std::lock_guard lock(output_mutex); - warning << msg << '\n'; -} -void PrintError(const std::string& msg) { - std::lock_guard lock(output_mutex); - error << msg << '\n'; -} + SwitchColour::SwitchColour(sColour colour, std::ostream &os) : os_(os), colour_(colour) + { + SetColour(colour_, os_); + } -SwitchColour::SwitchColour(sColour colour, std::ostream& os) : os_(os), colour_(colour) -{ - SetColour(colour_, os_); -} + SwitchColour::~SwitchColour() + { + SetColour(sColour::RESET, os_); + } -SwitchColour::~SwitchColour() -{ - SetColour(sColour::RESET, os_); -} +} // namespace dropshell \ No newline at end of file diff --git a/source/src/utils/output.hpp b/source/src/utils/output.hpp index 1e4c412..1f7e184 100644 --- a/source/src/utils/output.hpp +++ b/source/src/utils/output.hpp @@ -6,6 +6,8 @@ #include #include +namespace dropshell { + /* output.hpp and output.cpp - simple output helpers. @@ -62,16 +64,11 @@ enum class sColour { WARNING, ERROR }; +std::ostream& colourstream(sColour colour); // Set colour for a stream void SetColour(sColour colour, std::ostream& os = std::cerr); -// Helper print functions -void PrintDebug(const std::string& msg); -void PrintInfo(const std::string& msg); -void PrintWarning(const std::string& msg); -void PrintError(const std::string& msg); - class SwitchColour { public: @@ -81,4 +78,7 @@ class SwitchColour std::ostream& os_; sColour colour_; }; + +} // namespace dropshell + #endif // OUTPUT_HPP \ No newline at end of file diff --git a/source/src/utils/utils.cpp b/source/src/utils/utils.cpp index fad7193..92d4a02 100644 --- a/source/src/utils/utils.cpp +++ b/source/src/utils/utils.cpp @@ -10,10 +10,10 @@ namespace dropshell { -void maketitle(const std::string& title) { - std::cout << std::string(title.length() + 4, '-') << std::endl; - std::cout << "| " << title << " |" << std::endl; - std::cout << std::string(title.length() + 4, '-') << std::endl; +void maketitle(const std::string& title, sColour colour) { + colourstream(colour) << std::string(title.length() + 4, '-') << std::endl; + colourstream(colour) << "| " << title << " |" << std::endl; + colourstream(colour) << std::string(title.length() + 4, '-') << std::endl; } bool replace_line_in_file(const std::string& file_path, const std::string& search_string, const std::string& replacement_line) { diff --git a/source/src/utils/utils.hpp b/source/src/utils/utils.hpp index 9c00450..ee2dd49 100644 --- a/source/src/utils/utils.hpp +++ b/source/src/utils/utils.hpp @@ -3,6 +3,8 @@ #include #include +#include "output.hpp" + namespace dropshell { /** @@ -10,7 +12,7 @@ namespace dropshell { * * @param title The title string to display */ -void maketitle(const std::string& title); +void maketitle(const std::string& title, sColour colour=sColour::INFO); bool replace_line_in_file(const std::string& file_path, const std::string& search_string, const std::string& replacement_line);