implemented execution context. needs thoroughly tested.

master
Phanes 2017-12-07 22:37:42 -05:00
parent 9d89f5ad6a
commit 46e56b8d6f
10 changed files with 196 additions and 36 deletions

View File

@ -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"
}

View File

@ -23,8 +23,8 @@
#include "src/loaders/loaders.h"
#include <unistd.h>
#include <getopt.h>
#include <syslog.h>
#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 );

View File

@ -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;
}

View File

@ -21,17 +21,40 @@
#ifndef FTESTS_CONF_H
#define FTESTS_CONF_H
#include "JSON_Loader.h"
#include <exception>
#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

View File

@ -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() );

View File

@ -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<Task> tasks;
Conf * configuration;
public:
Plan();
Plan( Conf * configuration );
// append this->tasks from JSON file
void load_plan_file( std::string filename, bool verbose );

View File

@ -19,10 +19,10 @@
*/
#include "Task.h"
#include <unistd.h>
#include <stdio.h>
#include <syslog.h>
#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;

View File

@ -21,9 +21,11 @@
#ifndef FTESTS_TASK_H
#define FTESTS_TASK_H
#include <string>
#include <unistd.h>
#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();

View File

@ -25,3 +25,9 @@ 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("") );
}

View File

@ -22,9 +22,12 @@
#define FTESTS_HELPERS_H
#include <string>
#include <sys/stat.h>
#include <sys/param.h>
#include <unistd.h>
bool exists (const std::string& name);
std::string get_working_path();
#endif //FTESTS_HELPERS_H