proxygen
folly::NestedCommandLineApp Class Reference

#include <NestedCommandLineApp.h>

Classes

struct  CommandInfo
 

Public Types

typedef std::function< void(const std::string &command, const boost::program_options::variables_map &options, const std::vector< std::string > &args)> InitFunction
 
typedef std::function< void(const boost::program_options::variables_map &options, const std::vector< std::string > &)> Command
 

Public Member Functions

 NestedCommandLineApp (std::string programName=std::string(), std::string version=std::string(), std::string programHeading=std::string(), std::string programHelpFooter=std::string(), InitFunction initFunction=InitFunction())
 
void addGFlags (ProgramOptionsStyle style=ProgramOptionsStyle::GNU)
 
boost::program_options::options_description & globalOptions ()
 
boost::program_options::options_description & addCommand (std::string name, std::string argStr, std::string shortHelp, std::string fullHelp, Command command)
 
void addAlias (std::string newName, std::string oldName)
 
int run (int argc, const char *const argv[])
 
int run (const std::vector< std::string > &args)
 
bool isBuiltinCommand (const std::string &name) const
 

Static Public Attributes

static constexpr StringPiece const kHelpCommand = "help"
 
static constexpr StringPiece const kVersionCommand = "version"
 

Private Member Functions

void doRun (const std::vector< std::string > &args)
 
const std::stringresolveAlias (const std::string &name) const
 
const std::pair< const std::string, CommandInfo > & findCommand (const std::string &name) const
 
void displayHelp (const boost::program_options::variables_map &options, const std::vector< std::string > &args) const
 
void displayVersion () const
 

Private Attributes

std::string programName_
 
std::string programHeading_
 
std::string programHelpFooter_
 
std::string version_
 
InitFunction initFunction_
 
boost::program_options::options_description globalOptions_
 
std::map< std::string, CommandInfocommands_
 
std::map< std::string, std::stringaliases_
 
std::set< folly::StringPiecebuiltinCommands_
 

Detailed Description

App that uses a nested command line, of the form:

program [–global_options...] command [–command_options...] command_args...

Definition at line 51 of file NestedCommandLineApp.h.

Member Typedef Documentation

typedef std::function<void( const boost::program_options::variables_map& options, const std::vector<std::string>&)> folly::NestedCommandLineApp::Command

Definition at line 62 of file NestedCommandLineApp.h.

typedef std::function<void( const std::string& command, const boost::program_options::variables_map& options, const std::vector<std::string>& args)> folly::NestedCommandLineApp::InitFunction

Definition at line 57 of file NestedCommandLineApp.h.

Constructor & Destructor Documentation

folly::NestedCommandLineApp::NestedCommandLineApp ( std::string  programName = std::string(),
std::string  version = std::string(),
std::string  programHeading = std::string(),
std::string  programHelpFooter = std::string(),
InitFunction  initFunction = InitFunction() 
)
explicit

Initialize the app.

If programName is not set, we try to guess (readlink("/proc/self/exe")).

version is the version string printed when given the –version flag.

initFunction, if specified, is called after parsing the command line, right before executing the command.

Definition at line 51 of file NestedCommandLineApp.cpp.

References addCommand(), builtinCommands_, displayHelp(), displayVersion(), globalOptions_, kHelpCommand, kVersionCommand, and folly::Range< Iter >::str().

