Scarab  v3.2.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 
61  config_decorator( this, this ),
62  app(),
63  f_master_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  {
72 
73  allow_extras(); // allow unrecognized options, which are parsed into the nonoption args
74 
75  add_option( "-c,--config", f_config_filename, "Config file filename" )->check(CLI::ExistingFile);
76 
77  auto t_verbose_callback = [this]( unsigned a_count )
78  {
79  this->increase_global_verbosity( a_count );
80  };
81  add_flag_function( "-v,--verbose", t_verbose_callback, "Increase verbosity" );
82 
83  auto t_quiet_callback = [this]( unsigned a_count )
84  {
85  this->decrease_global_verbosity( a_count );
86  };
87  add_flag_function( "-q,--quiet", t_quiet_callback, "Decrease verbosity" );
88 
89  auto t_version_callback = [](int)
90  {
91  LPROG( applog, '\n' << version_wrapper::get_instance()->version_info_string() );
92  throw CLI::Success();
93  };
94  add_flag_function( "-V,--version", t_version_callback, "Print the version message and exit" );
95  }
96 
98  {
99  }
100 
102  {
104  }
105 
107  {
109 
111 
112  try
113  {
114  nonoption_parser t_no_parser( remaining() );
115  f_nonoption_kw_args = t_no_parser.kw_args();
116  f_nonoption_ord_args = t_no_parser.ord_args();
117  }
118  catch( error& e )
119  {
120  LERROR( applog, "Unable to parse remaining arguments: " << e.what() );
121  throw CLI::ParseError( std::string("Unable to parse remaining arguments due to parse error or unknown option: ") + e.what(), CLI::ExitCodes::ArgumentMismatch );
122  }
123 
125 
127 
128  LPROG( applog, "Final configuration:\n" << f_master_config );
129  LPROG( applog, "Ordered args:\n" << f_nonoption_ord_args );
130  }
131 
133  {
134  // first configuration stage: defaults
135  LDEBUG( applog, "first configuration stage" );
136  f_master_config.merge( f_default_config );
137  return;
138  }
139 
141  {
142  // second configuration stage: config file
143  LDEBUG( applog, "second configuration stage" );
144  if( ! f_config_filename.empty() )
145  {
146  path t_config_filepath = scarab::expand_path( f_config_filename );
147  LDEBUG( applog, "Loading config file <" << t_config_filepath << "> from filename <" << f_config_filename << ">" );
148  param_translator t_translator;
149  std::unique_ptr< param > t_config_from_file( t_translator.read_file( t_config_filepath.string() ));
150  if( t_config_from_file == NULL )
151  {
152  throw error() << "[application] error parsing config file";
153  }
154  if( ! t_config_from_file->is_node() )
155  {
156  throw error() << "[application] configuration file must consist of an object/node";
157  }
158  f_master_config.merge( t_config_from_file->as_node() );
159  }
160  return;
161  }
162 
164  {
165  // third configuration stage: keyword args
166  LDEBUG( applog, "third configuration stage" );
167  f_master_config.merge( f_nonoption_kw_args );
168  return;
169  }
170 
172  {
173  // fourth configuration stage: application options
174  std::for_each( f_app_option_holders.begin(), f_app_option_holders.end(),
175  [this]( std::shared_ptr< app_option_holder > a_ptr ){ a_ptr->add_to_app_options(f_app_options); } );
176  f_master_config.merge( f_app_options );
177  return;
178  }
179 
181  {
182  return f_global_verbosity->first;
183  }
184 
186  {
187  auto t_it = s_verbosities.find( a_verbosity );
188 
189  // if we don't match a value, then find the next higher value
190  if( t_it == s_verbosities.end() )
191  {
192  t_it = s_verbosities.upper_bound( a_verbosity );
193  // make sure we don't go off the end
194  if( t_it == s_verbosities.end() ) t_it = std::prev(s_verbosities.end());
195  }
196 
197  f_global_verbosity = t_it;
198 
199  // set the global verbosity in the logger
200  applog.SetGlobalLevel( f_global_verbosity->second );
201  return;
202  }
203 
205  {
206  set_global_verbosity( static_cast< verbosity_t >(a_verbosity) );
207  return;
208  }
209 
210  void main_app::increase_global_verbosity( unsigned an_offset )
211  {
212  // increased verbosity is lower in verbosity number
213  if( an_offset == 0 ) return;
214  // Move down, but don't go past the beginning
215  for( unsigned i_count = 0; i_count < an_offset; ++i_count )
216  {
217  if( f_global_verbosity == s_verbosities.begin() ) break;
219  }
220  // set the global verbosity in the logger
221  applog.SetGlobalLevel( f_global_verbosity->second );
222  return;
223  }
224 
225  void main_app::decrease_global_verbosity( unsigned an_offset )
226  {
227  // decreased verbosity is higher in verbosity number
228  if( an_offset == 0 ) return;
229  // Move up, but not past the end
230  for( unsigned i_count = 0; i_count < an_offset; ++i_count )
231  {
232  if( std::next(f_global_verbosity) == s_verbosities.end() ) break;
234  }
235  // set the global verbosity in the logger
236  applog.SetGlobalLevel( f_global_verbosity->second );
237  return;
238  }
239 
240 
241 } /* 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:210
fs::path path
Definition: path.hh:25
void decrease_global_verbosity(unsigned an_offset)
Definition: application.cc:225
std::map< verbosity_t, logger::ELevel > verbosity_map_t
Definition: application.hh:319
verbosity_t get_global_verbosity() const
Get the global verbosity.
Definition: application.cc:180
path expand_path(const string &a_path)
Definition: path.cc:19
verbosity_iterator_t f_global_verbosity
Definition: application.hh:324
std::underlying_type< logger::ELevel >::type verbosity_t
Definition: application.hh:307
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:185
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:101
#define LPROG(...)
Definition: logger.hh:380
#define LERROR(...)
Definition: logger.hh:382
void set_imp(version_semantic_ptr_t a_imp)
virtual void do_config_stage_4()
Load the application-specific options.
Definition: application.cc:171
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 void do_config_stage_1()
Load default values.
Definition: application.cc:132
LOGGER(applog, "application")
virtual void do_config_stage_2()
Load the config file.
Definition: application.cc:140
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 master config...
Definition: application.hh:55
virtual void pre_callback()
Definition: application.cc:106
Creates a command line program, with very few defaults.
Definition: CLI11.hpp:3696
#define LDEBUG(...)
Definition: logger.hh:377
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:321
This is a successful completion on parsing, supposed to exit.
Definition: CLI11.hpp:723
virtual ~main_app()
Definition: application.cc:97
Primary application class.
Definition: application.hh:256
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:163
main_app::verbosity_map_t fill_verbosities()
Definition: application.cc:44
virtual const char * what() const noexcept