Scarab  v2.0.1
Project 8 C++ Utility Library
configurator.cc
Go to the documentation of this file.
1 /*
2  * configurator.cc
3  *
4  * Created on: Nov 5, 2013
5  * Author: nsoblath
6  */
7 
8 #include "configurator.hh"
9 
10 #include "logger.hh"
11 #include "param_codec.hh"
12 #include "parser.hh"
13 #include "path.hh"
14 
15 #ifdef USE_CODEC_JSON
16 #include "param_json.hh"
17 #endif
18 
19 #ifdef __APPLE__
20 #include <mach-o/dyld.h>
21 #elif __linux
22 #include <unistd.h> // for readlink
23 #endif
24 
25 using std::string;
26 
27 namespace scarab
28 {
29  LOGGER( slog, "configurator" );
30 
31  configurator::configurator( int an_argc, char** an_argv, param_node* a_default ) :
32  f_exe_name( "unknown" ),
33  f_master_config( new param_node() ),
34  f_help_flag( false ),
35  f_version_flag( false ),
36  f_param_buffer( NULL ),
37  f_string_buffer()
38  {
39  parser t_parser( an_argc, an_argv );
40  //std::cout << "options parsed" << std::endl;
41  //cout << t_parser );
42 
43  // first configuration: defaults
44  if ( a_default != NULL )
45  {
46  f_master_config->merge( *a_default );
47  }
48 
49  //std::cout << "first configuration complete" << std::endl;
50  //cout << f_master_config );
51  //cout << t_parser );
52 
53  string t_name_logger( "logger" );
54  string t_name_exe( "executable" ); // the name used to specify the executable in parser
55  string t_name_config( "config" );
56  string t_name_json( "json" );
57 
58  if( t_parser.has( t_name_logger ) )
59  {
60  try
61  {
62  slog.SetGlobalLevel( (logger::ELevel)t_parser[t_name_logger]["verbosity"]().get< unsigned >() );
63  }
64  catch( std::exception& e ) {}
65  }
66 
67  // name of executable
68  //f_exe_name = t_parser.get_value( t_name_exe, f_exe_name );
69 #ifdef __APPLE__
70  char t_exe_buf[ 2048 ];
71  uint32_t t_bufsize = sizeof( t_exe_buf );
72  if( _NSGetExecutablePath( t_exe_buf, &t_bufsize ) != 0 )
73 #elif __linux
74  const size_t t_bufsize = 2048;
75  char t_exe_buf[ t_bufsize ];
76  if( readlink( "/proc/self/exe", t_exe_buf, t_bufsize ) < 0 )
77 #endif
78  {
79  LWARN( slog, "Could not retrieve executable file name" );
80 #ifdef __APPLE__
81  LWARN( slog, "Executable name buffer is too small; needs size %u\n" << t_bufsize );
82 #endif
83  }
84  f_exe_name = string( t_exe_buf );
85 
86  // second configuration: config file
87  if( t_parser.has( t_name_config ) )
88  {
89  path t_config_filename = scarab::expand_path( t_parser.get_value( t_name_config ) );
90  if( ! t_config_filename.empty() )
91  {
92  param_translator t_translator;
93  param* t_config_from_file = t_translator.read_file( t_config_filename.native() );
94  if( t_config_from_file == NULL )
95  {
96  throw error() << "[configurator] error parsing config file";
97  }
98  if( ! t_config_from_file->is_node() )
99  {
100  throw error() << "[configurator] configuration file must consist of an object/node";
101  }
102  f_master_config->merge( t_config_from_file->as_node() );
103  delete t_config_from_file;
104  }
105  }
106 
107  //std::cout << "second configuration complete" << std::endl;
108  //cout << f_master_config );
109  //cout << t_parser );
110 
111 #ifdef USE_CODEC_JSON
112  // third configuration: command line json
113  if( t_parser.has( t_name_json ) )
114  {
115  string t_config_json = t_parser.get_value( t_name_json );
116  if( ! t_config_json.empty() )
117  {
118  param_input_json t_input_json;
119  param* t_config_from_json = t_input_json.read_string( t_config_json );
120  if( ! t_config_from_json->is_node() )
121  {
122  throw error() << "[configurator] command line json must be an object";
123  }
124  f_master_config->merge( t_config_from_json->as_node() );
125  delete t_config_from_json;
126  }
127  }
128 #endif
129 
130  //std::cout << "third configuration complete" << std::endl;
131  //cout << f_master_config );
132  //cout << t_parser );
133 
134  // fourth configuration: command line arguments
135  t_parser.erase( t_name_exe );
136  t_parser.erase( t_name_config );
137  t_parser.erase( t_name_json );
138 
139  //std::cout << "removed config and json from parsed options" << std::endl;
140  //cout << t_parser );
141  //LDEBUG( slog, "adding command-line parser:\n" << t_parser << *f_master_config );
142  f_master_config->merge( t_parser );
143 
144  // check for help and version flags
145  if( f_master_config->has( "help" ) )
146  {
147  f_help_flag = true;
148  f_master_config->erase( "help" );
149  }
150  if( f_master_config->has( "version" ) )
151  {
152  f_version_flag = true;
153  f_master_config->erase( "version" );
154  }
155 
156  //std::cout << "fourth configuration complete" << std::endl;
157  LPROG( slog, "Final configuration:\n" << *f_master_config );
158  }
159 
161  {
162  delete f_master_config;
163  }
164 
165 } /* namespace scarab */
virtual bool is_node() const
void merge(const param_node &a_object)
Definition: param_node.cc:67
#define LWARN(...)
Definition: logger.hh:364
fs::path path
Definition: path.hh:25
void erase(const std::string &a_name)
Definition: param_node.hh:326
path expand_path(const string &a_path)
Definition: path.cc:19
#define LPROG(...)
Definition: logger.hh:363
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
std::string get_value(const std::string &a_name) const
Definition: param_node.hh:225
Convert JSON to Param.
Definition: param_json.hh:43
bool has(const std::string &a_name) const
Definition: param_node.hh:215
virtual param * read_string(const std::string &a_json_str, const param_node *a_options=nullptr)
Definition: param_json.cc:90
scarab::param_node * f_master_config
Definition: configurator.hh:39
param_node & as_node()
configurator(int an_argc, char **an_argv, scarab::param_node *a_default=NULL)
Definition: configurator.cc:31
std::string f_exe_name
Definition: configurator.hh:37
LOGGER(mtlog,"authentication")
param * read_file(const std::string &a_filename, const param_node *a_options=nullptr)
Definition: param_codec.cc:48