57  : programName_(std::move(programName)),
58  programHeading_(std::move(programHeading)),
59  programHelpFooter_(std::move(programHelpFooter)),
61  initFunction_(std::move(initFunction)),
62  globalOptions_("Global options") {
63  addCommand(
64  kHelpCommand.str(),
65  "[command]",
66  "Display help (globally or for a given command)",
67  "Displays help (globally or for a given command).",
68  [this](
69  const po::variables_map& vm, const std::vector<std::string>& args) {
70  displayHelp(vm, args);
71  });
73 
74  addCommand(
76  "[command]",
77  "Display version information",
78  "Displays version information.",
79  [this](const po::variables_map&, const std::vector<std::string>&) {
81  });
83 
84  globalOptions_.add_options()(
85  kHelpCommand.str().c_str(),
86  "Display help (globally or for a given command)")(
87  kVersionCommand.str().c_str(), "Display version information");
88 }
std::string str() const
Definition: Range.h:591
void displayHelp(const boost::program_options::variables_map &options, const std::vector< std::string > &args) const
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
boost::program_options::options_description & addCommand(std::string name, std::string argStr, std::string shortHelp, std::string fullHelp, Command command)
boost::program_options::options_description globalOptions_
ProtocolVersion version
static constexpr StringPiece const kVersionCommand
std::set< folly::StringPiece > builtinCommands_
static constexpr StringPiece const kHelpCommand

Member Function Documentation

void folly::NestedCommandLineApp::addAlias ( std::string  newName,
std::string  oldName 
)

Add an alias; running the command newName will have the same effect as running oldName.

Definition at line 109 of file NestedCommandLineApp.cpp.

References aliases_, commands_, and folly::gen::move.

Referenced by main().

109  {
110  CHECK(aliases_.count(oldName) || commands_.count(oldName))
111  << "Alias old name does not exist";
112  CHECK(!aliases_.count(newName) && !commands_.count(newName))
113  << "Alias new name already exists";
114  aliases_.emplace(std::move(newName), std::move(oldName));
115 }
std::map< std::string, std::string > aliases_
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
std::map< std::string, CommandInfo > commands_
po::options_description & folly::NestedCommandLineApp::addCommand ( std::string  name,
std::string  argStr,
std::string  shortHelp,
std::string  fullHelp,
Command  command 
)

Add a command.

name: command name argStr: description of arguments in help strings (<filename> <N>) shortHelp: one-line summary help string fullHelp: full help string command: function to run

Returns a reference to the options_description object that you can use to add options for this command.

Definition at line 90 of file NestedCommandLineApp.cpp.

References commands_, deadlock::info(), folly::gen::move, and folly::sformat().

Referenced by main(), and NestedCommandLineApp().

95  {
96  CommandInfo info{
97  std::move(argStr),
98  std::move(shortHelp),
99  std::move(fullHelp),
100  std::move(command),
101  po::options_description(folly::sformat("Options for `{}'", name))};
102 
103  auto p = commands_.emplace(std::move(name), std::move(info));
104  CHECK(p.second) << "Command already exists";
105 
106  return p.first->second.options;
107 }
def info()
Definition: deadlock.py:447
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
constexpr detail::Map< Move > move
Definition: Base-inl.h:2567
const char * name
Definition: http_parser.c:437
std::map< std::string, CommandInfo > commands_
void folly::NestedCommandLineApp::addGFlags ( ProgramOptionsStyle  style = ProgramOptionsStyle::GNU)
inline

Add GFlags to the list of supported options with the given style.

Definition at line 86 of file NestedCommandLineApp.h.

References folly::getGFlags().

Referenced by main().

86  {
87  globalOptions_.add(getGFlags(style));
88  }
boost::program_options::options_description globalOptions_
po::options_description getGFlags(ProgramOptionsStyle style)
void folly::NestedCommandLineApp::displayHelp ( const boost::program_options::variables_map &  options,
const std::vector< std::string > &  args 
) const
private

Definition at line 117 of file NestedCommandLineApp.cpp.

References aliases_, commands_, findCommand(), globalOptions_, deadlock::info(), max, programHeading_, programHelpFooter_, programName_, and resolveAlias().

Referenced by doRun(), and NestedCommandLineApp().

