You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2013/05/29 19:40:49 UTC
[11/35] git commit: Moved flags to stout.
Moved flags to stout.
Review: https://reviews.apache.org/r/11465
Project: http://git-wip-us.apache.org/repos/asf/incubator-mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mesos/commit/190a3bb8
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mesos/tree/190a3bb8
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mesos/diff/190a3bb8
Branch: refs/heads/master
Commit: 190a3bb80656ffdd435561d8e8f0f638bdcd7d6e
Parents: f122e61
Author: Benjamin Hindman <be...@twitter.com>
Authored: Tue May 21 10:55:30 2013 -0700
Committer: Benjamin Hindman <be...@twitter.com>
Committed: Tue May 28 14:18:39 2013 -0700
----------------------------------------------------------------------
third_party/libprocess/third_party/Makefile.am | 1 +
.../libprocess/third_party/stout/Makefile.am | 6 +
.../third_party/stout/include/stout/flags.hpp | 70 +++
.../third_party/stout/include/stout/flags/flag.hpp | 26 +
.../stout/include/stout/flags/flags.hpp | 481 +++++++++++++++
.../stout/include/stout/flags/loader.hpp | 109 ++++
.../stout/include/stout/flags/parse.hpp | 55 ++
.../third_party/stout/include/stout/os.hpp | 22 +
.../third_party/stout/tests/flags_tests.cpp | 349 +++++++++++
9 files changed, 1119 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/Makefile.am
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/Makefile.am b/third_party/libprocess/third_party/Makefile.am
index 812b7c3..2f0567b 100644
--- a/third_party/libprocess/third_party/Makefile.am
+++ b/third_party/libprocess/third_party/Makefile.am
@@ -119,6 +119,7 @@ stout_tests_SOURCES = \
$(STOUT)/tests/bytes_tests.cpp \
$(STOUT)/tests/duration_tests.cpp \
$(STOUT)/tests/error_tests.cpp \
+ $(STOUT)/tests/flags_tests.cpp \
$(STOUT)/tests/gzip_tests.cpp \
$(STOUT)/tests/hashset_tests.cpp \
$(STOUT)/tests/json_tests.cpp \
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/Makefile.am
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/Makefile.am b/third_party/libprocess/third_party/stout/Makefile.am
index 4af647e..fdd3482 100644
--- a/third_party/libprocess/third_party/stout/Makefile.am
+++ b/third_party/libprocess/third_party/stout/Makefile.am
@@ -11,6 +11,11 @@ EXTRA_DIST = \
include/stout/error.hpp \
include/stout/exit.hpp \
include/stout/fatal.hpp \
+ include/stout/flags.hpp \
+ include/stout/flags/flag.hpp \
+ include/stout/flags/flags.hpp \
+ include/stout/flags/loader.hpp \
+ include/stout/flags/parse.hpp \
include/stout/foreach.hpp \
include/stout/format.hpp \
include/stout/fs.hpp \
@@ -43,6 +48,7 @@ EXTRA_DIST = \
tests/bytes_tests.cpp \
tests/duration_tests.cpp \
tests/error_tests.cpp \
+ tests/flags_tests.cpp \
tests/gzip_tests.cpp \
tests/hashset_tests.cpp \
tests/json_tests.cpp \
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/flags.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/flags.hpp b/third_party/libprocess/third_party/stout/include/stout/flags.hpp
new file mode 100644
index 0000000..0efd079
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/include/stout/flags.hpp
@@ -0,0 +1,70 @@
+#ifndef __STOUT_FLAGS_HPP__
+#define __STOUT_FLAGS_HPP__
+
+#include <stout/flags/flags.hpp>
+
+// An abstraction for application/library "flags". An example is
+// probably best:
+// -------------------------------------------------------------
+// class MyFlags : public virtual FlagsBase // Use 'virtual' for composition!
+// {
+// public:
+// Flags()
+// {
+// add(&debug,
+// "debug",
+// "Help string for debug",
+// false);
+//
+// add(&name,
+// "name",
+// "Help string for name");
+// }
+
+// bool debug;
+// Option<string> name;
+// };
+//
+// ...
+//
+// map<string, Option<string> > values;
+// values["no-debug"] = None(); // --no-debug
+// values["debug"] = None(); // --debug
+// values["debug"] = Option<string>::some("true"); // --debug=true
+// values["debug"] = Option<string>::some("false"); // --debug=false
+// values["name"] = Option<string>::some("frank"); // --name=frank
+//
+// MyFlags flags;
+// flags.load(values);
+// flags.name.isSome() ...
+// flags.debug ...
+// -------------------------------------------------------------
+//
+// You can also compose flags provided that each has used "virtual
+// inheritance":
+// -------------------------------------------------------------
+// Flags<MyFlags1, MyFlags2> flags;
+// flags.add(...); // Any other flags you want to throw in there.
+// flags.load(values);
+// flags.flag_from_myflags1 ...
+// flags.flag_from_myflags2 ...
+// -------------------------------------------------------------
+//
+// "Fail early, fail often":
+//
+// You can not add duplicate flags, this is checked for you at compile
+// time for composite flags (e.g., Flag<MyFlags1, MyFlags2>) and also
+// checked at runtime for any other flags added via inheritance or
+// Flags::add(...).
+//
+// Flags that can not be loaded (e.g., attempting to use the 'no-'
+// prefix for a flag that is not boolean) will print a message to
+// standard error and abort the process.
+
+// TODO(benh): Provide a boolean which specifies whether or not to
+// abort on duplicates or load errors.
+
+// TODO(benh): Make prefix for environment variables configurable
+// (e.g., "MESOS_").
+
+#endif // __STOUT_FLAGS_HPP__
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/flags/flag.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/flags/flag.hpp b/third_party/libprocess/third_party/stout/include/stout/flags/flag.hpp
new file mode 100644
index 0000000..d31c984
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/include/stout/flags/flag.hpp
@@ -0,0 +1,26 @@
+#ifndef __STOUT_FLAGS_FLAG_HPP__
+#define __STOUT_FLAGS_FLAG_HPP__
+
+#include <string>
+
+#include <tr1/functional>
+
+#include <stout/nothing.hpp>
+#include <stout/try.hpp>
+
+namespace flags {
+
+// Forward declaration.
+class FlagsBase;
+
+struct Flag
+{
+ std::string name;
+ std::string help;
+ bool boolean;
+ std::tr1::function<Try<Nothing>(FlagsBase*, const std::string&)> loader;
+};
+
+} // namespace flags {
+
+#endif // __STOUT_FLAGS_FLAG_HPP__
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/flags/flags.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/flags/flags.hpp b/third_party/libprocess/third_party/stout/include/stout/flags/flags.hpp
new file mode 100644
index 0000000..77d36e6
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/include/stout/flags/flags.hpp
@@ -0,0 +1,481 @@
+#ifndef __STOUT_FLAGS_FLAGS_HPP__
+#define __STOUT_FLAGS_FLAGS_HPP__
+
+#include <stdlib.h> // For abort.
+
+#include <map>
+#include <string>
+#include <typeinfo> // For typeid.
+
+#include <tr1/functional>
+
+#include <stout/error.hpp>
+#include <stout/exit.hpp>
+#include <stout/foreach.hpp>
+#include <stout/none.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/os.hpp>
+#include <stout/stringify.hpp>
+#include <stout/strings.hpp>
+#include <stout/try.hpp>
+
+#include <stout/flags/flag.hpp>
+#include <stout/flags/loader.hpp>
+#include <stout/flags/parse.hpp>
+
+namespace flags {
+
+class FlagsBase
+{
+public:
+ virtual ~FlagsBase() {}
+
+ // Load any flags from the environment given the variable prefix,
+ // i.e., given prefix 'STOUT_' will load a flag named 'foo' via
+ // environment variables 'STOUT_foo' or 'STOUT_FOO'.
+ virtual Try<Nothing> load(
+ const std::string& prefix,
+ bool unknowns = false);
+
+ // Load any flags from the environment given the variable prefix
+ // (see above) followed by loading from the command line (via 'argc'
+ // and 'argv'). If 'unknowns' is true then we'll ignore unknown
+ // flags we see while loading. If 'duplicates' is true then we'll
+ // ignore any duplicates we see while loading.
+ virtual Try<Nothing> load(
+ const Option<std::string>& prefix,
+ int argc,
+ char** argv,
+ bool unknowns = false,
+ bool duplicates = false);
+
+ Try<Nothing> load(
+ const std::string& prefix,
+ int argc,
+ char** argv,
+ bool unknowns = false,
+ bool duplicates = false);
+
+ virtual Try<Nothing> load(
+ const std::map<std::string, Option<std::string> >& values,
+ bool unknowns = false);
+
+ virtual Try<Nothing> load(
+ const std::map<std::string, std::string>& values,
+ bool unknowns = false);
+
+ // Returns a string describing the flags.
+ std::string usage() const;
+
+ typedef std::map<std::string, Flag>::const_iterator const_iterator;
+
+ const_iterator begin() const { return flags.begin(); }
+ const_iterator end() const { return flags.end(); }
+
+ template <typename T1, typename T2>
+ void add(T1* t1,
+ const std::string& name,
+ const std::string& help,
+ const T2& t2);
+
+ template <typename T>
+ void add(Option<T>* option,
+ const std::string& name,
+ const std::string& help);
+
+protected:
+ template <typename Flags, typename T1, typename T2>
+ void add(T1 Flags::*t1,
+ const std::string& name,
+ const std::string& help,
+ const T2& t2);
+
+ template <typename Flags, typename T>
+ void add(Option<T> Flags::*option,
+ const std::string& name,
+ const std::string& help);
+
+ void add(const Flag& flag);
+
+private:
+ std::map<std::string, Flag> flags;
+};
+
+
+// Need to declare/define some explicit subclasses of FlagsBase so
+// that we can overload the 'Flags::operator FlagsN () const'
+// functions for each possible type.
+class _Flags1 : public virtual FlagsBase {};
+class _Flags2 : public virtual FlagsBase {};
+class _Flags3 : public virtual FlagsBase {};
+class _Flags4 : public virtual FlagsBase {};
+class _Flags5 : public virtual FlagsBase {};
+
+
+// TODO(benh): Add some "type constraints" for template paramters to
+// make sure they are all of type FlagsBase.
+template <typename Flags1 = _Flags1,
+ typename Flags2 = _Flags2,
+ typename Flags3 = _Flags3,
+ typename Flags4 = _Flags4,
+ typename Flags5 = _Flags5>
+class Flags : public virtual Flags1,
+ public virtual Flags2,
+ public virtual Flags3,
+ public virtual Flags4,
+ public virtual Flags5 {};
+
+
+template <typename T1, typename T2>
+void FlagsBase::add(
+ T1* t1,
+ const std::string& name,
+ const std::string& help,
+ const T2& t2)
+{
+ *t1 = t2; // Set the default.
+
+ Flag flag;
+ flag.name = name;
+ flag.help = help;
+ flag.boolean = typeid(T1) == typeid(bool);
+ flag.loader = std::tr1::bind(
+ &Loader<T1>::load,
+ t1,
+ std::tr1::function<Try<T1>(const std::string&)>(
+ std::tr1::bind(&parse<T1>, std::tr1::placeholders::_1)),
+ name,
+ std::tr1::placeholders::_2); // Use _2 because ignore FlagsBase*.
+
+ // Update the help string to include the default value.
+ flag.help += help.size() > 0 && help.find_last_of("\n\r") != help.size() - 1
+ ? " (default: " // On same line, add space.
+ : "(default: "; // On newline.
+ flag.help += stringify(t2);
+ flag.help += ")";
+
+ FlagsBase::add(flag);
+}
+
+
+template <typename T>
+void FlagsBase::add(
+ Option<T>* option,
+ const std::string& name,
+ const std::string& help)
+{
+ Flag flag;
+ flag.name = name;
+ flag.help = help;
+ flag.boolean = typeid(T) == typeid(bool);
+ flag.loader = std::tr1::bind(
+ &OptionLoader<T>::load,
+ option,
+ std::tr1::function<Try<T>(const std::string&)>(
+ std::tr1::bind(&parse<T>, std::tr1::placeholders::_1)),
+ name,
+ std::tr1::placeholders::_2); // Use _2 because ignore FlagsBase*.
+
+ FlagsBase::add(flag);
+}
+
+
+template <typename Flags, typename T1, typename T2>
+void FlagsBase::add(
+ T1 Flags::*t1,
+ const std::string& name,
+ const std::string& help,
+ const T2& t2)
+{
+ Flags* flags = dynamic_cast<Flags*>(this);
+ if (flags == NULL) {
+ std::cerr << "Attempted to add flag '" << name
+ << "' with incompatible type" << std::endl;
+ abort();
+ } else {
+ flags->*t1 = t2; // Set the default.
+ }
+
+ Flag flag;
+ flag.name = name;
+ flag.help = help;
+ flag.boolean = typeid(T1) == typeid(bool);
+ flag.loader = std::tr1::bind(
+ &MemberLoader<Flags, T1>::load,
+ std::tr1::placeholders::_1,
+ t1,
+ std::tr1::function<Try<T1>(const std::string&)>(
+ std::tr1::bind(&parse<T1>, std::tr1::placeholders::_1)),
+ name,
+ std::tr1::placeholders::_2);
+
+ // Update the help string to include the default value.
+ flag.help += help.size() > 0 && help.find_last_of("\n\r") != help.size() - 1
+ ? " (default: " // On same line, add space.
+ : "(default: "; // On newline.
+ flag.help += stringify(t2);
+ flag.help += ")";
+
+ add(flag);
+}
+
+
+template <typename Flags, typename T>
+void FlagsBase::add(
+ Option<T> Flags::*option,
+ const std::string& name,
+ const std::string& help)
+{
+ Flags* flags = dynamic_cast<Flags*>(this);
+ if (flags == NULL) {
+ std::cerr << "Attempted to add flag '" << name
+ << "' with incompatible type" << std::endl;
+ abort();
+ }
+
+ Flag flag;
+ flag.name = name;
+ flag.help = help;
+ flag.boolean = typeid(T) == typeid(bool);
+ flag.loader = std::tr1::bind(
+ &OptionMemberLoader<Flags, T>::load,
+ std::tr1::placeholders::_1,
+ option,
+ std::tr1::function<Try<T>(const std::string&)>(
+ std::tr1::bind(&parse<T>, std::tr1::placeholders::_1)),
+ name,
+ std::tr1::placeholders::_2);
+
+ add(flag);
+}
+
+
+inline void FlagsBase::add(const Flag& flag)
+{
+ if (flags.count(flag.name) > 0) {
+ EXIT(1) << "Attempted to add duplicate flag '" << flag.name << "'";
+ } else if (flag.name.find("no-") == 0) {
+ EXIT(1) << "Attempted to add flag '" << flag.name
+ << "' that starts with the reserved 'no-' prefix";
+ }
+
+ flags[flag.name] = flag;
+}
+
+
+// Extract environment variable "flags" with the specified prefix.
+inline std::map<std::string, Option<std::string> > extract(
+ const std::string& prefix)
+{
+ char** environ = os::environ();
+
+ std::map<std::string, Option<std::string> > values;
+
+ for (int i = 0; environ[i] != NULL; i++) {
+ std::string variable = environ[i];
+ if (variable.find(prefix) == 0) {
+ size_t eq = variable.find_first_of("=");
+ if (eq == std::string::npos) {
+ continue; // Not expecting a missing '=', but ignore anyway.
+ }
+ std::string name = variable.substr(prefix.size(), eq - prefix.size());
+ name = strings::lower(name); // Allow PREFIX_NAME or PREFIX_name.
+ std::string value = variable.substr(eq + 1);
+ values[name] = Option<std::string>::some(value);
+ }
+ }
+
+ return values;
+}
+
+
+inline Try<Nothing> FlagsBase::load(
+ const std::string& prefix,
+ bool unknowns)
+{
+ return load(extract(prefix), unknowns);
+}
+
+
+inline Try<Nothing> FlagsBase::load(
+ const Option<std::string>& prefix,
+ int argc,
+ char** argv,
+ bool unknowns,
+ bool duplicates)
+{
+ std::map<std::string, Option<std::string> > values;
+
+ if (prefix.isSome()) {
+ values = extract(prefix.get());
+ }
+
+ // Read flags from the command line.
+ for (int i = 1; i < argc; i++) {
+ const std::string arg(argv[i]);
+
+ std::string name;
+ Option<std::string> value = None();
+ if (arg.find("--") == 0) {
+ size_t eq = arg.find_first_of("=");
+ if (eq == std::string::npos && arg.find("--no-") == 0) { // --no-name
+ name = arg.substr(2);
+ } else if (eq == std::string::npos) { // --name
+ name = arg.substr(2);
+ } else { // --name=value
+ name = arg.substr(2, eq - 2);
+ value = arg.substr(eq + 1);
+ }
+ }
+ name = strings::lower(name);
+
+ if (!duplicates) {
+ if (values.count(name) > 0 ||
+ (name.find("no-") == 0 && values.count(name.substr(3)) > 0)) {
+ return Error("Duplicate flag '" + name + "' on command line");
+ }
+ }
+
+ values[name] = value;
+ }
+
+ return load(values, unknowns);
+}
+
+
+inline Try<Nothing> FlagsBase::load(
+ const std::string& prefix,
+ int argc,
+ char** argv,
+ bool unknowns,
+ bool duplicates)
+{
+ return load(Option<std::string>::some(prefix),
+ argc,
+ argv,
+ unknowns,
+ duplicates);
+}
+
+
+inline Try<Nothing> FlagsBase::load(
+ const std::map<std::string, Option<std::string> >& values,
+ bool unknowns)
+{
+ std::map<std::string, Option<std::string> >::const_iterator iterator;
+
+ for (iterator = values.begin(); iterator != values.end(); ++iterator) {
+ const std::string& name = iterator->first;
+ const Option<std::string>& value = iterator->second;
+
+ if (flags.count(name) > 0) {
+ if (value.isSome()) { // --name=value
+ if (flags[name].boolean && value.get() == "") {
+ flags[name].loader(this, "true"); // Should never fail.
+ } else {
+ Try<Nothing> loader = flags[name].loader(this, value.get());
+ if (loader.isError()) {
+ return Error(
+ "Failed to load flag '" + name + "': " + loader.error());
+ }
+ }
+ } else { // --name
+ if (flags[name].boolean) {
+ flags[name].loader(this, "true"); // Should never fail.
+ } else {
+ return Error(
+ "Failed to load non-boolean flag '" + name + "': Missing value");
+ }
+ }
+ } else if (name.find("no-") == 0) {
+ if (flags.count(name.substr(3)) > 0) { // --no-name
+ if (flags[name.substr(3)].boolean) {
+ if (value.isNone() || value.get() == "") {
+ flags[name.substr(3)].loader(this, "false"); // Should never fail.
+ } else {
+ return Error(
+ "Failed to load boolean flag '" + name.substr(3) +
+ "' via '" + name + "' with value '" + value.get() + "'");
+ }
+ } else {
+ return Error(
+ "Failed to load non-boolean flag '" + name.substr(3) +
+ "' via '" + name + "'");
+ }
+ } else {
+ return Error(
+ "Failed to load unknown flag '" + name.substr(3) +
+ "' via '" + name + "'");
+ }
+ } else if (!unknowns) {
+ return Error("Failed to load unknown flag '" + name + "'");
+ }
+ }
+
+ return Nothing();
+}
+
+
+inline Try<Nothing> FlagsBase::load(
+ const std::map<std::string, std::string>& _values,
+ bool unknowns)
+{
+ std::map<std::string, Option<std::string> > values;
+ std::map<std::string, std::string>::const_iterator iterator;
+ for (iterator = _values.begin(); iterator != _values.end(); ++iterator) {
+ const std::string& name = iterator->first;
+ const std::string& value = iterator->second;
+ values[name] = Option<std::string>::some(value);
+ }
+ return load(values, unknowns);
+}
+
+
+inline std::string FlagsBase::usage() const
+{
+ const int PAD = 5;
+
+ std::string usage;
+
+ std::map<std::string, std::string> col1; // key -> col 1 string
+
+ // Construct string for the first column and store width of column.
+ size_t width = 0;
+
+ foreachvalue (const flags::Flag& flag, *this) {
+ if (flag.boolean) {
+ col1[flag.name] = " --[no-]" + flag.name;
+ } else {
+ col1[flag.name] = " --" + flag.name + "=VALUE";
+ }
+ width = std::max(width, col1[flag.name].size());
+ }
+
+ foreachvalue (const flags::Flag& flag, *this) {
+ std::string line = col1[flag.name];
+
+ std::string pad(PAD + width - line.size(), ' ');
+ line += pad;
+
+ size_t pos1 = 0, pos2 = 0;
+ pos2 = flag.help.find_first_of("\n\r", pos1);
+ line += flag.help.substr(pos1, pos2 - pos1) + "\n";
+ usage += line;
+
+ while (pos2 != std::string::npos) { // Handle multi-line help strings.
+ line = "";
+ pos1 = pos2 + 1;
+ std::string pad2(PAD + width, ' ');
+ line += pad2;
+ pos2 = flag.help.find_first_of("\n\r", pos1);
+ line += flag.help.substr(pos1, pos2 - pos1) + "\n";
+ usage += line;
+ }
+ }
+ return usage;
+}
+
+} // namespace flags {
+
+#endif // __STOUT_FLAGS_FLAGS_HPP__
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/flags/loader.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/flags/loader.hpp b/third_party/libprocess/third_party/stout/include/stout/flags/loader.hpp
new file mode 100644
index 0000000..e5eaf24
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/include/stout/flags/loader.hpp
@@ -0,0 +1,109 @@
+#ifndef __STOUT_FLAGS_LOADER_HPP__
+#define __STOUT_FLAGS_LOADER_HPP__
+
+#include <string>
+
+#include <tr1/functional>
+
+#include <stout/error.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/try.hpp>
+
+#include <stout/flags/parse.hpp>
+
+namespace flags {
+
+// Forward declaration.
+class FlagsBase;
+
+template <typename T>
+struct Loader
+{
+ static Try<Nothing> load(
+ T* flag,
+ const std::tr1::function<Try<T>(const std::string&)>& parse,
+ const std::string& name,
+ const std::string& value)
+ {
+ Try<T> t = parse(value);
+ if (t.isSome()) {
+ *flag = t.get();
+ } else {
+ return Error("Failed to load value '" + value + "': " + t.error());
+ }
+ return Nothing();
+ }
+};
+
+
+template <typename T>
+struct OptionLoader
+{
+ static Try<Nothing> load(
+ Option<T>* flag,
+ const std::tr1::function<Try<T>(const std::string&)>& parse,
+ const std::string& name,
+ const std::string& value)
+ {
+ Try<T> t = parse(value);
+ if (t.isSome()) {
+ *flag = Option<T>::some(t.get());
+ } else {
+ return Error("Failed to load value '" + value + "': " + t.error());
+ }
+ return Nothing();
+ }
+};
+
+
+template <typename F, typename T>
+struct MemberLoader
+{
+ static Try<Nothing> load(
+ FlagsBase* base,
+ T F::*flag,
+ const std::tr1::function<Try<T>(const std::string&)>& parse,
+ const std::string& name,
+ const std::string& value)
+ {
+ F* f = dynamic_cast<F*>(base);
+ if (f != NULL) {
+ Try<T> t = parse(value);
+ if (t.isSome()) {
+ f->*flag = t.get();
+ } else {
+ return Error("Failed to load value '" + value + "': " + t.error());
+ }
+ }
+ return Nothing();
+ }
+};
+
+
+template <typename F, typename T>
+struct OptionMemberLoader
+{
+ static Try<Nothing> load(
+ FlagsBase* base,
+ Option<T> F::*flag,
+ const std::tr1::function<Try<T>(const std::string&)>& parse,
+ const std::string& name,
+ const std::string& value)
+ {
+ F* f = dynamic_cast<F*>(base);
+ if (f != NULL) {
+ Try<T> t = parse(value);
+ if (t.isSome()) {
+ f->*flag = Option<T>::some(t.get());
+ } else {
+ return Error("Failed to load value '" + value + "': " + t.error());
+ }
+ }
+ return Nothing();
+ }
+};
+
+} // namespace flags {
+
+#endif // __STOUT_FLAGS_LOADER_HPP__
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/flags/parse.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/flags/parse.hpp b/third_party/libprocess/third_party/stout/include/stout/flags/parse.hpp
new file mode 100644
index 0000000..54eb35c
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/include/stout/flags/parse.hpp
@@ -0,0 +1,55 @@
+#ifndef __STOUT_FLAGS_PARSE_HPP__
+#define __STOUT_FLAGS_PARSE_HPP__
+
+#include <sstream> // For istringstream.
+#include <string>
+
+#include <tr1/functional>
+
+#include <stout/duration.hpp>
+#include <stout/error.hpp>
+#include <stout/try.hpp>
+
+namespace flags {
+
+template <typename T>
+Try<T> parse(const std::string& value)
+{
+ T t;
+ std::istringstream in(value);
+ in >> t;
+ if (!in.good() && !in.eof()) {
+ return Error("Failed to convert into required type");
+ }
+ return t;
+}
+
+
+template <>
+inline Try<std::string> parse(const std::string& value)
+{
+ return value;
+}
+
+
+template <>
+inline Try<bool> parse(const std::string& value)
+{
+ if (value == "true" || value == "1") {
+ return true;
+ } else if (value == "false" || value == "0") {
+ return false;
+ }
+ return Error("Expecting a boolean (e.g., true or false)");
+}
+
+
+template <>
+inline Try<Duration> parse(const std::string& value)
+{
+ return Duration::parse(value);
+}
+
+} // namespace flags {
+
+#endif // __STOUT_FLAGS_PARSE_HPP__
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/include/stout/os.hpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/include/stout/os.hpp b/third_party/libprocess/third_party/stout/include/stout/os.hpp
index 00b2313..28a08cc 100644
--- a/third_party/libprocess/third_party/stout/include/stout/os.hpp
+++ b/third_party/libprocess/third_party/stout/include/stout/os.hpp
@@ -1,6 +1,9 @@
#ifndef __STOUT_OS_HPP__
#define __STOUT_OS_HPP__
+#ifdef __APPLE__
+#include <crt_externs.h> // For _NSGetEnviron().
+#endif
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
@@ -55,8 +58,27 @@
({ (void)ret; *(result) = gethostbyname2(name, af); 0; })
#endif // __APPLE__
+// Need to declare 'environ' pointer for non OS X platforms.
+#ifndef __APPLE__
+extern char** environ;
+#endif
+
namespace os {
+inline char** environ()
+{
+ // Accessing the list of environment variables is platform-specific.
+ // On OS X, the 'environ' symbol isn't visible to shared libraries,
+ // so we must use the _NSGetEnviron() function (see 'man environ' on
+ // OS X). On other platforms, it's fine to access 'environ' from
+ // shared libraries.
+#ifdef __APPLE__
+ return *_NSGetEnviron();
+#endif
+ return ::environ;
+}
+
+
// Checks if the specified key is in the environment variables.
inline bool hasenv(const std::string& key)
{
http://git-wip-us.apache.org/repos/asf/incubator-mesos/blob/190a3bb8/third_party/libprocess/third_party/stout/tests/flags_tests.cpp
----------------------------------------------------------------------
diff --git a/third_party/libprocess/third_party/stout/tests/flags_tests.cpp b/third_party/libprocess/third_party/stout/tests/flags_tests.cpp
new file mode 100644
index 0000000..2809280
--- /dev/null
+++ b/third_party/libprocess/third_party/stout/tests/flags_tests.cpp
@@ -0,0 +1,349 @@
+#include <gmock/gmock.h>
+
+#include <map>
+#include <string>
+
+#include <stout/duration.hpp>
+#include <stout/flags.hpp>
+#include <stout/gtest.hpp>
+#include <stout/none.hpp>
+#include <stout/nothing.hpp>
+#include <stout/option.hpp>
+#include <stout/os.hpp>
+
+
+using namespace flags;
+
+class TestFlags : public virtual FlagsBase
+{
+public:
+ TestFlags()
+ {
+ add(&TestFlags::name1,
+ "name1",
+ "Set name1",
+ "ben folds");
+
+ add(&TestFlags::name2,
+ "name2",
+ "Set name2",
+ 42);
+
+ add(&TestFlags::name3,
+ "name3",
+ "Set name3",
+ false);
+
+ add(&TestFlags::name4,
+ "name4",
+ "Set name4");
+
+ add(&TestFlags::name5,
+ "name5",
+ "Set name5");
+ }
+
+ std::string name1;
+ int name2;
+ bool name3;
+ Option<bool> name4;
+ Option<bool> name5;
+};
+
+
+TEST(FlagsTest, Load)
+{
+ TestFlags flags;
+
+ std::map<std::string, Option<std::string> > values;
+
+ values["name1"] = Option<std::string>::some("billy joel");
+ values["name2"] = Option<std::string>::some("43");
+ values["name3"] = Option<std::string>::some("false");
+ values["no-name4"] = None();
+ values["name5"] = None();
+
+ flags.load(values);
+
+ EXPECT_EQ("billy joel", flags.name1);
+ EXPECT_EQ(43, flags.name2);
+ EXPECT_FALSE(flags.name3);
+ ASSERT_SOME(flags.name4);
+ EXPECT_FALSE(flags.name4.get());
+ ASSERT_SOME(flags.name5);
+ EXPECT_TRUE(flags.name5.get());
+}
+
+
+TEST(FlagsTest, Add)
+{
+ Flags<TestFlags> flags;
+
+ Option<std::string> name6;
+
+ flags.add(&name6,
+ "name6",
+ "Also set name6");
+
+ bool name7;
+
+ flags.add(&name7,
+ "name7",
+ "Also set name7",
+ true);
+
+ Option<std::string> name8;
+
+ flags.add(&name8,
+ "name8",
+ "Also set name8");
+
+ std::map<std::string, Option<std::string> > values;
+
+ values["name6"] = Option<std::string>::some("ben folds");
+ values["no-name7"] = None();
+
+ flags.load(values);
+
+ ASSERT_SOME(name6);
+ EXPECT_EQ("ben folds", name6.get());
+
+ EXPECT_FALSE(name7);
+
+ ASSERT_TRUE(name8.isNone());
+}
+
+
+TEST(FlagsTest, Flags)
+{
+ TestFlags flags;
+
+ std::map<std::string, Option<std::string> > values;
+
+ values["name1"] = Option<std::string>::some("billy joel");
+ values["name2"] = Option<std::string>::some("43");
+ values["name3"] = Option<std::string>::some("false");
+ values["no-name4"] = None();
+ values["name5"] = None();
+
+ flags.load(values);
+
+ EXPECT_EQ("billy joel", flags.name1);
+ EXPECT_EQ(43, flags.name2);
+ EXPECT_FALSE(flags.name3);
+ ASSERT_SOME(flags.name4);
+ EXPECT_FALSE(flags.name4.get());
+ ASSERT_SOME(flags.name5);
+ EXPECT_TRUE(flags.name5.get());
+}
+
+
+TEST(FlagsTest, LoadFromEnvironment)
+{
+ TestFlags flags;
+
+ os::setenv("FLAGSTEST_name1", "billy joel");
+ os::setenv("FLAGSTEST_name2", "43");
+ os::setenv("FLAGSTEST_no-name3", "");
+ os::setenv("FLAGSTEST_no-name4", "");
+ os::setenv("FLAGSTEST_name5", "");
+
+ Try<Nothing> load = flags.load("FLAGSTEST_");
+ EXPECT_SOME(load);
+
+ EXPECT_EQ("billy joel", flags.name1);
+ EXPECT_EQ(43, flags.name2);
+ EXPECT_FALSE(flags.name3);
+ ASSERT_SOME(flags.name4);
+ EXPECT_FALSE(flags.name4.get());
+ ASSERT_SOME(flags.name5);
+ EXPECT_TRUE(flags.name5.get());
+
+ os::unsetenv("FLAGSTEST_name1");
+ os::unsetenv("FLAGSTEST_name2");
+ os::unsetenv("FLAGSTEST_no-name3");
+ os::unsetenv("FLAGSTEST_no-name4");
+ os::unsetenv("FLAGSTEST_name5");
+}
+
+
+TEST(FlagsTest, LoadFromCommandLine)
+{
+ TestFlags flags;
+
+ int argc = 6;
+ char* argv[argc];
+
+ argv[0] = (char*) "/path/to/program";
+ argv[1] = (char*) "--name1=billy joel";
+ argv[2] = (char*) "--name2=43";
+ argv[3] = (char*) "--no-name3";
+ argv[4] = (char*) "--no-name4";
+ argv[5] = (char*) "--name5";
+
+ Try<Nothing> load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_SOME(load);
+
+ EXPECT_EQ("billy joel", flags.name1);
+ EXPECT_EQ(43, flags.name2);
+ EXPECT_FALSE(flags.name3);
+ ASSERT_SOME(flags.name4);
+ EXPECT_FALSE(flags.name4.get());
+ ASSERT_SOME(flags.name5);
+ EXPECT_TRUE(flags.name5.get());
+}
+
+
+TEST(FlagsTest, DuplicatesFromEnvironment)
+{
+ TestFlags flags;
+
+ os::setenv("FLAGSTEST_name1", "ben folds");
+
+ int argc = 2;
+ char* argv[argc];
+
+ argv[0] = (char*) "/path/to/program";
+ argv[1] = (char*) "--name1=billy joel";
+
+ Try<Nothing> load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Duplicate flag 'name1' on command line", load.error());
+
+ os::unsetenv("FLAGSTEST_name1");
+}
+
+
+TEST(FlagsTest, DuplicatesFromCommandLine)
+{
+ TestFlags flags;
+
+ int argc = 3;
+ char* argv[argc];
+
+ argv[0] = (char*) "/path/to/program";
+ argv[1] = (char*) "--name1=billy joel";
+ argv[2] = (char*) "--name1=ben folds";
+
+ Try<Nothing> load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Duplicate flag 'name1' on command line", load.error());
+}
+
+
+TEST(FlagsTest, Errors)
+{
+ TestFlags flags;
+
+ int argc = 2;
+ char* argv[argc];
+
+ argv[0] = (char*) "/path/to/program";
+
+ // Test an unknown flag.
+ argv[1] = (char*) "--foo";
+
+ Try<Nothing> load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load unknown flag 'foo'", load.error());
+
+ // Now try an unknown flag with a value.
+ argv[1] = (char*) "--foo=value";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load unknown flag 'foo'", load.error());
+
+ // Now try an unknown flag with a 'no-' prefix.
+ argv[1] = (char*) "--no-foo";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load unknown flag 'foo' via 'no-foo'", load.error());
+
+ // Now test a boolean flag using the 'no-' prefix _and_ a value.
+ argv[1] = (char*) "--no-name3=value";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load boolean flag 'name3' via "
+ "'no-name3' with value 'value'", load.error());
+
+ // Now test a boolean flag that couldn't be parsed.
+ argv[1] = (char*) "--name3=value";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load flag 'name3': Failed to load value 'value': "
+ "Expecting a boolean (e.g., true or false)", load.error());
+
+ // Now test a non-boolean flag without a value.
+ argv[1] = (char*) "--name1";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load non-boolean flag 'name1': "
+ "Missing value", load.error());
+
+ // Now test a non-boolean flag using the 'no-' prefix.
+ argv[1] = (char*) "--no-name2";
+
+ load = flags.load("FLAGSTEST_", argc, argv);
+ EXPECT_ERROR(load);
+
+ EXPECT_EQ("Failed to load non-boolean flag 'name2' "
+ "via 'no-name2'", load.error());
+}
+
+
+TEST(FlagsTest, Usage)
+{
+ TestFlags flags;
+
+ EXPECT_EQ(
+ " --name1=VALUE Set name1 (default: ben folds)\n"
+ " --name2=VALUE Set name2 (default: 42)\n"
+ " --[no-]name3 Set name3 (default: false)\n"
+ " --[no-]name4 Set name4\n"
+ " --[no-]name5 Set name5\n",
+ flags.usage());
+}
+
+
+TEST(FlagsTest, Duration)
+{
+ Flags<TestFlags> flags;
+
+ Duration name6;
+
+ flags.add(&name6,
+ "name6",
+ "Amount of time",
+ Milliseconds(100));
+
+ Option<Duration> name7;
+
+ flags.add(&name7,
+ "name7",
+ "Also some amount of time");
+
+ std::map<std::string, Option<std::string> > values;
+
+ values["name6"] = Option<std::string>::some("2mins");
+ values["name7"] = Option<std::string>::some("3hrs");
+
+ flags.load(values);
+
+ EXPECT_EQ(Minutes(2), name6);
+
+ ASSERT_SOME(name7);
+ EXPECT_EQ(Hours(3), name7.get());
+}