Scarab  v2.4.9
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 "logger.hh"
13 #include "nonoption_parser.hh"
14 #include "param_codec.hh"
15 #include "version_wrapper.hh"
16 
17 using std::string;
18 
19 LOGGER(applog, "application");
20 
21 namespace scarab
22 {
23 
25  f_main( a_main ),
26  f_this( a_this_app ),
27  f_subcommand_decorators()
28  {
29  }
30 
32  {
33  }
34 
35  config_decorator* config_decorator::add_config_subcommand( std::string a_subcommand_name, std::string a_description )
36  {
37  app* t_subcommand = f_this->add_subcommand( a_subcommand_name, a_description );
38  //config_decorator* t_decorator = new config_decorator( f_main, t_subcommand );
39  f_subcommand_decorators.emplace_back( new config_decorator( f_main, t_subcommand ) );
40  return f_subcommand_decorators.back().get();
41  }
42 
43 
45  config_decorator( this, this ),
46  app(),
47  f_master_config(),
48  f_default_config(),
49  f_config_filename(),
50  f_global_verbosity( 1 ),
51  f_nonoption_kw_args(),
52  f_nonoption_ord_args(),
53  f_app_options(),
54  f_app_option_holders()
55  {
56  allow_extras(); // allow unrecognized options, which are parsed into the nonoption args
57 
58  add_option( "-c,--config", f_config_filename, "Config file filename" )->check(CLI::ExistingFile);
59  add_option( "--verbosity", f_global_verbosity, "Global logger verosity" );
60 
61  auto t_version_callback = [](int)
62  {
63  LPROG( applog, '\n' << version_wrapper::get_instance()->version_info_string() );
64  throw CLI::Success();
65  };
66  add_flag_function( "-V,--version", t_version_callback, "Print the version message and exit" );
67  }
68 
70  {
71  }
72 
74  {
76  }
77 
79  {
81 
82  applog.SetGlobalLevel( (logger::ELevel)f_global_verbosity );
83 
85 
86  try
87  {
88  nonoption_parser t_no_parser( remaining() );
89  f_nonoption_kw_args = t_no_parser.kw_args();
90  f_nonoption_ord_args = t_no_parser.ord_args();
91  }
92  catch( error& e )
93  {
94  LERROR( applog, "Unable to parse remaining arguments: " << e.what() );
95  throw CLI::ParseError( std::string("Unable to parse remaining arguments due to parse error or unknown option: ") + e.what(), CLI::ExitCodes::ArgumentMismatch );
96  }
97 
99 
101 
102  LPROG( applog, "Final configuration:\n" << f_master_config );
103  LPROG( applog, "Ordered args:\n" << f_nonoption_ord_args );
104  }
105 
107  {
108  // first configuration stage: defaults
109  LDEBUG( applog, "first configuration stage" );
110  f_master_config.merge( f_default_config );
111  return;
112  }
113 
115  {
116  // second configuration stage: config file
117  LDEBUG( applog, "second configuration stage" );
118  if( ! f_config_filename.empty() )
119  {
120  path t_config_filepath = scarab::expand_path( f_config_filename );
121  LDEBUG( applog, "Loading config file <" << t_config_filepath << "> from filename <" << f_config_filename << ">" );
122  param_translator t_translator;
123  std::unique_ptr< param > t_config_from_file( t_translator.read_file( t_config_filepath.string() ));
124  if( t_config_from_file == NULL )
125  {
126  throw error() << "[application] error parsing config file";
127  }
128  if( ! t_config_from_file->is_node() )
129  {
130  throw error() << "[application] configuration file must consist of an object/node";
131  }
132  f_master_config.merge( t_config_from_file->as_node() );
133  }
134  return;
135  }
136 
138  {
139  // third configuration stage: keyword args
140  LDEBUG( applog, "third configuration stage" );
141  f_master_config.merge( f_nonoption_kw_args );
142  return;
143  }
144 
146  {
147  // fourth configuration stage: application options
148  std::for_each( f_app_option_holders.begin(), f_app_option_holders.end(),
149  [this]( std::shared_ptr< app_option_holder > a_ptr ){ a_ptr->add_to_app_options(f_app_options); } );
150  f_master_config.merge( f_app_options );
151  return;
152  }
153 
154 
155 } /* 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:35
fs::path path
Definition: path.hh:25
path expand_path(const string &a_path)
Definition: path.cc:19
config_decorator(main_app *a_main, app *a_this_app)
Definition: application.cc:24
static version_wrapper * get_instance()
Definition: singleton.hh:53
CLI::App app
Definition: application.hh:18
#define LPROG(...)
Definition: logger.hh:368
virtual const char * what() const
Definition: error.cc:25
#define LERROR(...)
Definition: logger.hh:370
virtual void do_config_stage_4()
Load the application-specific options.
Definition: application.cc:145
Contains the logger class and macros, based on Kasper&#39;s KLogger class.
virtual void do_config_stage_1()
Load default values.
Definition: application.cc:106
LOGGER(applog, "application")
virtual void do_config_stage_2()
Load the config file.
Definition: application.cc:114
Adds the ability to create options and subcommands that are tied to a main_app&#39;s master config...
Definition: application.hh:51
virtual void pre_callback()
Definition: application.cc:78
#define LDEBUG(...)
Definition: logger.hh:365
void set_imp(scarab::version_semantic *a_imp)
std::vector< conf_dec_ptr_t > f_subcommand_decorators
Definition: application.hh:160
param_ptr_t read_file(const std::string &a_filename, const param_node &a_options=param_node())
Definition: param_codec.cc:47
void set_version(version_semantic *a_ver)
Definition: application.cc:73
This is a successful completion on parsing, supposed to exit.
Definition: CLI11.hpp:541
virtual ~main_app()
Definition: application.cc:69
Primary application class.
Definition: application.hh:252
Anything that can error in Parse.
Definition: CLI11.hpp:534
virtual void do_config_stage_3()
Load the directly-addressed non-option arguments.
Definition: application.cc:137