119  {
120  if (args.empty()) {
121  // General help
122  printf(
123  "%s\nUsage: %s [global_options...] <command> [command_options...] "
124  "[command_args...]\n\n",
125  programHeading_.c_str(),
126  programName_.c_str());
127  std::cout << globalOptions_;
128  printf("\nAvailable commands:\n");
129 
130  size_t maxLen = 0;
131  for (auto& p : commands_) {
132  maxLen = std::max(maxLen, p.first.size());
133  }
134  for (auto& p : aliases_) {
135  maxLen = std::max(maxLen, p.first.size());
136  }
137 
138  for (auto& p : commands_) {
139  printf(
140  " %-*s %s\n",
141  int(maxLen),
142  p.first.c_str(),
143  p.second.shortHelp.c_str());
144  }
145 
146  if (!aliases_.empty()) {
147  printf("\nAvailable aliases:\n");
148  for (auto& p : aliases_) {
149  printf(
150  " %-*s => %s\n",
151  int(maxLen),
152  p.first.c_str(),
153  resolveAlias(p.second).c_str());
154  }
155  }
156  std::cout << "\n" << programHelpFooter_ << "\n";
157  } else {
158  // Help for a given command
159  auto& p = findCommand(args.front());
160  if (p.first != args.front()) {
161  printf(
162  "`%s' is an alias for `%s'; showing help for `%s'\n",
163  args.front().c_str(),
164  p.first.c_str(),
165  p.first.c_str());
166  }
167  auto& info = p.second;
168 
169  printf(
170  "Usage: %s [global_options...] %s%s%s%s\n\n",
171  programName_.c_str(),
172  p.first.c_str(),
173  info.options.options().empty() ? "" : " [command_options...]",
174  info.argStr.empty() ? "" : " ",
175  info.argStr.c_str());
176 
177  printf("%s\n", info.fullHelp.c_str());
178 
179  std::cout << globalOptions_;
180 
181  if (!info.options.options().empty()) {
182  printf("\n");
183  std::cout << info.options;
184  }
185  }
186 }
def info()
Definition: deadlock.py:447
LogLevel max
Definition: LogLevel.cpp:31
std::map< std::string, std::string > aliases_
const std::pair< const std::string, CommandInfo > & findCommand(const std::string &name) const
boost::program_options::options_description globalOptions_
std::map< std::string, CommandInfo > commands_
const std::string & resolveAlias(const std::string &name) const
void folly::NestedCommandLineApp::displayVersion ( ) const
private

Definition at line 188 of file NestedCommandLineApp.cpp.

References programName_, and version_.

Referenced by doRun(), and NestedCommandLineApp().

188  {
189  printf("%s %s\n", programName_.c_str(), version_.c_str());
190 }
void folly::NestedCommandLineApp::doRun ( const std::vector< std::string > &  args)
private

Definition at line 266 of file NestedCommandLineApp.cpp.

References cmd, displayHelp(), displayVersion(), findCommand(), globalOptions_, deadlock::info(), initFunction_, kHelpCommand, kVersionCommand, folly::parseNestedCommandLine(), programName_, folly::sformat(), and folly::Range< Iter >::str().

Referenced by run().

