diff --git a/conf/config.json b/conf/config.json index 0a0a052..34b6bd1 100644 --- a/conf/config.json +++ b/conf/config.json @@ -1,5 +1,7 @@ { - "units_path": "/home/phanes/development/internal/Examplar/conf/units/all_test.units", - "plan_path": "/home/phanes/development/internal/Examplar/conf/plans/test.plan", - "config_version": "1" + "execution_context_override": true, + "execution_context": "/home/phanes/development/internal/Examplar/conf/", + "units_path": "units/all_test.units", + "plan_path": "plans/test.plan", + "config_version": "2" } diff --git a/examplar.cpp b/examplar.cpp index 654eb01..f0c4342 100644 --- a/examplar.cpp +++ b/examplar.cpp @@ -23,8 +23,8 @@ #include "src/loaders/loaders.h" #include #include - #include +#include "src/loaders/helpers.h" /* * TODO Commandline switches @@ -32,34 +32,45 @@ void print_usage() { - printf("examplar [ -h | --help ] [ -v | --verbose ] [ -c | --config CONFIG_PATH ]\n\n"); + printf("examplar [ -h | --help ] [ -v | --verbose ] [ -e | --execution-context EXECUTION_CONTEXT ][ -c | --config CONFIG_PATH ]\n\n"); } + + + int main( int argc, char * argv[] ) { int flags, opt; bool verbose = false; bool show_help = false; + + // indicator of whether examplar should use a commandline argument for overriding the context + // instead of what's supplied in the conf file + bool cli_context_supplied = false; + std::string config_path = "/etc/Examplar/config.json"; + std::string execution_context; // commandline switches: // -h help // -v verbose // -c CONFIG_FILE_PATH -- defaults to '/etc/Examplar/config.json' + // -e EXECUTION_CONTEXT -- current working directory when executing unit targets while (1) { static struct option long_options[] = { - {"verbose", no_argument, 0, 'v'}, - {"help", no_argument, 0, 'h'}, - {"config", required_argument, 0, 'c'}, + {"verbose", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'h'}, + {"config", required_argument, 0, 'c'}, + {"execution-context", required_argument, 0, 'e'}, {0, 0} }; + int option_index = 0; - opt = getopt_long (argc, argv, "vhc:", - long_options, &option_index); + opt = getopt_long (argc, argv, "vhec:", long_options, &option_index); if (opt == -1) break; @@ -80,6 +91,10 @@ int main( int argc, char * argv[] ) case '?': print_usage(); exit(1); + case 'e': + cli_context_supplied = true; + execution_context = std::string(optarg); + break; default: break; } @@ -99,14 +114,33 @@ int main( int argc, char * argv[] ) // A Plan declares what units are executed and a Suite declares the definitions of those units. Conf configuration = Conf(config_path, verbose ); - // load the configuration file which contains filepaths to definitions of a plan and definitions of units. + // if the user set this option as a commandline argument + if ( cli_context_supplied == true ) + { + // override the conf file's specified execution context + configuration.set_execution_context( execution_context ); + } + + // check if context override + if ( configuration.has_context_override() ) + { + // if so, set the CWD. + chdir( configuration.get_execution_context().c_str() ); + std::ostringstream infostring; + infostring << "Execution context: " << get_working_path() << std::endl; + syslog(LOG_INFO, infostring.str().c_str() ); + std::cout << infostring.str(); + } + + + // load the filepaths to definitions of a plan and definitions of units. std::string definitions_file = configuration.get_units_path(); std::string plan_file = configuration.get_plan_path(); Suite available_definitions; available_definitions.load_units_file( definitions_file, verbose ); - Plan plan; + Plan plan( &configuration ); plan.load_plan_file( plan_file, verbose ); plan.load_definitions( available_definitions, verbose ); diff --git a/src/loaders/Conf.cpp b/src/loaders/Conf.cpp index fafec04..37fe379 100644 --- a/src/loaders/Conf.cpp +++ b/src/loaders/Conf.cpp @@ -19,17 +19,48 @@ */ #include "Conf.h" -/// CONF_PLANPATH_INVALID - Exception thrown when the Conf type can not load the supplied path for the Plan definition -/// file. -class CONF_PLANPATH_INVALID: public std::runtime_error { public: - CONF_PLANPATH_INVALID(): std::runtime_error("conf: The supplied path for the plan definition file is invalid.") {} +/// ConfigLoadException - General exception handler for the Conf class. +class ConfigLoadException: public std::exception +{ +public: + /** Constructor (C strings). + * @param message C-style string error message. + * The string contents are copied upon construction. + * Hence, responsibility for deleting the char* lies + * with the caller. + */ + explicit ConfigLoadException(const char* message): + msg_(message) + { + } + + /** Constructor (C++ STL strings). + * @param message The error message. + */ + explicit ConfigLoadException(const std::string& message): + msg_(message) + {} + + /** Destructor. + * Virtual to allow for subclassing. + */ + virtual ~ConfigLoadException() throw (){} + + /** Returns a pointer to the (constant) error description. + * @return A pointer to a const char*. The underlying memory + * is in posession of the Exception object. Callers must + * not attempt to free the memory. + */ + virtual const char* what() const throw (){ + return msg_.c_str(); + } + +protected: + /** Error message. + */ + std::string msg_; }; -/// CONF_UNITSPATH_INVALID - Exception thrown when the Conf type can not load the supplied path for the Unit definition -/// files. -class CONF_UNITSPATH_INVALID: public std::runtime_error { public: - CONF_UNITSPATH_INVALID(): std::runtime_error("conf: The supplied path for the unit definition file is invalid.") {} -}; /// Conf::Conf - Constructor for Conf type. Loads the configuration for the application. /// TODO Expand to detect when a directory path is supplied for units_path or plan_path and import all Tasks and Units. @@ -37,18 +68,67 @@ class CONF_UNITSPATH_INVALID: public std::runtime_error { public: /// \param filename - The filename to load the configuration from. Conf::Conf( std::string filename, bool verbose ): JSON_Loader() { + // prepare context spaghetti + this->override_context = false; + // load the conf file. this->load_json_file( filename, verbose ); + if (this->get_serialized(this->config_version, "config_version" ,true) != 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 plan file - if (this->get_serialized(this->plan_path, "plan_path", true) != 0 ) { throw CONF_PLANPATH_INVALID(); } + if (this->get_serialized(this->plan_path, "plan_path", true) != 0 ) + { + throw ConfigLoadException("plan_path string is not set in the config file supplied:" + filename); + } // find the path to the unit definitions file - if (this->get_serialized(this->units_path, "units_path", true) != 0 ) { throw CONF_UNITSPATH_INVALID(); } + if (this->get_serialized(this->units_path, "units_path", true) != 0 ) + { + throw ConfigLoadException("units_path string is not set in the config file supplied: " + filename); + } + + if ( this->get_serialized(this->override_execution_context, "execution_context_override", true) != 0 ) + { + throw ConfigLoadException("execution_context_override boolean is not set in the config file supplied: " + filename); + } else { + this->override_context = true; + } + + if ( this->get_serialized(this->execution_context, "execution_context", true) != 0 ) + { + throw ConfigLoadException("execution_context string is not set in the config file supplied: " + filename); + } else { + this->execution_context_literal = this->execution_context.asString(); + } }; +/// 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(); +} + +/// 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; +} + /// Conf::get_plan_path - Retrieves the path to the Plan definition file from the application configuration file. std::string Conf::get_plan_path() { return this->plan_path.asString(); } + /// 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(); } + +/// Conf::set_execution_context- Sets the execution context. +void Conf::set_execution_context( std::string execution_context ) +{ + this->execution_context_literal = execution_context; +} diff --git a/src/loaders/Conf.h b/src/loaders/Conf.h index 5ac3a00..fb0b41a 100644 --- a/src/loaders/Conf.h +++ b/src/loaders/Conf.h @@ -21,17 +21,40 @@ #ifndef FTESTS_CONF_H #define FTESTS_CONF_H #include "JSON_Loader.h" +#include + + +#define STRINGIZE2(s) #s +#define STRINGIZE(s) STRINGIZE2(s) +# define IMPL_CONFIG_VERSION 2 +# 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; + + // flag to indicate if execution context should be overriden in config file + // if set to true Examplar should use whats in the config file for current working directory + // if set to false, Examplar should use the current working directory at time of execution + Json::Value override_execution_context; + + bool override_context; + std::string execution_context_literal; public: Conf( std::string filename, bool verbose ); std::string get_plan_path(); std::string get_units_path(); + + bool has_context_override(); + + std::string get_execution_context(); + void set_execution_context( std::string ); + }; #endif //FTESTS_CONF_H diff --git a/src/loaders/Plan.cpp b/src/loaders/Plan.cpp index 4e72dfe..fd22ddf 100644 --- a/src/loaders/Plan.cpp +++ b/src/loaders/Plan.cpp @@ -120,7 +120,10 @@ protected: /// Plan::Plan() - Constructor for Plan class. A Plan is a managed container for a Task vector. These tasks reference /// Units that are defined in the Units files (Suite). If Units are definitions, Tasks are selections of those /// definitions to execute, and if Units together form a Suite, Tasks together form a Plan. -Plan::Plan(): JSON_Loader() {}; +Plan::Plan( Conf * configuration ): JSON_Loader() +{ + this->configuration = configuration; +}; /// Plan::load_plan_file - Uses the json_root buffer on each run to append intact Units as they're deserialized from /// the provided file. @@ -259,7 +262,7 @@ void Plan::execute( bool verbose ) std::cout << "Executing task \"" << this->tasks[i].get_name() << "\"." << std::endl; } try { - this->tasks[i].execute( verbose ); + this->tasks[i].execute( this->configuration, verbose ); } catch (std::exception& e) { throw Plan_Task_GeneralExecutionException( "Plan Task: \"" + this->tasks[i].get_name() + "\" reported: " + e.what() ); diff --git a/src/loaders/Plan.h b/src/loaders/Plan.h index 6ba1f9c..fb482a4 100644 --- a/src/loaders/Plan.h +++ b/src/loaders/Plan.h @@ -25,15 +25,17 @@ #include "../json/json.h" #include "JSON_Loader.h" #include "Task.h" +#include "Conf.h" class Plan: public JSON_Loader { private: // storage for the tasks that make up the plan std::vector tasks; + Conf * configuration; public: - Plan(); + Plan( Conf * configuration ); // append this->tasks from JSON file void load_plan_file( std::string filename, bool verbose ); diff --git a/src/loaders/Task.cpp b/src/loaders/Task.cpp index 3ef903e..c8257f2 100644 --- a/src/loaders/Task.cpp +++ b/src/loaders/Task.cpp @@ -19,10 +19,10 @@ */ #include "Task.h" -#include #include #include #include "../sproc/Sproc.h" +#include "helpers.h" /// Task_InvalidDataStructure - Exception thrown when a Task is defined with invalid JSON. class Task_InvalidDataStructure: public std::runtime_error { @@ -174,15 +174,10 @@ bool Task::has_definition() return this->defined; } - - - - - /// Task::execute - execute a task's unit definition. /// See the design document for what flow control needs to look like here. /// \param verbose - Verbosity level - not implemented yet. -void Task::execute( bool verbose ) +void Task::execute( Conf * configuration, bool verbose ) { // DUFFING - If Examplar is broken it's probably going to be in this block. // Somebody come clean this up, eh? @@ -199,18 +194,28 @@ void Task::execute( bool verbose ) std::string task_name = this->definition.get_name(); // END PREWORK - // get the target execution command std::string target_command = this->definition.get_target(); // if we're in verbose mode, do some verbose things if ( verbose ) { + infostring = std::ostringstream(); infostring << "\tUsing unit \"" << task_name << "\"." << std::endl; syslog( LOG_INFO, infostring.str().c_str() ); std::cout << infostring.str(); + // check if context override + if ( configuration->has_context_override() ) + { + // if so, set the CWD. + chdir( configuration->get_execution_context().c_str() ); + infostring = std::ostringstream(); + infostring << "\tExecution context: " << get_working_path() << std::endl; + syslog(LOG_INFO, infostring.str().c_str() ); + std::cout << infostring.str(); + } infostring = std::ostringstream(); infostring << "\tExecuting target \"" << target_command << "\"." << std::endl; diff --git a/src/loaders/Task.h b/src/loaders/Task.h index d1f010a..4ae90cc 100644 --- a/src/loaders/Task.h +++ b/src/loaders/Task.h @@ -21,9 +21,11 @@ #ifndef FTESTS_TASK_H #define FTESTS_TASK_H #include +#include #include "../json/json.h" #include "Unit.h" #include "Suite.h" +#include "Conf.h" class Task { @@ -62,7 +64,7 @@ class Task std::string get_name(); // execute this task's definition - void execute( bool verbose ); + void execute( Conf * configuration, bool verbose ); void mark_complete(); diff --git a/src/loaders/helpers.cpp b/src/loaders/helpers.cpp index 5c43862..5176b39 100644 --- a/src/loaders/helpers.cpp +++ b/src/loaders/helpers.cpp @@ -24,4 +24,10 @@ bool exists(const std::string& name) { struct stat buffer; return (stat (name.c_str(), &buffer) == 0); +} + +std::string get_working_path() +{ + char temp[MAXPATHLEN]; + return ( getcwd(temp, MAXPATHLEN) ? std::string( temp ) : std::string("") ); } \ No newline at end of file diff --git a/src/loaders/helpers.h b/src/loaders/helpers.h index 77ff208..d4956cf 100644 --- a/src/loaders/helpers.h +++ b/src/loaders/helpers.h @@ -22,9 +22,12 @@ #define FTESTS_HELPERS_H #include #include +#include +#include + bool exists (const std::string& name); - +std::string get_working_path(); #endif //FTESTS_HELPERS_H