Add template manager for remote templates.
This commit is contained in:
parent
0e9466365e
commit
5286ec542a
@ -61,10 +61,13 @@ bool config::save_config()
|
||||
std::string dropshell_base = homedir + "/.dropshell";
|
||||
mConfig["tempfiles"] = dropshell_base + "/tmp";
|
||||
mConfig["backups"] = dropshell_base + "/backups";
|
||||
mConfig["template_cache"] = dropshell_base + "/cache";
|
||||
mConfig["template_registry_urls"] = {
|
||||
mConfig["template_cache"] = dropshell_base + "/template_cache";
|
||||
mConfig["template_registry_URLs"] = {
|
||||
"https://templates.dropshell.app"
|
||||
};
|
||||
mConfig["template_local_paths"] = {
|
||||
dropshell_base + "/local_templates"
|
||||
};
|
||||
mConfig["server_definition_paths"] = {
|
||||
dropshell_base + "/servers"
|
||||
};
|
||||
@ -102,7 +105,7 @@ std::string config::get_local_template_cache_path() {
|
||||
}
|
||||
|
||||
std::vector<std::string> config::get_template_registry_urls() {
|
||||
nlohmann::json template_registry_urls = mConfig["template_registry_urls"];
|
||||
nlohmann::json template_registry_urls = mConfig["template_registry_URLs"];
|
||||
std::vector<std::string> urls;
|
||||
for (auto &url : template_registry_urls) {
|
||||
urls.push_back(url);
|
||||
@ -110,11 +113,25 @@ std::vector<std::string> config::get_template_registry_urls() {
|
||||
return urls;
|
||||
}
|
||||
|
||||
std::vector<std::string> config::get_template_local_paths()
|
||||
{
|
||||
nlohmann::json template_local_paths = mConfig["template_local_paths"];
|
||||
std::vector<std::string> paths;
|
||||
for (auto &path : template_local_paths) {
|
||||
if (path.is_string() && !path.empty())
|
||||
paths.push_back(path);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
std::vector<std::string> config::get_local_server_definition_paths() {
|
||||
nlohmann::json server_definition_paths = mConfig["server_definition_paths"];
|
||||
std::vector<std::string> paths;
|
||||
for (auto &path : server_definition_paths) {
|
||||
paths.push_back(path);
|
||||
if (path.is_string() && !path.empty())
|
||||
paths.push_back(path);
|
||||
else
|
||||
std::cerr << "Warning: Invalid server definition path: " << path << std::endl;
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
@ -22,7 +22,9 @@ class config {
|
||||
std::string get_local_template_cache_path();
|
||||
|
||||
std::vector<std::string> get_template_registry_urls();
|
||||
std::vector<std::string> get_template_local_paths();
|
||||
std::vector<std::string> get_local_server_definition_paths();
|
||||
|
||||
std::string get_template_upload_registry_url();
|
||||
std::string get_template_upload_registry_token();
|
||||
|
||||
|
@ -1,14 +1,17 @@
|
||||
#include "server_env_manager.hpp"
|
||||
#include "utils/envmanager.hpp"
|
||||
#include "utils/directories.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "services.hpp"
|
||||
#include "contrib/base64.hpp"
|
||||
#include "templates.hpp"
|
||||
#include "utils/utils.hpp"
|
||||
#include "utils/json.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
@ -17,7 +20,7 @@ server_env_manager::server_env_manager(const std::string& server_name) : mValid(
|
||||
return;
|
||||
|
||||
// Construct the full path to server.env
|
||||
std::string server_env_path = localfile::server_env(server_name);
|
||||
std::string server_env_path = localfile::server_json(server_name);
|
||||
|
||||
// Check if file exists
|
||||
if (!std::filesystem::exists(server_env_path)) {
|
||||
@ -27,11 +30,16 @@ server_env_manager::server_env_manager(const std::string& server_name) : mValid(
|
||||
|
||||
try {
|
||||
// Use envmanager to handle the environment file
|
||||
envmanager env_manager(server_env_path);
|
||||
env_manager.load();
|
||||
|
||||
// Get all variables
|
||||
env_manager.get_all_variables_substituted(mVariables);
|
||||
nlohmann::json server_env_json = nlohmann::json::parse(std::ifstream(server_env_path));
|
||||
if (server_env_json.empty()) {
|
||||
std::cerr << "Error: Failed to parse server environment file: " + server_env_path << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the variables from the json
|
||||
for (const auto& var : server_env_json.items()) {
|
||||
mVariables[var.key()] = replace_with_environment_variables_like_bash(var.value());
|
||||
}
|
||||
|
||||
// Verify required variables exist
|
||||
for (const auto& var : {"SSH_HOST", "SSH_USER", "SSH_PORT", "DROPSHELL_DIR"}) {
|
||||
@ -51,6 +59,25 @@ server_env_manager::server_env_manager(const std::string& server_name) : mValid(
|
||||
}
|
||||
}
|
||||
|
||||
bool server_env_manager::create_server_env(const std::string &server_env_path, const std::string &SSH_HOST, const std::string &SSH_USER, const std::string &SSH_PORT, const std::string &DROPSHELL_DIR)
|
||||
{
|
||||
nlohmann::json server_env_json;
|
||||
server_env_json["SSH_HOST"] = SSH_HOST;
|
||||
server_env_json["SSH_USER"] = SSH_USER;
|
||||
server_env_json["SSH_PORT"] = SSH_PORT;
|
||||
server_env_json["DROPSHELL_DIR"] = DROPSHELL_DIR;
|
||||
|
||||
try {
|
||||
std::ofstream server_env_file(server_env_path);
|
||||
server_env_file << server_env_json.dump(4);
|
||||
server_env_file.close();
|
||||
return true;
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Failed to create server environment file: " + std::string(e.what()) << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string server_env_manager::get_variable(const std::string& name) const {
|
||||
auto it = mVariables.find(name);
|
||||
if (it == mVariables.end()) {
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "utils/envmanager.hpp"
|
||||
#include <vector>
|
||||
namespace dropshell {
|
||||
|
||||
// class to hold a command to run on the remote server.
|
||||
@ -47,6 +47,14 @@ std::string makesafecmd(const std::string& command);
|
||||
class server_env_manager {
|
||||
public:
|
||||
server_env_manager(const std::string& server_name);
|
||||
|
||||
static bool create_server_env(
|
||||
const std::string& server_env_path,
|
||||
const std::string& SSH_HOST,
|
||||
const std::string& SSH_USER,
|
||||
const std::string& SSH_PORT,
|
||||
const std::string& DROPSHELL_DIR);
|
||||
|
||||
std::string get_variable(const std::string& name) const;
|
||||
|
||||
// trivial getters.
|
||||
@ -83,6 +91,8 @@ class server_env_manager {
|
||||
bool mValid;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace dropshell
|
||||
|
||||
|
||||
|
@ -19,14 +19,12 @@ namespace dropshell {
|
||||
std::vector<ServerInfo> get_configured_servers() {
|
||||
std::vector<ServerInfo> servers;
|
||||
|
||||
std::vector<std::string> local_config_directories = gConfig().get_local_config_directories();
|
||||
if (local_config_directories.empty())
|
||||
std::vector<std::string> lsdp = gConfig().get_local_server_definition_paths();
|
||||
if (lsdp.empty())
|
||||
return servers;
|
||||
|
||||
for (int i = 0; i < local_config_directories.size(); i++) {
|
||||
std::string servers_dir = localpath::config_servers(i);
|
||||
for (auto servers_dir : lsdp) {
|
||||
if (!servers_dir.empty() && std::filesystem::exists(servers_dir)) {
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(servers_dir)) {
|
||||
if (std::filesystem::is_directory(entry)) {
|
||||
std::string server_name = entry.path().filename().string();
|
||||
@ -52,12 +50,12 @@ std::vector<ServerInfo> get_configured_servers() {
|
||||
|
||||
ServerInfo get_server_info(const std::string &server_name)
|
||||
{
|
||||
std::vector<std::string> local_config_directories = gConfig().get_local_config_directories();
|
||||
if (local_config_directories.empty())
|
||||
std::vector<std::string> lsdp = gConfig().get_local_server_definition_paths();
|
||||
if (lsdp.empty())
|
||||
return ServerInfo();
|
||||
|
||||
for (auto &config_dir : local_config_directories) {
|
||||
std::string server_dir = config_dir + "/servers/" + server_name;
|
||||
for (auto &config_dir : lsdp) {
|
||||
std::string server_dir = config_dir + "/" + server_name;
|
||||
if (std::filesystem::exists(server_dir)) {
|
||||
server_env_manager env(server_name);
|
||||
if (!env.is_valid()) {
|
||||
@ -177,8 +175,12 @@ void create_server(const std::string &server_name)
|
||||
}
|
||||
|
||||
// 2. create a new directory in the user config directory
|
||||
std::string config_servers_dir = localpath::config_servers();
|
||||
std::string server_dir = config_servers_dir + "/" + server_name;
|
||||
auto lsdp = gConfig().get_local_server_definition_paths();
|
||||
if (lsdp.empty() || lsdp[0].empty()) {
|
||||
std::cerr << "Error: Local server definition path not found - is DropShell initialised?" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string server_dir = lsdp[0] + "/" + server_name;
|
||||
std::filesystem::create_directory(server_dir);
|
||||
|
||||
// 3. create a template server.env file in the server directory
|
||||
|
@ -20,24 +20,25 @@ std::vector<LocalServiceInfo> get_server_services_info(const std::string& server
|
||||
if (server_name.empty())
|
||||
return services;
|
||||
|
||||
std::vector<std::string> local_config_directories = gConfig().get_local_config_directories();
|
||||
if (local_config_directories.empty()) {
|
||||
std::cerr << "Error: No local config directories found" << std::endl;
|
||||
std::vector<std::string> local_server_definition_paths = gConfig().get_local_server_definition_paths();
|
||||
if (local_server_definition_paths.empty()) {
|
||||
std::cerr << "Error: No local server definition paths found" << std::endl;
|
||||
std::cerr << "Run 'dropshell init' to initialise DropShell" << std::endl;
|
||||
return services;
|
||||
}
|
||||
|
||||
for (int i = 0; i < localpath::num_config_directories(); i++) {
|
||||
std::string serverpath = localpath::config_servers(i);
|
||||
if (serverpath.empty()) {
|
||||
for (const auto& server_definition_path : local_server_definition_paths) {
|
||||
fs::path serverpath = server_definition_path + "/" + server_name;
|
||||
if (serverpath.string().empty()) {
|
||||
std::cerr << "Error: Server directory not found: " << serverpath << std::endl;
|
||||
return services;
|
||||
}
|
||||
fs::path server_dir = fs::path(serverpath) / server_name;
|
||||
if (fs::exists(server_dir)) {
|
||||
for (const auto& entry : fs::directory_iterator(server_dir)) {
|
||||
fs::path servicepath = serverpath / "services";
|
||||
if (fs::exists(servicepath)) {
|
||||
for (const auto& entry : fs::directory_iterator(servicepath)) {
|
||||
if (fs::is_directory(entry)) {
|
||||
auto service = get_service_info(server_name, entry.path().filename().string());
|
||||
std::string service_name = entry.path().filename().string();
|
||||
auto service = get_service_info(server_name, service_name);
|
||||
if (!service.template_name.empty()) {
|
||||
services.push_back(service);
|
||||
}
|
||||
@ -45,7 +46,6 @@ std::vector<LocalServiceInfo> get_server_services_info(const std::string& server
|
||||
}
|
||||
} // end of for (int i = 0; i < getNumConfigDirectories(); i++)
|
||||
}
|
||||
|
||||
|
||||
return services;
|
||||
}
|
||||
@ -125,7 +125,7 @@ std::set<std::string> list_backups(const std::string &server_name, const std::st
|
||||
return backups;
|
||||
}
|
||||
|
||||
std::string backups_dir = localpath::backups_path();
|
||||
std::string backups_dir = gConfig().get_local_backup_path();
|
||||
if (backups_dir.empty())
|
||||
return backups;
|
||||
|
||||
|
@ -16,8 +16,8 @@
|
||||
namespace dropshell {
|
||||
|
||||
|
||||
bool get_templates(std::vector<template_info>& templates) {
|
||||
templates.clear();
|
||||
std::set<std::string> template_source_local::get_template_list() {
|
||||
std::set<std::string> templates;
|
||||
|
||||
// Helper function to add templates from a directory
|
||||
auto add_templates_from_dir = [&templates](const std::string& dir_path) {
|
||||
@ -25,68 +25,47 @@
|
||||
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);
|
||||
}
|
||||
if (entry.is_directory())
|
||||
templates.insert(entry.path().filename().string());
|
||||
};
|
||||
|
||||
// add templates from the local config directories
|
||||
std::vector<std::string> 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;
|
||||
add_templates_from_dir(mLocalPath);
|
||||
return templates;
|
||||
}
|
||||
|
||||
|
||||
bool get_template_info(const std::string& template_name, template_info& info) {
|
||||
// add templates from the local config directories
|
||||
std::vector<std::string> 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_source_local::has_template(const std::string& template_name) {
|
||||
return std::filesystem::exists(mLocalPath / template_name);
|
||||
}
|
||||
|
||||
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 template_source_local::template_command_filename(const std::string& template_name, const std::string& command) {
|
||||
std::vector<std::string> commands = {
|
||||
command,
|
||||
command + ".sh"
|
||||
};
|
||||
|
||||
for (const auto& cmd : commands) {
|
||||
std::filesystem::path path = mLocalPath / template_name / cmd;
|
||||
if (std::filesystem::exists(path))
|
||||
return cmd;
|
||||
}
|
||||
|
||||
std::string path = info.local_template_path + "/" + command + ".sh";
|
||||
return (std::filesystem::exists(path));
|
||||
return "";
|
||||
}
|
||||
|
||||
template_info template_source_local::get_template_info(const std::string& template_name) {
|
||||
std::filesystem::path path = mLocalPath / template_name;
|
||||
|
||||
if (!std::filesystem::exists(path))
|
||||
return template_info();
|
||||
|
||||
return template_info(
|
||||
template_name,
|
||||
mLocalPath.string(),
|
||||
path
|
||||
);
|
||||
}
|
||||
|
||||
void list_templates() {
|
||||
std::vector<template_info> templates;
|
||||
|
||||
if (!get_templates(templates)) {
|
||||
std::cerr << "Error: Failed to get templates" << std::endl;
|
||||
return;
|
||||
}
|
||||
void template_manager::list_templates() {
|
||||
auto templates = get_template_list();
|
||||
|
||||
if (templates.empty()) {
|
||||
std::cout << "No templates found." << std::endl;
|
||||
@ -94,44 +73,55 @@
|
||||
}
|
||||
|
||||
std::cout << "Available templates:" << std::endl;
|
||||
std::cout << std::left << std::setw(20) << "Name" << "Path" << std::endl;
|
||||
std::cout << std::string(60, '-') << std::endl;
|
||||
|
||||
|
||||
// sort templates alphabetically.
|
||||
std::sort(templates.begin(), templates.end());
|
||||
// print templates.
|
||||
std::cout << std::string(60, '-') << std::endl;
|
||||
bool first = true;
|
||||
for (const auto& t : templates) {
|
||||
std::cout << std::left << std::setw(20) << t.template_name << t.local_template_path << std::endl;
|
||||
std::cout << (first ? "" : ", ") << t;
|
||||
first = false;
|
||||
}
|
||||
std::cout << std::endl;
|
||||
std::cout << std::string(60, '-') << std::endl;
|
||||
}
|
||||
|
||||
void create_template(const std::string& template_name) {
|
||||
void template_manager::create_template(const std::string& template_name) {
|
||||
// 1. Create a new directory in the user templates directory
|
||||
std::vector<std::string> local_config_directories = gConfig().get_local_config_directories();
|
||||
std::vector<std::string> local_server_definition_paths = gConfig().get_local_server_definition_paths();
|
||||
|
||||
if (local_config_directories.empty()) {
|
||||
std::cerr << "Error: No local config directories found" << std::endl;
|
||||
if (local_server_definition_paths.empty()) {
|
||||
std::cerr << "Error: No local server definition paths 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;
|
||||
auto info = get_template_info(template_name);
|
||||
if (info.is_set()) {
|
||||
std::cerr << "Error: Template '" << template_name << "' already exists at " << info.locationID() << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string new_template_path = localpath::config_templates() + "/" + template_name;
|
||||
auto local_template_paths = gConfig().get_template_local_paths();
|
||||
if (local_template_paths.empty()) {
|
||||
std::cerr << "Error: No local template paths found" << std::endl;
|
||||
std::cerr << "Run 'dropshell edit' to add one to the DropShell config" << std::endl;
|
||||
return;
|
||||
}
|
||||
std::string new_template_path = local_template_paths[0] + "/" + 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;
|
||||
auto example_info = gTemplateManager().get_template_info("example-nginx");
|
||||
if (!example_info.is_set()) {
|
||||
std::cerr << "Error: Example template not found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string example_template_path = example_info.local_template_path();
|
||||
|
||||
// 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());
|
||||
@ -144,10 +134,9 @@
|
||||
}
|
||||
}
|
||||
|
||||
// modify the TEMPLATE=example line in the service.env file to TEMPLATE=<template_name>
|
||||
// modify the TEMPLATE=example line in the .template_info.env file to TEMPLATE=<template_name>
|
||||
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/.template_info.env";
|
||||
if (!replace_line_in_file(service_env_path, search_string, replacement_line)) {
|
||||
std::cerr << "Error: Failed to replace TEMPLATE= line in the .template_info.env file" << std::endl;
|
||||
@ -175,24 +164,10 @@
|
||||
|
||||
std::cout << std::endl;
|
||||
std::cout << "Template '" << template_name << "' created at " << new_template_path << std::endl;
|
||||
test_template(new_template_path);
|
||||
}
|
||||
|
||||
bool get_all_template_config_directories(std::vector<std::string> &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)
|
||||
bool template_manager::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;
|
||||
@ -201,7 +176,7 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
bool test_template(const std::string &template_path)
|
||||
bool template_manager::test_template(const std::string &template_path)
|
||||
{
|
||||
std::string template_name = std::filesystem::path(template_path).filename().string();
|
||||
|
||||
@ -256,4 +231,10 @@
|
||||
return true;
|
||||
}
|
||||
|
||||
template_manager & gTemplateManager()
|
||||
{
|
||||
static template_manager instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
||||
|
@ -1,39 +1,98 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
|
||||
#include "utils/json.hpp"
|
||||
|
||||
namespace dropshell {
|
||||
|
||||
typedef enum template_source_type {
|
||||
TEMPLATE_SOURCE_TYPE_LOCAL,
|
||||
TEMPLATE_SOURCE_TYPE_REGISTRY,
|
||||
TEMPLATE_SOURCE_NOT_SET
|
||||
} template_source_type;
|
||||
|
||||
class template_info {
|
||||
public:
|
||||
template_info() {}
|
||||
template_info(std::string n, std::string p) : template_name(n), local_template_path(p) {}
|
||||
|
||||
std::string template_name;
|
||||
std::string local_template_path;
|
||||
template_info() : mIsSet(false) {}
|
||||
template_info(const std::string& template_name, const std::string& location_id, const std::filesystem::path& local_template_path) : mTemplateName(template_name), mLocationID(location_id), mTemplateLocalPath(local_template_path), mIsSet(true) {}
|
||||
virtual ~template_info() {}
|
||||
bool is_set() { return mIsSet; }
|
||||
std::string name() { return mTemplateName; }
|
||||
std::string locationID() { return mLocationID; }
|
||||
std::filesystem::path local_template_path() { return mTemplateLocalPath; }
|
||||
private:
|
||||
std::string mTemplateName;
|
||||
std::string mLocationID;
|
||||
std::filesystem::path mTemplateLocalPath; // source or cache.
|
||||
bool mIsSet;
|
||||
};
|
||||
|
||||
// templates are stored in multiple locations:
|
||||
// 1. /opt/dropshell/templates
|
||||
// 2. CONFIG_DIR/templates
|
||||
class template_source_interface {
|
||||
public:
|
||||
virtual ~template_source_interface() {}
|
||||
virtual std::set<std::string> get_template_list() = 0;
|
||||
virtual bool has_template(const std::string& template_name) = 0;
|
||||
virtual template_info get_template_info(const std::string& template_name) = 0;
|
||||
virtual std::string template_command_filename(const std::string& template_name,const std::string& command) = 0;
|
||||
};
|
||||
|
||||
class template_source_registry : public template_source_interface {
|
||||
public:
|
||||
template_source_registry(std::string URL) : mURL(URL) {}
|
||||
|
||||
bool get_templates(std::vector<template_info>& templates);
|
||||
bool get_template_info(const std::string& template_name, template_info& info);
|
||||
bool template_command_exists(const std::string& template_name,const std::string& command);
|
||||
void list_templates();
|
||||
~template_source_registry() {}
|
||||
|
||||
std::set<std::string> get_template_list();
|
||||
bool has_template(const std::string& template_name);
|
||||
template_info get_template_info(const std::string& template_name);
|
||||
std::string template_command_filename(const std::string& template_name,const std::string& command);
|
||||
private:
|
||||
std::filesystem::path get_cache_dir();
|
||||
private:
|
||||
std::string mURL;
|
||||
std::vector<nlohmann::json> mTemplates; // cached list.
|
||||
};
|
||||
|
||||
// create a template
|
||||
// 1. create a new directory in the user templates directory
|
||||
// 2. copy the example template from the system templates directory into the new directory
|
||||
// 3. print out the README.txt file in the new template directory, and the path to the new template
|
||||
void create_template(const std::string& template_name);
|
||||
class template_source_local : public template_source_interface {
|
||||
public:
|
||||
template_source_local(std::string local_path) : mLocalPath(local_path) {}
|
||||
~template_source_local() {}
|
||||
std::set<std::string> get_template_list();
|
||||
bool has_template(const std::string& template_name);
|
||||
template_info get_template_info(const std::string& template_name);
|
||||
std::string template_command_filename(const std::string& template_name,const std::string& command);
|
||||
private:
|
||||
std::filesystem::path mLocalPath;
|
||||
};
|
||||
|
||||
bool get_all_template_config_directories(std::vector<std::string>& template_config_directories);
|
||||
class template_manager {
|
||||
public:
|
||||
template_manager() : mLoaded(false) {}
|
||||
~template_manager() {}
|
||||
|
||||
std::set<std::string> get_template_list();
|
||||
bool has_template(const std::string& template_name);
|
||||
template_info get_template_info(const std::string& template_name);
|
||||
|
||||
std::string template_command_filename(const std::string& template_name,const std::string& command);
|
||||
void create_template(const std::string& template_name);
|
||||
bool test_template(const std::string& template_path);
|
||||
|
||||
void list_templates();
|
||||
|
||||
private:
|
||||
void load_sources();
|
||||
bool required_file(std::string path, std::string template_name);
|
||||
|
||||
private:
|
||||
bool mLoaded;
|
||||
std::vector<std::unique_ptr<template_source_interface>> mSources;
|
||||
};
|
||||
|
||||
template_manager & gTemplateManager();
|
||||
|
||||
bool test_template(const std::string& template_path);
|
||||
|
||||
} // namespace dropshell
|
||||
|
@ -22,9 +22,9 @@ namespace localfile {
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string server_env(const std::string &server_name) {
|
||||
std::string server_json(const std::string &server_name) {
|
||||
std::string serverpath = localpath::server(server_name);
|
||||
return (serverpath.empty() ? "" : (fs::path(serverpath) / "server.env").string());
|
||||
return (serverpath.empty() ? "" : (fs::path(serverpath) / "server.json").string());
|
||||
}
|
||||
|
||||
std::string service_env(const std::string &server_name, const std::string &service_name) {
|
||||
|
@ -14,7 +14,7 @@ namespace dropshell {
|
||||
|
||||
// server_definition_path
|
||||
// |-- <server_name>
|
||||
// |-- server.env
|
||||
// |-- server.json
|
||||
// |-- services
|
||||
// |-- <service_name>
|
||||
// |-- service.env
|
||||
@ -42,7 +42,7 @@ namespace dropshell {
|
||||
namespace localfile {
|
||||
// ~/.config/dropshell/dropshell.json
|
||||
std::string dropshell_json();
|
||||
std::string server_env(const std::string &server_name);
|
||||
std::string server_json(const std::string &server_name);
|
||||
std::string service_env(const std::string &server_name, const std::string &service_name);
|
||||
std::string template_info_env(const std::string &server_name, const std::string &service_name);
|
||||
} // namespace localfile
|
||||
|
@ -72,18 +72,6 @@ void envmanager::get_all_variables(std::map<std::string, std::string>& variables
|
||||
variables = m_variables;
|
||||
}
|
||||
|
||||
std::string envmanager::get_variable_substituted(std::string key) const {
|
||||
std::string value = get_variable(key);
|
||||
return expand_patterns(value);
|
||||
}
|
||||
|
||||
void envmanager::get_all_variables_substituted(std::map<std::string, std::string>& variables) const {
|
||||
variables.clear();
|
||||
for (const auto& pair : m_variables) {
|
||||
variables[pair.first] = expand_patterns(pair.second);
|
||||
}
|
||||
}
|
||||
|
||||
void envmanager::add_variables(std::map<std::string, std::string> variables) {
|
||||
for (auto& pair : variables) {
|
||||
set_variable(pair.first, pair.second);
|
||||
@ -98,26 +86,4 @@ void envmanager::clear_variables() {
|
||||
m_variables.clear();
|
||||
}
|
||||
|
||||
std::string envmanager::expand_patterns(std::string str) const {
|
||||
// Combined regex pattern for both ${var} and $var formats
|
||||
std::regex var_pattern("\\$(?:\\{([^}]+)\\}|([a-zA-Z0-9_]+))");
|
||||
std::string result = str;
|
||||
std::smatch match;
|
||||
|
||||
while (std::regex_search(result, match, var_pattern)) {
|
||||
// match[1] will contain capture from ${var} format
|
||||
// match[2] will contain capture from $var format
|
||||
std::string var_name = match[1].matched ? match[1].str() : match[2].str();
|
||||
|
||||
// Get value from system environment variables
|
||||
const char* env_value = std::getenv(var_name.c_str());
|
||||
std::string value = env_value ? env_value : "";
|
||||
|
||||
result = result.replace(match.position(), match.length(), value);
|
||||
}
|
||||
|
||||
// dequote the result
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
||||
|
@ -25,20 +25,12 @@ class envmanager {
|
||||
std::string get_variable(std::string key) const;
|
||||
void get_all_variables(std::map<std::string, std::string>& variables) const;
|
||||
|
||||
// get variables, but replace patterns ${var} and $var with the actual environment variable in the returned string.
|
||||
// trim whitespace from the values.
|
||||
std::string get_variable_substituted(std::string key) const;
|
||||
void get_all_variables_substituted(std::map<std::string, std::string>& variables) const;
|
||||
|
||||
// add variables to the environment files.
|
||||
// trim whitespace from the values.
|
||||
void add_variables(std::map<std::string, std::string> variables);
|
||||
void set_variable(std::string key, std::string value);
|
||||
void clear_variables();
|
||||
|
||||
private:
|
||||
std::string expand_patterns(std::string str) const;
|
||||
|
||||
private:
|
||||
std::string m_path;
|
||||
std::map<std::string, std::string> m_variables;
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
namespace dropshell {
|
||||
|
||||
void maketitle(const std::string& title) {
|
||||
@ -268,4 +269,32 @@ std::vector<std::string> split(const std::string& str, const std::string& delimi
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
std::string replace_with_environment_variables_like_bash(std::string str) {
|
||||
// Combined regex pattern for both ${var} and $var formats
|
||||
std::regex var_pattern("\\$(?:\\{([^}]+)\\}|([a-zA-Z0-9_]+))");
|
||||
std::string result = str;
|
||||
std::smatch match;
|
||||
|
||||
while (std::regex_search(result, match, var_pattern)) {
|
||||
// match[1] will contain capture from ${var} format
|
||||
// match[2] will contain capture from $var format
|
||||
std::string var_name = match[1].matched ? match[1].str() : match[2].str();
|
||||
|
||||
// Get value from system environment variables
|
||||
const char* env_value = std::getenv(var_name.c_str());
|
||||
std::string value = env_value ? env_value : "";
|
||||
|
||||
result = result.replace(match.position(), match.length(), value);
|
||||
}
|
||||
|
||||
// dequote the result
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string requote(std::string str) {
|
||||
return quote(trim(dequote(trim(str))));
|
||||
}
|
||||
|
||||
} // namespace dropshell
|
@ -20,6 +20,8 @@ std::string trim(std::string str);
|
||||
std::string dequote(std::string str);
|
||||
std::string quote(std::string str);
|
||||
std::string halfquote(std::string str);
|
||||
std::string requote(std::string str);
|
||||
|
||||
std::string multi2string(std::vector<std::string> values);
|
||||
std::vector<std::string> string2multi(std::string values);
|
||||
std::vector<std::string> split(const std::string& str, const std::string& delimiter);
|
||||
@ -34,4 +36,6 @@ void ensure_directories_exist(std::vector<std::string> directories);
|
||||
std::vector<int> search(const std::string &pat, const std::string &txt);
|
||||
int count_substring(const std::string &substring, const std::string &text);
|
||||
|
||||
std::string replace_with_environment_variables_like_bash(std::string str);
|
||||
|
||||
} // namespace dropshell
|
Loading…
x
Reference in New Issue
Block a user