# # # patch "ChangeLog" # from [34e985d5726e7c0f57e125ac0919b3d940a6a193] # to [3393112ee3fedf9075dd7ecae14bf5f568305f4f] # # patch "automate.cc" # from [a416a0118ff66f167504e583eda3d2f19a2a24c9] # to [fb0db1dbda16a3056b64570590a919d9dcab9292] # # patch "cmd.hh" # from [b9f35eeccf525a4bc9dc9253a00989998e8bcb91] # to [5ce59450ff6e7246230f00e93772e50ae5f378a5] # # patch "cmd_automate.cc" # from [eca8e2b625e400ec961c9a2c9772097dbff8351c] # to [85043eb56ef6c10b90031981107c90c1c54b8927] # # patch "cmd_list.cc" # from [9f507eccb08b8547c27b4056bedeb47036e5a61f] # to [cfc890edde48be2b2e6921caa121401c45c5147e] # # patch "commands.cc" # from [6dd8601f071755ec0a1c1cabbb7e407c00bcd676] # to [9857319000bdce8f656dbbd72a282be01459fca6] # ============================================================ --- ChangeLog 34e985d5726e7c0f57e125ac0919b3d940a6a193 +++ ChangeLog 3393112ee3fedf9075dd7ecae14bf5f568305f4f @@ -1,5 +1,14 @@ 2006-06-17 Timothy Brownawell + * cmd.hh, commands.cc: Modify how command parameters description + strings are handled. + * cmd_automate.cc, cmd.hh: Use this to make the parameters for + each automate subcommand be a parameter of the ATUOMATE() macro, + instead of all being a big block in the automate command. + * automate.cc, cmd_list.cc, cmd_automate.cc: Update AUTOMATE() usage. + +2006-06-17 Timothy Brownawell + (see bug #15995, asking for a more comprehensive automate command set) Start splitting up automate.cc . There is now an AUTOMATE() macro in cmd.hh , similar to the CMD() macro. Individual automate commands can ============================================================ --- automate.cc a416a0118ff66f167504e583eda3d2f19a2a24c9 +++ automate.cc fb0db1dbda16a3056b64570590a919d9dcab9292 @@ -60,7 +60,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If the branch does not exist, prints nothing. (There are // no heads.) -AUTOMATE(heads) +AUTOMATE(heads, N_("[BRANCH]")) { if (args.size() > 1) throw usage(help_name); @@ -84,7 +84,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If any of the revisions do not exist, prints nothing to // stdout, prints an error message to stderr, and exits with status 1. -AUTOMATE(ancestors) +AUTOMATE(ancestors, N_("REV1 [REV2 [REV3 [...]]]")) { if (args.size() == 0) throw usage(help_name); @@ -131,7 +131,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If any of the revisions do not exist, prints nothing to // stdout, prints an error message to stderr, and exits with status 1. -AUTOMATE(descendents) +AUTOMATE(descendents, N_("REV1 [REV2 [REV3 [...]]]")) { if (args.size() == 0) throw usage(help_name); @@ -179,7 +179,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If any of the revisions do not exist, prints nothing to // stdout, prints an error message to stderr, and exits with status 1. -AUTOMATE(erase_ancestors) +AUTOMATE(erase_ancestors, N_("[REV1 [REV2 [REV3 [...]]]]")) { set revs; for (vector::const_iterator i = args.begin(); i != args.end(); ++i) @@ -202,7 +202,7 @@ // Output format: A list of file names in alphabetically sorted order, // or a list of attributes if a file name provided. // Error conditions: If the file name has no attributes, prints nothing. -AUTOMATE(attributes) +AUTOMATE(attributes, N_("[FILE]")) { if (args.size() > 1) throw usage(help_name); @@ -252,7 +252,7 @@ // newline. Revisions are printed in topologically sorted order. // Error conditions: If any of the revisions do not exist, prints nothing to // stdout, prints an error message to stderr, and exits with status 1. -AUTOMATE(toposort) +AUTOMATE(toposort, N_("[REV1 [REV2 [REV3 [...]]]]")) { set revs; for (vector::const_iterator i = args.begin(); i != args.end(); ++i) @@ -284,7 +284,7 @@ // newline. Revisions are printed in topologically sorted order. // Error conditions: If any of the revisions do not exist, prints nothing to // stdout, prints an error message to stderr, and exits with status 1. -AUTOMATE(ancestry_difference) +AUTOMATE(ancestry_difference, N_("NEW_REV [OLD_REV1 [OLD_REV2 [...]]]")) { if (args.size() == 0) throw usage(help_name); @@ -323,7 +323,7 @@ // Output format: A list of revision ids, in hexadecimal, each followed by a // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: None. -AUTOMATE(leaves) +AUTOMATE(leaves, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -351,7 +351,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If the revision does not exist, prints nothing to stdout, // prints an error message to stderr, and exits with status 1. -AUTOMATE(parents) +AUTOMATE(parents, N_("REV")) { if (args.size() != 1) throw usage(help_name); @@ -375,7 +375,7 @@ // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: If the revision does not exist, prints nothing to stdout, // prints an error message to stderr, and exits with status 1. -AUTOMATE(children) +AUTOMATE(children, N_("REV")) { if (args.size() != 1) throw usage(help_name); @@ -409,7 +409,7 @@ // The output as a whole is alphabetically sorted; additionally, the parents // within each line are alphabetically sorted. // Error conditions: None. -AUTOMATE(graph) +AUTOMATE(graph, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -452,7 +452,7 @@ // Output format: A list of revision ids, in hexadecimal, each followed by a // newline. Revision ids are printed in alphabetically sorted order. // Error conditions: None. -AUTOMATE(select) +AUTOMATE(select, N_("SELECTOR")) { if (args.size() != 1) throw usage(help_name); @@ -634,7 +634,7 @@ // Error conditions: If no workspace book keeping _MTN directory is found, // prints an error message to stderr, and exits with status 1. -AUTOMATE(inventory) +AUTOMATE(inventory, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -816,7 +816,7 @@ // the same type will be sorted by the filename they refer to. // Error conditions: If the revision specified is unknown or invalid // prints an error message to stderr and exits with status 1. -AUTOMATE(get_revision) +AUTOMATE(get_revision, N_("[REVID]")) { if (args.size() > 1) throw usage(help_name); @@ -860,7 +860,7 @@ // on. This is the value stored in _MTN/revision // Error conditions: If no workspace book keeping _MTN directory is found, // prints an error message to stderr, and exits with status 1. -AUTOMATE(get_base_revision_id) +AUTOMATE(get_base_revision_id, N_("")) { if (args.size() > 0) throw usage(help_name); @@ -881,7 +881,7 @@ // files in the workspace. // Error conditions: If no workspace book keeping _MTN directory is found, // prints an error message to stderr, and exits with status 1. -AUTOMATE(get_current_revision_id) +AUTOMATE(get_current_revision_id, N_("")) { if (args.size() > 0) throw usage(help_name); @@ -946,7 +946,7 @@ // // Error conditions: If the revision ID specified is unknown or // invalid prints an error message to stderr and exits with status 1. -AUTOMATE(get_manifest_of) +AUTOMATE(get_manifest_of, N_("[REVID]")) { if (args.size() > 1) throw usage(help_name); @@ -989,7 +989,7 @@ // // Error conditions: If the file id specified is unknown or invalid prints // an error message to stderr and exits with status 1. -AUTOMATE(get_file) +AUTOMATE(get_file, N_("FILEID")) { if (args.size() != 1) throw usage(help_name); @@ -1015,7 +1015,7 @@ // // Error conditions: If the revision id specified is unknown or // invalid prints an error message to stderr and exits with status 1. -AUTOMATE(packet_for_rdata) +AUTOMATE(packet_for_rdata, N_("REVID")) { if (args.size() != 1) throw usage(help_name); @@ -1041,7 +1041,7 @@ // // Error conditions: If the revision id specified is unknown or // invalid prints an error message to stderr and exits with status 1. -AUTOMATE(packets_for_certs) +AUTOMATE(packets_for_certs, N_("REVID")) { if (args.size() != 1) throw usage(help_name); @@ -1068,7 +1068,7 @@ // // Error conditions: If the file id specified is unknown or invalid // prints an error message to stderr and exits with status 1. -AUTOMATE(packet_for_fdata) +AUTOMATE(packet_for_fdata, N_("FILEID")) { if (args.size() != 1) throw usage(help_name); @@ -1095,7 +1095,7 @@ // // Error conditions: If any of the file ids specified are unknown or // invalid prints an error message to stderr and exits with status 1. -AUTOMATE(packet_for_fdelta) +AUTOMATE(packet_for_fdelta, N_("OLD_FILE NEW_FILE")) { if (args.size() != 2) throw usage(help_name); @@ -1129,7 +1129,7 @@ // Error conditions: If any of the revisions do not exist, prints // nothing to stdout, prints an error message to stderr, and exits // with status 1. -AUTOMATE(common_ancestors) +AUTOMATE(common_ancestors, N_("REV1 [REV2 [REV3 [...]]]")) { if (args.size() == 0) throw usage(help_name); ============================================================ --- cmd.hh b9f35eeccf525a4bc9dc9253a00989998e8bcb91 +++ cmd.hh 5ce59450ff6e7246230f00e93772e50ae5f378a5 @@ -18,6 +18,7 @@ namespace commands { + const char * safe_gettext(const char * msgid); struct no_opts {}; struct command_opts { @@ -39,8 +40,8 @@ // command objects have all been constructed. std::string name; std::string cmdgroup; - std::string params; - std::string desc; + std::string params_; + std::string desc_; bool use_workspace_options; command_opts options; command(std::string const & n, @@ -50,6 +51,8 @@ bool u, command_opts const & o); virtual ~command(); + virtual std::string params(); + virtual std::string desc(); virtual void exec(app_state & app, std::vector const & args) = 0; }; @@ -130,8 +133,27 @@ static cmd_ ## C C ## _cmd; \ } \ void commands::cmd_ ## C::exec(app_state & app, \ - std::vector const & args) \ + std::vector const & args) +// Use this for commands that want to define a params() function +// instead of having a static description. (Good for "automate" +// and possibly "list".) +#define CMD_PARAMS_FN(C, group, desc, opts) \ +namespace commands { \ + struct cmd_ ## C : public command \ + { \ + cmd_ ## C() : command(#C, group, "", desc, true, \ + command_opts() % opts) \ + {} \ + virtual void exec(app_state & app, \ + std::vector const & args); \ + std::string params(); \ + }; \ + static cmd_ ## C C ## _cmd; \ +} \ +void commands::cmd_ ## C::exec(app_state & app, \ + std::vector const & args) + // Use this for commands that should specifically _not_ look for an // _MTN dir and load options from it. @@ -151,8 +173,8 @@ std::vector const & args) \ #define ALIAS(C, realcommand) \ -CMD(C, realcommand##_cmd.cmdgroup, realcommand##_cmd.params, \ - realcommand##_cmd.desc + "\nAlias for " #realcommand, \ +CMD(C, realcommand##_cmd.cmdgroup, realcommand##_cmd.params_, \ + realcommand##_cmd.desc_ + "\nAlias for " #realcommand, \ realcommand##_cmd.options) \ { \ process(app, std::string(#realcommand), args); \ @@ -161,7 +183,9 @@ namespace automation { struct automate { - automate(std::string const & name); + std::string name; + std::string params; + automate(std::string const & n, std::string const & p); virtual void run(std::vector args, std::string const & help_name, app_state & app, @@ -170,11 +194,11 @@ }; } -#define AUTOMATE(NAME) \ +#define AUTOMATE(NAME, PARAMS) \ namespace automation { \ struct auto_ ## NAME : public automate \ { \ - auto_ ## NAME () : automate(#NAME) {} \ + auto_ ## NAME () : automate(#NAME, PARAMS) {} \ void run(std::vector args, std::string const & help_name, \ app_state & app, std::ostream & output) const; \ virtual ~auto_ ## NAME() {} \ ============================================================ --- cmd_automate.cc eca8e2b625e400ec961c9a2c9772097dbff8351c +++ cmd_automate.cc 85043eb56ef6c10b90031981107c90c1c54b8927 @@ -25,7 +25,8 @@ // guarantees about initialization order. So, use something we can // initialize ourselves. static map * automations; - automate::automate(string const &name) + automate::automate(string const &n, string const &p) + : name(n), params(p) { static bool first(true); if (first) @@ -63,7 +64,7 @@ // Output format: ".\n". Always matches // "[0-9]+\.[0-9]+\n". // Error conditions: None. -AUTOMATE(interface_version) +AUTOMATE(interface_version, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -204,7 +205,7 @@ return rv; } -AUTOMATE(stdio) +AUTOMATE(stdio, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -291,36 +292,9 @@ } -CMD(automate, N_("automation"), - N_("interface_version\n" - "heads [BRANCH]\n" - "ancestors REV1 [REV2 [REV3 [...]]]\n" - "attributes [FILE]\n" - "parents REV\n" - "descendents REV1 [REV2 [REV3 [...]]]\n" - "children REV\n" - "graph\n" - "erase_ancestors [REV1 [REV2 [REV3 [...]]]]\n" - "toposort [REV1 [REV2 [REV3 [...]]]]\n" - "ancestry_difference NEW_REV [OLD_REV1 [OLD_REV2 [...]]]\n" - "common_ancestors REV1 [REV2 [REV3 [...]]]\n" - "leaves\n" - "inventory\n" - "stdio\n" - "certs REV\n" - "select SELECTOR\n" - "get_file FILEID\n" - "get_manifest_of [REVID]\n" - "get_revision [REVID]\n" - "get_base_revision_id\n" - "get_current_revision_id\n" - "packet_for_rdata REVID\n" - "packets_for_certs REVID\n" - "packet_for_fdata FILEID\n" - "packet_for_fdelta OLD_FILE NEW_FILE\n" - "keys\n"), - N_("automation interface"), - OPT_NONE) +CMD_PARAMS_FN(automate, N_("automation"), + N_("automation interface"), + OPT_NONE) { if (args.size() == 0) throw usage(name); @@ -335,7 +309,22 @@ automate_command(cmd, cmd_args, name, app, std::cout); } +std::string commands::cmd_automate::params() +{ + std::string out; + map::const_iterator i; + for (i = automation::automations->begin(); + i != automation::automations->end(); ++i) + { + char const * const p = commands::safe_gettext(i->second->params.c_str()); + out += i->second->name + " " + p; + if (out[out.size()-1] != '\n') + out += "\n"; + } + return out; +} + // Local Variables: // mode: C++ // fill-column: 76 ============================================================ --- cmd_list.cc 9f507eccb08b8547c27b4056bedeb47036e5a61f +++ cmd_list.cc cfc890edde48be2b2e6921caa121401c45c5147e @@ -536,7 +536,7 @@ // private_location "keystore" // // Error conditions: None. -AUTOMATE(keys) +AUTOMATE(keys, N_("")) { if (args.size() != 0) throw usage(help_name); @@ -627,7 +627,7 @@ // key, a warning message is printed to stderr. If the revision // specified is unknown or invalid prints an error message to stderr // and exits with status 1. -AUTOMATE(certs) +AUTOMATE(certs, N_("REV")) { if (args.size() != 1) throw usage(help_name); ============================================================ --- commands.cc 6dd8601f071755ec0a1c1cabbb7e407c00bcd676 +++ commands.cc 9857319000bdce8f656dbbd72a282be01459fca6 @@ -37,6 +37,14 @@ namespace commands { + const char * safe_gettext(const char * msgid) + { + if (strlen(msgid) == 0) + return msgid; + + return _(msgid); + } + using std::map; // This must be a pointer. // It's used by the constructor of other static objects in different @@ -51,7 +59,7 @@ string const & d, bool u, command_opts const & o) - : name(n), cmdgroup(g), params(p), desc(d), use_workspace_options(u), + : name(n), cmdgroup(g), params_(p), desc_(d), use_workspace_options(u), options(o) { static bool first(true); @@ -61,6 +69,8 @@ (*cmds)[n] = this; } command::~command() {} + std::string command::params() {return safe_gettext(params_.c_str());} + std::string command::desc() {return safe_gettext(desc_.c_str());} bool operator<(command const & self, command const & other); }; @@ -130,14 +140,6 @@ return cmd; } - const char * safe_gettext(const char * msgid) - { - if (strlen(msgid) == 0) - return msgid; - - return _(msgid); - } - void explain_usage(string const & cmd, ostream & out) { map::const_iterator i; @@ -148,13 +150,13 @@ if (i != (*cmds).end()) { - string params = safe_gettext(i->second->params.c_str()); + string params = i->second->params(); vector lines; split_into_lines(params, lines); for (vector::const_iterator j = lines.begin(); j != lines.end(); ++j) out << " " << i->second->name << " " << *j << endl; - split_into_lines(safe_gettext(i->second->desc.c_str()), lines); + split_into_lines(i->second->desc(), lines); for (vector::const_iterator j = lines.begin(); j != lines.end(); ++j) out << " " << *j << endl;