#include #include #include #include #include #include #include #include #include "utils/envmanager.hpp" #include "utils/directories.hpp" #include "utils/utils.hpp" #include "templates.hpp" #include "config.hpp" namespace dropshell { bool get_templates(std::vector& templates) { templates.clear(); // Helper function to add templates from a directory auto add_templates_from_dir = [&templates](const std::string& dir_path) { if (!std::filesystem::exists(dir_path)) return; for (const auto& entry : std::filesystem::directory_iterator(dir_path)) if (entry.is_directory()) { template_info info(entry.path().filename().string(), entry.path().string()); // Check if template with same name already exists bool duplicate = false; auto it = std::find_if(templates.begin(), templates.end(), [&info](const template_info& t) { return t.template_name == info.template_name; }); duplicate = (it!=templates.end()); if (!duplicate) templates.push_back(info); } }; // add templates from the local config directories std::vector template_config_directories; get_all_template_config_directories(template_config_directories); for (const auto& path : template_config_directories) { add_templates_from_dir(path); } return true; } bool get_template_info(const std::string& template_name, template_info& info) { // add templates from the local config directories std::vector paths_to_search; get_all_template_config_directories(paths_to_search); for (const auto& path : paths_to_search) { std::filesystem::path full_path = path + "/" + template_name; if (std::filesystem::exists(full_path)) { info.template_name = template_name; info.local_template_path = full_path.string(); return true; } } std::cout << "Warning: Template '" << template_name << "' not found" << std::endl; return false; } bool template_command_exists(const std::string &template_name, const std::string &command) { template_info info; if (!get_template_info(template_name, info)) { return false; } std::string path = info.local_template_path + "/" + command + ".sh"; return (std::filesystem::exists(path)); } void list_templates() { std::vector templates; if (!get_templates(templates)) { std::cerr << "Error: Failed to get templates" << std::endl; return; } if (templates.empty()) { std::cout << "No templates found." << std::endl; return; } std::cout << "Available templates:" << std::endl; std::cout << std::left << std::setw(20) << "Name" << "Path" << std::endl; std::cout << std::string(60, '-') << std::endl; for (const auto& t : templates) { std::cout << std::left << std::setw(20) << t.template_name << t.local_template_path << std::endl; } } void create_template(const std::string& template_name) { // 1. Create a new directory in the user templates directory std::vector local_config_directories = gConfig().get_local_config_directories(); if (local_config_directories.empty()) { std::cerr << "Error: No local config directories found" << std::endl; std::cerr << "Run 'dropshell init' to initialise DropShell" << std::endl; return; } template_info info; if (get_template_info(template_name, info)) { std::cerr << "Error: Template '" << template_name << "' already exists at " << info.local_template_path << std::endl; return; } std::string new_template_path = localpath::config_templates() + "/" + template_name; // Create the new template directory std::filesystem::create_directories(new_template_path); // 2. Copy the example template from the system templates directory std::string system_templates_dir = localpath::system_templates(); std::string example_template_path = system_templates_dir + "/example-nginx"; if (!std::filesystem::exists(example_template_path)) { std::cerr << "Error: Example template not found at " << example_template_path << std::endl; return; } // Copy all files from example template to new template for (const auto& entry : std::filesystem::recursive_directory_iterator(example_template_path)) { std::string relative_path = entry.path().string().substr(example_template_path.length()); std::string target_path = new_template_path + relative_path; if (entry.is_directory()) { std::filesystem::create_directory(target_path); } else { std::filesystem::copy_file(entry.path(), target_path); } } // modify the TEMPLATE=example line in the service.env file to TEMPLATE= std::string search_string = "TEMPLATE="; std::string replacement_line = "TEMPLATE=" + template_name; // replace the line in the example/service.env file with the replacement line std::string service_env_path = new_template_path + "/example/service.env"; if (!replace_line_in_file(service_env_path, search_string, replacement_line)) { std::cerr << "Error: Failed to replace TEMPLATE= line in service.env file" << std::endl; return; } // 3. Print out the README.txt file and the path std::string readme_path = new_template_path + "/README.txt"; if (std::filesystem::exists(readme_path)) { std::cout << "\nREADME contents:" << std::endl; std::cout << std::string(60, '-') << std::endl; std::ifstream readme_file(readme_path); if (readme_file.is_open()) { std::string line; while (std::getline(readme_file, line)) { std::cout << line << std::endl; } readme_file.close(); } std::cout << std::string(60, '-') << std::endl; } else { std::cout << "No README.txt file found in the template." << std::endl; } std::cout << std::endl; std::cout << "Template '" << template_name << "' created at " << new_template_path << std::endl; } bool get_all_template_config_directories(std::vector &template_config_directories) { template_config_directories.clear(); for (int i = 0; i < localpath::num_config_directories(); i++) { std::string config_templates_path = localpath::config_templates(i); if (config_templates_path.empty()) { std::cerr << "Error: Templates directory not found: " << config_templates_path << std::endl; return false; } template_config_directories.push_back(config_templates_path); } template_config_directories.push_back(localpath::system_templates()); return true; } bool required_file(std::string path, std::string template_name) { if (!std::filesystem::exists(path)) { std::cerr << "Error: " << path << " file not found in template " << template_name << std::endl; return false; } return true; } bool test_template(const std::string &template_path) { std::string template_name = std::filesystem::path(template_path).filename().string(); std::vector required_files = { "example/service.env", "example/.template_info.env", "_default.env", "install.sh", "uninstall.sh" }; for (const auto& file : required_files) { if (!required_file(template_path + "/" + file, template_name)) return false; } // ------------------------------------------------------------ // check TEMPLATE= line. std::map all_env_vars; std::vector env_files = { "example/service.env", "example/.template_info.env" }; for (const auto& file : env_files) { { // load service.env from the service on this machine. std::map env_vars; envmanager env_manager(template_path + "/" + file); env_manager.load(); env_manager.get_all_variables(env_vars); all_env_vars.merge(env_vars); } // determine template name. auto it = all_env_vars.find("TEMPLATE"); if (it == all_env_vars.end()) { std::cerr << "Error: TEMPLATE variable not found in " << file << std::endl; return false; } std::string env_template_name = it->second; if (env_template_name.empty()) { std::cerr << "Error: TEMPLATE variable is empty in " << file << std::endl; return false; } if (env_template_name != template_name) { std::cerr << "Error: TEMPLATE variable is wrong in " << file << std::endl; return false; } return true; } } // namespace dropshell