]> granicus.if.org Git - icinga2/commitdiff
Use boost::program_options to parse arguments.
authorGunnar Beutner <gunnar.beutner@netways.de>
Sat, 2 Feb 2013 22:22:27 +0000 (23:22 +0100)
committerGunnar Beutner <gunnar.beutner@netways.de>
Sat, 2 Feb 2013 22:22:27 +0000 (23:22 +0100)
Fixes #3536
Fixes #3184

configure.ac
icinga-app/Makefile.am
icinga-app/icinga.cpp
lib/base/application.cpp
lib/base/application.h
lib/base/i2-base.h
lib/base/logger.cpp
lib/config/configcompiler.cpp
lib/icinga/icingaapplication.cpp
lib/icinga/icingaapplication.h
m4/ax_boost_program_options.m4 [new file with mode: 0644]

index f4d50c9f6b10e47feb33269eedce3c5e946c1d47..283a7e905386435f0388f99c33f78817708976ac 100644 (file)
@@ -56,6 +56,7 @@ AX_BOOST_SIGNALS
 AX_BOOST_THREAD
 AX_BOOST_SYSTEM
 AX_BOOST_UNIT_TEST_FRAMEWORK
+AX_BOOST_PROGRAM_OPTIONS
 AX_CHECK_OPENSSL([], [AC_MSG_ERROR([You need the OpenSSL headers and libraries in order to build this application])])
 AC_CHECK_LIB(ssl, SSL_new)
 AC_CHECK_LIB(crypto, X509_NAME_oneline)
index 9665a9f583d5de4ce0018d86f3a081585fc24160..087edcc86e192d5cb46c7ca76547ea4f0911660d 100644 (file)
@@ -28,6 +28,7 @@ icinga2_LDADD = \
        $(BOOST_SIGNALS_LIB) \
        $(BOOST_THREAD_LIB) \
        $(BOOST_SYSTEM_LIB) \
+       $(BOOST_PROGRAM_OPTIONS_LIB) \
        ${top_builddir}/lib/base/libbase.la \
        ${top_builddir}/lib/config/libconfig.la \
        ${top_builddir}/lib/remoting/libremoting.la \
index b117fb53ba558698d7886391f669761f6cc17554..2b3ae47c7244fb732a2728b57c678224cf3103d3 100644 (file)
@@ -28,6 +28,7 @@
 #endif /* _WIN32 */
 
 using namespace icinga;
+namespace po = boost::program_options;
 
 /**
  * Entry point for the Icinga application.
@@ -75,56 +76,90 @@ int main(int argc, char **argv)
 #endif /* _WIN32 */
        );
 
