#include "version.hpp" #include "config.hpp" #include "service_runner.hpp" #include "services.hpp" #include "servers.hpp" #include "utils/directories.hpp" #include "templates.hpp" #include "utils/utils.hpp" #include "utils/readmes.hpp" #include "autocomplete.hpp" #include "main_commands.hpp" #include "utils/hash.hpp" #include #include #include #include #include #include namespace dropshell { void 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; std::cout << " help Show this help message" << std::endl; std::cout << " init DIR Add DIR as a local server config directory (can add several)" << std::endl; if (gConfig().is_config_set()) { std::cout << " server NAME Show details for specific server" << std::endl; 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 << " install SERVER [SERVICE] Install/reinstall/update service(s). Non-destructive." << 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 << " COMMAND SERVER [SERVICE] Run a command on service(s)." << std::endl; std::cout << std::endl; std::cout << "Standard commands: install, uninstall, backup, restore, start, stop" << 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)"<& servicelist) { if (arg2.empty()) return false; server_name = arg2; if (arg3.empty()) { servicelist = dropshell::get_server_services_info(server_name); } else { servicelist.push_back(dropshell::get_service_info(server_name, arg3)); } return true; } std::string safearg(int argc, char *argv[], int index) { if (index >= argc) return ""; return argv[index]; } int main(int argc, char* argv[]) { try { // silently attempt to load the config file. dropshell::gConfig().load_config(); if (argc < 2) { dropshell::print_help(); return 0; } std::string cmd = argv[1]; std::vector argvec; for (int i=0; i' to initialise the user directory and create a configuration file."); const std::vector & local_config_directories = dropshell::gConfig().get_local_config_directories(); std::cout << "Config directories: "; for (auto & dir : local_config_directories) std::cout << "["<< dir << "] "; std::cout << std::endl; if (cmd == "server" || cmd == "servers" || cmd == "list" || cmd == "view") switch (argc) { case 2: dropshell::list_servers(); return 0; case 3: dropshell::show_server_details(argv[2]); return 0; case 4: cmd="logs"; break; default: return die("dropshell server: too many arguments"); } if (cmd == "templates") { dropshell::list_templates(); return 0; } if (cmd == "create-template") { if (argc < 3) return die("Error: create-template requires a template name"); dropshell::create_template(argv[2]); return 0; } if (cmd == "create-server") { if (argc < 3) return die("Error: create-server requires a server name"); dropshell::create_server(argv[2]); return 0; } if (cmd == "create-service") { if (argc < 5) return die("Error: not enough arguments.\ndropshell create-service server template service"); dropshell::create_service(argv[2], argv[3], argv[4]); return 0; } if (cmd == "ssh" && argc < 4) { if (argc < 3) return die("Error: ssh requires a server name and optionally service name"); dropshell::interactive_ssh(argv[2], "bash"); return 0; } if (cmd == "edit" && argc < 4) { ASSERT_ALWAYS(argc>=3); dropshell::edit_server(argv[2]); return 0; } if (cmd == "backup" || cmd=="backups") { if (argc < 4) return die("Error: backup requires a target server and target service to back up"); return dropshell::main_commands::backup(argvec); } if (cmd == "restore") { if (argc < 4) return die("Error: restore requires a target server, target service the backup file to restore"); return dropshell::main_commands::restore(argvec); } if (cmd == "hash") { if (argc < 3) return die("Error: hash requires a directory to hash"); dropshell::hash_demo(argvec[2]); return 0; } // handle running a command. std::set commands; dropshell::get_all_used_commands(commands); commands.merge(std::set{"ssh","edit","_allservicesstatus"}); // handled by service_runner, but not in template_shell_commands. for (const auto& command : commands) { if (cmd == command) { std::string server_name; std::vector servicelist; if (!parseargs(safearg(argc, argv, 2), safearg(argc, argv, 3), server_name, servicelist)) { std::cerr << "Error: " << command << " command requires server name and optionally service name" << std::endl; return 1; } for (const auto& service_info : servicelist) { dropshell::service_runner runner(server_name, service_info.service_name); if (!runner.isValid()) { std::cerr << "Error: Failed to initialize service" << std::endl; return 1; } if (!runner.run_command(command)) { std::cerr << command +" failed." << std::endl; return 1; } } return 0; } } // Unknown command std::cerr << "Error: Unknown command '" << cmd << "'" << std::endl; std::cerr << "Valid commands: "; for (const auto& command : commands) { std::cerr << command << " "; } std::cerr << std::endl; return 1; } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } }