diff --git a/source/agent-remote/datacommands.sh b/source/agent-remote/datacommands.sh index 7259e60..b325a20 100755 --- a/source/agent-remote/datacommands.sh +++ b/source/agent-remote/datacommands.sh @@ -12,6 +12,10 @@ _autocommandrun_volume() { case "$command" in create) + if docker volume ls | grep -q ${volume_name}; then + echo "Volume ${volume_name} already exists - leaving unchanged" + return + fi echo "Creating volume ${volume_name}" docker volume create ${volume_name} ;; @@ -39,6 +43,10 @@ _autocommandrun_path() { case "$command" in create) + if [ -d "${path}" ]; then + echo "Path ${path} already exists - unchanged" + return + fi echo "Creating path ${path}" mkdir -p ${path} ;; @@ -80,6 +88,12 @@ _autocommandrun_file() { case "$command" in create) + filepath_parent=$(dirname ${filepath}) + filepath_child=$(basename ${filepath}) + if [ ! -d "${filepath_parent}" ]; then + echo "Parent directory ${filepath_parent} of ${filepath_child} does not exist - creating" + mkdir -p ${filepath_parent} + fi ;; nuke) rm -f ${filepath} diff --git a/source/src/commands/create-service.cpp b/source/src/commands/create-service.cpp index ce1c762..d1b8fae 100644 --- a/source/src/commands/create-service.cpp +++ b/source/src/commands/create-service.cpp @@ -7,6 +7,8 @@ #include "utils/utils.hpp" #include "services.hpp" +#include + namespace dropshell { @@ -65,6 +67,39 @@ namespace dropshell namespace shared_commands { + + bool print_readme(const template_info &tinfo, std::string server, std::string service) + { + std::vector variants_to_try = {"README.txt", "readme.txt", "ReadMe.txt", "README", "readme", "README.md", "readme.md"}; + std::filesystem::path readme_path = tinfo.local_template_path(); + for (const auto &variant : variants_to_try) + { + if (std::filesystem::exists(readme_path / variant)) + { + readme_path = readme_path / variant; + break; + } + } + + if (!std::filesystem::exists(readme_path)) + return false; + + std::map all_env_vars; + get_all_service_env_vars(server, service, all_env_vars); + all_env_vars["LOCAL_CONFIG_PATH"] = localpath::service(server, service); + all_env_vars["LOCAL_TEMPLATE_PATH"] = tinfo.local_template_path().string(); + + info << std::endl; + std::ifstream readme_file(readme_path); + std::string line; + while (std::getline(readme_file, line)) + { + info << substitute_provided_key_value_pairs(line, all_env_vars) << std::endl; + } + return true; + } + + bool create_service(const std::string &server_name, const std::string &template_name, const std::string &service_name) { if (server_name.empty() || template_name.empty() || service_name.empty()) @@ -112,10 +147,14 @@ namespace dropshell recursive_copy(tinfo.local_template_path() / "config", service_dir); info << "Service " << service_name << " created successfully" << std::endl; - info << std::endl; - info << "To complete the installation, please:" << std::endl; - info << "1. edit the service config file: dropshell edit " << server_name << " " << service_name << std::endl; - info << "2. install the remote service: dropshell install " << server_name << " " << service_name << std::endl; + + if (!print_readme(tinfo, server_name, service_name)) + { + info << std::endl; + info << "To complete the installation, please:" << std::endl; + info << "1. edit the service config file: dropshell edit " << server_name << " " << service_name << std::endl; + info << "2. install the remote service: dropshell install " << server_name << " " << service_name << std::endl; + } return true; } diff --git a/source/src/commands/install.cpp b/source/src/commands/install.cpp index 559b681..f44d2f5 100644 --- a/source/src/commands/install.cpp +++ b/source/src/commands/install.cpp @@ -10,6 +10,7 @@ #include "services.hpp" #include "utils/output.hpp" +#include #include #include #include @@ -55,6 +56,7 @@ namespace dropshell } } install_command_register; + namespace shared_commands { @@ -132,6 +134,8 @@ namespace dropshell // print health tick info << "Health: " << shared_commands::healthtick(server, service) << std::endl; + + return true; } diff --git a/source/src/templates.hpp b/source/src/templates.hpp index 79a0660..2397c65 100644 --- a/source/src/templates.hpp +++ b/source/src/templates.hpp @@ -19,11 +19,11 @@ class template_info { template_info() : mIsSet(false) {} template_info(const std::string& template_name, const std::string& location_id, const std::filesystem::path& local_template_path); 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; } - bool template_valid() { return mTemplateValid; } + bool is_set() const { return mIsSet; } + std::string name() const { return mTemplateName; } + std::string locationID() const { return mLocationID; } + std::filesystem::path local_template_path() const { return mTemplateLocalPath; } + bool template_valid() const { return mTemplateValid; } private: std::string mTemplateName; std::string mLocationID; diff --git a/source/src/utils/utils.cpp b/source/src/utils/utils.cpp index c75f5da..4e7f26d 100644 --- a/source/src/utils/utils.cpp +++ b/source/src/utils/utils.cpp @@ -286,29 +286,6 @@ std::vector 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 random_alphanumeric_string(int length) { static std::mt19937 generator(std::random_device{}()); @@ -366,5 +343,49 @@ std::string center_align(const std::string & str, int width) { } +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 substitute_provided_key_value_pairs(std::string str, const std::map &env_vars) +{ + // 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 environment variables map + auto it = env_vars.find(var_name); + std::string value = (it != env_vars.end()) ? it->second : ""; + + result = result.replace(match.position(), match.length(), value); + } + + return result; +} } // namespace dropshell \ No newline at end of file diff --git a/source/src/utils/utils.hpp b/source/src/utils/utils.hpp index f9a57dc..a1425b9 100644 --- a/source/src/utils/utils.hpp +++ b/source/src/utils/utils.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "output.hpp" @@ -41,8 +42,6 @@ void ensure_directories_exist(std::vector directories); std::vector 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); - std::string random_alphanumeric_string(int length); int die(const std::string & msg); @@ -53,4 +52,7 @@ std::string left_align(const std::string & str, int width); std::string right_align(const std::string & str, int width); std::string center_align(const std::string & str, int width); +std::string replace_with_environment_variables_like_bash(std::string str); +std::string substitute_provided_key_value_pairs(std::string str, const std::map & env_vars); + } // namespace dropshell \ No newline at end of file