Skip to content
Snippets Groups Projects
Commit 19e76288 authored by Michael Davis's avatar Michael Davis
Browse files

[cta_admin] Provides help for all CTA Admin commands and options

parent fd69c3d4
Branches
Tags
No related merge requests found
......@@ -48,6 +48,12 @@ CtaAdminCmd::CtaAdminCmd(int argc, const char *const *const argv) :
admincmd.set_cmd(cmd_it->second);
}
// Help is a special subcommand which suppresses errors and prints usage
if(argc > 2 && std::string(argv[2]) == "help") {
throwUsage();
}
// Parse the subcommand
bool has_subcommand = cmdHelp.at(admincmd.cmd()).has_subcommand();
......@@ -56,8 +62,10 @@ CtaAdminCmd::CtaAdminCmd(int argc, const char *const *const argv) :
{
subcmdLookup_t::const_iterator subcmd_it;
if(argc < 3 || (subcmd_it = subcmdLookup.find(argv[2])) == subcmdLookup.end()) {
throwUsage();
if(argc < 3) {
throwUsage("Missing subcommand");
} else if((subcmd_it = subcmdLookup.find(argv[2])) == subcmdLookup.end()) {
throwUsage(std::string("Invalid subcommand: ") + argv[2]);
} else {
admincmd.set_subcmd(subcmd_it->second);
}
......@@ -68,7 +76,7 @@ CtaAdminCmd::CtaAdminCmd(int argc, const char *const *const argv) :
auto option_list_it = cmdOptions.find(cmd_key_t{ admincmd.cmd(), admincmd.subcmd() });
if(option_list_it == cmdOptions.end()) {
throwUsage();
throwUsage(std::string("Invalid subcommand: ") + argv[2]);
}
parseOptions(has_subcommand ? 3 : 2, argc, argv, option_list_it->second);
......@@ -178,9 +186,10 @@ void CtaAdminCmd::throwUsage(const std::string &error_txt) const
{
// Command has not been set: show generic help
help << "CTA Admin commands:" << std::endl << std::endl
<< "For each command there is a short version and a long one. "
<< "Subcommands (add/ch/ls/rm/etc.) do not have short versions." << std::endl << std::endl;
help << "CTA Admin commands:" << std::endl << std::endl
<< "For each command there is a short version and a long one. Subcommands (add/ch/ls/rm/etc.)" << std::endl
<< "do not have short versions. For detailed help on the options of each subcommand, type:" << std::endl
<< " " << m_execname << " <command> help" << std::endl << std::endl;
for(auto cmd_it = cmdHelp.begin(); cmd_it != cmdHelp.end(); ++cmd_it)
{
......
......@@ -68,24 +68,28 @@ std::string CmdHelp::short_help() const
std::string CmdHelp::help() const
{
const int INDENT = 4;
const int WRAP_MARGIN = 80;
// As we lazy evaluate the full help text, normally the help text will not be set when we call this method
if(m_help_full != "") return m_help_full;
std::string help = m_cmd_short + '/' + m_cmd_long;
std::string cmd_line = m_cmd_short + '/' + m_cmd_long;
for(auto sc_it = m_sub_cmd.begin(); sc_it != m_sub_cmd.end(); ++sc_it) {
help += (sc_it == m_sub_cmd.begin() ? ' ' : '/') + *sc_it;
cmd_line += (sc_it == m_sub_cmd.begin() ? ' ' : '/') + *sc_it;
}
// Print main command options if there are any
auto key = cmd_key_t{ cmdLookup.at(m_cmd_short), AdminCmd::SUBCMD_NONE };
add_options(cmd_line, key, INDENT);
// Find the length of the longest subcommand (if there is one)
auto max_sub_cmd = std::max_element(m_sub_cmd.begin(), m_sub_cmd.end(),
[](std::string const& lhs, std::string const& rhs) { return lhs.size() < rhs.size(); });
// Terminate with a colon if there are subcommands to follow
help += (max_sub_cmd != m_sub_cmd.end()) ? ":\n" : "\n";
m_help_full += (max_sub_cmd != m_sub_cmd.end()) ? ":\n" : "\n";
// Optional additional help
help += m_help_txt;
// Add optional additional help
m_help_full += m_help_extra;
// Per-subcommand help
for(auto sc_it = m_sub_cmd.begin(); sc_it != m_sub_cmd.end(); ++sc_it) {
......@@ -94,22 +98,32 @@ std::string CmdHelp::help() const
cmd_line.resize(INDENT + max_sub_cmd->size(), ' ');
auto key = cmd_key_t{ cmdLookup.at(m_cmd_short), subcmdLookup.at(*sc_it) };
auto options = cmdOptions.at(key);
add_options(cmd_line, key, INDENT + max_sub_cmd->size());
m_help_full += '\n';
}
return m_help_full;
}
for(auto op_it = options.begin(); op_it != options.end(); ++op_it)
{
if(cmd_line.size() + op_it->help().size() > WRAP_MARGIN)
{
help += cmd_line + '\n';
cmd_line = std::string(INDENT + max_sub_cmd->size(), ' ');
}
cmd_line += op_it->help();
void CmdHelp::add_options(std::string &cmd_line, cmd_key_t &key, unsigned int indent) const
{
auto options = cmdOptions.find(key);
if(options == cmdOptions.end()) return;
for(auto op_it = options->second.begin(); op_it != options->second.end(); ++op_it)
{
if(cmd_line.size() + op_it->help().size() > WRAP_MARGIN)
{
m_help_full += cmd_line + '\n';
cmd_line = std::string(indent, ' ');
}
help += cmd_line + '\n';
}
return help;
cmd_line += op_it->help();
}
m_help_full += cmd_line;
}
......
......@@ -114,6 +114,16 @@ private:
/*
* Type aliases
*/
using cmdLookup_t = std::map<std::string, AdminCmd::Cmd>;
using subcmdLookup_t = std::map<std::string, AdminCmd::SubCmd>;
using cmd_key_t = std::pair<AdminCmd::Cmd, AdminCmd::SubCmd>;
using cmd_val_t = std::vector<Option>;
/*!
* Command/subcommand help class
*/
......@@ -128,7 +138,7 @@ public:
m_cmd_long(cmd_long),
m_cmd_short(cmd_short),
m_sub_cmd(sub_cmd),
m_help_txt(help_txt) {}
m_help_extra(help_txt) {}
/*!
* Can we parse subcommands for this command?
......@@ -146,25 +156,25 @@ public:
std::string help() const;
private:
/*!
* Called by help() to add command line options to the full help text
*/
void add_options(std::string &cmd_line, cmd_key_t &key, unsigned int indent) const;
const unsigned int INDENT = 4; //!< Number of spaces to indent when listing subcommands
const unsigned int WRAP_MARGIN = 80; //!< Number of characters per line before word wrapping
std::string m_cmd_long; //!< Command string (long version)
std::string m_cmd_short; //!< Command string (short version)
std::vector<std::string> m_sub_cmd; //!< Subcommands which are valid for this command, in the
//!< same order that they should be displayed in the help
std::string m_help_txt; //!< Optional extra help text above the options
std::string m_help_extra; //!< Optional extra help text above the options
mutable std::string m_help_full; //!< The full text of the detailed help for this command.
//!< Mutable because it is lazy evaluated when we call help()
};
/*
* Type aliases
*/
using cmdLookup_t = std::map<std::string, AdminCmd::Cmd>;
using subcmdLookup_t = std::map<std::string, AdminCmd::SubCmd>;
using cmd_key_t = std::pair<AdminCmd::Cmd, AdminCmd::SubCmd>;
using cmd_val_t = std::vector<Option>;
/*!
* Map short and long command names to Protocol Buffer enum values
*/
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment