NestedCommandLineApp.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright 2015-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <functional>
  18. #include <set>
  19. #include <stdexcept>
  20. #include <folly/CPortability.h>
  21. #include <folly/String.h>
  22. #include <folly/experimental/ProgramOptions.h>
  23. namespace folly {
  24. /**
  25. * Exception that commands may throw to force the program to exit cleanly
  26. * with a given exit code. NestedCommandLineApp::run() catches this and
  27. * makes run() print the given message on stderr (followed by a newline, unless
  28. * empty; the message is only allowed when exiting with a non-zero status), and
  29. * return the exit code. (Other exceptions will propagate out of run())
  30. */
  31. class FOLLY_EXPORT ProgramExit : public std::runtime_error {
  32. public:
  33. explicit ProgramExit(int status, const std::string& msg = std::string());
  34. int status() const {
  35. return status_;
  36. }
  37. private:
  38. int status_;
  39. };
  40. /**
  41. * App that uses a nested command line, of the form:
  42. *
  43. * program [--global_options...] command [--command_options...] command_args...
  44. */
  45. class NestedCommandLineApp {
  46. public:
  47. typedef std::function<void(
  48. const std::string& command,
  49. const boost::program_options::variables_map& options,
  50. const std::vector<std::string>& args)>
  51. InitFunction;
  52. typedef std::function<void(
  53. const boost::program_options::variables_map& options,
  54. const std::vector<std::string>&)>
  55. Command;
  56. static constexpr StringPiece const kHelpCommand = "help";
  57. static constexpr StringPiece const kVersionCommand = "version";
  58. /**
  59. * Initialize the app.
  60. *
  61. * If programName is not set, we try to guess (readlink("/proc/self/exe")).
  62. *
  63. * version is the version string printed when given the --version flag.
  64. *
  65. * initFunction, if specified, is called after parsing the command line,
  66. * right before executing the command.
  67. */
  68. explicit NestedCommandLineApp(
  69. std::string programName = std::string(),
  70. std::string version = std::string(),
  71. std::string programHeading = std::string(),
  72. std::string programHelpFooter = std::string(),
  73. InitFunction initFunction = InitFunction());
  74. /**
  75. * Add GFlags to the list of supported options with the given style.
  76. */
  77. void addGFlags(ProgramOptionsStyle style = ProgramOptionsStyle::GNU) {
  78. globalOptions_.add(getGFlags(style));
  79. }
  80. /**
  81. * Return the global options object, so you can add options.
  82. */
  83. boost::program_options::options_description& globalOptions() {
  84. return globalOptions_;
  85. }
  86. /**
  87. * Add a command.
  88. *
  89. * name: command name
  90. * argStr: description of arguments in help strings
  91. * (<filename> <N>)
  92. * shortHelp: one-line summary help string
  93. * fullHelp: full help string
  94. * command: function to run
  95. *
  96. * Returns a reference to the options_description object that you can
  97. * use to add options for this command.
  98. */
  99. boost::program_options::options_description& addCommand(
  100. std::string name,
  101. std::string argStr,
  102. std::string shortHelp,
  103. std::string fullHelp,
  104. Command command);
  105. /**
  106. * Add an alias; running the command newName will have the same effect
  107. * as running oldName.
  108. */
  109. void addAlias(std::string newName, std::string oldName);
  110. /**
  111. * Run the command and return; the return code is 0 on success or
  112. * non-zero on error, so it is idiomatic to call this at the end of main():
  113. * return app.run(argc, argv);
  114. *
  115. * On successful exit, run() will check for errors on stdout (and flush
  116. * it) to help command-line applications that need to write to stdout
  117. * (failing to write to stdout is an error). If there is an error on stdout,
  118. * we'll print a helpful message on stderr and return an error status (1).
  119. */
  120. int run(int argc, const char* const argv[]);
  121. int run(const std::vector<std::string>& args);
  122. /**
  123. * Return true if name represent known built-in command (help, version)
  124. */
  125. bool isBuiltinCommand(const std::string& name) const;
  126. private:
  127. void doRun(const std::vector<std::string>& args);
  128. const std::string& resolveAlias(const std::string& name) const;
  129. struct CommandInfo {
  130. std::string argStr;
  131. std::string shortHelp;
  132. std::string fullHelp;
  133. Command command;
  134. boost::program_options::options_description options;
  135. };
  136. const std::pair<const std::string, CommandInfo>& findCommand(
  137. const std::string& name) const;
  138. void displayHelp(
  139. const boost::program_options::variables_map& options,
  140. const std::vector<std::string>& args) const;
  141. void displayVersion() const;
  142. std::string programName_;
  143. std::string programHeading_;
  144. std::string programHelpFooter_;
  145. std::string version_;
  146. InitFunction initFunction_;
  147. boost::program_options::options_description globalOptions_;
  148. std::map<std::string, CommandInfo> commands_;
  149. std::map<std::string, std::string> aliases_;
  150. std::set<folly::StringPiece> builtinCommands_;
  151. };
  152. } // namespace folly