2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
42#include "utils/Config.h"
44#include "utils/Daemon.h"
45#include "utils/Exceptions.h"
46#include "utils/Formatter.h"
48#ifndef DOXYGEN_SHOULD_SKIP_THIS
50#include "log/Logger.h"
70#pragma GCC diagnostic push
71#pragma GCC diagnostic ignored "-Wfloat-equal"
73#if __has_warning
("-Wweak-vtables")
74#pragma GCC diagnostic ignored "-Wweak-vtables"
76#if __has_warning
("-Wcovered-switch-default")
77#pragma GCC diagnostic ignored "-Wcovered-switch-default"
81#include "utils/CLI11.hpp"
83#pragma GCC diagnostic pop
94 const std::shared_ptr<
CLI::App> app = std::make_shared<
CLI::App>();
96 app->configurable(
false);
98 app->allow_config_extras();
102 helpFormatter->label(
"SUBCOMMAND",
"INSTANCE");
103 helpFormatter->label(
"SUBCOMMANDS",
"INSTANCES");
104 helpFormatter->label(
"PERSISTENT",
"");
105 helpFormatter->label(
"Persistent Options",
"Options (persistent)");
106 helpFormatter->label(
"Nonpersistent Options",
"Options (nonpersistent)");
107 helpFormatter->label(
"Usage",
"\nUsage");
108 helpFormatter->label(
"bool:{true,false}",
"{true,false}");
109 helpFormatter->label(
":{standard,required,full,default}",
"{standard,required,full,default}");
110 helpFormatter->label(
":{standard,expanded}",
"{standard,expanded}");
111 helpFormatter->column_width(7);
113 app->formatter(helpFormatter);
116 app->get_config_formatter_base()->arrayDelimiter(
' ');
118 app->option_defaults()->take_last();
119 app->option_defaults()->group(app->get_formatter()->get_label(
"Nonpersistent Options"));
121 logger::Logger::init();
128 bool Config::init(
int argc,
char* argv[]) {
134 applicationName = std::filesystem::path(argv[0]).filename();
137 struct passwd* pw =
nullptr;
138 struct group* gr =
nullptr;
140 if ((pw = getpwuid(getuid())) ==
nullptr) {
142 }
else if ((gr = getgrgid(pw->pw_gid)) ==
nullptr) {
144 }
else if ((euid = geteuid()) == 0) {
145 configDirectory =
"/etc/snode.c";
146 logDirectory =
"/var/log/snode.c";
147 pidDirectory =
"/var/run/snode.c";
149 const char* homedir =
nullptr;
150 if ((homedir = std::getenv(
"XDG_CONFIG_HOME")) ==
nullptr) {
151 if ((homedir = std::getenv(
"HOME")) ==
nullptr) {
152 homedir = pw->pw_dir;
156 if (homedir !=
nullptr) {
157 configDirectory = std::string(homedir) +
"/.config/snode.c";
158 logDirectory = std::string(homedir) +
"/.local/log/snode.c";
159 pidDirectory = std::string(homedir) +
"/.local/run/snode.c";
165 if (proceed && !std::filesystem::exists(configDirectory)) {
166 if (std::filesystem::create_directories(configDirectory)) {
167 std::filesystem::permissions(
169 (std::filesystem::perms::owner_all | std::filesystem::perms::group_read | std::filesystem::perms::group_exec) &
170 ~std::filesystem::perms::others_all);
171 if (geteuid() == 0) {
172 struct group* gr =
nullptr;
173 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
174 if (chown(configDirectory.c_str(), euid, gr->gr_gid) < 0) {
175 std::cout <<
"Warning: Can not set group ownership of '" << configDirectory
176 <<
"' to 'snodec':" << strerror(errno) << std::endl;
179 std::cout <<
"Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
180 std::cout <<
" and add the current user to this group." << std::endl;
181 std::filesystem::remove(configDirectory);
186 std::cout <<
"Error: Can not create directory '" << configDirectory <<
"'" << std::endl;
191 if (proceed && !std::filesystem::exists(logDirectory)) {
192 if (std::filesystem::create_directories(logDirectory)) {
193 std::filesystem::permissions(logDirectory,
194 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
195 ~std::filesystem::perms::others_all);
196 if (geteuid() == 0) {
197 struct group* gr =
nullptr;
198 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
199 if (chown(logDirectory.c_str(), euid, gr->gr_gid) < 0) {
200 std::cout <<
"Warning: Can not set group ownership of '" << logDirectory <<
"' to 'snodec':" << strerror(errno)
204 std::cout <<
"Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
205 std::cout <<
" and add the current user to this group." << std::endl;
206 std::filesystem::remove(configDirectory);
211 std::cout <<
"Error: Can not create directory '" << logDirectory <<
"'" << std::endl;
216 if (proceed && !std::filesystem::exists(pidDirectory)) {
217 if (std::filesystem::create_directories(pidDirectory)) {
218 std::filesystem::permissions(pidDirectory,
219 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
220 ~std::filesystem::perms::others_all);
221 if (geteuid() == 0) {
222 struct group* gr =
nullptr;
223 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
224 if (chown(pidDirectory.c_str(), euid, gr->gr_gid) < 0) {
225 std::cout <<
"Warning: Can not set group ownership of '" << pidDirectory <<
"' to 'snodec':" << strerror(errno)
229 std::cout <<
"Error: Can not find group 'snodec'. Add it using groupadd or addgroup." << std::endl;
230 std::cout <<
" and add the current user to this group." << std::endl;
231 std::filesystem::remove(configDirectory);
236 std::cout <<
"Error: Can not create directory '" << pidDirectory <<
"'" << std::endl;
242 app->description(
"Configuration for Application '" + applicationName +
"'");
244 app->footer(
"Application '" + applicationName +
245 "' powered by SNode.C\n"
246 "(C) 2020-2025 Volker Christian <me@vchrist.at>\n"
247 "https://github.com/SNodeC/snode.c");
251 configDirectory +
"/" + applicationName +
".conf",
252 "Read a config file",
255 ->type_name(
"configfile")
256 ->check(!
CLI::ExistingDirectory);
258 app->add_option_function<std::string>(
260 []([[maybe_unused]]
const std::string& configFile) {
263 "Write config file and exit")
264 ->configurable(
false)
265 ->default_val(configDirectory +
"/" + applicationName +
".conf")
266 ->type_name(
"[configfile]")
267 ->check(!
CLI::ExistingDirectory)
272 "Kill running daemon")
273 ->configurable(
false)
274 ->disable_flag_override();
277 "-i,--instance-alias",
278 "Make an instance also known as an alias in configuration files")
279 ->configurable(
false)
280 ->type_name(
"instance=instance_alias [instance=instance_alias [...]]")
281 ->each([](
const std::string& item) {
282 const auto it = item.find(
'=');
283 if (it != std::string::npos) {
284 aliases[item.substr(0, it)] = item.substr(it + 1);
286 throw CLI::ConversionError(
"Can not convert '" + item +
"' to a 'instance=instance_alias' pair");
290 addStandardFlags(app.get());
292 logLevelOpt = app->add_option(
297 ->check(
CLI::Range(0, 6))
298 ->group(app->get_formatter()->get_label(
"Persistent Options"));
300 verboseLevelOpt = app->add_option(
301 "-v,--verbose-level",
305 ->check(
CLI::Range(0, 10))
306 ->group(app->get_formatter()->get_label(
"Persistent Options"));
308 quietOpt = app->add_flag(
309 "-q{true},!-u,--quiet{true}",
311 ->default_val(
"false")
313 ->check(
CLI::IsMember({
"true",
"false"}))
314 ->group(app->get_formatter()->get_label(
"Persistent Options"));
316 logFileOpt = app->add_option(
319 ->default_val(logDirectory +
"/" + applicationName +
".log")
320 ->type_name(
"logfile")
321 ->check(!
CLI::ExistingDirectory)
322 ->group(app->get_formatter()->get_label(
"Persistent Options"));
324 enforceLogFileOpt = app->add_flag(
325 "-e{true},!-n,--enforce-log-file{true}",
326 "Enforce writing of logs to file for foreground applications")
327 ->default_val(
"false")
329 ->check(
CLI::IsMember({
"true",
"false"}))
330 ->group(app->get_formatter()->get_label(
"Persistent Options"));
332 daemonizeOpt = app->add_flag(
333 "-d{true},!-f,--daemonize{true}",
334 "Start application as daemon")
335 ->default_val(
"false")
337 ->check(
CLI::IsMember({
"true",
"false"}))
338 ->group(app->get_formatter()->get_label(
"Persistent Options"));
340 userNameOpt = app->add_option(
342 "Run daemon under specific user permissions")
343 ->default_val(pw->pw_name)
344 ->type_name(
"username")
345 ->needs(daemonizeOpt)
346 ->group(app->get_formatter()->get_label(
"Persistent Options"));
348 groupNameOpt = app->add_option(
350 "Run daemon under specific group permissions")
351 ->default_val(gr->gr_name)
352 ->type_name(
"groupname")
353 ->needs(daemonizeOpt)
354 ->group(app->get_formatter()->get_label(
"Persistent Options"));
358 app->set_version_flag(
"--version",
"1.0-rc1",
"Framework version");
365 bool Config::bootstrap() {
368 app->final_callback([]() {
369 if (daemonizeOpt->as<
bool>() && (*app)[
"--show-config"]->count() == 0 && (*app)[
"--write-config"]->count() == 0 &&
370 (*app)[
"--command-line"]->count() == 0) {
371 std::cout <<
"Running as daemon (double fork)" << std::endl;
374 pidDirectory +
"/" + applicationName +
".pid", userNameOpt->as<std::string>()
, groupNameOpt->as<std::string>()
);
376 logger::Logger::setQuiet();
378 const std::string logFile = logFileOpt->as<std::string>();
379 if (!logFile.empty()) {
380 logger::Logger::logToFile(logFile);
382 }
else if ((*app)[
"--enforce-log-file"]->as<
bool>()) {
383 const std::string logFile = logFileOpt->as<std::string>();
384 if (!logFile.empty()) {
385 std::cout <<
"Writing logs to file " << logFile << std::endl;
387 logger::Logger::logToFile(logFile);
395 bool Config::parse1() {
399 app->parse(argc, argv);
400 }
catch (
const CLI::ParseError&) {
404 if ((*app)[
"--kill"]->count() > 0) {
407 std::cout <<
"Daemon terminated: Pid = " << daemonPid << std::endl;
409 std::cout <<
"DaemonError: " << e.what() << std::endl;
411 std::cout <<
"DaemonFailure: " << e.what() << std::endl;
416 if ((*app)[
"--show-config"]->count() == 0 && (*app)[
"--write-config"]->count() == 0 && (*app)[
"--command-line"]->count() == 0) {
417 app->allow_extras(
false);
420 if (!quietOpt->as<
bool>()) {
421 logger::Logger::setLogLevel(logLevelOpt->as<
int>());
422 logger::Logger::setVerboseLevel(verboseLevelOpt->as<
int>());
425 logger::Logger::setQuiet(quietOpt->as<
bool>());
432 CLI::Option* disabledOpt = app->get_option_no_throw(
"--disabled");
433 const bool disabled = disabledOpt !=
nullptr ? disabledOpt->as<
bool>() :
false;
435 for (
const CLI::Option* option : app->get_options()) {
436 if (option->get_configurable()) {
441 if (option->count() > 0) {
442 value = option->as<std::string>();
443 }
else if (option->get_required()) {
444 value =
"<REQUIRED>";
448 if (option->get_required()) {
449 if (option->count() > 0) {
450 value = option->as<std::string>();
452 value =
"<REQUIRED>";
457 if (option->count() > 0) {
458 value = option->as<std::string>();
459 }
else if (!option->get_default_str().empty()) {
460 value = option->get_default_str();
461 }
else if (!option->get_required()) {
464 value =
"<REQUIRED>";
468 if (!option->get_default_str().empty()) {
469 value = option->get_default_str();
470 }
else if (!option->get_required()) {
473 value =
"<REQUIRED>";
479 if (!value.empty()) {
480 if (value.starts_with(
"[") && value.ends_with(
"]")) {
481 value = value.substr(1, value.size() - 2);
484 out <<
"--" << option->get_single_name() << ((option->get_items_expected_max() == 0) ?
"=" :
" ") << value <<
" ";
488 }
else if (disabledOpt->get_default_str() ==
"false") {
489 out <<
"--disabled=true ";
494 std::stringstream out;
498 std::string optionString = out.str();
499 if (optionString.back() ==
' ') {
500 optionString.pop_back();
509 std::stringstream out;
511 CLI::Option* disabledOpt = app->get_option_no_throw(
"--disabled");
513 for (
CLI::App* subcommand : app->get_subcommands({})) {
514 if (!subcommand->get_name().empty()) {
524 std::string outString;
527 if (!outString.empty()) {
533 if (!outString.empty()) {
534 out << app->get_name() <<
" " << outString;
539 std::stringstream out;
543 std::string outString = out.str();
544 while (app->get_parent() !=
nullptr) {
545 app = app->get_parent();
548 std::string(app->get_name()).append(
" ").append(!parentOptions.empty() ? parentOptions.append(
" ") :
"").append(outString);
551 if (outString.empty()) {
552 outString = Config::getApplicationName();
558 bool Config::parse2() {
559 bool success =
false;
563 app->parse(argc, argv);
566 std::cout <<
"Daemon error: " << e.what() <<
" ... exiting" << std::endl;
568 std::cout <<
"Daemon failure: " << e.what() <<
" ... exiting" << std::endl;
570 std::cout <<
"Pid: " << getpid() <<
", child pid: " << e
.getPid() <<
": " << e.what() << std::endl;
571 }
catch (
const CLI::CallForHelp&) {
572 std::cout << app->help() << std::endl;
573 }
catch (
const CLI::CallForAllHelp&) {
574 std::cout << app->help(
"",
CLI::AppFormatMode::All) << std::endl;
575 }
catch (
const CLI::CallForVersion&) {
576 std::cout << app->version() << std::endl << std::endl;
578 std::cout << e.what() << std::endl;
579 std::cout << std::endl
580 << Color::Code::FG_GREEN <<
"command@line" << Color::Code::FG_DEFAULT <<
":" << Color::Code::FG_BLUE <<
"~/> "
585 std::cout << e
.getApp()->config_to_str(
true,
true);
586 }
catch (
const CLI::ParseError& e1) {
587 std::cout <<
"Error showing config file: " << e
.getApp() <<
" " << e1.get_name() <<
" " << e1.what() << std::endl;
591 std::cout << e.what() << std::endl;
593 if (confFile.is_open()) {
595 confFile << app->config_to_str(
true,
true);
597 }
catch (
const CLI::ParseError& e1) {
599 std::cout <<
"Error writing config file: " << e1.get_name() <<
" " << e1.what() << std::endl;
603 std::cout <<
"Error writing config file: " << std::strerror(errno) << std::endl;
605 }
catch (
const CLI::ConversionError& e) {
606 std::cout <<
"[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT <<
"] " << e.what() << std::endl;
608 }
catch (
const CLI::ArgumentMismatch& e) {
609 std::cout <<
"[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT <<
"] " << e.what() << std::endl;
611 }
catch (
const CLI::ConfigError& e) {
612 std::cout <<
"[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT <<
"] " << e.what() << std::endl;
613 std::cout <<
" Adding '-w' on the command line may solve this problem" << std::endl;
615 }
catch (
const CLI::ParseError& e) {
616 const std::string what = e.what();
617 if (what.find(
"[Option Group: ") != std::string::npos) {
619 std::cout << Color::Code::FG_RED <<
"[BootstrapError]" << Color::Code::FG_DEFAULT
620 <<
" Anonymous instance(s) not configured in source code " << std::endl;
622 std::cout <<
"[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT <<
"] " << what << std::endl;
626 }
catch ([[maybe_unused]]
const CLI::ParseError& e) {
627 std::cout << std::endl <<
"Append -h or --help to your command line for more information." << std::endl;
628 }
catch (
const CLI::Error& e) {
629 std::cout <<
"[" << Color::Code::FG_RED << e.get_name() << Color::Code::FG_DEFAULT <<
"] " << e.what() << std::endl;
630 std::cout <<
"Append -h or --help to your command line for more information." << std::endl;
634 logger::Logger::setQuiet();
640 void Config::terminate() {
641 if ((*app)[
"--daemonize"]->as<
bool>()) {
642 std::ifstream pidFile(pidDirectory +
"/" + applicationName +
".pid", std::ifstream::in);
644 if (pidFile.good()) {
648 if (getpid() == pid) {
652 }
else if (fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK) >= 0) {
654 while (read(STDIN_FILENO, buf, 1024) > 0) {
662 sectionFormatter->label(
"SUBCOMMAND",
"SECTION");
663 sectionFormatter->label(
"SUBCOMMANDS",
"SECTIONS");
664 sectionFormatter->label(
"PERSISTENT",
"");
665 sectionFormatter->label(
"Persistent Options",
"Options (persistent)");
666 sectionFormatter->label(
"Nonpersistent Options",
"Options (nonpersistent)");
667 sectionFormatter->label(
"Usage",
"\nUsage");
668 sectionFormatter->label(
"bool:{true,false}",
"{true,false}");
669 sectionFormatter->label(
":{standard,required,full,default}",
"{standard,required,full,default}");
670 sectionFormatter->label(
":{standard,expanded}",
"{standard,expanded}");
671 sectionFormatter->column_width(7);
673 return sectionFormatter;
678 CLI::App* Config::addInstance(
const std::string& name,
const std::string& description,
const std::string& group) {
679 CLI::App* instance = app->add_subcommand(name, description)
682 ->formatter(sectionFormatter)
683 ->configurable(
false)
684 ->allow_extras(
false)
685 ->disabled(name.empty());
689 ->configurable(!instance->get_disabled());
691 if (!instance->get_disabled()) {
692 if (aliases.contains(name)) {
694 ->alias(aliases[name]);
701 CLI::App* Config::addStandardFlags(
CLI::App* app) {
708 "Show current configuration and exit")
709 ->configurable(
false)
710 ->disable_flag_override();
714 "--command-line{standard}",
715 [app]([[maybe_unused]] std::int64_t count) {
716 const std::string& result = app->get_option(
"--command-line")->as<std::string>();
717 if (result ==
"standard") {
720 "Below is a command line viewing all non-default and required options:\n"
721 "* Options show their configured value\n"
722 "* Required but not yet configured options show <REQUIRED> as value\n"
723 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
726 if (result ==
"required") {
729 "Below is a command line viewing required options only:\n"
730 "* Options show either their configured or default value\n"
731 "* Required but not yet configured options show <REQUIRED> as value\n"
732 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
735 if (result ==
"full") {
738 "Below is a command line viewing the full set of options with their default or configured values:\n"
739 "* Options show either their configured or default value\n"
740 "* Required but not yet configured options show <REQUIRED> as value\n"
741 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
744 if (result ==
"default") {
747 "Below is a command line viewing the full set of options with their default values\n"
748 "* Options show their default value\n"
749 "* Required but not yet configured options show <REQUIRED> as value\n"
750 "* Options marked as <REQUIRED> need to be configured for a successful bootstrap",
754 "Print a command line\n"
755 " standard (default): View all non-default and required options\n"
756 " required: View required options only\n"
757 " full: View the full set of options with their default or configured values\n"
758 " default: View the full set of options with their default values")
759 ->configurable(
false)
760 ->check(
CLI::IsMember({
"standard",
"required",
"full",
"default"}));
765 CLI::App* Config::addHelp(
CLI::App* app) {
771 "-h{standard},--help{standard}",
772 [app]([[maybe_unused]] std::int64_t count) {
773 const std::size_t disabledCount =
774 app->get_subcommands([](
CLI::App* app) ->
bool {
775 return app->get_group() ==
"Instance" && app->get_option(
"--disabled")->as<
bool>();
778 const std::size_t enabledCount =
779 app->get_subcommands([](
CLI::App* app) ->
bool {
780 return app->get_group() ==
"Instance" && !app->get_option(
"--disabled")->as<
bool>();
784 for (
auto* instance : app->get_subcommands({})) {
785 if (instance->get_group() ==
"Instance") {
786 if (instance->get_option(
"--disabled")->as<
bool>()) {
787 instance->group(std::string(
"Instance").append((disabledCount > 1) ?
"s" :
"").append(
" (disabled)"));
789 instance->group(std::string(
"Instance").append((enabledCount > 1) ?
"s" :
""));
794 const std::string& result = app->get_option(
"--help")->as<std::string>();
796 if (result ==
"standard") {
797 throw CLI::CallForHelp();
799 if (result ==
"expanded") {
800 throw CLI::CallForAllHelp();
803 "Print help message")
804 ->configurable(
false)
805 ->check(
CLI::IsMember({
"standard",
"expanded"}));
810 CLI::App* Config::addSimpleHelp(
CLI::App* app) {
817 []([[maybe_unused]] std::int64_t count) {
818 throw CLI::CallForHelp();
820 "Print help message")
821 ->configurable(
false)
822 ->disable_flag_override();
827 void Config::required(
CLI::App* instance,
bool reqired) {
829 app->needs(instance);
831 for (
const auto& sub : instance->get_subcommands([](
const CLI::App* sc) ->
bool {
832 return sc->get_required();
834 instance->needs(sub);
837 app->remove_needs(instance);
839 for (
const auto& sub : instance->get_subcommands([](
const CLI::App* sc) ->
bool {
840 return sc->get_required();
842 instance->remove_needs(sub);
846 instance->required(reqired);
849 void Config::disabled(
CLI::App* instance,
bool disabled) {
851 app->remove_needs(instance);
853 for (
const auto& sub : instance->get_subcommands([](
const CLI::App* sc) ->
bool {
854 return !sc->get_disabled();
858 if (sub->get_required()) {
859 instance->remove_needs(sub);
863 app->needs(instance);
865 for (
const auto& sub : instance->get_subcommands([](
const CLI::App* sc) ->
bool {
866 return sc->get_disabled();
868 sub->disabled(
false);
870 if (sub->get_required()) {
871 instance->needs(sub);
876 instance->required(!disabled);
879 bool Config::removeInstance(
CLI::App* instance) {
880 Config::required(instance,
false);
882 return app->remove_subcommand(instance);
885 CLI::Option* Config::addStringOption(
const std::string& name,
const std::string& description,
const std::string& typeName) {
886 applicationOptions[name] = app
887 ->add_option(name, description)
888 ->type_name(typeName)
891 ->group(
"Application Options");
893 app->needs(applicationOptions[name]);
895 return applicationOptions[name];
899 Config::addStringOption(
const std::string& name,
const std::string& description,
const std::string& typeName,
bool configurable) {
900 addStringOption(name, description, typeName);
901 return applicationOptions[name]
902 ->configurable(configurable);
905 CLI::Option* Config::addStringOption(
const std::string& name,
906 const std::string& description,
907 const std::string& typeName,
908 const std::string& defaultValue) {
909 addStringOption(name, description, typeName);
911 applicationOptions[name]
913 ->default_str(defaultValue);
915 app->remove_needs(applicationOptions[name]);
917 return applicationOptions[name];
920 CLI::Option* Config::addStringOption(
const std::string& name,
921 const std::string& description,
922 const std::string& typeName,
923 const std::string& defaultValue,
925 addStringOption(name, description, typeName, defaultValue);
926 return applicationOptions[name]
927 ->configurable(configurable);
930 CLI::Option* Config::addStringOption(
const std::string& name,
931 const std::string& description,
932 const std::string& typeName,
933 const char* defaultValue) {
934 return addStringOption(name, description, typeName, std::string(defaultValue));
937 CLI::Option* Config::addStringOption(
938 const std::string& name,
const std::string& description,
const std::string& typeName,
const char* defaultValue,
bool configurable) {
939 return addStringOption(name, description, typeName, std::string(defaultValue), configurable);
942 std::string Config::getStringOptionValue(
const std::string& name) {
943 if (app->get_option(name) ==
nullptr) {
944 throw CLI::OptionNotFound(name);
947 return (*app)[name]->as<std::string>();
950 void Config::addFlag(
const std::string& name,
952 const std::string& description,
955 const std::string& groupName) {
956 app->add_flag(name, variable, description)
958 ->configurable(configurable)
962 std::string Config::getApplicationName() {
963 return applicationName;
966 int Config::getLogLevel() {
967 return logLevelOpt->as<
int>();
970 int Config::getVerboseLevel() {
971 return verboseLevelOpt->as<
int>();
974 int Config::argc = 0;
975 char** Config::argv =
nullptr;
977 std::string Config::applicationName;
979 std::string Config::configDirectory;
980 std::string Config::logDirectory;
981 std::string Config::pidDirectory;
983 CLI::Option* Config::daemonizeOpt =
nullptr;
984 CLI::Option* Config::logFileOpt =
nullptr;
985 CLI::Option* Config::userNameOpt =
nullptr;
986 CLI::Option* Config::groupNameOpt =
nullptr;
987 CLI::Option* Config::enforceLogFileOpt =
nullptr;
988 CLI::Option* Config::logLevelOpt =
nullptr;
989 CLI::Option* Config::verboseLevelOpt =
nullptr;
990 CLI::Option* Config::quietOpt =
nullptr;
992 std::map<std::string, std::string> Config::aliases;
993 std::map<std::string,
CLI::Option*> Config::applicationOptions;
CLI::App * getApp() const
CallForCommandline(CLI::App *app, const std::string &description, Mode mode)
CLI::App * getApp() const
CallForShowConfig(CLI::App *app)
std::string getConfigFile() const
CallForWriteConfig(const std::string &configFile)
static void startDaemon(const std::string &pidFileName, const std::string &userName, const std::string &groupName)
static pid_t stopDaemon(const std::string &pidFileName)
static void erasePidFile(const std::string &pidFileName)
static const std::shared_ptr< CLI::App > makeApp()
static std::string createCommandLineTemplate(CLI::App *app, CLI::CallForCommandline::Mode mode)
static const std::shared_ptr< CLI::HelpFormatter > makeSectionFormatter()
static void createCommandLineTemplate(std::stringstream &out, CLI::App *app, CLI::CallForCommandline::Mode mode)
static void createCommandLineOptions(std::stringstream &out, CLI::App *app, CLI::CallForCommandline::Mode mode)
static std::string createCommandLineOptions(CLI::App *app, CLI::CallForCommandline::Mode mode)
static std::string createCommandLineSubcommands(CLI::App *app, CLI::CallForCommandline::Mode mode)