266  {
267  if (programName_.empty()) {
268  programName_ = guessProgramName();
269  }
270 
271  bool not_clean = false;
272  std::vector<std::string> cleanArgs;
273  std::vector<std::string> endArgs;
274 
275  for (auto& na : args) {
276  if (na == "--") {
277  not_clean = true;
278  } else if (not_clean) {
279  endArgs.push_back(na);
280  } else {
281  cleanArgs.push_back(na);
282  }
283  }
284 
285  auto parsed = parseNestedCommandLine(cleanArgs, globalOptions_);
286  po::variables_map vm;
287  po::store(parsed.options, vm);
288  if (vm.count(kHelpCommand.str())) {
289  std::vector<std::string> helpArgs;
290  if (parsed.command) {
291  helpArgs.push_back(*parsed.command);
292  }
293  displayHelp(vm, helpArgs);
294  return;
295  }
296 
297  if (vm.count(kVersionCommand.str())) {
298  displayVersion();
299  return;
300  }
301 
302  if (!parsed.command) {
303  throw ProgramExit(
304  1,
306  "Command not specified. Run '{} {}' for help.",
307  programName_,
308  kHelpCommand));
309  }
310 
311  auto& p = findCommand(*parsed.command);
312  auto& cmd = p.first;
313  auto& info = p.second;
314 
315  auto cmdOptions =
316  po::command_line_parser(parsed.rest).options(info.options).run();
317 
318  po::store(cmdOptions, vm);
319  po::notify(vm);
320 
321  auto cmdArgs =
322  po::collect_unrecognized(cmdOptions.options, po::include_positional);
323 
324  cmdArgs.insert(cmdArgs.end(), endArgs.begin(), endArgs.end());
325 
326  if (initFunction_) {
327  initFunction_(cmd, vm, cmdArgs);
328  }
329 
330  info.command(vm, cmdArgs);
331 }
def info()
Definition: deadlock.py:447
std::string str() const
Definition: Range.h:591
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
void displayHelp(const boost::program_options::variables_map &options, const std::vector< std::string > &args) const
NestedCommandLineParseResult parseNestedCommandLine(int argc, const char *const argv[], const po::options_description &desc)
const std::pair< const std::string, CommandInfo > & findCommand(const std::string &name) const
boost::program_options::options_description globalOptions_
static constexpr StringPiece const kVersionCommand
cmd
Definition: gtest-cfgcmd.txt:1
static constexpr StringPiece const kHelpCommand
auto folly::NestedCommandLineApp::findCommand ( const std::string name) const
private

Definition at line 205 of file NestedCommandLineApp.cpp.

References commands_, kHelpCommand, name, programName_, resolveAlias(), and folly::sformat().

Referenced by displayHelp(), and doRun().

206  {
207  auto pos = commands_.find(resolveAlias(name));
208  if (pos == commands_.end()) {
209  throw ProgramExit(
210  1,
212  "Command '{}' not found. Run '{} {}' for help.",
213  name,
214  programName_,
215  kHelpCommand));
216  }
217  return *pos;
218 }
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
const char * name
Definition: http_parser.c:437
std::map< std::string, CommandInfo > commands_
const std::string & resolveAlias(const std::string &name) const
static constexpr StringPiece const kHelpCommand
boost::program_options::options_description& folly::NestedCommandLineApp::globalOptions ( )
inline

Return the global options object, so you can add options.

Definition at line 93 of file NestedCommandLineApp.h.

References argv, name, folly::run(), and string.

93  {
94  return globalOptions_;
95  }
boost::program_options::options_description globalOptions_
bool folly::NestedCommandLineApp::isBuiltinCommand ( const std::string name) const

Return true if name represent known built-in command (help, version)

Definition at line 333 of file NestedCommandLineApp.cpp.

References builtinCommands_.

Referenced by folly::test::TEST().

333  {
334  return builtinCommands_.count(name);
335 }
const char * name
Definition: http_parser.c:437
std::set< folly::StringPiece > builtinCommands_
const std::string & folly::NestedCommandLineApp::resolveAlias ( const std::string name) const
private

Definition at line 192 of file NestedCommandLineApp.cpp.

References aliases_, upload::dest, and name.

Referenced by displayHelp(), and findCommand().

193  {
194  auto dest = &name;
195  for (;;) {
196  auto pos = aliases_.find(*dest);
197  if (pos == aliases_.end()) {
198  break;
199  }
200  dest = &pos->second;
201  }
202  return *dest;
203 }
std::map< std::string, std::string > aliases_
dest
Definition: upload.py:394
const char * name
Definition: http_parser.c:437
int folly::NestedCommandLineApp::run ( int  argc,
const char *const  argv[] 
)

Run the command and return; the return code is 0 on success or non-zero on error, so it is idiomatic to call this at the end of main(): return app.run(argc, argv);

On successful exit, run() will check for errors on stdout (and flush it) to help command-line applications that need to write to stdout (failing to write to stdout is an error). If there is an error on stdout, we'll print a helpful message on stderr and return an error status (1).

