Scarab  v3.2.0
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_master_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_master_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_master_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_master_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;
106  std::string f_master_config_addr;
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_master_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_master_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_master_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 
256  class SCARAB_API main_app : public config_decorator, public app
257  {
258  public:
259  main_app();
260  virtual ~main_app();
261 
262  public:
265  virtual void pre_callback();
266 
267  // Functions to perform each configuration stage
269  virtual void do_config_stage_1();
271  virtual void do_config_stage_2();
273  virtual void do_config_stage_3();
275  virtual void do_config_stage_4();
276 
277  void set_version( scarab::version_semantic_ptr_t a_ver );
278 
280  mv_referrable( param_node, master_config );
281 
282  // configuration stage 1
284  mv_referrable( param_node, default_config );
285 
286  // configuration stage 2
288  mv_referrable_const( std::string, config_filename );
289 
290  // configuration stage 3
292  mv_referrable( param_node, nonoption_kw_args );
294  mv_referrable( param_array, nonoption_ord_args );
295 
296  // configuration stage 4
298  mv_referrable( param_node, app_options );
299 
301  mv_referrable( std::vector< std::shared_ptr< app_option_holder > >, app_option_holders );
302 
303  //*************************
304  // Verbosity
305  //*************************
306  public:
308 
310  verbosity_t get_global_verbosity() const;
312  void set_global_verbosity( verbosity_t a_verbosity );
314  void set_global_verbosity( logger::ELevel a_verbosity );
315 
316  void increase_global_verbosity( unsigned an_offset );
317  void decrease_global_verbosity( unsigned an_offset );
318 
319  using verbosity_map_t = std::map< verbosity_t, logger::ELevel >;
320  using verbosity_iterator_t = verbosity_map_t::iterator;
322 
323  protected:
325 
326  };
327 
328 
329  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
331  std::string a_master_config_addr,
332  std::string a_description )
333  {
334  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
335  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
336  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
337  f_main->app_option_holders().push_back( t_opt_holder_ptr );
338  return t_opt_holder_ptr->f_option;
339  }
340 
341  template< typename T, CLI::enable_if_t< ! CLI::is_vector<T>::value, CLI::detail::enabler > >
343  std::string a_master_config_addr,
344  std::string a_description )
345  {
346  auto t_opt_holder_ptr = std::make_shared< app_option_holder_vector_typed<T> >();
347  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
348  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
349  f_main->app_option_holders().push_back( t_opt_holder_ptr );
350  return t_opt_holder_ptr->f_option;
351  }
352 
353  template< typename T, CLI::enable_if_t< std::is_integral<T>::value && ! CLI::is_bool<T>::value, CLI::detail::enabler > >
355  std::string a_master_config_addr,
356  std::string a_description )
357  {
358  auto t_opt_holder_ptr = std::make_shared< app_option_holder_typed<T> >();
359  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
360  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
361  f_main->app_option_holders().push_back( t_opt_holder_ptr );
362  return t_opt_holder_ptr->f_option;
363  }
364 
365  template< typename T, CLI::enable_if_t< CLI::is_bool<T>::value, CLI::detail::enabler > >
366  CLI::Option* config_decorator::add_config_flag( std::string a_name,
367  std::string a_master_config_addr,
368  std::string a_description )
369  {
370  auto t_opt_holder_ptr = std::make_shared< app_option_holder_bool_flag >();
371  t_opt_holder_ptr->f_option = f_this->add_flag( a_name, a_description ); // throws CLI::OptionAlreadyAdded if the option's already there
372  t_opt_holder_ptr->f_master_config_addr = a_master_config_addr;
373  f_main->app_option_holders().push_back( t_opt_holder_ptr );
374  return t_opt_holder_ptr->f_option;
375  }
376 
377  inline app* config_decorator::this_app() const
378  {
379  return f_this;
380  }
381 
383  {
384  return f_main;
385  }
386 
387 } /* namespace scarab */
388 
389 #endif /* SCARAB_APPLICATION_HH_ */
void merge(const param_node &a_object)
Definition: param_node.cc:90
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:319
verbosity_iterator_t f_global_verbosity
Definition: application.hh:324
std::underlying_type< logger::ELevel >::type verbosity_t
Definition: application.hh:307
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
enabler
Simple empty scoped class.
Definition: CLI11.hpp:907
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
Adds the ability to create options and subcommands that are tied to a main_app&#39;s master config...
Definition: application.hh:55
CLI::Option * add_config_flag(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Definition: application.hh:354
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
CLI::Option * add_config_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:330
CLI::Option * add_config_multi_option(std::string a_name, std::string a_master_config_addr, std::string a_description="")
Add an option that gets automatically added to the master config of a main_app.
Definition: application.hh:342
static verbosity_map_t s_verbosities
Definition: application.hh:321
std::unique_ptr< param > param_ptr_t
Definition: param_base.hh:23
#define mv_referrable_const
Primary application class.
Definition: application.hh:256
verbosity_map_t::iterator verbosity_iterator_t
Definition: application.hh:320
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:382