#include "command_registry.hpp" #include "directories.hpp" #include "shared_commands.hpp" #include "templates.hpp" #include "utils/assert.hpp" namespace dropshell { int uninstall_handler(const CommandContext &ctx); static std::vector uninstall_name_list = {"uninstall", "remove"}; // Static registration struct UninstallCommandRegister { UninstallCommandRegister() { CommandRegistry::instance().register_command({uninstall_name_list, uninstall_handler, std_autocomplete_allowallservices, false, // hidden true, // requires_config true, // requires_install 1, // min_args (after command) 2, // max_args (after command) "uninstall SERVER [SERVICE|*]", "Uninstall a service on a server. Does not remove configuration or user data.", // heredoc R"( Uninstall a service on a server. Does not remove configuration or user data. uninstall SERVER SERVICE uninstall the given service on the given server. uninstall SERVER * uninstall all services on the given server. )"}); } } uninstall_command_register; int uninstall_handler(const CommandContext &ctx) { if (ctx.args.size() < 1) { std::cerr << "Error: uninstall requires a server and (optionally) a service" << std::endl; return 1; } std::string server = safearg(ctx.args, 0); if (ctx.args.size() == 1) { // uninstall all services on the server bool okay = true; std::vector services = get_server_services_info(server); for (const auto &service : services) { if (!uninstall_service(server, service.service_name, false)) okay = false; } return okay ? 0 : 1; } std::string service = safearg(ctx.args, 1); return uninstall_service(server, service, false) ? 0 : 1; } bool uninstall_service(const std::string &server, const std::string &service, bool silent) { if (!silent) maketitle("Uninstalling " + service + " on " + server); server_env_manager server_env(server); if (!server_env.is_valid()) { std::cerr << "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; return true; // Nothing to uninstall } // 3. Run uninstall script if it exists std::string uninstall_script = remotepath::service_template(server, service) + "/uninstall.sh"; if (gTemplateManager().template_command_exists(service, "uninstall")) if (server_env.check_remote_file_exists(uninstall_script)) 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; // 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; } else if (!silent) std::cerr << "Warning: Failed to remove remote service directory" << std::endl; if (!silent) std::cout << "Completed service " << service << " uninstall on " << server << std::endl; return true; } } // namespace dropshell