-       if (argc < 3 || strcmp(argv[1], "-c") != 0) {
-               stringstream msgbuf;
-               msgbuf << "Syntax: " << argv[0] << " -c <config-file> ...";    
-               Logger::Write(LogInformation, "icinga-app", msgbuf.str());
-               return EXIT_FAILURE;
+       po::options_description desc("Supported options");
+       desc.add_options()
+               ("help,h", "show this help message")
+               ("library,l", po::value<vector<String> >(), "load a library")
+               ("include,I", po::value<vector<String> >(), "add include search directory")
+               ("config,c", po::value<vector<String> >(), "parse a configuration file")
+               ("validate,v", "exit after validating the configuration")
+               ("debug", "enable debugging")
+               ("daemonize,d", "daemonize after reading the configuration files")
+       ;
+
+       po::variables_map vm;
+       po::store(po::parse_command_line(argc, argv, desc), vm);
+       po::notify(vm);
+
+       if (vm.count("debug"))
+               Application::SetDebugging(true);
+
+       if (vm.count("help")) {
+               std::cout << desc << "\n";
+
+               return EXIT_SUCCESS;
        }
 
        Component::AddSearchDir(Application::GetPkgLibDir());
 
        Utility::LoadIcingaLibrary("icinga", false);
 
+       if (vm.count("library")) {
+               BOOST_FOREACH(const String& libraryName, vm["library"].as<vector<String> >()) {
+                       Utility::LoadIcingaLibrary(libraryName, false);
+               }
+       }
+
        ConfigCompiler::AddIncludeSearchDir(Application::GetPkgDataDir());
 
+       if (vm.count("include")) {
+               BOOST_FOREACH(const String& includePath, vm["include"].as<vector<String> >()) {
+                       ConfigCompiler::AddIncludeSearchDir(includePath);
+               }
+       }
+
+       if (vm.count("config") == 0) {
+               Logger::Write(LogCritical, "icinga-app", "You need to specify at least one config file (using the --config option).");
+
+               return EXIT_FAILURE;
+       }
+
        try {
                DynamicObject::BeginTx();
 
-               /* load config file */
-               String configFile = argv[2];
-               vector<ConfigItem::Ptr> items;
-               vector<ConfigType::Ptr> types;
+               /* load config files */
+               BOOST_FOREACH(const String& configPath, vm["config"].as<vector<String> >()) {
+                       String configFile = argv[2];
+                       vector<ConfigItem::Ptr> items;
+                       vector<ConfigType::Ptr> types;
                
-               ConfigCompiler::CompileFile(configFile, &items, &types);
+                       ConfigCompiler::CompileFile(configFile, &items, &types);
 
-               Logger::Write(LogInformation, "icinga-app", "Registering config types...");
-               
-               BOOST_FOREACH(const ConfigType::Ptr& type, types) {
-                       type->Commit();
-               }
-               
-               Logger::Write(LogInformation, "icinga-app", "Executing config items...");  
-
-               BOOST_FOREACH(const ConfigItem::Ptr& item, items) {
-                       item->Commit();
-               }
-
-               Logger::Write(LogInformation, "icinga-app", "Validating config items...");
+                       Logger::Write(LogInformation, "icinga-app", "Registering config types...");
+                       BOOST_FOREACH(const ConfigType::Ptr& type, types) {
+                               type->Commit();
+                       }
                
-               DynamicType::Ptr type;
-               BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
-                       ConfigType::Ptr ctype = ConfigType::GetByName(type->GetName());
-                       
-                       if (!ctype) {
-                               Logger::Write(LogWarning, "icinga-app", "No config type found for type '" + type->GetName() + "'");
-                               
-                               continue;
+                       Logger::Write(LogInformation, "icinga-app", "Executing config items...");  
+                       BOOST_FOREACH(const ConfigItem::Ptr& item, items) {
+                               item->Commit();
                        }
+
+                       Logger::Write(LogInformation, "icinga-app", "Validating config items...");      
+                       DynamicType::Ptr type;
+                       BOOST_FOREACH(tie(tuples::ignore, type), DynamicType::GetTypes()) {
+                               ConfigType::Ptr ctype = ConfigType::GetByName(type->GetName());
                        
-                       DynamicObject::Ptr object;
-                       BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
-                               ctype->ValidateObject(object);
+                               if (!ctype) {
+                                       Logger::Write(LogWarning, "icinga-app", "No config type found for type '" + type->GetName() + "'");
+
+                                       continue;
+                               }
+
+                               DynamicObject::Ptr object;
+                               BOOST_FOREACH(tie(tuples::ignore, object), type->GetObjects()) {
+                                       ctype->ValidateObject(object);
+                               }
                        }
                }
                
@@ -139,8 +174,16 @@ int main(int argc, char **argv)
        if (!app)
                throw_exception(runtime_error("Configuration must create an Application object."));
 
-       /* The application class doesn't need to know about the "-c configFile"
-        * command-line arguments. */
-       return app->Run(argc - 2, &(argv[2]));
+       if (vm.count("validate")) {
+               Logger::Write(LogInformation, "icinga-app", "Terminating as requested by --validate.");
+               return EXIT_SUCCESS;
+       }
+
+       if (vm.count("daemonize")) {
+               Logger::Write(LogInformation, "icinga", "Daemonizing.");
+               Utility::Daemonize();
+       }
+
+       return app->Run();
 }
 
index e0a77022ad9d0b7db07e7316cb048ab70a5c47d8..cd7c2cae6411d7b25a5860b17e48c383041f62ff 100644 (file)
@@ -246,6 +246,16 @@ String Application::GetExePath(const String& argv0)
 #endif /* _WIN32 */
 }
 
+/**
+ * Sets whether debugging is enabled.
+ *
+ * @param debug Whether to enable debugging.
+ */
+void Application::SetDebugging(bool debug)
+{
+       m_Debugging = debug;
+}
+
 /**
  * Retrieves the debugging mode of the application.
  *
@@ -394,11 +404,9 @@ void Application::InstallExceptionHandlers(void)
 /**
  * Runs the application.
  *
- * @param argc The number of arguments.
- * @param argv The arguments that should be passed to the application.
  * @returns The application's exit code.
  */
-int Application::Run(int argc, char **argv)
+int Application::Run(void)
 {
        int result;
 
@@ -414,13 +422,9 @@ int Application::Run(int argc, char **argv)
        SetConsoleCtrlHandler(&Application::CtrlHandler, TRUE);
 #endif /* _WIN32 */
 
-       m_Arguments.clear();
-       for (int i = 0; i < argc; i++)
-               m_Arguments.push_back(String(argv[i]));
-
        DynamicObject::BeginTx();
 
-       result = Main(m_Arguments);
+       result = Main();
 
        DynamicObject::FinishTx();
        DynamicObject::DeactivateObjects();
index 974c9d82c98aa1fde83c08398a283af9c07763ce..b75ce64a86f73746a8cf028da4199aaccb81f56a 100644 (file)
@@ -39,21 +39,21 @@ public:
 
        static Application::Ptr GetInstance(void);
 
-       int Run(int argc, char **argv);
+       int Run(void);
 
        /**
         * Starts the application.
         *
-        * @param args Arguments for the application.
         * @returns The exit code of the application.
         */
-       virtual int Main(const vector<String>& args) = 0;
+       virtual int Main(void) = 0;
 
        static void InstallExceptionHandlers(void);
 
        static void RequestShutdown(void);
        static void Terminate(int exitCode);
 
+       static void SetDebugging(bool debug);
        static bool IsDebugging(void);
 
        static bool IsMainThread(void);
index 2b27f51483e18c4831fc5db9166d2fdf3cc84ba4..c48b007aeb15e68ded903d1ddc8fac0e3b80c57a 100644 (file)
@@ -137,6 +137,7 @@ using std::type_info;
 #include <boost/uuid/uuid.hpp>
 #include <boost/uuid/uuid_generators.hpp>
 #include <boost/uuid/uuid_io.hpp>
+#include <boost/program_options.hpp>
 
 using boost::shared_ptr;
 using boost::weak_ptr;
index 86871cdf641a9e8b76d2a9ba773e2d8bc5746bd8..95af4c214f9fa3d3d1d66e548553a001a47b88d2 100644 (file)
@@ -119,7 +119,14 @@ void Logger::ForwardLogEntry(const LogEntry& entry)
                processed = true;
        }
 
-       if (!processed && entry.Severity >= LogInformation) {
+       LogSeverity defaultLogLevel;
+
+       if (Application::IsDebugging())
+               defaultLogLevel = LogDebug;
+       else
+               defaultLogLevel = LogInformation;
+
+       if (!processed && entry.Severity >= defaultLogLevel) {
                static bool tty = StreamLogger::IsTty(std::cout);
 
                StreamLogger::ProcessLogEntry(std::cout, tty, entry);
index a9b1a25acb9e6cf57e214355e8a7abc16fe372f3..a4332b49362cf43225df57b740cf3092d8fb0af6 100644 (file)
@@ -250,6 +250,8 @@ void ConfigCompiler::AddObject(const ConfigItem::Ptr& object)
  */
 void ConfigCompiler::AddIncludeSearchDir(const String& dir)
 {
+       Logger::Write(LogInformation, "config", "Adding include search dir: " + dir);
+
        m_IncludeSearchDirs.push_back(dir);
 }
 
index 777180756e334947867cb03751da09479eef2f0e..4b3e5edc8cfcba3d0db63017b6aac12067377a66 100644 (file)
@@ -48,50 +48,14 @@ IcingaApplication::IcingaApplication(const Dictionary::Ptr& serializedUpdate)
 /**
  * The entry point for the Icinga application.
  *
- * @param args Command-line arguments.
  * @returns An exit status.
  */
-int IcingaApplication::Main(const vector<String>& args)
+int IcingaApplication::Main(void)
 {
        Logger::Write(LogInformation, "icinga", "In IcingaApplication::Main()");
 
        m_StartTime = Utility::GetTime();
 
-       if (args.size() == 1 && args[0] == "--help") {
-               stringstream msgbuf;
-               msgbuf << "Syntax: " << args[0] << " ... -d";
-               Logger::Write(LogInformation, "icinga", msgbuf.str());
-               return EXIT_FAILURE;
-       }
-
-       bool daemonize = false;
-       bool parseOpts = true;
-       String configFile;
-
-       /* TODO: clean up this mess; for now it will just have to do */
-       vector<String>::const_iterator it;
-       for (it = args.begin() + 1 ; it != args.end(); it++) {
-               String arg = *it;
-
-               /* ignore empty arguments */
-               if (arg.IsEmpty())
-                       continue;
-
-               if (arg == "--") {
-                       parseOpts = false;
-                       continue;
-               }
-
-               if (parseOpts && arg[0] == '-') {
-                       if (arg == "-d") {
-                               daemonize = true;
-                               continue;
-                       } else {
-                               throw_exception(invalid_argument("Unknown option: " + arg));
-                       }
-               }
-       }
-
        UpdatePidFile(GetPidPath());
 
        if (!GetCertificateFile().IsEmpty() && !GetCAFile().IsEmpty()) {
@@ -110,13 +74,6 @@ int IcingaApplication::Main(const vector<String>& args)
        if (!GetService().IsEmpty())
                EndpointManager::GetInstance()->AddListener(GetService());
 
-       if (daemonize) {
-               Logger::Write(LogInformation, "icinga", "Daemonizing.");
-               ClosePidFile();
-               Utility::Daemonize();
-               UpdatePidFile(GetPidPath());
-       }
-
        /* restore the previous program state */
        DynamicObject::RestoreObjects(GetStatePath());
 
index 01c1a920bfe0ef813e9280e1063a2c6bf49a9773..f17222afb5bcbfb3a1935c964a077f4d9ba459a5 100644 (file)
@@ -36,7 +36,7 @@ public:
 
        IcingaApplication(const Dictionary::Ptr& serializedUpdate);
 
-       int Main(const vector<String>& args);
+       int Main(void);
 
        static IcingaApplication::Ptr GetInstance(void);
 
diff --git a/m4/ax_boost_program_options.m4 b/m4/ax_boost_program_options.m4
new file mode 100644 (file)
index 0000000..38b9539
--- /dev/null
@@ -0,0 +1,111 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_boost_program_options.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_BOOST_PROGRAM_OPTIONS
+#
+# DESCRIPTION
+#
+#   Test for program options library from the Boost C++ libraries. The macro
+#   requires a preceding call to AX_BOOST_BASE. Further documentation is
+#   available at <http://randspringer.de/boost/index.html>.
+#
+#   This macro calls:
+#
+#     AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB)
+#
+#   And sets:
+#
+#     HAVE_BOOST_PROGRAM_OPTIONS
+#
+# LICENSE
+#
+#   Copyright (c) 2009 Thomas Porschberg <thomas@randspringer.de>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 22
+
+AC_DEFUN([AX_BOOST_PROGRAM_OPTIONS],
+[
+       AC_ARG_WITH([boost-program-options],
+               AS_HELP_STRING([--with-boost-program-options@<:@=special-lib@:>@],
+                       [use the program options library from boost - it is possible to specify a certain library for the linker
+                        e.g. --with-boost-program-options=boost_program_options-gcc-mt-1_33_1 ]),
+        [
+        if test "$withval" = "no"; then
+                       want_boost="no"
+        elif test "$withval" = "yes"; then
+            want_boost="yes"
+            ax_boost_user_program_options_lib=""
+        else
+                   want_boost="yes"
+               ax_boost_user_program_options_lib="$withval"
+               fi
+        ],
+        [want_boost="yes"]
+       )
+
+       if test "x$want_boost" = "xyes"; then
+        AC_REQUIRE([AC_PROG_CC])
+           export want_boost
+               CPPFLAGS_SAVED="$CPPFLAGS"
+               CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+               export CPPFLAGS
+               LDFLAGS_SAVED="$LDFLAGS"
+               LDFLAGS="$LDFLAGS $BOOST_LDFLAGS"
+               export LDFLAGS
+               AC_CACHE_CHECK([whether the Boost::Program_Options library is available],
+                                          ax_cv_boost_program_options,
+                                          [AC_LANG_PUSH(C++)
+                               AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include <boost/program_options.hpp>
+                                                          ]],
+                                  [[boost::program_options::options_description generic("Generic options");
+                                   return 0;]])],
+                           ax_cv_boost_program_options=yes, ax_cv_boost_program_options=no)
+                                       AC_LANG_POP([C++])
+               ])
+               if test "$ax_cv_boost_program_options" = yes; then
+                               AC_DEFINE(HAVE_BOOST_PROGRAM_OPTIONS,,[define if the Boost::PROGRAM_OPTIONS library is available])
+                  BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'`
+                if test "x$ax_boost_user_program_options_lib" = "x"; then
+                for libextension in `ls $BOOSTLIBDIR/libboost_program_options*.so* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.so.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.dylib* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.dylib.*$;\1;'` `ls $BOOSTLIBDIR/libboost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_program_options.*\)\.a.*$;\1;'` ; do
+                     ax_lib=${libextension}
+                                   AC_CHECK_LIB($ax_lib, exit,
+                                 [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
+                                 [link_program_options="no"])
+                               done
+                if test "x$link_program_options" != "xyes"; then
+                for libextension in `ls $BOOSTLIBDIR/boost_program_options*.dll* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.dll.*$;\1;'` `ls $BOOSTLIBDIR/boost_program_options*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_program_options.*\)\.a.*$;\1;'` ; do
+                     ax_lib=${libextension}
+                                   AC_CHECK_LIB($ax_lib, exit,
+                                 [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
+                                 [link_program_options="no"])
+                               done
+                fi
+                else
+                  for ax_lib in $ax_boost_user_program_options_lib boost_program_options-$ax_boost_user_program_options_lib; do
+                                     AC_CHECK_LIB($ax_lib, main,
+                                   [BOOST_PROGRAM_OPTIONS_LIB="-l$ax_lib"; AC_SUBST(BOOST_PROGRAM_OPTIONS_LIB) link_program_options="yes"; break],
+                                   [link_program_options="no"])
+                  done
+                fi
+            if test "x$ax_lib" = "x"; then
+                AC_MSG_ERROR(Could not find a version of the library!)
+            fi
+                               if test "x$link_program_options" != "xyes"; then
+                                       AC_MSG_ERROR([Could not link against [$ax_lib] !])
+                               fi
+               fi
+
+               ax_lib=""
+
+               CPPFLAGS="$CPPFLAGS_SAVED"
+       LDFLAGS="$LDFLAGS_SAVED"
+       fi
+])