Scarab  v3.9.4
Project 8 C++ Utility Library
application.cc
Go to the documentation of this file.
1 /*
2  * application.cc
3  *
4  * Created on: Jul 20, 2018
5  * Author: N.S. Oblath
6  */
7 
8 #define SCARAB_API_EXPORTS
9 
10 #include "application.hh"
11 
12 #include "nonoption_parser.hh"
13 #include "param_codec.hh"
14 #include "version_wrapper.hh"
15 
16 using std::string;
17 
18 LOGGER(applog, "application");
19 
20 namespace scarab
21 {
22 
24  f_main( a_main ),
25  f_this( a_this_app ),
26  f_subcommand_decorators()
27  {
28  }
29 
31  {
32  }
33 
34  config_decorator* config_decorator::add_config_subcommand( std::string a_subcommand_name, std::string a_description )
35  {
36  app* t_subcommand = f_this->add_subcommand( a_subcommand_name, a_description );
37  //config_decorator* t_decorator = new config_decorator( f_main, t_subcommand );
38  f_subcommand_decorators.emplace_back( new config_decorator( f_main, t_subcommand ) );
39  return f_subcommand_decorators.back().get();
40  }
41 
42 
43  // utility function to fill the verbosity map
45  {
47  // have to hard-code the filling of the verbosity map because you can't iterate over an enum
55  return t_map;
56  }
57 
59 
60  main_app::main_app( bool a_use_config ) :
61  config_decorator( this, this ),
62  app(),
63  f_primary_config(),
64  f_default_config(),
65  f_config_filename(),
66  f_nonoption_kw_args(),
67  f_nonoption_ord_args(),
68  f_app_options(),
69  f_app_option_holders(),
70  f_use_config( a_use_config )
71  {
73 
74  allow_extras(); // allow unrecognized options, which are parsed into the nonoption args
75 
76  if( f_use_config )
77  {
78  add_option( "-c,--config", f_config_filename, "Config file filename" )->check(CLI::ExistingFile);
79  }
80 
81  auto t_verbose_callback = [this]( unsigned a_count )
82  {
83  this->increase_global_verbosity( a_count );
84  };
85  add_flag_function( "-v,--verbose", t_verbose_callback, "Increase verbosity" );
86 
87  auto t_quiet_callback = [this]( unsigned a_count )
88  {
89  this->decrease_global_verbosity( a_count );
90  };
91  add_flag_function( "-q,--quiet", t_quiet_callback, "Decrease verbosity" );
92 
93  auto t_version_callback = [](int)
94  {
95  LPROG( applog, '\n' << version_wrapper::get_instance()->version_info_string() );
96  throw CLI::Success();
97  };
98  add_flag_function( "-V,--version", t_version_callback, "Print the version message and exit" );
99  }
100 
102  {
103  }
104 
106  {
108  }
109 
111  {
112  if( f_use_config )
113  {
115 
117 
118  try
119  {
120  nonoption_parser t_no_parser( remaining() );
121  f_nonoption_kw_args = t_no_parser.kw_args();
122  f_nonoption_ord_args = t_no_parser.ord_args();
123  }
124  catch( error& e )
125  {
126  LERROR( applog, "Unable to parse remaining arguments: " << e.what() );
127  throw CLI::ParseError( std::string("Unable to parse remaining arguments due to parse error or unknown option: ") + e.what(), CLI::ExitCodes::ArgumentMismatch );
128  }
129 
131 
133 
134  LPROG( applog, "Final configuration:\n" << f_primary_config );
135  LPROG( applog, "Ordered args:\n" << f_nonoption_ord_args );
136  }
137  return;
138  }
139 
141  {
142  // first configuration stage: defaults
143 
144  if( ! f_use_config ) return;
145 
146  LDEBUG( applog, "first configuration stage" );
147  f_primary_config.merge( f_default_config );
148  return;
149  }
150 
152  {
153  // second configuration stage: config file
154 
155  if( ! f_use_config ) return;
156 
157  LDEBUG( applog, "second configuration stage" );
158  if( ! f_config_filename.empty() )
159  {
160  path t_config_filepath = scarab::expand_path( f_config_filename );
161  LDEBUG( applog, "Loading config file <" << t_config_filepath << "> from filename <" << f_config_filename << ">" );
162  param_translator t_translator;
163  std::unique_ptr< param > t_config_from_file( t_translator.read_file( t_config_filepath.string() ));
164  if( t_config_from_file == NULL )
165  {
166  throw error() << "[application] error parsing config file";
167  }
168  if( ! t_config_from_file->is_node() )
169  {
170  throw error() << "[application] configuration file must consist of an object/node";
171  }
172  f_primary_config.merge( t_config_from_file->as_node() );
173  }
174  return;
175  }
176 
178  {
179  // third configuration stage: keyword args
180 
181  if( ! f_use_config ) return;
182 
183  LDEBUG( applog, "third configuration stage" );
184  f_primary_config.merge( f_nonoption_kw_args );
185  return;
186  }
187 
189  {
190  // fourth configuration stage: application options
191 
192  if( ! f_use_config ) return;
193 
194  std::for_each( f_app_option_holders.begin(), f_app_option_holders.end(),
195  [this]( std::shared_ptr< app_option_holder > a_ptr ){ a_ptr->add_to_app_options(f_app_options); } );
196  f_primary_config.merge( f_app_options );
197  return;
198  }
199 
201  {
202  return f_global_verbosity->first;
203  }
204 
206  {
207  auto t_it = s_verbosities.find( a_verbosity );
208 
209  // if we don't match a value, then find the next higher value
210  if( t_it == s_verbosities.end() )
211  {
212  t_it = s_verbosities.upper_bound( a_verbosity );
213  // make sure we don't go off the end
214  if( t_it == s_verbosities.end() ) t_it = std::prev(s_verbosities.end());
215  }
216 
217  f_global_verbosity = t_it;
218 
219  // set the global verbosity in the logger
221  return;
222  }
223 
225  {
226  set_global_verbosity( static_cast< verbosity_t >(a_verbosity) );
227  return;
228  }
229 
230  void main_app::increase_global_verbosity( unsigned an_offset )
231  {
232  // increased verbosity is lower in verbosity number
233  if( an_offset == 0 ) return;
234  // Move down, but don't go past the beginning
235  for( unsigned i_count = 0; i_count < an_offset; ++i_count )
236  {
237  if( f_global_verbosity == s_verbosities.begin() ) break;
239  }
240  // set the global verbosity in the logger
241  applog.SetGlobalLevel( f_global_verbosity->second );
242  return;
243  }
244 
245  void main_app::decrease_global_verbosity( unsigned an_offset )
246  {
247  // decreased verbosity is higher in verbosity number
248  if( an_offset == 0 ) return;
249  // Move up, but not past the end
250  for( unsigned i_count = 0; i_count < an_offset; ++i_count )
251  {
252  if( std::next(f_global_verbosity) == s_verbosities.end() ) break;
254  }
255  // set the global verbosity in the logger
256  applog.SetGlobalLevel( f_global_verbosity->second );
257  return;
258  }
259 
260 
261 } /* namespace scarab */
config_decorator * add_config_subcommand(std::string a_subcommand_name, std::string a_description="")
Add a subcommand that is linked to a particular main_app and can create options that modify that main...
Definition: application.cc:34
void increase_global_verbosity(unsigned an_offset)
Definition: application.cc:230
fs::path path
Definition: path.hh:26
void decrease_global_verbosity(unsigned an_offset)
Definition: application.cc:245
std::map< verbosity_t, logger::ELevel > verbosity_map_t
Definition: application.hh:326
verbosity_t get_global_verbosity() const
Get the global verbosity.
Definition: application.cc:200
path expand_path(const string &a_path)
Definition: path.cc:20
verbosity_iterator_t f_global_verbosity
Definition: application.hh:331
std::underlying_type< logger::ELevel >::type verbosity_t
Definition: application.hh:314
main_app(bool a_use_config=true)
Definition: application.cc:60
config_decorator(main_app *a_main, app *a_this_app)
Definition: application.cc:23
void set_global_verbosity(verbosity_t a_verbosity)
Set the global verbosity with the verbosity value.
Definition: application.cc:205
Option * add_option(std::string option_name, callback_t option_callback, std::string option_description="", bool defaulted=false, std::function< std::string()> func={})
Definition: CLI11.hpp:4074
std::shared_ptr< version_semantic > version_semantic_ptr_t
static version_wrapper * get_instance()
Definition: singleton.hh:80
void set_version(scarab::version_semantic_ptr_t a_ver)
Definition: application.cc:105
#define LPROG(...)
Definition: logger.hh:392
#define LERROR(...)
Definition: logger.hh:394
void set_imp(version_semantic_ptr_t a_imp)
virtual void do_config_stage_4()
Load the application-specific options.
Definition: application.cc:188
Option * add_flag_function(std::string flag_name, std::function< void(int64_t)> function, std::string flag_description="")
Add option for callback with an integer value.
Definition: CLI11.hpp:4370
virtual const char * what() const noexcept
virtual void do_config_stage_1()
Load default values.
Definition: application.cc:140
LOGGER(applog, "application")
virtual void do_config_stage_2()
Load the config file.
Definition: application.cc:151
std::vector< std::string > remaining(bool recurse=false) const
This returns the missing options from the current subcommand.
Definition: CLI11.hpp:5383
Adds the ability to create options and subcommands that are tied to a main_app&#39;s primary config...
Definition: application.hh:55
virtual void pre_callback()
Definition: application.cc:110
Creates a command line program, with very few defaults.
Definition: CLI11.hpp:3696
#define LDEBUG(...)
Definition: logger.hh:389
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:164
param_ptr_t read_file(const std::string &a_filename, const param_node &a_options=param_node())
Definition: param_codec.cc:47
const detail::ExistingFileValidator ExistingFile
Check for existing file (returns error message if check fails)
Definition: CLI11.hpp:1860
static verbosity_map_t s_verbosities
Definition: application.hh:328
This is a successful completion on parsing, supposed to exit.
Definition: CLI11.hpp:723
virtual ~main_app()
Definition: application.cc:101
Primary application class.
Definition: application.hh:261
Anything that can error in Parse.
Definition: CLI11.hpp:716
App * add_subcommand(std::string subcommand_name="", std::string subcommand_description="")
Add a subcommand. Inherits INHERITABLE and OptionDefaults, and help flag.
Definition: CLI11.hpp:4691
App * allow_extras(bool allow=true)
Remove the error when extras are left over on the command line.
Definition: CLI11.hpp:3940
Option * check(Validator validator, std::string validator_name="")
Adds a Validator with a built in type name.
Definition: CLI11.hpp:2992
virtual void do_config_stage_3()
Load the directly-addressed non-option arguments.
Definition: application.cc:177
main_app::verbosity_map_t fill_verbosities()
Definition: application.cc:44
static void SetGlobalLevel(ELevel level)
Definition: logger.cc:303