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 2015/06/02 01:00:12 UTC

[1/2] mesos git commit: Refactoring to use FlagsBase common functionality.

Repository: mesos
Updated Branches:
  refs/heads/master f855fb7f2 -> 4cc0ffc4e


Refactoring to use FlagsBase common functionality.

Jira: MESOS-2711

All the main() methods have been refactored to use the definition of
FlagsBase::help flag and FlagsBase::usage().

This CL also tries to bring some uniformity to the use of exit codes:
if this is deemed to be worth making it uniform, we can come up with
common rules and extend the changes here to be compliant.

This touches a lot of files, but keep scrolling, and you will see a
pattern emerge.

Review: https://reviews.apache.org/r/34195


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4cc0ffc4
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4cc0ffc4
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4cc0ffc4

Branch: refs/heads/master
Commit: 4cc0ffc4e5198af8bec78dca892b021f6b07d908
Parents: 1694bda
Author: Marco Massenzio <ma...@mesosphere.io>
Authored: Mon Jun 1 10:53:59 2015 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Jun 1 15:59:38 2015 -0700

----------------------------------------------------------------------
 src/cli/execute.cpp                             |  66 +++++-------
 src/cli/mesos.cpp                               |  10 +-
 src/cli/resolve.cpp                             |  77 ++++----------
 src/docker/executor.cpp                         |  57 ++++------
 src/examples/load_generator_framework.cpp       |  38 +++----
 src/examples/low_level_scheduler_libprocess.cpp |   2 +-
 src/examples/low_level_scheduler_pthread.cpp    |   2 +-
 src/examples/persistent_volume_framework.cpp    |  31 ++----
 src/health-check/main.cpp                       |  66 ++++++------
 src/launcher/executor.cpp                       |  28 ++---
 src/local/main.cpp                              |  35 ++-----
 src/log/tool/benchmark.cpp                      |  51 ++++-----
 src/log/tool/benchmark.hpp                      |   3 -
 src/log/tool/initialize.cpp                     |  37 ++-----
 src/log/tool/initialize.hpp                     |   3 -
 src/log/tool/read.cpp                           |  35 ++-----
 src/log/tool/read.hpp                           |   3 -
 src/log/tool/replica.cpp                        |  40 +++----
 src/log/tool/replica.hpp                        |   3 -
 src/master/main.cpp                             | 103 +++++++++----------
 .../isolators/network/port_mapping.cpp          |  10 --
 .../isolators/network/port_mapping.hpp          |   2 -
 src/slave/main.cpp                              |  58 +++++------
 src/tests/main.cpp                              |  35 ++-----
 src/usage/main.cpp                              |  37 ++-----
 25 files changed, 282 insertions(+), 550 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/cli/execute.cpp
----------------------------------------------------------------------
diff --git a/src/cli/execute.cpp b/src/cli/execute.cpp
index dbd19e6..b387b64 100644
--- a/src/cli/execute.cpp
+++ b/src/cli/execute.cpp
@@ -50,15 +50,6 @@ using std::string;
 using std::vector;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 class Flags : public flags::FlagsBase
 {
 public:
@@ -287,50 +278,43 @@ int main(int argc, char** argv)
 {
   Flags flags;
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   // Load flags from environment and command line.
   Try<Nothing> load = flags.load(None(), argc, argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    return -1;
+  // TODO(marco): this should be encapsulated entirely into the
+  // FlagsBase API - possibly with a 'guard' that prevents FlagsBase
+  // from calling ::exit(EXIT_FAILURE) after calling usage() (which
+  // would be the default behavior); see MESOS-2766.
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.master.isNone()) {
-    cerr << "Missing --master=IP:PORT" << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage("Missing required option --master") << endl;
+    return EXIT_FAILURE;
   }
 
   UPID master("master@" + flags.master.get());
-
   if (!master) {
-    cerr << "Could not parse --master=" << flags.master.get() << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage("Could not parse --master=" + flags.master.get())
+         << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.name.isNone()) {
-    cerr << "Missing --name=NAME" << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage("Missing required option --name") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.command.isNone()) {
-    cerr << "Missing --command=COMMAND" << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage("Missing required option --command") << endl;
+    return EXIT_FAILURE;
   }
 
   Result<string> user = os::user();
@@ -340,10 +324,10 @@ int main(int argc, char** argv)
     } else {
       cerr << "No username for uid " << ::getuid() << endl;
     }
-    return -1;
+    return EXIT_FAILURE;
   }
 
