Commit acd1c17a authored by Denis Samoylov's avatar Denis Samoylov Committed by Facebook Github Bot

brush up built-in commands in NestedCommandLineApp

Summary:
Tudor who wrote this left the company... so RB.. you are the reviewers :)

1. make default commands as constants
2. remove fake message about ",h"
3. align quota usage from mix to '
4. add support for version command
5. add function to identify built-in command (is needed for an external application to make a decision if something is mandatory or not)

Reviewed By: marcinpe

Differential Revision: D7048169

fbshipit-source-id: b48cf7df28cfa387e028a1cc869332407314c906
parent 6d3f73dd
......@@ -46,6 +46,9 @@ ProgramExit::ProgramExit(int status, const std::string& msg)
CHECK(status_ != 0 || msg.empty());
}
constexpr StringPiece const NestedCommandLineApp::kHelpCommand;
constexpr StringPiece const NestedCommandLineApp::kVersionCommand;
NestedCommandLineApp::NestedCommandLineApp(
std::string programName,
std::string version,
......@@ -58,17 +61,31 @@ NestedCommandLineApp::NestedCommandLineApp(
version_(std::move(version)),
initFunction_(std::move(initFunction)),
globalOptions_("Global options") {
addCommand("help", "[command]",
"Display help (globally or for a given command)",
"Displays help (globally or for a given command).",
[this] (const po::variables_map& vm,
const std::vector<std::string>& args) {
displayHelp(vm, args);
});
globalOptions_.add_options()
("help,h", "Display help (globally or for a given command)")
("version", "Display version information");
addCommand(
kHelpCommand.str(),
"[command]",
"Display help (globally or for a given command)",
"Displays help (globally or for a given command).",
[this](
const po::variables_map& vm, const std::vector<std::string>& args) {
displayHelp(vm, args);
});
builtinCommands_.insert(kHelpCommand);
addCommand(
kVersionCommand.str(),
"[command]",
"Display version information",
"Displays version information.",
[this](const po::variables_map&, const std::vector<std::string>&) {
displayVersion();
});
builtinCommands_.insert(kVersionCommand);
globalOptions_.add_options()(
kHelpCommand.str().c_str(),
"Display help (globally or for a given command)")(
kVersionCommand.str().c_str(), "Display version information");
}
po::options_description& NestedCommandLineApp::addCommand(
......@@ -102,7 +119,7 @@ void NestedCommandLineApp::addAlias(std::string newName,
void NestedCommandLineApp::displayHelp(
const po::variables_map& /* globalOptions */,
const std::vector<std::string>& args) {
const std::vector<std::string>& args) const {
if (args.empty()) {
// General help
printf(
......@@ -162,6 +179,10 @@ void NestedCommandLineApp::displayHelp(
}
}
void NestedCommandLineApp::displayVersion() const {
printf("%s %s\n", programName_.c_str(), version_.c_str());
}
const std::string& NestedCommandLineApp::resolveAlias(
const std::string& name) const {
auto dest = &name;
......@@ -181,8 +202,11 @@ auto NestedCommandLineApp::findCommand(const std::string& name) const
if (pos == commands_.end()) {
throw ProgramExit(
1,
folly::sformat("Command `{}' not found. Run `{} help' for help.",
name, programName_));
folly::sformat(
"Command '{}' not found. Run '{} {}' for help.",
name,
programName_,
kHelpCommand));
}
return *pos;
}
......@@ -205,8 +229,15 @@ int NestedCommandLineApp::run(const std::vector<std::string>& args) {
}
status = ex.status();
} catch (const po::error& ex) {
fprintf(stderr, "%s. Run `%s help' for help.\n",
ex.what(), programName_.c_str());
fprintf(
stderr,
"%s",
folly::sformat(
"{}. Run '{} help' for {}.\n",
ex.what(),
programName_,
kHelpCommand)
.c_str());
status = 1;
}
......@@ -246,7 +277,7 @@ void NestedCommandLineApp::doRun(const std::vector<std::string>& args) {
auto parsed = parseNestedCommandLine(cleanArgs, globalOptions_);
po::variables_map vm;
po::store(parsed.options, vm);
if (vm.count("help")) {
if (vm.count(kHelpCommand.str())) {
std::vector<std::string> helpArgs;
if (parsed.command) {
helpArgs.push_back(*parsed.command);
......@@ -255,16 +286,18 @@ void NestedCommandLineApp::doRun(const std::vector<std::string>& args) {
return;
}
if (vm.count("version")) {
printf("%s %s\n", programName_.c_str(), version_.c_str());
if (vm.count(kVersionCommand.str())) {
displayVersion();
return;
}
if (!parsed.command) {
throw ProgramExit(
1,
folly::sformat("Command not specified. Run `{} help' for help.",
programName_));
folly::sformat(
"Command not specified. Run '{} {}' for help.",
programName_,
kHelpCommand));
}
auto& p = findCommand(*parsed.command);
......@@ -289,4 +322,8 @@ void NestedCommandLineApp::doRun(const std::vector<std::string>& args) {
info.command(vm, cmdArgs);
}
bool NestedCommandLineApp::isBuiltinCommand(const std::string& name) const {
return builtinCommands_.count(name);
}
} // namespace folly
......@@ -16,9 +16,11 @@
#pragma once
#include <functional>
#include <set>
#include <stdexcept>
#include <folly/CPortability.h>
#include <folly/String.h>
#include <folly/experimental/ProgramOptions.h>
namespace folly {
......@@ -54,6 +56,8 @@ class NestedCommandLineApp {
const boost::program_options::variables_map& options,
const std::vector<std::string>&)> Command;
static constexpr StringPiece const kHelpCommand = "help";
static constexpr StringPiece const kVersionCommand = "version";
/**
* Initialize the app.
*
......@@ -124,6 +128,11 @@ class NestedCommandLineApp {
int run(int argc, const char* const argv[]);
int run(const std::vector<std::string>& args);
/**
* Return true if name represent known built-in command (help, version)
*/
bool isBuiltinCommand(const std::string& name) const;
private:
void doRun(const std::vector<std::string>& args);
const std::string& resolveAlias(const std::string& name) const;
......@@ -141,7 +150,9 @@ class NestedCommandLineApp {
void displayHelp(
const boost::program_options::variables_map& options,
const std::vector<std::string>& args);
const std::vector<std::string>& args) const;
void displayVersion() const;
std::string programName_;
std::string programHeading_;
......@@ -151,6 +162,7 @@ class NestedCommandLineApp {
boost::program_options::options_description globalOptions_;
std::map<std::string, CommandInfo> commands_;
std::map<std::string, std::string> aliases_;
std::set<folly::StringPiece> builtinCommands_;
};
} // namespace folly
......@@ -145,5 +145,14 @@ TEST(ProgramOptionsTest, Aliases) {
"a", "b"}));
}
TEST(ProgramOptionsTest, BuiltinCommand) {
NestedCommandLineApp app;
ASSERT_TRUE(app.isBuiltinCommand(NestedCommandLineApp::kHelpCommand.str()));
ASSERT_TRUE(
app.isBuiltinCommand(NestedCommandLineApp::kVersionCommand.str()));
ASSERT_FALSE(app.isBuiltinCommand(
NestedCommandLineApp::kHelpCommand.str() + "nonsense"));
}
} // namespace test
} // namespace folly
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment