From ebdb9d643a140a7a02fa8de834181cd2de8f9bec Mon Sep 17 00:00:00 2001 From: phanes Date: Mon, 17 Jan 2022 00:12:13 -0500 Subject: [PATCH] experimental #2: now interpolates environment variables in config object file --- .gitignore | 5 +++ CMakeLists.txt | 1 + src/loaders/abstract/Conf.cpp | 62 +++++++++++++-------------- src/loaders/abstract/Conf.h | 16 +++---- src/loaders/low_level/JSON_Loader.cpp | 56 +++++++++++++++++++++++- src/loaders/low_level/JSON_Loader.h | 4 +- src/loaders/misc/helpers.cpp | 13 ++++++ src/loaders/misc/helpers.h | 8 ++++ 8 files changed, 121 insertions(+), 44 deletions(-) diff --git a/.gitignore b/.gitignore index 9a421d7..1357f27 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,8 @@ cmake-build-debug .idea ./.idea +./cmake-build-release/ +cmake-build-release +CMakeFiles +CMakeLists.txt +Makefile \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index af26149..bf3a9d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,4 +4,5 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -std=c++1z -O0 -DDEBUG=1") set(SOURCE_FILES Rex.cpp src/loaders/abstract/loaders.cpp src/loaders/abstract/loaders.h src/json/jsoncpp.cpp src/loaders/low_level/JSON_Loader.cpp src/loaders/low_level/JSON_Loader.h src/loaders/misc/helpers.cpp src/loaders/misc/helpers.h src/loaders/abstract/Suite.cpp src/loaders/abstract/Suite.h src/loaders/abstract/Plan.cpp src/loaders/abstract/Plan.h src/loaders/abstract/Conf.cpp src/loaders/abstract/Conf.h src/loaders/abstract/Unit.cpp src/loaders/abstract/Unit.h src/loaders/abstract/Task.cpp src/loaders/abstract/Task.h src/Sproc/Sproc.cpp src/Sproc/Sproc.h src/Logger/Logger.cpp src/Logger/Logger.h) + add_executable(rex ${SOURCE_FILES}) diff --git a/src/loaders/abstract/Conf.cpp b/src/loaders/abstract/Conf.cpp index 67dbbdd..d111e59 100644 --- a/src/loaders/abstract/Conf.cpp +++ b/src/loaders/abstract/Conf.cpp @@ -70,6 +70,8 @@ protected: Conf::Conf(std::string filename, int LOG_LEVEL ): JSON_Loader(LOG_LEVEL ), slog(LOG_LEVEL, "_conf_" ) { this->LOG_LEVEL = LOG_LEVEL; + std::string jval_s; + bool jval_b; // prepare context spaghetti this->override_context = false; @@ -83,65 +85,59 @@ Conf::Conf(std::string filename, int LOG_LEVEL ): JSON_Loader(LOG_LEVEL ), slog( throw ConfigLoadException("Config file not found."); } - if (this->get_serialized(this->config_version, "config_version" ) != 0) - { - throw ConfigLoadException("config_version string is not set in the config file supplied: " + filename); - } - if ( this->config_version.asString() != VERSION_STRING ) - { - throw ConfigLoadException("config_version string expected was " + std::string(VERSION_STRING) + " in: " + filename); - } - // find the path to the unit definitions file - if (this->get_serialized(this->units_path, "units_path" ) != 0 ) - { - throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename); + if (this->get_string(jval_s, "units_path") != 0 ) + { throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename); } else { + this->units_path = jval_s; } + jval_s = {0}; // find the path to logs directory - if (this->get_serialized(this->logs_path, "logs_path" ) != 0 ) - { - throw ConfigLoadException("logs_path string is not set in the config file supplied: " + filename); + if (this->get_string(jval_s, "logs_path") != 0 ) + { throw ConfigLoadException("logs_path string is not set in the config file supplied: " + filename); } else { + this->logs_path = jval_s; } + jval_s = {0}; - if ( this->get_serialized(this->override_execution_context, "execution_context_override" ) != 0 ) - { - throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename); - } else { - this->override_context = true; + if (this->get_bool(jval_b, "execution_context_override") != 0 ) + { throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename); } else { + this->override_context = jval_b; } + jval_b = {0}; - if ( this->get_serialized(this->execution_context, "execution_context" ) != 0 ) - { - throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename); - } else { - if ( is_dir( this->execution_context.asString() ) ) { - this->execution_context_literal = this->execution_context.asString(); - } else { - throw ConfigLoadException( "The execution context supplied is an invalid directory."); + if (this->get_string(jval_s, "execution_context") != 0 ) + { throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename); } else { + if ( ! is_dir( jval_s ) ) { throw ConfigLoadException( "The execution context supplied is an invalid directory."); } else { + this->execution_context = jval_s; } } + jval_s = {0}; + + interpolate( this->units_path ); + interpolate( this->logs_path ); + interpolate( this->execution_context ); + }; /// Conf::has_context_override - Specifies whether or not the override context function is enabled in the Conf file. bool Conf::has_context_override() { - return this->override_execution_context.asBool(); + return this->override_execution_context; } /// Conf::get_execution_context - Specifies the path to the current working directory to set for all unit executions. std::string Conf::get_execution_context() { - return this->execution_context_literal; + return this->execution_context; } /// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file. -std::string Conf::get_units_path() { return this->units_path.asString(); } +std::string Conf::get_units_path() { return this->units_path; } /// Conf::get_units_path - Retrieves the path to the Unit definition file from the application configuration file. -std::string Conf::get_logs_path() { return this->logs_path.asString(); } +std::string Conf::get_logs_path() { return this->logs_path; } /// Conf::set_execution_context- Sets the execution context. void Conf::set_execution_context(std::string execution_context ) { - this->execution_context_literal = execution_context; + this->execution_context = execution_context; } diff --git a/src/loaders/abstract/Conf.h b/src/loaders/abstract/Conf.h index 37bd8aa..35a810a 100644 --- a/src/loaders/abstract/Conf.h +++ b/src/loaders/abstract/Conf.h @@ -28,28 +28,26 @@ #define STRINGIZE2(s) #s #define STRINGIZE(s) STRINGIZE2(s) -# define IMPL_CONFIG_VERSION 4 +# define IMPL_CONFIG_VERSION 5 # define VERSION_STRING STRINGIZE(IMPL_CONFIG_VERSION) class Conf: public JSON_Loader { private: - Json::Value plan_path; - Json::Value units_path; - Json::Value execution_context; - Json::Value config_version; - Json::Value logs_path; + std::string plan_path; + std::string units_path; + std::string execution_context; + std::string logs_path; // flag to indicate if execution context should be overriden in config file // if set to true rex should use whats in the config file for current working directory // if set to false, rex should use the current working directory at time of execution - Json::Value override_execution_context; + bool override_execution_context; bool override_context; - std::string execution_context_literal; public: - Conf(std::string filename, int LOG_LEVEL ); + Conf( std::string filename, int LOG_LEVEL ); bool has_context_override(); diff --git a/src/loaders/low_level/JSON_Loader.cpp b/src/loaders/low_level/JSON_Loader.cpp index 31aaf62..b85effd 100644 --- a/src/loaders/low_level/JSON_Loader.cpp +++ b/src/loaders/low_level/JSON_Loader.cpp @@ -130,7 +130,7 @@ std::string JSON_Loader::as_string() /// \param key - The JSON key name to assign the value to (the root of the json::value object by name) /// \param verbose - Whether or not to print verbose output to STDOUT. /// \return - Boolean indicator of success or failure (0|1) -int JSON_Loader::get_serialized(Json::Value &input, std::string key ) +int JSON_Loader::get_serialized( Json::Value &input, std::string key ) { // throw if the class is not ready to be used. if ( ! this->populated ) { throw JSON_Loader_NotReady(); } @@ -147,6 +147,60 @@ int JSON_Loader::get_serialized(Json::Value &input, std::string key ) // verbose mode tells the user what key we were looking for. this->slog.log( E_FATAL, "Failed to find key '" + key + "'." ); + // exit code for failure + return 1; +} + +/// JSON_Loader::get_string - assigns the serialized representation of the value of a key (json::value) +/// +/// \param input - A reference to the json::value object to receive the new value. +/// \param key - The JSON key name to assign the value to (the root of the json::value object by name) +/// \param verbose - Whether or not to print verbose output to STDOUT. +/// \return - Boolean indicator of success or failure (0|1) +int JSON_Loader::get_string( std::string &input, std::string key ) +{ + // throw if the class is not ready to be used. + if ( ! this->populated ) { throw JSON_Loader_NotReady(); } + + if ( this->json_root.isMember( key ) ) + { + // key was found so return it to the passed input ref + input = this->json_root[ key ].asString(); + return 0; + } + + // key was not found + + // verbose mode tells the user what key we were looking for. + this->slog.log( E_FATAL, "Failed to find key '" + key + "'." ); + + // exit code for failure + return 1; +} + +/// JSON_Loader::get_bool - assigns the serialized representation of the value of a key (json::value) +/// +/// \param input - A reference to the json::value object to receive the new value. +/// \param key - The JSON key name to assign the value to (the root of the json::value object by name) +/// \param verbose - Whether or not to print verbose output to STDOUT. +/// \return - Boolean indicator of success or failure (0|1) +int JSON_Loader::get_bool( bool & input, std::string key ) +{ + // throw if the class is not ready to be used. + if ( ! this->populated ) { throw JSON_Loader_NotReady(); } + + if ( this->json_root.isMember( key ) ) + { + // key was found so return it to the passed input ref + input = this->json_root[ key ].asBool(); + return 0; + } + + // key was not found + + // verbose mode tells the user what key we were looking for. + this->slog.log( E_FATAL, "Failed to find key '" + key + "'." ); + // exit code for failure return 1; } \ No newline at end of file diff --git a/src/loaders/low_level/JSON_Loader.h b/src/loaders/low_level/JSON_Loader.h index fd89990..ff87350 100644 --- a/src/loaders/low_level/JSON_Loader.h +++ b/src/loaders/low_level/JSON_Loader.h @@ -50,7 +50,9 @@ class JSON_Loader std::string as_string(); // safely handle deserialized type retrieval (if we want it to be safe) - int get_serialized(Json::Value &input, std::string key ); + int get_serialized( Json::Value & input, std::string key ); + int get_string(std::string & input, std::string key ); + int get_bool(bool & input, std::string key ); private: Logger slog; diff --git a/src/loaders/misc/helpers.cpp b/src/loaders/misc/helpers.cpp index 39f8087..5fb2880 100644 --- a/src/loaders/misc/helpers.cpp +++ b/src/loaders/misc/helpers.cpp @@ -56,4 +56,17 @@ std::string get_8601() // ss << std::put_time(gmtime(&itt), "%FT%TZ"); ss << std::put_time(localtime(&itt), "%Y-%m-%d_%H:%M:%S"); return ss.str(); +} + +void interpolate( std::string & text ) +{ + static std::regex env( "\\$\\{([^}]+)\\}" ); + std::smatch match; + while ( std::regex_search( text, match, env ) ) + { + const char * s = getenv( match[1].str().c_str() ); + const std::string var( s == NULL ? "" : s ); + text.replace( match[0].first, match[0].second, var ); + } + } \ No newline at end of file diff --git a/src/loaders/misc/helpers.h b/src/loaders/misc/helpers.h index a62cfcc..42339b8 100644 --- a/src/loaders/misc/helpers.h +++ b/src/loaders/misc/helpers.h @@ -32,14 +32,22 @@ #include #include #include +#include + bool exists (const std::string& name); std::string get_working_path(); + bool is_file( std::string ); + bool is_dir( std::string ); +// expand environment variables in string +void interpolate( std::string & text); + std::string get_8601(); + const char * command2args( std::string input_string ); #endif //REX_HELPERS_JH