-  Option<hashmap<string, string>> environment;
+  Option<hashmap<string, string>> environment = None();
 
   if (flags.environment.isSome()) {
     environment = flags.environment.get();
@@ -370,22 +354,22 @@ int main(int argc, char** argv)
     Try<bool> exists = hdfs.exists(path);
     if (exists.isError()) {
       cerr << "Failed to check if file exists: " << exists.error() << endl;
-      return -1;
+      return EXIT_FAILURE;
     } else if (exists.get() && flags.overwrite) {
       Try<Nothing> rm = hdfs.rm(path);
       if (rm.isError()) {
         cerr << "Failed to remove existing file: " << rm.error() << endl;
-        return -1;
+        return EXIT_FAILURE;
       }
     } else if (exists.get()) {
       cerr << "File already exists (see --overwrite)" << endl;
-      return -1;
+      return EXIT_FAILURE;
     }
 
     Try<Nothing> copy = hdfs.copyFromLocal(flags.package.get(), path);
     if (copy.isError()) {
       cerr << "Failed to copy package: " << copy.error() << endl;
-      return -1;
+      return EXIT_FAILURE;
     }
 
     // Now save the URI.
@@ -413,5 +397,5 @@ int main(int argc, char** argv)
 
   MesosSchedulerDriver driver(&scheduler, framework, flags.master.get());
 
-  return driver.run() == DRIVER_STOPPED ? 0 : 1;
+  return driver.run() == DRIVER_STOPPED ? EXIT_SUCCESS : EXIT_FAILURE;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/cli/mesos.cpp
----------------------------------------------------------------------
diff --git a/src/cli/mesos.cpp b/src/cli/mesos.cpp
index 171a707..1121e19 100644
--- a/src/cli/mesos.cpp
+++ b/src/cli/mesos.cpp
@@ -65,7 +65,7 @@ int main(int argc, char** argv)
 
   if (argc < 2) {
     usage(argv[0]);
-    exit(1);
+    return EXIT_FAILURE;
   }
 
   // Update PYTHONPATH to include path to installed 'mesos' module.
@@ -78,7 +78,7 @@ int main(int argc, char** argv)
   if (string(argv[1]) == "help") {
     if (argc == 2) {
       usage(argv[0]);
-      return 0;
+      return EXIT_SUCCESS;
     } else {
       // 'mesos help command' => 'mesos command --help'
       argv[1] = argv[2];
@@ -88,7 +88,7 @@ int main(int argc, char** argv)
   } else if (string(argv[1]).find("--") == 0) {
     cerr << "Not expecting '" << argv[1] << "' before command" << endl;
     usage(argv[0]);
-    return -1;
+    return EXIT_FAILURE;
   } else {
     string command = argv[1];
     string executable = "mesos-" + command;
@@ -101,8 +101,8 @@ int main(int argc, char** argv)
       cerr << "Failed to execute " << command
            << ": " << strerror(errno) << endl;
     }
-    return -1;
+    return EXIT_FAILURE;
   }
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/cli/resolve.cpp
----------------------------------------------------------------------
diff --git a/src/cli/resolve.cpp b/src/cli/resolve.cpp
index a99b609..74545a0 100644
--- a/src/cli/resolve.cpp
+++ b/src/cli/resolve.cpp
@@ -43,24 +43,10 @@ using std::endl;
 using std::string;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " <master>" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char** argv)
 {
   flags::FlagsBase flags;
-
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
+  flags.setUsageMessage("Usage: " + os::basename(argv[0]).get() + " <master>");
 
   Duration timeout;
   flags.add(&timeout,
@@ -68,75 +54,54 @@ int main(int argc, char** argv)
             "How long to wait to resolve master",
             Seconds(5));
 
+  // TODO(marco): `verbose` is also a great candidate for FlagsBase.
   bool verbose;
   flags.add(&verbose,
             "verbose",
             "Be verbose",
             false);
 
-  // Load flags from environment and command line.
-  Try<Nothing> load = flags.load(None(), argc, argv);
+  // Load flags from environment and command line, and remove
+  // them from argv.
+  Try<Nothing> load = flags.load(None(), &argc, &argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    return -1;
-  }
-
-  if (help) {
-    usage(argv[0], flags);
-    return -1;
-  }
-
-  if (argc < 2) {
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  Option<string> master = None();
-
-  // Find 'master' argument (the only argument not prefixed by '--').
-  for (int i = 1; i < argc; i++) {
-    const std::string arg(strings::trim(argv[i]));
-    if (arg.find("--") != 0) {
-      if (master.isSome()) {
-        // There should only be one non-flag argument.
-        cerr << "Ambiguous 'master': "
-             << master.get() << " and " << arg << endl;
-        usage(argv[0], flags);
-        return -1;
-      } else {
-        master = arg;
-      }
-    }
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
-  if (master.isNone()) {
-    cerr << "Missing 'master'" << endl;
-    usage(argv[0], flags);
-    return -1;
+  // 'master' argument must be the only argument left after parsing.
+  if (argc != 2) {
+    cerr << flags.usage("There must be only one argument: <master>") << endl;
+    return EXIT_FAILURE;
   }
 
-  Try<MasterDetector*> detector = MasterDetector::create(master.get());
+  string master = argv[1];
+  Try<MasterDetector*> detector = MasterDetector::create(master);
 
   if (detector.isError()) {
     cerr << "Failed to create a master detector: " << detector.error() << endl;
-    return -1;
+    return EXIT_FAILURE;
   }
 
   Future<Option<MasterInfo> > masterInfo = detector.get()->detect();
 
   if (!masterInfo.await(timeout)) {
-    cerr << "Failed to detect master from '" << master.get()
+    cerr << "Failed to detect master from '" << master
          << "' within " << timeout << endl;
     return -1;
   } else {
     CHECK(!masterInfo.isDiscarded());
 
     if (masterInfo.isFailed()) {
-      cerr << "Failed to detect master from '" << master.get()
+      cerr << "Failed to detect master from '" << master
            << "': " << masterInfo.failure() << endl;
-      return -1;
+      return EXIT_FAILURE;
     }
   }
 
@@ -144,5 +109,5 @@ int main(int argc, char** argv)
   CHECK_SOME(masterInfo.get());
   cout << strings::remove(masterInfo.get().get().pid(), "master@") << endl;
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/docker/executor.cpp
----------------------------------------------------------------------
diff --git a/src/docker/executor.cpp b/src/docker/executor.cpp
index 709fbe3..cdcd8ee 100644
--- a/src/docker/executor.cpp
+++ b/src/docker/executor.cpp
@@ -348,75 +348,54 @@ private:
 } // namespace mesos {
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char** argv)
 {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
   mesos::internal::docker::Flags flags;
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   // Load flags from environment and command line.
   Try<Nothing> load = flags.load(None(), &argc, &argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
   std::cout << stringify(flags) << std::endl;
 
   mesos::internal::logging::initialize(argv[0], flags, true); // Catch signals.
 
-  if (help) {
-    usage(argv[0], flags);
-    return -1;
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   std::cout << stringify(flags) << std::endl;
 
   if (flags.docker.isNone()) {
-    LOG(WARNING) << "Expected docker executable path";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --docker") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.container.isNone()) {
-    LOG(WARNING) << "Expected container name";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --container") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.sandbox_directory.isNone()) {
-    LOG(WARNING) << "Expected sandbox directory path";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --sandbox_directory") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.mapped_directory.isNone()) {
-    LOG(WARNING) << "Expected mapped sandbox directory path";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --mapped_directory") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.stop_timeout.isNone()) {
-    LOG(WARNING) << "Expected stop timeout";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --stop_timeout") << endl;
+    return EXIT_FAILURE;
   }
 
   // The 2nd argument for docker create is set to false so we skip
@@ -424,8 +403,8 @@ int main(int argc, char** argv)
   // should have already validated docker.
   Try<Docker*> docker = Docker::create(flags.docker.get(), false);
   if (docker.isError()) {
-    LOG(WARNING) << "Unable to create docker abstraction: " << docker.error();
-    return -1;
+    cerr << "Unable to create docker abstraction: " << docker.error() << endl;
+    return EXIT_FAILURE;
   }
 
   mesos::internal::docker::DockerExecutor executor(
@@ -436,5 +415,5 @@ int main(int argc, char** argv)
       flags.stop_timeout.get());
 
   mesos::MesosExecutorDriver driver(&executor);
-  return driver.run() == mesos::DRIVER_STOPPED ? 0 : 1;
+  return driver.run() == mesos::DRIVER_STOPPED ? EXIT_SUCCESS : EXIT_FAILURE;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/examples/load_generator_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/load_generator_framework.cpp b/src/examples/load_generator_framework.cpp
index be1a3bf..6e83308 100644
--- a/src/examples/load_generator_framework.cpp
+++ b/src/examples/load_generator_framework.cpp
@@ -270,32 +270,17 @@ public:
         "Run LoadGenerator for the specified duration.\n"
         "Without this option this framework would keep generating load\n"
         "forever as long as it is connected to the master");
-
-    add(&Flags::help,
-        "help",
-        "Print this help message",
-        false);
   }
 
   Option<string> master;
   string principal;
   Option<string> secret;
   bool authenticate;
-  bool help;
   Option<double> qps;
   Option<Duration> duration;
 };
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char** argv)
 {
   Flags flags;
@@ -303,26 +288,28 @@ int main(int argc, char** argv)
   Try<Nothing> load = flags.load("MESOS_", argc, argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    exit(1);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.help) {
-    usage(argv[0], flags);
-    exit(1);
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.master.isNone()) {
-    EXIT(1) << "Missing required option --master. See --help";
+    cerr << flags.usage( "Missing required option --master") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.qps.isNone()) {
-    EXIT(1) << "Missing required option --qps. See --help";
+    cerr << flags.usage("Missing required option --qps") << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.qps.get() <= 0) {
-    EXIT(1) << "--qps needs to be greater than zero";
+    cerr << flags.usage("--qps needs to be greater than zero") << endl;
+    return EXIT_FAILURE;
   }
 
   // We want the logger to catch failure signals.
@@ -344,7 +331,8 @@ int main(int argc, char** argv)
     cout << "Enabling authentication for the framework" << endl;
 
     if (flags.secret.isNone()) {
-      EXIT(1) << "Expecting --secret when --authenticate is set";
+      cerr << "Expecting --secret when --authenticate is set" << endl;
+      return EXIT_FAILURE;
     }
 
     string secret = flags.secret.get();
@@ -364,7 +352,7 @@ int main(int argc, char** argv)
         &scheduler, framework, flags.master.get());
   }
 
-  int status = driver->run() == DRIVER_STOPPED ? 0 : 1;
+  int status = driver->run() == DRIVER_STOPPED ? EXIT_SUCCESS : EXIT_SUCCESS;
 
   // Ensure that the driver process terminates.
   driver->stop();

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/examples/low_level_scheduler_libprocess.cpp
----------------------------------------------------------------------
diff --git a/src/examples/low_level_scheduler_libprocess.cpp b/src/examples/low_level_scheduler_libprocess.cpp
index bee2e7e..bd228fd 100644
--- a/src/examples/low_level_scheduler_libprocess.cpp
+++ b/src/examples/low_level_scheduler_libprocess.cpp
@@ -427,5 +427,5 @@ int main(int argc, char** argv)
   process::wait(scheduler);
   delete scheduler;
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/examples/low_level_scheduler_pthread.cpp
----------------------------------------------------------------------
diff --git a/src/examples/low_level_scheduler_pthread.cpp b/src/examples/low_level_scheduler_pthread.cpp
index fb8cd66..81388f1 100644
--- a/src/examples/low_level_scheduler_pthread.cpp
+++ b/src/examples/low_level_scheduler_pthread.cpp
@@ -483,5 +483,5 @@ int main(int argc, char** argv)
   scheduler->wait();
   delete scheduler;
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/examples/persistent_volume_framework.cpp
----------------------------------------------------------------------
diff --git a/src/examples/persistent_volume_framework.cpp b/src/examples/persistent_volume_framework.cpp
index 8a893fc..6a0c0cb 100644
--- a/src/examples/persistent_volume_framework.cpp
+++ b/src/examples/persistent_volume_framework.cpp
@@ -43,6 +43,7 @@
 using namespace mesos;
 using namespace mesos::internal;
 
+using std::cerr;
 using std::cout;
 using std::endl;
 using std::ostringstream;
