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