ALib C++ Framework
by
Library Version: 2511 R0
Documentation generated by doxygen
Loading...
Searching...
No Matches
appcli.cpp
1//--------------------------------------------------------------------------------------------------
2// ALib C++ Framework
3// Configuration Sample
4//
5// Copyright 2025 A-Worx GmbH, Germany
6// Published under Boost Software License (a free software license, see LICENSE.txt)
7//--------------------------------------------------------------------------------------------------
8#include "alib_precompile.hpp"
9#if !defined(ALIB_C20_MODULES) || ((ALIB_C20_MODULES != 0) && (ALIB_C20_MODULES != 1))
10# error "Configuration MACRO ALIB_C20_MODULES has to be given to the compiler as either 0 or 1"
11#endif
12#if ALIB_C20_MODULES
13 module;
14#endif
15
16//========================================= Global Fragment ========================================
20//============================================== Module ============================================
21#if ALIB_C20_MODULES
22 module ALib.App;
23 import ALib.App.Impl;
24 import ALib.Lang;
25 import ALib.Strings;
26 import ALib.Boxing;
27 import ALib.EnumRecords;
28 import ALib.EnumRecords.Bootstrap;
29 import ALib.Variables;
30#else
31# include "ALib.Bootstrap.H"
33# include "ALib.App.CLI.H"
34#endif
35
36namespace alib::app {
37
39: App {&APPCLI_CAMP} {
40 machine.Program.AddBefore( App::States::ImportConfig ,
41 StateMachine::Command::MakeCustom<AppCli, &AppCli::bsCLIDefine> (States::CLIDefine) );
42
43 machine.Program.AddAfter( States::CLIDefine ,
44 StateMachine::Command::MakeCustom<AppCli, &AppCli::bsCLIReadOptions> (States::CLIReadOptions) );
45
46 machine.Program.AddBefore( App::States::SetupALox ,
47 StateMachine::Command::MakeCustom<AppCli, &AppCli::bsReadDryRunOption>(States::ReadDryRunOption) );
48
49 machine.Program.AddAfter ( App::States::ImportConfig,
50 StateMachine::Command::MakeCustom<AppCli, &AppCli::bsConfigureCLI> (States::ConfigureCLI) );
51
52}
53
55 // check with parent
56 Enum result= App::exceptionToExitCode(exception);
57
58 // handle cli-exceptions
59 if ( result == BuiltInExitCodes::ErrUnknown
60 && exception.Type().IsEnumType<cli::Exceptions>() ) {
61
62 // todo: gibt es diese method nicht bereits im CLIUtil?
63 auto element= exception.Type().Get<cli::Exceptions>();
64 for( auto& exitCodeDecl : cli.ExitCodeDecls )
65 if( exitCodeDecl.second->AssociatedCLIException() == element ) {
66 result= exitCodeDecl.first;
67 break;
68 } }
69
70 // also, we do not know. This is not good!
71
72 return result;
73}
74
75
76
86
88 cli.Init( &APPCLI_CAMP );
89 cli.DefineExitCodes <ExitCodes >();
90 cli.DefineParameters<Parameters>();
91 cli.DefineCommands <Commands >();
92 cli.DefineOptions <Options >();
93}
94
95void AppCli::bsCLIReadOptions() { cli.ReadOptions(); }
96
98 // set remaining cli args to configuration and allow shortcuts for cli variables
99 variables::CLIVariablesPlugin* cliParameterPlugin=
100 APPCLI_CAMP.GetConfig()->GetPluginTypeSafe<variables::CLIVariablesPlugin>();
101 for( auto& arg : cli.OptionArgsIgnored )
102 cliParameterPlugin->AlternativeArgs.emplace_back( arg );
103
104 cliParameterPlugin->DefaultCategories.emplace_back("ALIB");
105 cliParameterPlugin->DefaultCategories.emplace_back("ALOX");
106}
107
108
110 auto* dryOpt= cli.GetOption( Options::DryRun );
111 if( dryOpt != nullptr ) {
112 if( !CLIUtil::GetDryOpt( cli, *dryOpt ) ) {
114 dryOpt->Declaration->Identifier(),
115 dryOpt->Args.front() ,
116 dryOpt->Declaration->Identifier() );
117 cliStop= true;
118 return;
119 }
120
121 // with debug option "CLIDeclarations", we stop right now
122 if( cli.DryRun == cli::DryRunModes::CLIDeclarations ) {
124 machine.EmergencyStop= true;
125} } }
126
127
130 //AppCliCamp.GetConfig()->PreloadVariables<Variables>();
131}
132
137
139
140 auto* optionConfig= cli.GetOption(Options::Config);
141 if( optionConfig == nullptr )
142 return;
143
144 Substring names= optionConfig->Args.front();
145 size_t cnt= 0;
146 while (names.IsNotEmpty()) {
147 Substring name= names.ConsumeToken(',');
148 name.Trim();
149 if (files.size() <= cnt)
150 files.emplace_back();
151 Path& path= files.at(cnt).Pathname;
152 if( !name.IsEmpty()
153 && !String("Default").StartsWith<CHK,lang::Case::Ignore>( name ) )
154 path.Reset(name);
155 ++cnt;
156 }
157 return;
158}
159
160//==================================================================================================
161// Run
162//==================================================================================================
164 if ( cliStop )
165 return;
166
167 // if 'dryrun' was recognized, output resource "DryRunStart"
168 // todo: This has to be doxed: A user can add a resource here.
169 String resource= APPCLI_CAMP.TryResource( "AppStart" );
170 if ( resource.IsNotEmpty() )
171 cOut->AddMarked( resource, GetName(), GetVersion() );
172
173 if( cli.DryRun == cli::DryRunModes::Application ) {
174 resource= APPCLI_CAMP.TryResource( "DryRunStart" );
175 if ( resource.IsNotEmpty() )
176 cOut->AddMarked( resource, appName );
177 }
178
179 //------- check for option 'help' -------
180 cli::Option* option= cli.GetOption( Options::Help);
181 if( option ) {
182 if( !CLIUtil::GetHelp( cli, option, *cOut ) )
184 option->Declaration->Identifier(),
185 option->Args.front(),
186 option->Declaration->Identifier() );
187 cliStop= true;
188 return;
189} }
190
191void AppCli::exitWithHelpOutput( Enum exitCode, const String& helpTopic, Box fp1, Box fp2 ) {
192 cErr->Add( cli.ExitCodeDecls.Find(exitCode).Mapped()->FormatString(), fp1, fp2,
193 APPCLI_CAMP.GetResource("USAGEFOLLOWS") );
194 cErr->Buffer << NEW_LINE;
195 onSdOutput();
196 CLIUtil::GetHelp( cli, helpTopic, *cOut );
197 machine.SetExitCode(exitCode);
198}
199
201 if ( cliStop )
202 return;
203
204 cli.ReadNextCommands();
205
206 //------- No command recognized? This is allowed, calls cliProcessCmd with nullptr -------
207 if( cli.CommandsParsed.size() == 0 ) {
208 // No command. If derived does not process no-commands, then throw.
209 if (!cliProcessCmd(nullptr) )
211
212 // Still an argument was left? This is not allowed
213 if( cli.ArgsLeft.size() > 0 ) {
215 ARG_VN[cli.ArgsLeft.front() + 1]);
216 return;
217 }
218
219 return;
220 }
221
222 //------- Command loop -------
223 // Note: Making a loop here is optional. We do it to allow multiple commands
224 // with one invocation of the application.
225 cli::Command* actCmd;
226 while ( !cliStop && (actCmd= cli.NextCommand()) != nullptr ) {
227 ALIB_DBG( bool processed= )
228 cliProcessCmd(actCmd);
229 ALIB_ASSERT_ERROR(processed, "APP",
230 "Command \"{}\" recognized but not processed by the App.",
231 actCmd->Declaration->Identifier() )
232} }
233
235 if ( cliStop )
236 return;
237
238 // if 'dryrun' was recognized, output resource "DryRunEnd"
239 if( cli.DryRun == cli::DryRunModes::Application ) {
240 String dryRunEnd= APPCLI_CAMP.TryResource( "DryRunEnd" );
241 if ( dryRunEnd.IsNotEmpty() )
242 cOut->AddMarked( dryRunEnd );
243} }
244
245
247 if ( cmd == nullptr )
248 return false;
249
250 if( cmd->Declaration->Element() == Commands::Help ) {
251 if( !CLIUtil::GetHelp( cli, cmd, *cOut ) ) {
252 // Assert that one argument was consumed as the help topic.
253 // No other circumstance could make GetHelp fail.
254 ALIB_ASSERT(cmd->ConsumedArguments== 2, "APP") // 2 means the command and the argument
256 ARG_VN[cmd->Position + 2], cmd->Declaration->Identifier() );
257 }
258 cliStop= true;
259 return true;
260 }
261
262 return false;
263}
264
265
266
267
268} // namespace [alib::app]
#define ALIB_ASSERT(cond, domain)
Definition alib.inl:1143
#define ALIB_LOCK_RECURSIVE_WITH(lock)
Definition alib.inl:1414
#define ALIB_DBG(...)
Definition alib.inl:931
#define ALIB_ASSERT_ERROR(cond, domain,...)
Definition alib.inl:1144
Enum exceptionToExitCode(Exception &exception) override
Definition appcli.cpp:54
void onRunEnd() override
Definition appcli.cpp:234
void onRunStart() override
Definition appcli.cpp:163
bool cliStop
Flag to stop the CLI processing loop.
Definition appcli.inl:43
virtual bool cliProcessCmd(cli::Command *cmd)
Definition appcli.cpp:246
virtual void getConfigFilePathsFromCLIParam(StdVectorMA< ConfigFileDescriptor > &files)
Definition appcli.cpp:138
virtual void bsReadDryRunOption()
Implements #"States::ReadDryRunOption": evaluate early flags (e.g., –dry-run).
Definition appcli.cpp:109
virtual void bsCLIReadOptions()
Definition appcli.cpp:95
cli::CommandLine cli
The command-line parser provided by module ALib CLI.
Definition appcli.inl:36
void getConfigFilePaths(StdVectorMA< ConfigFileDescriptor > &files) override
Definition appcli.cpp:133
AppCli()
Constructs an instance and registers additional bootstrap states.
Definition appcli.cpp:38
void onBsPreloadVariables() override
Definition appcli.cpp:128
void onRun() override
Definition appcli.cpp:200
virtual void exitWithHelpOutput(Enum exitCode, const String &helpTopic=NULL_STRING, Box formatParam1=EMPTY_STRING, Box formatParam2=EMPTY_STRING)
Definition appcli.cpp:191
virtual void bsCLIDefine()
Implements #"States::CLIDefine": define CLI options, flags and commands.
Definition appcli.cpp:87
virtual void bsConfigureCLI()
Implements #"States::ConfigureCLI": finalize CLI after configuration import.
Definition appcli.cpp:97
@ CLIReadOptions
Inserted behind #"CLIDefine".
Definition appcli.inl:29
@ ConfigureCLI
Inserted after #"States::ImportConfig": finalize CLI setup based on config.
Definition appcli.inl:31
@ CLIDefine
Inserted before #"States::ImportConfig": define CLI options and commands.
Definition appcli.inl:28
@ ReadDryRunOption
Inserted before #"States::SetupALox": evaluate early flags (e.g., dry-run).
Definition appcli.inl:30
void onBsSetNameVersionAndInfo() override
Definition appcli.cpp:77
virtual void onBsPreloadVariables()
Definition app.cpp:335
virtual void onBsSetNameVersionAndInfo()
Definition app.cpp:316
@ SetupALox
Invokes the virtual method onBsSetupALox.
Definition app.inl:127
@ ImportConfig
Invokes the virtual method onBsImportConfig.
Definition app.inl:122
String GetName()
Definition app.inl:480
String appName
Definition app.inl:384
String appVersion
Definition app.inl:389
StateMachine machine
The state-machine singleton.
Definition app.inl:371
Paragraphs * cOut
Definition app.inl:401
virtual void onSdOutput()
Definition app.cpp:465
virtual Enum exceptionToExitCode(alib::Exception &exception)
Definition app.cpp:141
App(camp::Camp *appCamp)
Definition app.cpp:43
virtual void getConfigFilePaths(StdVectorMA< ConfigFileDescriptor > &files)
Definition app.cpp:282
String GetVersion()
Definition app.inl:485
@ ErrUnknown
An unknown exception occurred.
Definition app.inl:52
Paragraphs * cErr
Same as cOut, but used for stream std::err.
Definition app.inl:404
static bool GetDryOpt(CommandLine &cmdLine, Option &dryOpt)
Definition cliutil.cpp:264
static AString & DumpDeclarations(CommandLine &cmdLine, Paragraphs &text)
Definition cliutil.cpp:297
static bool GetHelp(CommandLine &cmdLine, const String &topics, Paragraphs &text)
Definition cliutil.cpp:110
const Enum & Element() const
const String & Identifier()
const String & Identifier()
const Enum & Type() const
static threads::RecursiveLock DEFAULT_LOCK
static SPFormatter DEFAULT
constexpr bool IsEmpty() const
Definition string.inl:353
constexpr bool IsNotEmpty() const
Definition string.inl:357
TSubstring & Trim(const TCString< TChar > &whiteSpaces=CStringConstantsTraits< TChar >::DefaultWhitespaces())
TString< TChar > ConsumeToken(TChar separator=',', lang::Inclusion includeSeparator=lang::Inclusion::Include)
Options
Built-in options used with class #"AppCli".
@ DryRun
Show help text.
@ Config
Change name of config file(s).
ExitCodes
Built-in exit-code used with class #"AppCli".
@ ErrUnknownCommand
Unknown command.
@ ErrNoCmdGiven
No command given.
@ ErrBadParamValue
Bad parameter value.
Commands
Built-in commands used with class #"AppCli".
@ Help
Show help text.
Parameters
Built-in parameters of commands and options used with class #"AppCli".
@ CLIDeclarations
Just displays the cli setup. This is more for debugging or interested users.
Definition clicamp.inl:89
TMonoAllocator< lang::HeapAllocator > GLOBAL_ALLOCATOR
constexpr String NULL_STRING
A nulled string of the default character type.
Definition string.inl:2254
constexpr CString NEW_LINE
A zero-terminated string containing the new-line character sequence.
Definition cstring.inl:540
boxing::Box Box
Type alias in namespace alib.
Definition box.inl:1135
int VERSION
strings::TString< character > String
Type alias in namespace alib.
Definition string.inl:2172
app::AppCliCamp APPCLI_CAMP
The singleton instance of the camp class used by class #"AppCli".
system::Path Path
Type alias in namespace alib.
Definition path.inl:375
strings::TSubstring< character > Substring
Type alias in namespace alib.
exceptions::Exception Exception
Type alias in namespace alib.
LocalString< 128 > String128
Type alias name for #"TLocalString;TLocalString<character,128>".
std::vector< T, StdMA< T > > StdVectorMA
Type alias in namespace alib.
const char ** ARG_VN
Definition mainargs.cpp:24
boxing::Enum Enum
Type alias in namespace alib.
Definition enum.inl:211
unsigned char REVISION
bool IsEnumType() const
Definition enum.inl:142
TEnum Get() const
Definition enum.inl:75
A command of a ALib CLI command-line.
CommandDecl * Declaration
The underlying declaration.
OptionDecl * Declaration
The declaration struct.
ListMA< String, Recycling::Shared > Args
Arguments belonging to this option.
integer ConsumedArguments
Definition arguments.inl:35