@@ -403,11 +404,6 @@ public:
         "tasks_per_shard",
         "The number of tasks should be launched per shard.",
         3);
-
-    add(&help,
-        "help",
-        "Print this help message",
-        false);
   }
 
   Option<string> master;
@@ -415,23 +411,9 @@ public:
   string principal;
   size_t num_shards;
   size_t tasks_per_shard;
-  bool help;
 };
 
 
-static string usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  ostringstream stream;
-
-  stream << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-         << endl
-         << "Supported options:" << endl
-         << flags.usage();
-
-  return stream.str();
-}
-
-
 int main(int argc, char** argv)
 {
   Flags flags;
@@ -439,15 +421,18 @@ int main(int argc, char** argv)
   Try<Nothing> load = flags.load("MESOS_", argc, argv);
 
   if (load.isError()) {
-    EXIT(1) << load.error() << endl << usage(argv[0], flags);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.help) {
-    EXIT(1) << usage(argv[0], flags);
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.master.isNone()) {
-    EXIT(1) << "Missing required option --master. See --help";
+    cerr << flags.usage("Missing required option --master") << endl;
+    return EXIT_FAILURE;
   }
 
   logging::initialize(argv[0], flags, true); // Catch signals.
@@ -489,7 +474,7 @@ int main(int argc, char** argv)
       framework,
       flags.master.get());
 
-  int status = driver->run() == DRIVER_STOPPED ? 0 : 1;
+  int status = driver->run() == DRIVER_STOPPED ? EXIT_SUCCESS : EXIT_FAILURE;
 
   driver->stop();
   delete driver;

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/health-check/main.cpp
----------------------------------------------------------------------
diff --git a/src/health-check/main.cpp b/src/health-check/main.cpp
index a4ce742..3607479 100644
--- a/src/health-check/main.cpp
+++ b/src/health-check/main.cpp
@@ -294,66 +294,60 @@ int main(int argc, char** argv)
 
   Flags flags;
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   Try<Nothing> load = flags.load(None(), argc, argv);
 
   if (load.isError()) {
-    LOG(WARNING) << load.error();
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    return 0;
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.health_check_json.isNone()) {
-    LOG(WARNING) << "Expected JSON with health check description";
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Expected JSON with health check description") << endl;
+    return EXIT_FAILURE;
   }
 
   Try<JSON::Object> parse =
     JSON::parse<JSON::Object>(flags.health_check_json.get());
-  if (parse.isError()) {
-    LOG(WARNING) << "JSON parse error: " << parse.error();
-    usage(argv[0], flags);
-    return 0;
-  }
 
-  if (flags.executor.isNone()) {
-    LOG(WARNING) << "Expected UPID for health check";
-    usage(argv[0], flags);
-    return 0;
+  if (parse.isError()) {
+    cerr << flags.usage("Failed to parse --health_check_json: " + parse.error())
+         << endl;
+    return EXIT_FAILURE;
   }
 
   Try<HealthCheck> check = protobuf::parse<HealthCheck>(parse.get());
+
   if (check.isError()) {
-    LOG(WARNING) << "JSON error: " << check.error();
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Failed to parse --health_check_json: " + check.error())
+         << endl;
+    return EXIT_SUCCESS;
+  }
+
+  if (flags.executor.isNone()) {
+    cerr << flags.usage("Missing required option --executor") << endl;
+    return EXIT_FAILURE;
   }
 
   if (check.get().has_http() && check.get().has_command()) {
-    LOG(WARNING) << "Both HTTP and Command check passed in";
-    return -1;
+    cerr << flags.usage("Both 'http' and 'command' health check requested")
+         << endl;
+    return EXIT_FAILURE;
   }
 
   if (!check.get().has_http() && !check.get().has_command()) {
-    LOG(WARNING) << "No health check found";
-    return -1;
+    cerr << flags.usage("Expecting one of 'http' or 'command' health check")
+         << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.task_id.isNone()) {
-    LOG(WARNING) << "TaskID error: " << check.error();
-    usage(argv[0], flags);
-    return 0;
+    cerr << flags.usage("Missing required option --task_id") << endl;
+    return EXIT_FAILURE;
   }
 
   TaskID taskID;
@@ -377,8 +371,8 @@ int main(int argc, char** argv)
 
   if (checking.isFailed()) {
     LOG(WARNING) << "Health check failed " << checking.failure();
-    return 1;
+    return EXIT_FAILURE;
   }
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/launcher/executor.cpp
----------------------------------------------------------------------
diff --git a/src/launcher/executor.cpp b/src/launcher/executor.cpp
index de6f1b1..f79dc60 100644
--- a/src/launcher/executor.cpp
+++ b/src/launcher/executor.cpp
@@ -581,15 +581,6 @@ private:
 } // namespace mesos {
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 class Flags : public flags::FlagsBase
 {
 public:
@@ -615,24 +606,17 @@ int main(int argc, char** argv)
 {
   Flags flags;
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   // Load flags from command line.
   Try<Nothing> load = flags.load(None(), &argc, &argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    return -1;
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   // After flags.load(..., &argc, &argv) all flags will have been
@@ -653,5 +637,5 @@ int main(int argc, char** argv)
   }
   mesos::internal::CommandExecutor executor(override, path);
   mesos::MesosExecutorDriver driver(&executor);
-  return driver.run() == mesos::DRIVER_STOPPED ? 0 : 1;
+  return driver.run() == mesos::DRIVER_STOPPED ? EXIT_SUCCESS : EXIT_FAILURE;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/local/main.cpp
----------------------------------------------------------------------
diff --git a/src/local/main.cpp b/src/local/main.cpp
index a641b9e..ec21ed0 100644
--- a/src/local/main.cpp
+++ b/src/local/main.cpp
@@ -39,21 +39,11 @@ using mesos::internal::master::Master;
 using mesos::internal::slave::Slave;
 
 using std::cerr;
+using std::cout;
 using std::endl;
 using std::string;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Launches an in-memory cluster within a single process."
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char **argv)
 {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
@@ -64,6 +54,10 @@ int main(int argc, char **argv)
   // master::flags, then slave::Flags, then local::Flags.
   local::Flags flags;
 
+  flags.setUsageMessage(
+      "Usage: " + os::basename(argv[0]).get() + " [...]\n\n" +
+      "Launches an in-memory cluster within a single process.");
+
   // The following flags are executable specific (e.g., since we only
   // have one instance of libprocess per execution, we only want to
   // advertise the port and ip option once, here).
@@ -73,25 +67,18 @@ int main(int argc, char **argv)
   Option<string> ip;
   flags.add(&ip, "ip", "IP address to listen on");
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   // Load flags from environment and command line but allow unknown
   // flags since we might have some master/slave flags as well.
   Try<Nothing> load = flags.load("MESOS_", argc, argv, true);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    exit(1);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    exit(1);
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   // Initialize libprocess.
@@ -107,5 +94,5 @@ int main(int argc, char **argv)
 
   process::wait(local::launch(flags));
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/benchmark.cpp
----------------------------------------------------------------------
diff --git a/src/log/tool/benchmark.cpp b/src/log/tool/benchmark.cpp
index 01e5511..4895dd8 100644
--- a/src/log/tool/benchmark.cpp
+++ b/src/log/tool/benchmark.cpp
@@ -47,7 +47,6 @@ using std::cout;
 using std::endl;
 using std::ifstream;
 using std::ofstream;
-using std::ostringstream;
 using std::string;
 using std::vector;
 
@@ -95,44 +94,30 @@ Benchmark::Flags::Flags()
       "initialize",
       "Whether to initialize the log",
       true);
-
-  add(&Flags::help,
-      "help",
-      "Prints the help message",
-      false);
-}
-
-
-string Benchmark::usage(const string& argv0) const
-{
-  ostringstream out;
-
-  out << "Usage: " << argv0 << " " << name() << " [OPTIONS]" << endl
-      << endl
-      << "This command is used to do performance test on the" << endl
-      << "replicated log. It takes a trace file of write sizes" << endl
-      << "and replay that trace to measure the latency of each" << endl
-      << "write. The data to be written for each write can be" << endl
-      << "specified using the '--type' flag." << endl
-      << endl
-      << "Supported OPTIONS:" << endl
-      << flags.usage();
-
-  return out.str();
 }
 
 
 Try<Nothing> Benchmark::execute(int argc, char** argv)
 {
+  flags.setUsageMessage(
+      "Usage: " + name() + " [options]\n"
+      "\n"
+      "This command is used to do performance test on the\n"
+      "replicated log. It takes a trace file of write sizes\n"
+      "and replay that trace to measure the latency of each\n"
+      "write. The data to be written for each write can be\n"
+      "specified using the --type flag.\n"
+      "\n");
+
   // Configure the tool by parsing command line arguments.
   if (argc > 0 && argv != NULL) {
     Try<Nothing> load = flags.load(None(), argc, argv);
     if (load.isError()) {
-      return Error(load.error() + "\n\n" + usage(argv[0]));
+      return Error(flags.usage(load.error()));
     }
 
     if (flags.help) {
-      return Error(usage(argv[0]));
+      return Error(flags.usage());
     }
 
     process::initialize();
@@ -140,27 +125,27 @@ Try<Nothing> Benchmark::execute(int argc, char** argv)
   }
 
   if (flags.quorum.isNone()) {
-    return Error("Missing flag '--quorum'");
+    return Error(flags.usage("Missing required option --quorum"));
   }
 
   if (flags.path.isNone()) {
-    return Error("Missing flag '--path'");
+    return Error(flags.usage("Missing required option --path"));
   }
 
   if (flags.servers.isNone()) {
-    return Error("Missing flag '--servers'");
+    return Error(flags.usage("Missing required option --servers"));
   }
 
   if (flags.znode.isNone()) {
-    return Error("Missing flag '--znode'");
+    return Error(flags.usage("Missing required option --znode"));
   }
 
   if (flags.input.isNone()) {
-    return Error("Missing flag '--input'");
+    return Error(flags.usage("Missing required option --input"));
   }
 
   if (flags.output.isNone()) {
-    return Error("Missing flag '--output'");
+    return Error(flags.usage("Missing required option --output"));
   }
 
   // Initialize the log.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/benchmark.hpp
----------------------------------------------------------------------
diff --git a/src/log/tool/benchmark.hpp b/src/log/tool/benchmark.hpp
index e0109e2..5714b87 100644
--- a/src/log/tool/benchmark.hpp
+++ b/src/log/tool/benchmark.hpp
@@ -55,9 +55,6 @@ public:
 
   // Users can change the default configuration by setting this flags.
   Flags flags;
-
-private:
-  std::string usage(const std::string& argv0) const;
 };
 
 } // namespace tool {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/initialize.cpp
