Scarab  v3.5.4
Project 8 C++ Utility Library
application.hh
Go to the documentation of this file.
1 /*
2  * application.hh
3  *
4  * Created on: Jul 20, 2018
5  * Author: N.S. Oblath
6  */
7 
8 #ifndef SCARAB_APPLICATION_HH_
9 #define SCARAB_APPLICATION_HH_
10 
11 #include "CLI11.hpp"
12 
13 #include "logger.hh"
14 #include "member_variables.hh"
15 #include "param_helpers.hh"
16 #include "version_semantic.hh"
17 
18 #include <type_traits>
19 
20 namespace scarab
21 {
22  typedef CLI::App app;
23 
24  class version_semantic;
25 
26  class main_app;
27 
56  {
57  public:
58  config_decorator( main_app* a_main, app* a_this_app );
59  config_decorator( const config_decorator& ) = delete;
60  config_decorator( config_decorator&& ) = delete;
61  virtual ~config_decorator();
62 
63  config_decorator& operator=( const config_decorator& ) = delete;
64  config_decorator& operator=( config_decorator&& ) = delete;
65 
66  main_app* main() const;
67  app* this_app() const;
68 
70  config_decorator* add_config_subcommand( std::string a_subcommand_name, std::string a_description="" );
71 
73  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
74  CLI::Option* add_config_option( std::string a_name,
75  std::string a_primary_config_addr,
76  std::string a_description = "" );
77 
79  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
80  CLI::Option* add_config_multi_option( std::string a_name,
81  std::string a_primary_config_addr,
82  std::string a_description = "" );
83 
86  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
87  CLI::Option* add_config_flag( std::string a_name,
88  std::string a_primary_config_addr,
89  std::string a_description = "" );
90 
93  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > = CLI::detail::dummy >
94  CLI::Option* add_config_flag( std::string a_name,
95  std::string a_primary_config_addr,
96  std::string a_description = "" );
97 
98  public:
99  // these structs provide a type erasure mechanism that:
100  // - holds the actual value provided on the CL, and
101  // - adds the value to the f_app_options, and then to the global config, from the pre_callback function
103  {
104  virtual void add_to_app_options( param_node& a_app_options ) = 0;
107  virtual ~app_option_holder() {}
108  };
109 
110  template< typename T >
112  {
113  void add_to_app_options( param_node& a_app_options )
114  {
115  if( ! (*f_option) ) return;
116  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
117  f_primary_config_addr,
118  param_ptr_t( new param_value(f_value) ) ); // throws scarab::error if top-level param object is not a node
119  a_app_options.merge( t_new_config_ptr->as_node() );
120  return;
121  }
124  };
125 
126  template< typename T >
128  {
129  void add_to_app_options( param_node& a_app_options )
130  {
131  if( ! (*f_option) ) return;
132  param_array t_array;
133  std::for_each( f_values.begin(), f_values.end(), [&t_array]( T a_value ){ t_array.push_back( a_value ); } );
134  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
135  f_primary_config_addr,
136  param_ptr_t( new param_array(std::move(t_array)) ) ); // throws scarab::error if top-level param object is not a node
137  a_app_options.merge( t_new_config_ptr->as_node() );
138  return;
139  }
140  std::vector< T > f_values;
142  };
143 
145  {
146  void add_to_app_options( param_node& a_app_options )
147  {
148  if( ! (*f_option) ) return;
149  param_ptr_t t_new_config_ptr = simple_parser::parse_address(
150  f_primary_config_addr,
151  param_ptr_t( new param_value(*f_option) ) ); // throws scarab::error if top-level param object is not a node
152  a_app_options.merge( t_new_config_ptr->as_node() );
153  return;
154  }
156  };
157 
158  protected:
160  app* f_this;
161 
162  // config_decorator owns the decorators of subcommands just like app owns the apps of subcommands
163  using conf_dec_ptr_t = std::unique_ptr< config_decorator >;
164  std::vector< conf_dec_ptr_t > f_subcommand_decorators;
165  };
166 
167 
261  class SCARAB_API main_app : public config_decorator, public app
262  {
263  public:
264  main_app( bool a_use_config = true );
265  virtual ~main_app();
266 
267  public:
270  virtual void pre_callback();
271 
272  // Functions to perform each configuration stage
274  virtual void do_config_stage_1();
276  virtual void do_config_stage_2();
278  virtual void do_config_stage_3();
280  virtual void do_config_stage_4();
281 
282  void set_version( scarab::version_semantic_ptr_t a_ver );
283 
285  mv_referrable( param_node, primary_config );
286 
287  // configuration stage 1
289  mv_referrable( param_node, default_config );
290 
291  // configuration stage 2
293  mv_referrable_const( std::string, config_filename );
294 
295  // configuration stage 3
297  mv_referrable( param_node, nonoption_kw_args );
299  mv_referrable( param_array, nonoption_ord_args );
300 
301  // configuration stage 4
303  mv_referrable( param_node, app_options );
304 
306  mv_referrable( std::vector< std::shared_ptr< app_option_holder > >, app_option_holders );
307 
308  mv_accessible_noset( bool, use_config );
309 
310  //*************************
311  // Verbosity
312  //*************************
313  public:
315 
317  verbosity_t get_global_verbosity() const;
319  void set_global_verbosity( verbosity_t a_verbosity );
321  void set_global_verbosity( logger::ELevel a_verbosity );
322 
323  void increase_global_verbosity( unsigned an_offset );
324  void decrease_global_verbosity( unsigned an_offset );
325 
326  using verbosity_map_t = std::map< verbosity_t, logger::ELevel >;
327  using verbosity_iterator_t = verbosity_map_t::iterator;
329 
330  protected:
332 
333  };
334 
335 
336  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
338  std::string a_primary_config_addr,
339  std::string a_description )
340  {
341  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
342  t_opt_holder_ptr->f_option = f_this->add_option( a_name, t_opt_holder_ptr->f_value, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
343  t_opt_holder_ptr->f_primary_config_addr = a_primary_config_addr;
344  f_main->app_option_holders().push_back( t_opt_holder_ptr );
345  return t_opt_holder_ptr->f_option;
346  }
347 
348  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
350  std::string a_primary_config_addr,
351  std::string a_description )
352  {
353  auto t_opt_holder_ptr = std::make_shared< app_option_holder_vector_typed<T> >();
354  t_opt_holder_ptr->f_option = f_this->add_option( a_name, t_opt_holder_ptr->f_values, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
355  t_opt_holder_ptr->f_primary_config_addr = a_primary_config_addr;
356  f_main->app_option_holders().push_back( t_opt_holder_ptr );
357  return t_opt_holder_ptr->f_option;
358  }
359 
360  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > >
362  std::string a_primary_config_addr,
363  std::string a_description )
364  {
365  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
366  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, t_opt_holder_ptr->f_value, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
367  t_opt_holder_ptr->f_primary_config_addr = a_primary_config_addr;
368  f_main->app_option_holders().push_back( t_opt_holder_ptr );
369  return t_opt_holder_ptr->f_option;
370  }
371 
372  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > >
373  CLI::Option* config_decorator::add_config_flag( std::string a_name,
374  std::string a_primary_config_addr,
375  std::string a_description )
376  {
377  auto t_opt_holder_ptr = std::make_shared< app_option_holder_bool_flag >();
378  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
379  t_opt_holder_ptr->f_primary_config_addr = a_primary_config_addr;
380  f_main->app_option_holders().push_back( t_opt_holder_ptr );
381  return t_opt_holder_ptr->f_option;
382  }
383 
384  inline app* config_decorator::this_app() const
385  {
386  return f_this;
387  }
388 
390  {
391  return f_main;
392  }
393 
394 } /* namespace scarab */
395 
396 #endif /* SCARAB_APPLICATION_HH_ */
void merge(const param_node &a_object)
Definition: param_node.cc:90
CLI::Option * add_config_multi_option(std::string a_name, std::string a_primary_config_addr, std::string a_description="")
Add an option that gets automatically added to the primary config of a main_app.
Definition: application.hh:349
constexpr enabler dummy
An instance to use in EnableIf.
Definition: CLI11.hpp:910
std::map< verbosity_t, logger::ELevel > verbosity_map_t
Definition: application.hh:326
verbosity_iterator_t f_global_verbosity
Definition: application.hh:331
std::underlying_type< logger::ELevel >::type verbosity_t
Definition: application.hh:314
static param_ptr_t parse_address(const std::string &an_addr, param_ptr_t a_value=param_ptr_t())
Converts an address into a nested param structure, and optionally attaches a value.
#define SCARAB_API
Definition: scarab_api.hh:24
std::shared_ptr< version_semantic > version_semantic_ptr_t
CLI::App app
Definition: application.hh:22
std::string type(const x_type &a_param)
Definition: typename.hh:24
std::unique_ptr< config_decorator > conf_dec_ptr_t
Definition: application.hh:163
#define mv_accessible_noset
enabler
Simple empty scoped class.
Definition: CLI11.hpp:907
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
CLI::Option * add_config_flag(std::string a_name, std::string a_primary_config_addr, std::string a_description="")
Definition: application.hh:361
Adds the ability to create options and subcommands that are tied to a main_app&#39;s primary config...
Definition: application.hh:55
Creates a command line program, with very few defaults.
Definition: CLI11.hpp:3696
#define mv_referrable
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:164
Check to see if something is bool (fail check by default)
Definition: CLI11.hpp:936
static verbosity_map_t s_verbosities
Definition: application.hh:328
std::unique_ptr< param > param_ptr_t
Definition: param_base.hh:23
CLI::Option * add_config_option(std::string a_name, std::string a_primary_config_addr, std::string a_description="")
Add an option that gets automatically added to the primary config of a main_app.
Definition: application.hh:337
#define mv_referrable_const
Primary application class.
Definition: application.hh:261
verbosity_map_t::iterator verbosity_iterator_t
Definition: application.hh:327
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:146
void push_back(const param &a_value)
Definition: param_array.hh:238
void add_to_app_options(param_node &a_app_options)
Definition: application.hh:113
main_app * main() const
Definition: application.hh:389