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