----------------------------------------------------------------------
diff --git a/src/log/tool/initialize.cpp b/src/log/tool/initialize.cpp
index ccda7fb..a5146fd 100644
--- a/src/log/tool/initialize.cpp
+++ b/src/log/tool/initialize.cpp
@@ -16,9 +16,6 @@
  * limitations under the License.
  */
 
-#include <iostream>
-#include <sstream>
-
 #include <process/process.hpp>
 #include <process/timeout.hpp>
 
@@ -31,8 +28,6 @@
 
 using namespace process;
 
-using std::endl;
-using std::ostringstream;
 using std::string;
 
 namespace mesos {
@@ -50,40 +45,26 @@ Initialize::Flags::Flags()
       "timeout",
       "Maximum time allowed for the command to finish\n"
       "(e.g., 500ms, 1sec, etc.)");
-
-  add(&Flags::help,
-      "help",
-      "Prints the help message",
-      false);
-}
-
-
-string Initialize::usage(const string& argv0) const
-{
-  ostringstream out;
-
-  out << "Usage: " << argv0 << " " << name() << " [OPTIONS]" << endl
-      << endl
-      << "This command is used to initialize the log" << endl
-      << endl
-      << "Supported OPTIONS:" << endl
-      << flags.usage();
-
-  return out.str();
 }
 
 
 Try<Nothing> Initialize::execute(int argc, char** argv)
 {
+  flags.setUsageMessage(
+      "Usage: " + name() + " [option]\n"
+      "\n"
+      "This command is used to initialize the log.\n"
+      "\n");
+
   // Configure the tool by parsing command line arguments.
   if (argc > 0 && argv != NULL) {
     Try<Nothing> load = flags.load(None(), argc, argv);
     if (load.isError()) {
-      return Error(load.error() + "\n\n" + usage(argv[0]));
+      return Error(flags.usage(load.error()));
     }
 
     if (flags.help) {
-      return Error(usage(argv[0]));
+      return Error(flags.usage());
     }
 
     process::initialize();
@@ -91,7 +72,7 @@ Try<Nothing> Initialize::execute(int argc, char** argv)
   }
 
   if (flags.path.isNone()) {
-    return Error("Missing flag: '--path'");
+    return Error(flags.usage("Missing required option --path"));
   }
 
   // Setup the timeout if specified.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/initialize.hpp
----------------------------------------------------------------------
diff --git a/src/log/tool/initialize.hpp b/src/log/tool/initialize.hpp
index 10ac269..dc25e97 100644
--- a/src/log/tool/initialize.hpp
+++ b/src/log/tool/initialize.hpp
@@ -50,9 +50,6 @@ public:
 
   // Users can change the default configuration by setting this flags.
   Flags flags;
-
-private:
-  std::string usage(const std::string& argv0) const;
 };
 
 } // namespace tool {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/read.cpp
----------------------------------------------------------------------
diff --git a/src/log/tool/read.cpp b/src/log/tool/read.cpp
index d141385..08d1932 100644
--- a/src/log/tool/read.cpp
+++ b/src/log/tool/read.cpp
@@ -19,12 +19,12 @@
 #include <stdint.h>
 
 #include <iostream>
-#include <sstream>
 
 #include <process/process.hpp>
 #include <process/timeout.hpp>
 
 #include <stout/error.hpp>
+#include <stout/stringify.hpp>
 
 #include "log/replica.hpp"
 #include "log/tool/read.hpp"
@@ -36,7 +36,6 @@ using namespace process;
 using std::cout;
 using std::endl;
 using std::list;
-using std::ostringstream;
 using std::string;
 
 namespace mesos {
@@ -62,40 +61,26 @@ Read::Flags::Flags()
       "timeout",
       "Maximum time allowed for the command to finish\n"
       "(e.g., 500ms, 1sec, etc.)");
-
-  add(&Flags::help,
-      "help",
-      "Prints the help message",
-      false);
-}
-
-
-string Read::usage(const string& argv0) const
-{
-  ostringstream out;
-
-  out << "Usage: " << argv0 << " " << name() << " [OPTIONS]" << endl
-      << endl
-      << "This command is used to read the log" << endl
-      << endl
-      << "Supported OPTIONS:" << endl
-      << flags.usage();
-
-  return out.str();
 }
 
 
 Try<Nothing> Read::execute(int argc, char** argv)
 {
+  flags.setUsageMessage(
+      "Usage: " + name() + " [options]\n"
+      "\n"
+      "This command is used to read the log.\n"
+      "\n");
+
   // Configure the tool by parsing command line arguments.
   if (argc > 0 && argv != NULL) {
     Try<Nothing> load = flags.load(None(), argc, argv);
     if (load.isError()) {
-      return Error(load.error() + "\n\n" + usage(argv[0]));
+      return Error(flags.usage(load.error()));
     }
 
     if (flags.help) {
-      return Error(usage(argv[0]));
+      return Error(flags.usage());
     }
 
     process::initialize();
@@ -103,7 +88,7 @@ Try<Nothing> Read::execute(int argc, char** argv)
   }
 
   if (flags.path.isNone()) {
-    return Error("Missing flag '--path'");
+    return Error(flags.usage("Missing required flag --path"));
   }
 
   // Setup the timeout if specified.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/read.hpp
----------------------------------------------------------------------
diff --git a/src/log/tool/read.hpp b/src/log/tool/read.hpp
index 9a6971b..f5958cd 100644
--- a/src/log/tool/read.hpp
+++ b/src/log/tool/read.hpp
@@ -54,9 +54,6 @@ public:
 
   // Users can change the default configuration by setting this flags.
   Flags flags;
-
-private:
-  std::string usage(const std::string& argv0) const;
 };
 
 } // namespace tool {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/replica.cpp
----------------------------------------------------------------------
diff --git a/src/log/tool/replica.cpp b/src/log/tool/replica.cpp
index 3985fc7..1eba480 100644
--- a/src/log/tool/replica.cpp
+++ b/src/log/tool/replica.cpp
@@ -17,7 +17,6 @@
  */
 
 #include <iostream>
-#include <sstream>
 
 #include <process/future.hpp>
 #include <process/process.hpp>