Definition at line 220 of file NestedCommandLineApp.cpp.

References programName_.

Referenced by main().

220  {
221  if (programName_.empty()) {
222  programName_ = fs::path(argv[0]).filename().string();
223  }
224  return run(std::vector<std::string>(argv + 1, argv + argc));
225 }
char ** argv
int run(int argc, const char *const argv[])
int folly::NestedCommandLineApp::run ( const std::vector< std::string > &  args)

Definition at line 227 of file NestedCommandLineApp.cpp.

References doRun(), folly::errnoStr(), folly::pushmi::operators::error(), kHelpCommand, programName_, folly::sformat(), and folly::ProgramExit::status().

227  {
228  int status;
229  try {
230  doRun(args);
231  status = 0;
232  } catch (const ProgramExit& ex) {
233  if (ex.what()[0]) { // if not empty
234  fprintf(stderr, "%s\n", ex.what());
235  }
236  status = ex.status();
237  } catch (const po::error& ex) {
238  fprintf(
239  stderr,
240  "%s",
242  "{}. Run '{} help' for {}.\n",
243  ex.what(),
244  programName_,
245  kHelpCommand)
246  .c_str());
247  status = 1;
248  }
249 
250  if (status == 0) {
251  if (ferror(stdout)) {
252  fprintf(stderr, "error on standard output\n");
253  status = 1;
254  } else if (fflush(stdout)) {
255  fprintf(
256  stderr,
257  "standard output flush failed: %s\n",
258  errnoStr(errno).c_str());
259  status = 1;
260  }
261  }
262 
263  return status;
264 }
std::string sformat(StringPiece fmt, Args &&...args)
Definition: Format.h:280
requires And< SemiMovable< VN >... > &&SemiMovable< E > auto error(E e)
Definition: error.h:48
void doRun(const std::vector< std::string > &args)
fbstring errnoStr(int err)
Definition: String.cpp:463
static constexpr StringPiece const kHelpCommand

Member Data Documentation

std::map<std::string, std::string> folly::NestedCommandLineApp::aliases_
private

Definition at line 169 of file NestedCommandLineApp.h.

Referenced by addAlias(), displayHelp(), and resolveAlias().

std::set<folly::StringPiece> folly::NestedCommandLineApp::builtinCommands_
private

Definition at line 170 of file NestedCommandLineApp.h.

Referenced by isBuiltinCommand(), and NestedCommandLineApp().

std::map<std::string, CommandInfo> folly::NestedCommandLineApp::commands_
private

Definition at line 168 of file NestedCommandLineApp.h.

Referenced by addAlias(), addCommand(), displayHelp(), and findCommand().

boost::program_options::options_description folly::NestedCommandLineApp::globalOptions_
private

Definition at line 167 of file NestedCommandLineApp.h.

Referenced by displayHelp(), doRun(), and NestedCommandLineApp().

InitFunction folly::NestedCommandLineApp::initFunction_
private

Definition at line 166 of file NestedCommandLineApp.h.

Referenced by doRun().

constexpr StringPiece const folly::NestedCommandLineApp::kHelpCommand = "help"
static
constexpr StringPiece const folly::NestedCommandLineApp::kVersionCommand = "version"
static
std::string folly::NestedCommandLineApp::programHeading_
private

Definition at line 163 of file NestedCommandLineApp.h.

Referenced by displayHelp().

std::string folly::NestedCommandLineApp::programHelpFooter_
private

Definition at line 164 of file NestedCommandLineApp.h.

Referenced by displayHelp().

std::string folly::NestedCommandLineApp::programName_
private

Definition at line 162 of file NestedCommandLineApp.h.

Referenced by displayHelp(), displayVersion(), doRun(), findCommand(), and run().

std::string folly::NestedCommandLineApp::version_
private

Definition at line 165 of file NestedCommandLineApp.h.

Referenced by displayVersion().


The documentation for this class was generated from the following files: