summaryrefslogtreecommitdiff
path: root/src/mongo/util
diff options
context:
space:
mode:
authorShaun Verch <shaun.verch@10gen.com>2013-10-17 22:23:45 -0400
committerShaun Verch <shaun.verch@10gen.com>2013-10-23 19:41:30 -0400
commit107978292c125ebb6674ad57548f1a4dc8f977d1 (patch)
tree3354909dcab4a6dfdd1013ea461bd948b54b19f7 /src/mongo/util
parente7089550acfde9507dcae677e03000e8b2dad3b4 (diff)
downloadmongo-107978292c125ebb6674ad57548f1a4dc8f977d1.tar.gz
SERVER-11144 Chaining interface for option registration
Diffstat (limited to 'src/mongo/util')
-rw-r--r--src/mongo/util/options_parser/SConscript1
-rw-r--r--src/mongo/util/options_parser/option_description.cpp39
-rw-r--r--src/mongo/util/options_parser/option_description.h10
-rw-r--r--src/mongo/util/options_parser/option_section.cpp40
-rw-r--r--src/mongo/util/options_parser/option_section.h30
-rw-r--r--src/mongo/util/options_parser/options_parser_test.cpp218
6 files changed, 322 insertions, 16 deletions
diff --git a/src/mongo/util/options_parser/SConscript b/src/mongo/util/options_parser/SConscript
index 2390c19d6eb..0ca160f82a1 100644
--- a/src/mongo/util/options_parser/SConscript
+++ b/src/mongo/util/options_parser/SConscript
@@ -6,6 +6,7 @@ env.StaticLibrary('options_parser', ['environment.cpp',
'value.cpp',
'constraints.cpp',
'option_section.cpp',
+ 'option_description.cpp',
'options_parser.cpp',
'startup_option_init.cpp',
'startup_options.cpp',
diff --git a/src/mongo/util/options_parser/option_description.cpp b/src/mongo/util/options_parser/option_description.cpp
new file mode 100644
index 00000000000..fe052c9f716
--- /dev/null
+++ b/src/mongo/util/options_parser/option_description.cpp
@@ -0,0 +1,39 @@
+/* Copyright 2013 10gen Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "mongo/util/options_parser/option_description.h"
+
+namespace mongo {
+namespace optionenvironment {
+
+ OptionDescription& OptionDescription::hidden() {
+ _isVisible = false;
+ return *this;
+ }
+ OptionDescription& OptionDescription::setDefault(Value defaultValue) {
+ _default = defaultValue;
+ return *this;
+ }
+ OptionDescription& OptionDescription::setImplicit(Value implicitValue) {
+ _implicit = implicitValue;
+ return *this;
+ }
+ OptionDescription& OptionDescription::composing() {
+ _isComposing = true;
+ return *this;
+ }
+
+} // namespace optionenvironment
+} // namespace mongo
diff --git a/src/mongo/util/options_parser/option_description.h b/src/mongo/util/options_parser/option_description.h
index 6f3320e1e79..22fe12c0d74 100644
--- a/src/mongo/util/options_parser/option_description.h
+++ b/src/mongo/util/options_parser/option_description.h
@@ -62,6 +62,16 @@ namespace optionenvironment {
_implicit(implicitValue),
_isComposing(isComposing) { }
+ /*
+ * The following functions are part of the chaining interface for option registration. See
+ * comments below for what each of these attributes mean, and the OptionSection class for
+ * more details on the chaining interface.
+ */
+ OptionDescription& hidden();
+ OptionDescription& setDefault(Value defaultValue);
+ OptionDescription& setImplicit(Value implicitValue);
+ OptionDescription& composing();
+
std::string _dottedName; // Used for JSON config and in Environment
std::string _singleName; // Used for boost command line and INI
OptionType _type; // Storage type of the argument value, or switch type (bool)
diff --git a/src/mongo/util/options_parser/option_section.cpp b/src/mongo/util/options_parser/option_section.cpp
index 79d20a8a5e4..1fef8c21b54 100644
--- a/src/mongo/util/options_parser/option_section.cpp
+++ b/src/mongo/util/options_parser/option_section.cpp
@@ -18,6 +18,7 @@
#include <sstream>
#include "mongo/bson/util/builder.h"
+#include "mongo/util/assert_util.h"
#include "mongo/util/options_parser/value.h"
namespace mongo {
@@ -99,7 +100,7 @@ namespace optionenvironment {
Status OptionSection::addOption(const OptionDescription& option) {
// Verify that neither the single name nor the dotted name for this option conflicts with
// the names for any options we have already registered
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
if (option._dottedName == oditerator->_dottedName) {
StringBuilder sb;
@@ -159,10 +160,23 @@ namespace optionenvironment {
return Status::OK();
}
+ OptionDescription& OptionSection::addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description) {
+ OptionDescription option(dottedName, singleName, type, description);
+ Status ret = addOption(option);
+ if (!ret.isOK()) {
+ // TODO: Determine if this is the exception we want to throw
+ throw DBException(ret.reason(), ret.code());
+ }
+ return _options.back();
+ }
+
Status OptionSection::addPositionalOption(const PositionalOptionDescription& positionalOption) {
// Verify that the name for this positional option does not conflict with the name for any
// positional option we have already registered
- std::vector<PositionalOptionDescription>::const_iterator poditerator;
+ std::list<PositionalOptionDescription>::const_iterator poditerator;
for (poditerator = _positionalOptions.begin();
poditerator != _positionalOptions.end(); poditerator++) {
if (positionalOption._name == poditerator->_name) {
@@ -177,7 +191,7 @@ namespace optionenvironment {
// positional options that we also want to be visible command line flags
//
// TODO: More robust way to do this. This only works if we register the flag first
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
if (positionalOption._name == oditerator->_dottedName) {
_positionalOptions.push_back(positionalOption);
@@ -465,7 +479,7 @@ namespace optionenvironment {
bool visibleOnly,
bool includeDefaults) const {
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
if (!visibleOnly || (oditerator->_isVisible)) {
std::auto_ptr<po::value_semantic> boostType;
@@ -485,7 +499,7 @@ namespace optionenvironment {
}
}
- std::vector<OptionSection>::const_iterator ositerator;
+ std::list<OptionSection>::const_iterator ositerator;
for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
po::options_description subGroup = ositerator->_name.empty()
? po::options_description()
@@ -500,7 +514,7 @@ namespace optionenvironment {
Status OptionSection::getBoostPositionalOptions(
po::positional_options_description* boostPositionalOptions) const {
- std::vector<PositionalOptionDescription>::const_iterator poditerator;
+ std::list<PositionalOptionDescription>::const_iterator poditerator;
for (poditerator = _positionalOptions.begin();
poditerator != _positionalOptions.end(); poditerator++) {
boostPositionalOptions->add(poditerator->_name.c_str(), poditerator->_count);
@@ -514,12 +528,12 @@ namespace optionenvironment {
Status OptionSection::getAllOptions(std::vector<OptionDescription>* options) const {
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
options->push_back(*oditerator);
}
- std::vector<OptionSection>::const_iterator ositerator;
+ std::list<OptionSection>::const_iterator ositerator;
for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
ositerator->getAllOptions(options);
}
@@ -529,14 +543,14 @@ namespace optionenvironment {
Status OptionSection::getDefaults(std::map<Key, Value>* values) const {
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
if (!oditerator->_default.isEmpty()) {
(*values)[oditerator->_dottedName] = oditerator->_default;
}
}
- std::vector<OptionSection>::const_iterator ositerator;
+ std::list<OptionSection>::const_iterator ositerator;
for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
ositerator->getDefaults(values);
}
@@ -602,7 +616,7 @@ namespace optionenvironment {
/* Debugging */
void OptionSection::dump() const {
- std::vector<PositionalOptionDescription>::const_iterator poditerator;
+ std::list<PositionalOptionDescription>::const_iterator poditerator;
for (poditerator = _positionalOptions.begin();
poditerator != _positionalOptions.end(); poditerator++) {
std::cout << " _name: " << poditerator->_name
@@ -610,7 +624,7 @@ namespace optionenvironment {
<< " _count: " << poditerator->_count << std::endl;
}
- std::vector<OptionDescription>::const_iterator oditerator;
+ std::list<OptionDescription>::const_iterator oditerator;
for (oditerator = _options.begin(); oditerator != _options.end(); oditerator++) {
std::cout << " _dottedName: " << oditerator->_dottedName
<< " _singleName: " << oditerator->_singleName
@@ -619,7 +633,7 @@ namespace optionenvironment {
<< " _isVisible: " << oditerator->_isVisible << std::endl;
}
- std::vector<OptionSection>::const_iterator ositerator;
+ std::list<OptionSection>::const_iterator ositerator;
for (ositerator = _subSections.begin(); ositerator != _subSections.end(); ositerator++) {
std::cout << "Section Name: " << ositerator->_name << std::endl;
ositerator->dump();
diff --git a/src/mongo/util/options_parser/option_section.h b/src/mongo/util/options_parser/option_section.h
index fd115e4d55d..f729bc74b1b 100644
--- a/src/mongo/util/options_parser/option_section.h
+++ b/src/mongo/util/options_parser/option_section.h
@@ -18,6 +18,7 @@
#include <boost/program_options.hpp>
#include <iostream>
+#include <list>
#include "mongo/base/status.h"
@@ -78,6 +79,29 @@ namespace optionenvironment {
*/
Status addOption(const OptionDescription& option);
/**
+ * Add an option to this section, but returns a reference to an OptionDescription to allow
+ * for chaining.
+ *
+ * Example:
+ *
+ * options.addOptionChaining("option", "option", moe::String, "Chaining Registration")
+ * .hidden().setDefault(moe::Value("default"))
+ * .setImplicit(moe::Value("implicit")).composing();
+ *
+ * This creates a hidden option that is composing and has default and implicit values. See
+ * the OptionDescription class for details on these attributes.
+ *
+ * throws DBException on errors, such as attempting to register an option with the same name
+ * as another option, registering a composing option that does not have the type
+ * StringVector, or registering an option with a default value that does not match its type.
+ * All of these cases represent programming errors and should not happen during normal
+ * operation.
+ */
+ OptionDescription& addOptionChaining(const std::string& dottedName,
+ const std::string& singleName,
+ const OptionType type,
+ const std::string& description);
+ /**
* Add a positional option to this section. Also adds a normal hidden option with the same
* name as the PositionalOptionDescription because that is the mechanism boost program
* options uses. Unfortunately this means that positional options can also be accessed by
@@ -111,9 +135,9 @@ namespace optionenvironment {
private:
std::string _name;
- std::vector<OptionSection> _subSections;
- std::vector<OptionDescription> _options;
- std::vector<PositionalOptionDescription> _positionalOptions;
+ std::list<OptionSection> _subSections;
+ std::list<OptionDescription> _options;
+ std::list<PositionalOptionDescription> _positionalOptions;
};
} // namespace optionenvironment
diff --git a/src/mongo/util/options_parser/options_parser_test.cpp b/src/mongo/util/options_parser/options_parser_test.cpp
index 9c1abff4353..e8a028485c8 100644
--- a/src/mongo/util/options_parser/options_parser_test.cpp
+++ b/src/mongo/util/options_parser/options_parser_test.cpp
@@ -1626,4 +1626,222 @@ namespace {
ASSERT_EQUALS(host, "localhost");
}
+ TEST(ChainingInterface, GoodReference) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ // This test is to make sure our reference stays good even after we add more options. This
+ // would not be true if we were using a std::vector in our option section which may need to
+ // be moved and resized.
+ moe::OptionDescription& optionRef = testOpts.addOptionChaining("ref", "ref", moe::String,
+ "Save this Reference");
+ int i;
+ for (i = 0; i < 100; i++) {
+ ::mongo::StringBuilder sb;
+ sb << "filler" << i;
+ testOpts.addOptionChaining(sb.str(), sb.str(), moe::String, "Filler Option");
+ }
+ moe::Value defaultVal("default");
+ moe::Value implicitVal("implicit");
+ optionRef.hidden().setDefault(defaultVal);
+ optionRef.setImplicit(implicitVal).composing();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ bool foundRef = false;
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "ref") {
+ ASSERT_EQUALS(iterator->_singleName, "ref");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Save this Reference");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, true);
+ foundRef = true;
+ }
+ }
+ if (!foundRef) {
+ FAIL("Could not find \"ref\" options that we registered");
+ }
+ }
+
+ TEST(ChainingInterface, Basic) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("basic",
+ "basic",
+ moe::String,
+ "Default Option");
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "basic") {
+ ASSERT_EQUALS(iterator->_singleName, "basic");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Default Option");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ }
+ else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName <<
+ " which we did not register";
+ FAIL(sb.str());
+ }
+ }
+ }
+
+ TEST(ChainingInterface, Hidden) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("hidden",
+ "hidden",
+ moe::String,
+ "Hidden Option").hidden();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "hidden") {
+ ASSERT_EQUALS(iterator->_singleName, "hidden");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Hidden Option");
+ ASSERT_EQUALS(iterator->_isVisible, false);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ }
+ else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName <<
+ " which we did not register";
+ FAIL(sb.str());
+ }
+ }
+ }
+
+ TEST(ChainingInterface, DefaultValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value defaultVal("default");
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("default",
+ "default",
+ moe::String,
+ "Option With Default Value").setDefault(defaultVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "default") {
+ ASSERT_EQUALS(iterator->_singleName, "default");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Default Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.equal(defaultVal));
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ }
+ else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName <<
+ " which we did not register";
+ FAIL(sb.str());
+ }
+ }
+ }
+
+ TEST(ChainingInterface, ImplicitValue) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::Value implicitVal("implicit");
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("implicit",
+ "implicit",
+ moe::String,
+ "Option With Implicit Value").setImplicit(implicitVal);
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "implicit") {
+ ASSERT_EQUALS(iterator->_singleName, "implicit");
+ ASSERT_EQUALS(iterator->_type, moe::String);
+ ASSERT_EQUALS(iterator->_description, "Option With Implicit Value");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.equal(implicitVal));
+ ASSERT_EQUALS(iterator->_isComposing, false);
+ }
+ else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName <<
+ " which we did not register";
+ FAIL(sb.str());
+ }
+ }
+ }
+
+ TEST(ChainingInterface, Composing) {
+ OptionsParserTester parser;
+ moe::Environment environment;
+
+ moe::OptionSection testOpts;
+ testOpts.addOptionChaining("setParameter",
+ "setParameter",
+ moe::StringVector,
+ "Multiple Values").composing();
+
+ std::vector<moe::OptionDescription> options_vector;
+ ASSERT_OK(testOpts.getAllOptions(&options_vector));
+
+ for(std::vector<moe::OptionDescription>::const_iterator iterator = options_vector.begin();
+ iterator != options_vector.end(); iterator++) {
+
+ if (iterator->_dottedName == "setParameter") {
+ ASSERT_EQUALS(iterator->_singleName, "setParameter");
+ ASSERT_EQUALS(iterator->_type, moe::StringVector);
+ ASSERT_EQUALS(iterator->_description, "Multiple Values");
+ ASSERT_EQUALS(iterator->_isVisible, true);
+ ASSERT_TRUE(iterator->_default.isEmpty());
+ ASSERT_TRUE(iterator->_implicit.isEmpty());
+ ASSERT_EQUALS(iterator->_isComposing, true);
+ }
+ else {
+ ::mongo::StringBuilder sb;
+ sb << "Found extra option: " << iterator->_dottedName <<
+ " which we did not register";
+ FAIL(sb.str());
+ }
+ }
+ }
+
} // unnamed namespace