@@ -33,7 +32,6 @@
 using namespace process;
 
 using std::endl;
-using std::ostringstream;
 using std::string;
 
 namespace mesos {
@@ -63,40 +61,26 @@ Replica::Flags::Flags()
       "initialize",
       "Whether to initialize the log",
       true);
-
-  add(&Flags::help,
-      "help",
-      "Prints the help message",
-      false);
-}
-
-
-string Replica::usage(const string& argv0) const
-{
-  ostringstream out;
-
-  out << "Usage: " << argv0 << " " << name() << " [OPTIONS]" << endl
-      << endl
-      << "This command is used to start a replica server" << endl
-      << endl
-      << "Supported OPTIONS:" << endl
-      << flags.usage();
-
-  return out.str();
 }
 
 
 Try<Nothing> Replica::execute(int argc, char** argv)
 {
+  flags.setUsageMessage(
+      "Usage: " + name() + " [options]\n"
+      "\n"
+      "This command is used to start a replica server.\n"
+      "\n");
+
   // Configure the tool by parsing command line arguments.
   if (argc > 0 && argv != NULL) {
     Try<Nothing> load = flags.load(None(), argc, argv);
     if (load.isError()) {
-      return Error(load.error() + "\n\n" + usage(argv[0]));
+      return Error(flags.usage(load.error()));
     }
 
     if (flags.help) {
-      return Error(usage(argv[0]));
+      return Error(flags.usage());
     }
 
     process::initialize();
@@ -104,19 +88,19 @@ Try<Nothing> Replica::execute(int argc, char** argv)
   }
 
   if (flags.quorum.isNone()) {
-    return Error("Missing flag '--quorum'");
+    return Error(flags.usage("Missing required option --quorum"));
   }
 
   if (flags.path.isNone()) {
-    return Error("Missing flag '--path'");
+    return Error(flags.usage("Missing required option --path"));
   }
 
   if (flags.servers.isNone()) {
-    return Error("Missing flag '--servers'");
+    return Error(flags.usage("Missing required option --servers"));
   }
 
   if (flags.znode.isNone()) {
-    return Error("Missing flag '--znode'");
+    return Error(flags.usage("Missing required option --znode"));
   }
 
   // Initialize the log.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/log/tool/replica.hpp
----------------------------------------------------------------------
diff --git a/src/log/tool/replica.hpp b/src/log/tool/replica.hpp
index 7140c7e..7a8f391 100644
--- a/src/log/tool/replica.hpp
+++ b/src/log/tool/replica.hpp
@@ -55,9 +55,6 @@ public:
 
   // Users can change the default configuration by setting this flags.
   Flags flags;
-
-private:
-  std::string usage(const std::string& argv0) const;
 };
 
 } // namespace tool {

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/master/main.cpp
----------------------------------------------------------------------
diff --git a/src/master/main.cpp b/src/master/main.cpp
index d5666bc..3d490c3 100644
--- a/src/master/main.cpp
+++ b/src/master/main.cpp
@@ -98,15 +98,6 @@ using std::string;
 using std::vector;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 void version()
 {
   cout << "mesos" << " " << MESOS_VERSION << endl;
@@ -137,28 +128,21 @@ int main(int argc, char** argv)
             "  zk://username:password@host1:port1,host2:port2,.../path\n"
             "  file:///path/to/file (where file contains one of the above)");
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   Try<Nothing> load = flags.load("MESOS_", argc, argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    exit(1);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
   if (flags.version) {
     version();
-    exit(0);
+    return EXIT_SUCCESS;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    exit(1);
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   // Initialize modules. Note that since other subsystems may depend
@@ -166,7 +150,7 @@ int main(int argc, char** argv)
   if (flags.modules.isSome()) {
     Try<Nothing> result = ModuleManager::load(flags.modules.get());
     if (result.isError()) {
-      EXIT(1) << "Error loading modules: " << result.error();
+      EXIT(EXIT_FAILURE) << "Error loading modules: " << result.error();
     }
   }
 
@@ -174,7 +158,7 @@ int main(int argc, char** argv)
   if (flags.hooks.isSome()) {
     Try<Nothing> result = HookManager::initialize(flags.hooks.get());
     if (result.isError()) {
-      EXIT(1) << "Error installing hooks: " << result.error();
+      EXIT(EXIT_FAILURE) << "Error installing hooks: " << result.error();
     }
   }
 
@@ -206,8 +190,9 @@ int main(int argc, char** argv)
   Try<Allocator*> allocator = Allocator::create(allocatorName);
 
   if (allocator.isError()) {
-    EXIT(1) << "Failed to create '" << allocatorName << "' allocator: "
-            << allocator.error();
+    EXIT(EXIT_FAILURE)
+      << "Failed to create '" << allocatorName
+      << "' allocator: " << allocator.error();
   }
 
   CHECK_NOTNULL(allocator.get());
@@ -218,8 +203,9 @@ int main(int argc, char** argv)
 
   if (flags.registry == "in_memory") {
     if (flags.registry_strict) {
-      EXIT(1) << "Cannot use '--registry_strict' when using in-memory storage"
-              << " based registry";
+      EXIT(EXIT_FAILURE)
+        << "Cannot use '--registry_strict' when using in-memory storage"
+        << " based registry";
     }
     storage = new state::InMemoryStorage();
   } else if (flags.registry == "replicated_log" ||
@@ -227,25 +213,28 @@ int main(int argc, char** argv)
     // TODO(bmahler): "log_storage" is present for backwards
     // compatibility, can be removed before 0.19.0.
     if (flags.work_dir.isNone()) {
-      EXIT(1) << "--work_dir needed for replicated log based registry";
+      EXIT(EXIT_FAILURE)
+        << "--work_dir needed for replicated log based registry";
     }
 
     Try<Nothing> mkdir = os::mkdir(flags.work_dir.get());
     if (mkdir.isError()) {
-      EXIT(1) << "Failed to create work directory '" << flags.work_dir.get()
-              << "': " << mkdir.error();
+      EXIT(EXIT_FAILURE)
+        << "Failed to create work directory '" << flags.work_dir.get()
+        << "': " << mkdir.error();
     }
 
     if (zk.isSome()) {
       // Use replicated log with ZooKeeper.
       if (flags.quorum.isNone()) {
-        EXIT(1) << "Need to specify --quorum for replicated log based"
-                << " registry when using ZooKeeper";
+        EXIT(EXIT_FAILURE)
+          << "Need to specify --quorum for replicated log based"
+          << " registry when using ZooKeeper";
       }
 
       Try<zookeeper::URL> url = zookeeper::URL::parse(zk.get());
       if (url.isError()) {
-        EXIT(1) << "Error parsing ZooKeeper URL: " << url.error();
+        EXIT(EXIT_FAILURE) << "Error parsing ZooKeeper URL: " << url.error();
       }
 
       log = new Log(
@@ -266,8 +255,9 @@ int main(int argc, char** argv)
     }
     storage = new state::LogStorage(log);
   } else {
-    EXIT(1) << "'" << flags.registry << "' is not a supported"
-            << " option for registry persistence";
+    EXIT(EXIT_FAILURE)
+      << "'" << flags.registry << "' is not a supported"
+      << " option for registry persistence";
   }
 
   CHECK_NOTNULL(storage);
@@ -285,7 +275,8 @@ int main(int argc, char** argv)
   // Option<string>.
   Try<MasterContender*> contender_ = MasterContender::create(zk.get(""));
   if (contender_.isError()) {
-    EXIT(1) << "Failed to create a master contender: " << contender_.error();
+    EXIT(EXIT_FAILURE)
+      << "Failed to create a master contender: " << contender_.error();
   }
   contender = contender_.get();
 
@@ -293,7 +284,8 @@ int main(int argc, char** argv)
   // Option<string>.
   Try<MasterDetector*> detector_ = MasterDetector::create(zk.get(""));
   if (detector_.isError()) {
-    EXIT(1) << "Failed to create a master detector: " << detector_.error();
+    EXIT(EXIT_FAILURE)
+      << "Failed to create a master detector: " << detector_.error();
   }
   detector = detector_.get();
 
@@ -302,8 +294,9 @@ int main(int argc, char** argv)
     Try<Owned<Authorizer>> create = Authorizer::create(flags.acls.get());
 
     if (create.isError()) {
-      EXIT(1) << "Failed to initialize the authorizer: "
-              << create.error() << " (see --acls flag)";
+      EXIT(EXIT_FAILURE)
+        << "Failed to initialize the authorizer: "
+        << create.error() << " (see --acls flag)";
     }
 
     // Now pull out the authorizer but need to make a copy since we
@@ -320,25 +313,28 @@ int main(int argc, char** argv)
       strings::tokenize(flags.slave_removal_rate_limit.get(), "/");
 
     if (tokens.size() != 2) {
-      EXIT(1) << "Invalid slave_removal_rate_limit: "
-              << flags.slave_removal_rate_limit.get()
-              << ". Format is <Number of slaves>/<Duration>";
+      EXIT(EXIT_FAILURE)
+        << "Invalid slave_removal_rate_limit: "
+        << flags.slave_removal_rate_limit.get()
+        << ". Format is <Number of slaves>/<Duration>";
     }
 
     Try<int> permits = numify<int>(tokens[0]);
     if (permits.isError()) {
-      EXIT(1) << "Invalid slave_removal_rate_limit: "
-              << flags.slave_removal_rate_limit.get()
-              << ". Format is <Number of slaves>/<Duration>"
-              << ": " << permits.error();
+      EXIT(EXIT_FAILURE)
+        << "Invalid slave_removal_rate_limit: "
+        << flags.slave_removal_rate_limit.get()
+        << ". Format is <Number of slaves>/<Duration>"
+        << ": " << permits.error();
     }
 
     Try<Duration> duration = Duration::parse(tokens[1]);
     if (duration.isError()) {
-      EXIT(1) << "Invalid slave_removal_rate_limit: "
-              << flags.slave_removal_rate_limit.get()
-              << ". Format is <Number of slaves>/<Duration>"
-              << ": " << duration.error();
+      EXIT(EXIT_FAILURE)
+        << "Invalid slave_removal_rate_limit: "
+        << flags.slave_removal_rate_limit.get()
+        << ". Format is <Number of slaves>/<Duration>"
+        << ": " << duration.error();
     }
 
     slaveRemovalLimiter = new RateLimiter(permits.get(), duration.get());
@@ -348,7 +344,8 @@ int main(int argc, char** argv)
   foreach (const string& name, ModuleManager::find<Anonymous>()) {
     Try<Anonymous*> create = ModuleManager::create<Anonymous>(name);
     if (create.isError()) {
-      EXIT(1) << "Failed to create anonymous module named '" << name << "'";
+      EXIT(EXIT_FAILURE)
+        << "Failed to create anonymous module named '" << name << "'";
     }
 
     // We don't bother keeping around the pointer to this anonymous
@@ -399,5 +396,5 @@ int main(int argc, char** argv)
     delete authorizer.get();
   }
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/slave/containerizer/isolators/network/port_mapping.cpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/isolators/network/port_mapping.cpp b/src/slave/containerizer/isolators/network/port_mapping.cpp
index d3c1918..781c35b 100644
--- a/src/slave/containerizer/isolators/network/port_mapping.cpp
+++ b/src/slave/containerizer/isolators/network/port_mapping.cpp
@@ -312,11 +312,6 @@ const char* PortMappingUpdate::NAME = "update";
 
 PortMappingUpdate::Flags::Flags()
 {
-  add(&help,
-      "help",
-      "Prints this help message",
-      false);
-
   add(&eth0_name,
       "eth0_name",
       "The name of the public network interface (e.g., eth0)");
@@ -581,11 +576,6 @@ const char* PortMappingStatistics::NAME = "statistics";
 
 PortMappingStatistics::Flags::Flags()
 {
-  add(&help,
-      "help",
-      "Prints this help message",
-      false);
-
   add(&pid,
       "pid",
       "The pid of the process whose namespaces we will enter");

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/slave/containerizer/isolators/network/port_mapping.hpp
----------------------------------------------------------------------
diff --git a/src/slave/containerizer/isolators/network/port_mapping.hpp b/src/slave/containerizer/isolators/network/port_mapping.hpp
index 52c7e7c..9f83af1 100644
--- a/src/slave/containerizer/isolators/network/port_mapping.hpp
+++ b/src/slave/containerizer/isolators/network/port_mapping.hpp
@@ -342,7 +342,6 @@ public:
   {
     Flags();
 
-    bool help;
     Option<std::string> eth0_name;
     Option<std::string> lo_name;
     Option<pid_t> pid;
@@ -372,7 +371,6 @@ public:
   {
     Flags();
 
-    bool help;
     Option<pid_t> pid;
     bool enable_socket_statistics_summary;
     bool enable_socket_statistics_details;

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/slave/main.cpp
----------------------------------------------------------------------
diff --git a/src/slave/main.cpp b/src/slave/main.cpp
index f762f5b..e3a45f4 100644
--- a/src/slave/main.cpp
+++ b/src/slave/main.cpp
@@ -62,15 +62,6 @@ using std::endl;
 using std::string;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 void version()
 {
   cout << "mesos" << " " << MESOS_VERSION << endl;
@@ -100,32 +91,28 @@ int main(int argc, char** argv)
             "  zk://username:password@host1:port1,host2:port2,.../path\n"
             "  file:///path/to/file (where file contains one of the above)");
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   Try<Nothing> load = flags.load("MESOS_", argc, argv);
 
+  // TODO(marco): this pattern too should be abstracted away
+  // in FlagsBase; I have seen it at least 15 times.
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    EXIT(1);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    EXIT(1);
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.version) {
     version();
-    exit(0);
+    return EXIT_SUCCESS;
   }
 
   if (master.isNone()) {
-    EXIT(1) << "Missing required option --master";
+    cerr << flags.usage("Missing required option --master") << endl;
+    return EXIT_FAILURE;
   }
 
   // Initialize modules. Note that since other subsystems may depend
@@ -133,7 +120,7 @@ int main(int argc, char** argv)
   if (flags.modules.isSome()) {
     Try<Nothing> result = ModuleManager::load(flags.modules.get());
     if (result.isError()) {
-      EXIT(1) << "Error loading modules: " << result.error();
+      EXIT(EXIT_FAILURE) << "Error loading modules: " << result.error();
     }
   }
 
@@ -141,7 +128,7 @@ int main(int argc, char** argv)
   if (flags.hooks.isSome()) {
     Try<Nothing> result = HookManager::initialize(flags.hooks.get());
     if (result.isError()) {
-      EXIT(1) << "Error installing hooks: " << result.error();
+      EXIT(EXIT_FAILURE) << "Error installing hooks: " << result.error();
     }
   }
 
@@ -174,21 +161,23 @@ int main(int argc, char** argv)
     Containerizer::create(flags, false, &fetcher);
 
   if (containerizer.isError()) {
-    EXIT(1) << "Failed to create a containerizer: "
-            << containerizer.error();
+    EXIT(EXIT_FAILURE)
+      << "Failed to create a containerizer: " << containerizer.error();
   }
 
   Try<MasterDetector*> detector = MasterDetector::create(master.get());
 
   if (detector.isError()) {
-    EXIT(1) << "Failed to create a master detector: " << detector.error();
+    EXIT(EXIT_FAILURE)
+      << "Failed to create a master detector: " << detector.error();
   }
 
   // Create anonymous modules.
   foreach (const string& name, ModuleManager::find<Anonymous>()) {
     Try<Anonymous*> create = ModuleManager::create<Anonymous>(name);
     if (create.isError()) {
-      EXIT(1) << "Failed to create anonymous module named '" << name << "'";
+      EXIT(EXIT_FAILURE)
+        << "Failed to create anonymous module named '" << name << "'";
     }
 
     // We don't bother keeping around the pointer to this anonymous
@@ -200,8 +189,6 @@ int main(int argc, char** argv)
     // terminating.
   }
 
-  LOG(INFO) << "Starting Mesos slave";
-
   Files files;
   GarbageCollector gc;
   StatusUpdateManager statusUpdateManager(flags);
@@ -210,10 +197,13 @@ int main(int argc, char** argv)
     ResourceEstimator::create(flags.resource_estimator);
 
   if (resourceEstimator.isError()) {
-    EXIT(1) << "Failed to create resource estimator: "
-            << resourceEstimator.error();
+    cerr << "Failed to create resource estimator: "
+         << resourceEstimator.error() << endl;
+    return EXIT_FAILURE;
   }
 
+  LOG(INFO) << "Starting Mesos slave";
+
   Slave* slave = new Slave(
       flags,
       detector.get(),
@@ -234,5 +224,5 @@ int main(int argc, char** argv)
 
   delete containerizer.get();
 
-  return 0;
+  return EXIT_SUCCESS;
 }

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/tests/main.cpp
----------------------------------------------------------------------
diff --git a/src/tests/main.cpp b/src/tests/main.cpp
index e3fff5d..970a8b0 100644
--- a/src/tests/main.cpp
+++ b/src/tests/main.cpp
@@ -43,52 +43,37 @@ using namespace mesos::internal;
 using namespace mesos::internal::tests;
 
 using std::cerr;
+using std::cout;
 using std::endl;
 using std::string;
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char** argv)
 {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
   using mesos::internal::tests::flags; // Needed to disabmiguate.
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   // Load flags from environment and command line but allow unknown
   // flags (since we might have gtest/gmock flags as well).
   Try<Nothing> load = flags.load("MESOS_", argc, argv, true);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    exit(1);
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    cerr << endl;
+  if (flags.help) {
+    cout << flags.usage() << endl;
     testing::InitGoogleTest(&argc, argv); // Get usage from gtest too.
-    exit(1);
+    return EXIT_SUCCESS;
   }
 
   // Initialize Modules.
   Try<Nothing> result = tests::initModules(flags.modules);
   if (result.isError()) {
-    EXIT(1) << "Error initializing modules: " << result.error();
+    cerr << "Error initializing modules: " << result.error() << endl;
+    return EXIT_FAILURE;
   }
 
   // Initialize libprocess.
@@ -114,8 +99,8 @@ int main(int argc, char** argv)
   testing::InitGoogleTest(&argc, argv);
   testing::FLAGS_gtest_death_test_style = "threadsafe";
 
-  std::cout << "Source directory: " << flags.source_dir << std::endl;
-  std::cout << "Build directory: " << flags.build_dir << std::endl;
+  cout << "Source directory: " << flags.source_dir << endl;
+  cout << "Build directory: " << flags.build_dir << endl;
 
   // Instantiate our environment. Note that it will be managed by
   // gtest after we add it via testing::AddGlobalTestEnvironment.

http://git-wip-us.apache.org/repos/asf/mesos/blob/4cc0ffc4/src/usage/main.cpp
----------------------------------------------------------------------
diff --git a/src/usage/main.cpp b/src/usage/main.cpp
index 97f55e9..86fd796 100644
--- a/src/usage/main.cpp
+++ b/src/usage/main.cpp
@@ -60,62 +60,45 @@ public:
 };
 
 
-void usage(const char* argv0, const flags::FlagsBase& flags)
-{
-  cerr << "Usage: " << os::basename(argv0).get() << " [...]" << endl
-       << endl
-       << "Supported options:" << endl
-       << flags.usage();
-}
-
-
 int main(int argc, char** argv)
 {
   GOOGLE_PROTOBUF_VERIFY_VERSION;
 
   Flags flags;
 
-  bool help;
-  flags.add(&help,
-            "help",
-            "Prints this help message",
-            false);
-
   Try<Nothing> load = flags.load(None(), argc, argv);
 
   if (load.isError()) {
-    cerr << load.error() << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage(load.error()) << endl;
+    return EXIT_FAILURE;
   }
 
-  if (help) {
-    usage(argv[0], flags);
-    return 0;
+  if (flags.help) {
+    cout << flags.usage() << endl;
+    return EXIT_SUCCESS;
   }
 
   if (flags.pid.isNone()) {
-    cerr << "Missing pid" << endl;
-    usage(argv[0], flags);
-    return -1;
+    cerr << flags.usage("Missing required option --pid") << endl;
+    return EXIT_FAILURE;
   }
 
   Try<ResourceStatistics> statistics = mesos::internal::usage(flags.pid.get());
 
   if (statistics.isError()) {
     cerr << "Failed to get usage: " << statistics.error() << endl;
-    return -1;
+    return EXIT_FAILURE;
   }
 
   if (flags.recordio) {
     Try<Nothing> write = protobuf::write(STDOUT_FILENO, statistics.get());
     if (write.isError()) {
       cerr << "Failed to write record: " << write.error() << endl;
-      return -1;
+      return EXIT_FAILURE;
     }
   } else {
     cout << stringify(JSON::Protobuf(statistics.get())) << endl;
   }
 
-  return 0;
+  return EXIT_SUCCESS;
 }


[2/2] mesos git commit: Refactored common functionality into FlagsBase.

Posted by be...@apache.org.
Refactored common functionality into FlagsBase.

Jira: MESOS-2711

Every program that uses stout's `FlagsBase` ends up re-implementing
the `usage()` function, and adding a `bool help` (and associated
--help flag); this functionality has now been refactored in the base
class and is available everywhere.

This change attempts to be backward-compatible, so it does not alter
the behavior of the program when --help is invoked (by, e.g.,
automatically printing usage and exiting) but leaves up to the caller
to check for `flags.help` and then decide what action to take.

There is now a default behavior for the "leader" ("Usage: <program
name> [options]") but the client API allows to modify that too.

Note - anywhere I found the use of the `--help` flag the behavior was
the same: print usage and exit (see also
https://reviews.apache.org/r/34195).

Review: https://reviews.apache.org/r/34193


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/1694bda8
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/1694bda8
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/1694bda8

Branch: refs/heads/master
Commit: 1694bda8d8b7a43ac8fd857c5909d8a1a25f2754
Parents: f855fb7
Author: Marco Massenzio <ma...@mesosphere.io>
Authored: Mon Jun 1 03:49:00 2015 -0700
Committer: Benjamin Hindman <be...@gmail.com>
Committed: Mon Jun 1 15:59:38 2015 -0700

----------------------------------------------------------------------
 .../stout/include/stout/flags/flags.hpp         | 126 +++++++++++++++----
 .../3rdparty/stout/tests/flags_tests.cpp        |  70 ++++++++++-
 2 files changed, 171 insertions(+), 25 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/1694bda8/3rdparty/libprocess/3rdparty/stout/include/stout/flags/flags.hpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/include/stout/flags/flags.hpp b/3rdparty/libprocess/3rdparty/stout/include/stout/flags/flags.hpp
index fb383b4..61a405f 100644
--- a/3rdparty/libprocess/3rdparty/stout/include/stout/flags/flags.hpp
+++ b/3rdparty/libprocess/3rdparty/stout/include/stout/flags/flags.hpp
@@ -42,6 +42,7 @@ namespace flags {
 class FlagsBase
 {
 public:
+  FlagsBase() { add(&help, "help", "Prints this help message", false); }
   virtual ~FlagsBase() {}
 
   // Load any flags from the environment given the variable prefix,
@@ -64,11 +65,11 @@ public:
   // Load any flags from the environment as above but remove processed
   // flags from 'argv' and update 'argc' appropriately. For example:
   //
-  // argv = ["/path/to/program", "--arg1", "hello", "--arg2", "--", "world"]
+  // argv = ["/path/program", "--arg1", "hi", "--arg2", "--", "bye"]
   //
   // Becomes:
   //
-  // argv = ["/path/to/program", "hello", "world"]
+  // argv = ["/path/program", "hi", "bye"]
   virtual Try<Nothing> load(
       const Option<std::string>& prefix,
       int* argc,
@@ -84,18 +85,57 @@ public:
       const std::map<std::string, std::string>& values,
       bool unknowns = false);
 
-  // Returns a string describing the flags.
-  std::string usage() const;
+  // Returns a string describing the flags, preceded by a "usage
+  // message" that will be prepended to that description (see
+  // 'FlagsBase::usageMessage_').
+  //
+  // The optional 'message' passed to this function will be prepended
+  // to the generated string returned from this function.
+  //
+  // Derived classes and clients can modify the standard usage message
+  // by setting it before calling this method via 'setUsageMessage()'.
+  //
+  // This allows one to set a generic message that will be used for
+  // each invocation of this method, and to additionally add one for
+  // the particular invocation:
+  //
+  //    MyFlags flags;
+  //    flags.setUsageMessage("Custom Usage Message");
+  //    ...
+  //    if (flags.foo.isNone()) {
+  //      std::cerr << flags.usage("Missing required --foo flag");
+  //    }
+  //
+  // The 'message' would be emitted first, followed by a blank line,
+  // then the 'usageMessage_', finally followed by the flags'
+  // description, for example:
+  //
+  //    Missing required --foo flag
+  //
+  //    Custom Usage Message
+  //
+  //      --[no-]help       Prints this help message. (default: false)
+  //      --foo=VALUE       Description about 'foo' here.
+  //      --bar=VALUE       Description about 'bar' here. (default: 42)
+  //
+  std::string usage(const Option<std::string>& message = None()) const;
+
+  // Sets the default message that is prepended to the flags'
+  // description in 'usage()'.
+  void setUsageMessage(const std::string& message)
+  {
+    usageMessage_ = Some(message);
+  }
 
   typedef std::map<std::string, Flag>::const_iterator const_iterator;
 
-  const_iterator begin() const { return flags.begin(); }
-  const_iterator end() const { return flags.end(); }
+  const_iterator begin() const { return flags_.begin(); }
+  const_iterator end() const { return flags_.end(); }
 
   typedef std::map<std::string, Flag>::iterator iterator;
 
-  iterator begin() { return flags.begin(); }
-  iterator end() { return flags.end(); }
+  iterator begin() { return flags_.begin(); }
+  iterator end() { return flags_.end(); }
 
   template <typename T1, typename T2>
   void add(T1* t1,
@@ -122,12 +162,31 @@ protected:
 
   void add(const Flag& flag);
 
+public:
+  // TODO(marco): IMO the entire --help functionality should be
+  // encapsulated inside the FlagsBase class.
+  // For now, exposing this for the caller(s) to decide what to
+  // do when the user asks for help.
+  bool help;
+
+protected:
+  // The program's name, extracted from argv[0] by default;
+  // declared 'protected' so that derived classes can alter this
+  // behavior.
+  std::string programName_;
+
+  // An optional custom usage message, will be printed 'as is'
+  // just above the list of flags and their explanation.
+  // It is 'None' by default, in which case the default
+  // behavior is to print "Usage:" followed by the 'programName_'.
+  Option<std::string> usageMessage_;
+
 private:
   // Extract environment variable "flags" with the specified prefix.
   std::map<std::string, Option<std::string> > extract(
       const std::string& prefix);
 
-  std::map<std::string, Flag> flags;
+  std::map<std::string, Flag> flags_;
 };
 
 
@@ -141,7 +200,7 @@ class _Flags4 : public virtual FlagsBase {};
 class _Flags5 : public virtual FlagsBase {};
 
 
-// TODO(benh): Add some "type constraints" for template paramters to
+// TODO(benh): Add some "type constraints" for template parameters to
 // make sure they are all of type FlagsBase.
 template <typename Flags1 = _Flags1,
           typename Flags2 = _Flags2,
@@ -287,14 +346,14 @@ void FlagsBase::add(
 
 inline void FlagsBase::add(const Flag& flag)
 {
-  if (flags.count(flag.name) > 0) {
+  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;
+  flags_[flag.name] = flag;
 }
 
 
@@ -312,8 +371,8 @@ inline std::map<std::string, Option<std::string> > FlagsBase::extract(
       name = strings::lower(name); // Allow PREFIX_NAME or PREFIX_name.
 
       // Only add if it's a known flag.
-      if (flags.count(name) > 0 ||
-          (name.find("no-") == 0 && flags.count(name.substr(3)) > 0)) {
+      if (flags_.count(name) > 0 ||
+          (name.find("no-") == 0 && flags_.count(name.substr(3)) > 0)) {
         values[name] = Some(value);
       }
     }
@@ -338,10 +397,15 @@ inline Try<Nothing> FlagsBase::load(
 {
   std::map<std::string, Option<std::string> > values;
 
+  // Grab the program name from argv[0].
+  programName_ = argc > 0 ? os::basename(argv[0]).get() : "";
+
   if (prefix.isSome()) {
     values = extract(prefix.get());
   }
 
+
+
   // Read flags from the command line.
   for (int i = 1; i < argc; i++) {
     const std::string arg(strings::trim(argv[i]));
@@ -398,6 +462,9 @@ inline Try<Nothing> FlagsBase::load(
     values = extract(prefix.get());
   }
 
+  // Grab the program name from argv, without removing it.
+  programName_ = argc > 0 ? os::basename(*(argv[0])).get() : "";
+
   // Keep the arguments that are not being processed as flags.
   std::vector<char*> args;
 
@@ -477,30 +544,30 @@ inline Try<Nothing> FlagsBase::load(
     const std::string& name = iterator->first;
     const Option<std::string>& value = iterator->second;
 
-    if (flags.count(name) > 0) {
+    if (flags_.count(name) > 0) {
       if (value.isSome()) {                        // --name=value
-        if (flags[name].boolean && value.get() == "") {
-          flags[name].loader(this, "true"); // Should never fail.
+        if (flags_[name].boolean && value.get() == "") {
+          flags_[name].loader(this, "true"); // Should never fail.
         } else {
-          Try<Nothing> loader = flags[name].loader(this, value.get());
+          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.
+        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 (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.
+            flags_[name.substr(3)].loader(this, "false"); // Should never fail.
           } else {
             return Error(
                 "Failed to load boolean flag '" + name.substr(3) +
@@ -540,12 +607,22 @@ inline Try<Nothing> FlagsBase::load(
 }
 
 
-inline std::string FlagsBase::usage() const
+inline std::string FlagsBase::usage( const Option<std::string>& message) const
 {
   const int PAD = 5;
 
   std::string usage;
 
+  if (message.isSome()) {
+    usage = message.get() + "\n\n";
+  }
+
+  if (usageMessage_.isNone()) {
+    usage += "Usage: " + programName_ + " [options]\n\n";
+  } else {
+    usage += usageMessage_.get() + "\n\n";
+  }
+
   std::map<std::string, std::string> col1; // key -> col 1 string.
 
   // Construct string for the first column and store width of column.
@@ -581,6 +658,7 @@ inline std::string FlagsBase::usage() const
       usage += line;
     }
   }
+
   return usage;
 }
 

http://git-wip-us.apache.org/repos/asf/mesos/blob/1694bda8/3rdparty/libprocess/3rdparty/stout/tests/flags_tests.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/3rdparty/stout/tests/flags_tests.cpp b/3rdparty/libprocess/3rdparty/stout/tests/flags_tests.cpp
index 0028119..a6e8ba9 100644
--- a/3rdparty/libprocess/3rdparty/stout/tests/flags_tests.cpp
+++ b/3rdparty/libprocess/3rdparty/stout/tests/flags_tests.cpp
@@ -19,9 +19,17 @@
 
 using namespace flags;
 
+using std::cout;
+using std::endl;
 using std::string;
 using std::map;
 
+
+// Just used to test that the default implementation
+// of --help and 'usage()' works as intended.
+class EmptyFlags : public FlagsBase {};
+
+
 class TestFlags : public virtual FlagsBase
 {
 public:
@@ -478,11 +486,15 @@ TEST(FlagsTest, Errors)
 }
 
 
-TEST(FlagsTest, Usage)
+TEST(FlagsTest, UsageMessage)
 {
   TestFlags flags;
+  flags.setUsageMessage("This is a test");
 
   EXPECT_EQ(
+      "This is a test\n"
+      "\n"
+      "  --[no-]help       Prints this help message (default: false)\n"
       "  --name1=VALUE     Set name1 (default: ben folds)\n"
       "  --name2=VALUE     Set name2 (default: 42)\n"
       "  --[no-]name3      Set name3 (default: false)\n"
@@ -492,6 +504,62 @@ TEST(FlagsTest, Usage)
 }
 
 
+TEST(FlagsTest, EmptyUsage)
+{
+  EmptyFlags flags;
+
+  EXPECT_EQ(
+      "Usage:  [options]\n"
+      "\n"
+      "  --[no-]help     Prints this help message (default: false)\n",
+      flags.usage());
+}
+
+
+TEST(FlagsTest, ProgramName)
+{
+  // To test with a custom program name.
+  class MyTestFlags : public TestFlags
+  {
+  public:
+    MyTestFlags() { programName_ = "TestProgram"; }
+  };
+
+
+  MyTestFlags flags;
+
+  EXPECT_EQ(
+      "Usage: TestProgram [options]\n"
+      "\n"
+      "  --[no-]help       Prints this help message (default: false)\n"
+      "  --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, OptionalMessage)
+{
+  TestFlags flags;
+
+  EXPECT_EQ(
+      "Good news: this test passed!\n"
+      "\n"
+      "Usage:  [options]\n"
+      "\n"
+      "  --[no-]help       Prints this help message (default: false)\n"
+      "  --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("Good news: this test passed!"));
+}
+
+
 TEST(FlagsTest, Duration)
 {
   Flags<TestFlags> flags;