diff options
author | Charles E. Rolke <chug@apache.org> | 2012-09-20 13:48:40 +0000 |
---|---|---|
committer | Charles E. Rolke <chug@apache.org> | 2012-09-20 13:48:40 +0000 |
commit | e20a23b370e64c6f09a57b4ddefd6f650e89ba13 (patch) | |
tree | 9a8c05e15b071bc7fd3f78017d76b8ffb4824e32 | |
parent | a848dc683403f7f2cb26c693b561d3aa70506efb (diff) | |
download | qpid-python-e20a23b370e64c6f09a57b4ddefd6f650e89ba13.tar.gz |
QPID-3500 C++ qpidd broker --help should work despite parse errors
This patch finds and processes --version before anything else.
Then it finds --help before fully parsing command line options.
In the event of a parse error, help usage may be shown as requested.
git-svn-id: https://svn.apache.org/repos/asf/qpid/trunk@1388032 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r-- | qpid/cpp/include/qpid/Options.h | 5 | ||||
-rw-r--r-- | qpid/cpp/src/posix/QpiddBroker.cpp | 16 | ||||
-rw-r--r-- | qpid/cpp/src/qpid/Options.cpp | 42 | ||||
-rw-r--r-- | qpid/cpp/src/qpidd.cpp | 38 | ||||
-rw-r--r-- | qpid/cpp/src/qpidd.h | 3 | ||||
-rw-r--r-- | qpid/cpp/src/windows/QpiddBroker.cpp | 12 |
6 files changed, 89 insertions, 27 deletions
diff --git a/qpid/cpp/include/qpid/Options.h b/qpid/cpp/include/qpid/Options.h index 0bbe7b704f..feef5d8b98 100644 --- a/qpid/cpp/include/qpid/Options.h +++ b/qpid/cpp/include/qpid/Options.h @@ -149,6 +149,11 @@ struct Options : public po::options_description { const std::string& configfile=std::string(), bool allowUnknown = false); + /** + * Tests for presence of argc/argv switch + */ + QPID_COMMON_EXTERN bool findArg(int argc, char const* const* argv, + const std::string& theArg); boost::program_options::options_description_easy_init addOptions() { return add_options(); diff --git a/qpid/cpp/src/posix/QpiddBroker.cpp b/qpid/cpp/src/posix/QpiddBroker.cpp index 76e3bb6674..f1f9009568 100644 --- a/qpid/cpp/src/posix/QpiddBroker.cpp +++ b/qpid/cpp/src/posix/QpiddBroker.cpp @@ -48,6 +48,10 @@ BootstrapOptions::BootstrapOptions(const char* argv0) add(log); } +void BootstrapOptions::usage() const { + cout << "Usage: qpidd [OPTIONS]" << endl << endl << *this << endl; +} + namespace { const std::string TCP = "tcp"; } @@ -111,17 +115,17 @@ void QpiddOptions::usage() const { // Set the broker pointer on the signal handler, then reset at end of scope. // This is to ensure that the signal handler doesn't keep a broker // reference after main() has returned. -// +// struct ScopedSetBroker { ScopedSetBroker(const boost::intrusive_ptr<Broker>& broker) { qpid::broker::SignalHandler::setBroker(broker.get()); } ~ScopedSetBroker() { qpid::broker::SignalHandler::setBroker(0); } }; - + struct QpiddDaemon : public Daemon { QpiddPosixOptions *options; - + QpiddDaemon(std::string pidDir, QpiddPosixOptions *opts) : Daemon(pidDir), options(opts) {} @@ -129,7 +133,7 @@ struct QpiddDaemon : public Daemon { void parent() { uint16_t port = wait(options->daemon.wait); if (options->parent->broker.port == 0 || options->daemon.transport != TCP) - cout << port << endl; + cout << port << endl; } /** Code for forked child process */ @@ -162,12 +166,12 @@ int QpiddBroker::execute (QpiddOptions *options) { QPID_LOG(notice, "Cannot stop broker: " << e.what()); return 1; } - if (pid < 0) + if (pid < 0) return 1; if (myOptions->daemon.check) cout << pid << endl; if (myOptions->daemon.quit) { - if (kill(pid, SIGINT) < 0) + if (kill(pid, SIGINT) < 0) throw Exception("Failed to stop daemon: " + qpid::sys::strError(errno)); // Wait for the process to die before returning int retry=10000; // Try up to 10 seconds diff --git a/qpid/cpp/src/qpid/Options.cpp b/qpid/cpp/src/qpid/Options.cpp index 35787aa8f3..9813dda697 100644 --- a/qpid/cpp/src/qpid/Options.cpp +++ b/qpid/cpp/src/qpid/Options.cpp @@ -41,13 +41,13 @@ struct EnvOptMapper { return desc->long_name().size() == env.size() && std::equal(env.begin(), env.end(), desc->long_name().begin(), &matchChar); } - + static bool matchCase(const string& env, boost::shared_ptr<po::option_description> desc) { return env == desc->long_name(); } - + EnvOptMapper(const Options& o) : opts(o) {} - + string operator()(const string& envVar) { static const std::string prefix("QPID_"); if (envVar.substr(0, prefix.size()) == prefix) { @@ -75,7 +75,7 @@ struct EnvOptMapper { string configFileLine (string& line) { - + if ( isComment ( line ) ) return string(); @@ -85,7 +85,7 @@ struct EnvOptMapper { string key = line.substr (0, pos); #if (BOOST_VERSION >= 103300) typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs; - OptDescs::const_iterator i = + OptDescs::const_iterator i = find_if(opts.options().begin(), opts.options().end(), boost::bind(matchCase, key, _1)); if (i != opts.options().end()) return string (line) + "\n"; @@ -109,8 +109,8 @@ std::string prettyArg(const std::string& name, const std::string& value) { return value.empty() ? name+" " : name+" ("+value+") "; } -Options::Options(const string& name) : - po::options_description(name) +Options::Options(const string& name) : + po::options_description(name) { } @@ -197,5 +197,33 @@ CommonOptions::CommonOptions(const string& name, const string& configfile, const } + +bool Options::findArg(int argc, char const* const* argv, const std::string& theArg) +{ + const string parsing("command line options"); + bool result(false); + try { + if (argc > 0 && argv != 0) { + po::command_line_parser clp = po::command_line_parser(argc, const_cast<char**>(argv)). + options(*this).allow_unregistered(); + po::parsed_options opts = clp.run(); + + for (std::vector< po::basic_option<char> >::iterator + i = opts.options.begin(); i != opts.options.end(); i++) { + if (theArg.compare(i->string_key) == 0) { + result = true; + break; + } + } + } + return result; + } + catch (const std::exception& e) { + ostringstream msg; + msg << "Error in " << parsing << ": " << e.what() << endl; + throw Exception(msg.str()); + } +} + } // namespace qpid diff --git a/qpid/cpp/src/qpidd.cpp b/qpid/cpp/src/qpidd.cpp index b5686c6ab8..920009580c 100644 --- a/qpid/cpp/src/qpidd.cpp +++ b/qpid/cpp/src/qpidd.cpp @@ -41,6 +41,18 @@ int run_broker(int argc, char *argv[], bool hidden) { BootstrapOptions bootOptions(argv[0]); string defaultPath (bootOptions.module.loadDir); + + // --version causes print and exit + if (bootOptions.findArg(argc, argv, "version")) { + cout << "qpidd (" << qpid::product << ") version " + << qpid::version << endl; + return 0; + } + + // --help sets a flag so that its presence is known despite + // subsequent parse problems. + bool helpArgSeen = bootOptions.findArg(argc, argv, "help"); + // Parse only the common, load, and log options to see which // modules need to be loaded. Once the modules are loaded, // the command line will be re-parsed with all of the @@ -51,8 +63,12 @@ int run_broker(int argc, char *argv[], bool hidden) bootOptions.log.sinkOptions->detached(); qpid::log::Logger::instance().configure(bootOptions.log); } catch (const std::exception& e) { + if (helpArgSeen) { + // provide help even when parsing fails + bootOptions.usage(); + } // Couldn't configure logging so write the message direct to stderr. - cerr << "Unexpected error: " << e.what() << endl; + cerr << endl << "Unexpected error: " << e.what() << endl; return 1; } @@ -67,16 +83,20 @@ int run_broker(int argc, char *argv[], bool hidden) } // Parse options - options.reset(new QpiddOptions(argv[0])); - options->parse(argc, argv, options->common.config); + try { + options.reset(new QpiddOptions(argv[0])); + options->parse(argc, argv, options->common.config); + } catch (const std::exception& /*e*/) { + if (helpArgSeen) { + // provide help even when parsing fails + options->usage(); + } + throw; + } // Options that just print information. - if (options->common.help || options->common.version) { - if (options->common.version) - cout << "qpidd (" << qpid::product << ") version " - << qpid::version << endl; - else if (options->common.help) - options->usage(); + if (helpArgSeen) { + options->usage(); return 0; } diff --git a/qpid/cpp/src/qpidd.h b/qpid/cpp/src/qpidd.h index f7f84d11da..08356ab29e 100644 --- a/qpid/cpp/src/qpidd.h +++ b/qpid/cpp/src/qpidd.h @@ -37,9 +37,10 @@ namespace broker { struct BootstrapOptions : public qpid::Options { qpid::CommonOptions common; qpid::ModuleOptions module; - qpid::log::Options log; + qpid::log::Options log; BootstrapOptions(const char *argv0); + void usage() const; }; // Each platform derives an options struct from QpiddOptionsPrivate, adding diff --git a/qpid/cpp/src/windows/QpiddBroker.cpp b/qpid/cpp/src/windows/QpiddBroker.cpp index 4ca3f3059c..de2e41dd4d 100644 --- a/qpid/cpp/src/windows/QpiddBroker.cpp +++ b/qpid/cpp/src/windows/QpiddBroker.cpp @@ -53,6 +53,10 @@ BootstrapOptions::BootstrapOptions(const char* argv0) add(log); } +void BootstrapOptions::usage() const { + std::cout << "Usage: qpidd [OPTIONS]" << std::endl << std::endl << *this << std::endl; +} + // Local functions to set and get the pid via a LockFile. namespace { @@ -225,10 +229,10 @@ VOID WINAPI SvcCtrlHandler(DWORD control) ::SetServiceStatus(svcStatusHandle, &svcStatus); CtrlHandler(CTRL_C_EVENT); break; - + case SERVICE_CONTROL_INTERROGATE: break; - + default: break; } @@ -306,7 +310,7 @@ struct ServiceOptions : public qpid::Options { std::string password; std::string depends; - ServiceOptions() + ServiceOptions() : qpid::Options("Service options"), install(false), start(false), @@ -423,7 +427,7 @@ int QpiddBroker::execute (QpiddOptions *options) { // Relies on port number being set via --port or QPID_PORT env variable. NamedSharedMemory<BrokerInfo> info(brokerInfoName(options->broker.port)); int pid = info.get().pid; - if (pid < 0) + if (pid < 0) return 1; if (myOptions->control.check) std::cout << pid << std::endl; |