# # # patch "cmd.hh" # from [613d087be522ebe28d2aebb1eee1538247e188f8] # to [359aed34af4f3472410fbce80f9637eb20efb551] # # patch "cmd_automate.cc" # from [53848e84a859576e826eee4855d0c758d5b4f939] # to [7d41b05ca58eba4d17eee85c91106cec99a61407] # # patch "cmd_db.cc" # from [f61dfeb6fd035dd3a468fd5fff35d42407b6575a] # to [ba66fcc874a0d6d53ec65f4ec2a1055e3ddc9f91] # # patch "commands.cc" # from [4cdd6c02ce00454a314bf17f2a35dd7c5e3b570b] # to [64ecb6b65dc7922f9cea68f0016f961dbf3dd267] # # patch "monotone.cc" # from [8c79550c27a5c737f2a5415a2586d7a696341d59] # to [36b847fc599875695adfd6a14288b8253f1aea02] # # patch "tests/schema_migration_error_recovery/__driver__.lua" # from [a4b51f336dff083ec53c2199d398f8edb90da941] # to [3e15d6854115ab39828211aea9171394cbc6ec5c] # ============================================================ --- cmd.hh 613d087be522ebe28d2aebb1eee1538247e188f8 +++ cmd.hh 359aed34af4f3472410fbce80f9637eb20efb551 @@ -44,7 +44,8 @@ namespace commands children_set m_children; std::map< command_id, command * > - find_completions(utf8 const & prefix, command_id const & completed); + find_completions(utf8 const & prefix, command_id const & completed) + const; command * find_child_by_name(utf8 const & name) const; public: @@ -60,7 +61,7 @@ namespace commands virtual ~command(void); - command_id ident(utf8 const & name = utf8()) const; + command_id ident(void) const; utf8 const & primary_name(void) const; names_set const & names(void) const; @@ -85,7 +86,7 @@ namespace commands command * find_command(command_id const & id); std::set< command_id > complete_command(command_id const & id, - command_id completed = command_id()); + command_id completed = command_id()) const; }; class automate : public command ============================================================ --- cmd_automate.cc 53848e84a859576e826eee4855d0c758d5b4f939 +++ cmd_automate.cc 7d41b05ca58eba4d17eee85c91106cec99a61407 @@ -362,8 +362,8 @@ CMD_AUTOMATE(stdio, "", N(matches.size() == 1, F("invalid automation specified")); id = *matches.begin(); - id.erase(id.begin()); // Remove 'automate' from the beginning. + I(args.size() >= id.size()); for (command_id::size_type i = 0; i < id.size(); i++) args.erase(args.begin()); ============================================================ --- cmd_db.cc f61dfeb6fd035dd3a468fd5fff35d42407b6575a +++ cmd_db.cc ba66fcc874a0d6d53ec65f4ec2a1055e3ddc9f91 @@ -24,6 +24,11 @@ using std::string; using std::set; using std::string; +CMD_GROUP(db, "", CMD_REF(database), + N_("Deals with the database"), + N_(""), + options::opts::none); + // Deletes a revision from the local database. This can be used to // 'undo' a changed revision from a local database without leaving // (much of) a trace. @@ -45,7 +50,7 @@ kill_rev_locally(app_state& app, string app.db.delete_existing_rev_and_certs(ident); } -CMD(init, "", CMD_REF(database), "", +CMD(init, "", CMD_REF(db), "", N_("Initializes a database"), N_("Creates a new database file and initializes it."), options::opts::none) @@ -56,7 +61,7 @@ CMD(init, "", CMD_REF(database), "", app.db.initialize(); } -CMD(info, "", CMD_REF(database), "", +CMD(info, "", CMD_REF(db), "", N_("Shows information about the database"), N_(""), options::opts::none) @@ -67,7 +72,7 @@ CMD(info, "", CMD_REF(database), "", app.db.info(cout); } -CMD(version, "", CMD_REF(database), "", +CMD(version, "", CMD_REF(db), "", N_("Shows the database's version"), N_(""), options::opts::none) @@ -78,7 +83,7 @@ CMD(version, "", CMD_REF(database), "", app.db.version(cout); } -CMD(dump, "", CMD_REF(database), "", +CMD(dump, "", CMD_REF(db), "", N_("Dumps the contents of the database"), N_("Generates a list of SQL instructions that represent the whole " "contents of the database. The resulting output is useful to later " @@ -91,7 +96,7 @@ CMD(dump, "", CMD_REF(database), "", app.db.dump(cout); } -CMD(load, "", CMD_REF(database), "", +CMD(load, "", CMD_REF(db), "", N_("Loads the contents of the database"), N_("Reads a list of SQL instructions that regenerate the contents of " "the database. This is supposed to be used in conjunction with the " @@ -104,7 +109,7 @@ CMD(load, "", CMD_REF(database), "", app.db.load(cin); } -CMD(migrate, "", CMD_REF(database), "", +CMD(migrate, "", CMD_REF(db), "", N_("Migrates the database to a newer schema"), N_("Updates the database's internal schema to the most recent one. " "Needed to automatically resolve incompatibilities that may be " @@ -117,7 +122,7 @@ CMD(migrate, "", CMD_REF(database), "", app.db.migrate(); } -CMD(execute, "", CMD_REF(database), "", +CMD(execute, "", CMD_REF(db), "", N_("Executes an SQL command on the database"), N_("Directly executes the given SQL command on the database"), options::opts::none) @@ -128,7 +133,7 @@ CMD(execute, "", CMD_REF(database), "", app.db.debug(idx(args, 0)(), cout); } -CMD(kill_rev_locally, "", CMD_REF(database), "ID", +CMD(kill_rev_locally, "", CMD_REF(db), "ID", N_("Kills a revision from the local database"), N_(""), options::opts::none) @@ -139,7 +144,7 @@ CMD(kill_rev_locally, "", CMD_REF(databa kill_rev_locally(app,idx(args, 0)()); } -CMD(kill_branch_certs_locally, "", CMD_REF(database), "BRANCH", +CMD(kill_branch_certs_locally, "", CMD_REF(db), "BRANCH", N_("Kills branch certificates from the local database"), N_(""), options::opts::none) @@ -150,7 +155,7 @@ CMD(kill_branch_certs_locally, "", CMD_R app.db.delete_branch_named(cert_value(idx(args, 0)())); } -CMD(kill_tag_locally, "", CMD_REF(database), "TAG", +CMD(kill_tag_locally, "", CMD_REF(db), "TAG", N_("Kills a tag from the local database"), N_(""), options::opts::none) @@ -161,7 +166,7 @@ CMD(kill_tag_locally, "", CMD_REF(databa app.db.delete_tag_named(cert_value(idx(args, 0)())); } -CMD(check, "", CMD_REF(database), "", +CMD(check, "", CMD_REF(db), "", N_("Does some sanity checks on the database"), N_("Ensures that the database is consistent by issuing multiple " "checks."), @@ -173,7 +178,7 @@ CMD(check, "", CMD_REF(database), "", check_db(app); } -CMD(changesetify, "", CMD_REF(database), "", +CMD(changesetify, "", CMD_REF(db), "", N_("Converts the database to the changeset format"), N_(""), options::opts::none) @@ -184,7 +189,7 @@ CMD(changesetify, "", CMD_REF(database), build_changesets_from_manifest_ancestry(app); } -CMD(rosterify, "", CMD_REF(database), "", +CMD(rosterify, "", CMD_REF(db), "", N_("Converst the database to the rosters format"), N_(""), options::opts::drop_attr) @@ -195,7 +200,7 @@ CMD(rosterify, "", CMD_REF(database), "" build_roster_style_revs_from_manifest_style_revs(app); } -CMD(regenerate_caches, "", CMD_REF(database), "", +CMD(regenerate_caches, "", CMD_REF(db), "", N_("Regenerates the caches stored in the database"), N_(""), options::opts::none) @@ -206,7 +211,7 @@ CMD(regenerate_caches, "", CMD_REF(datab regenerate_caches(app); } -CMD_HIDDEN(clear_epoch, "", CMD_REF(database), "BRANCH", +CMD_HIDDEN(clear_epoch, "", CMD_REF(db), "BRANCH", N_("Clears the database's epoch"), N_(""), options::opts::none) @@ -217,7 +222,7 @@ CMD_HIDDEN(clear_epoch, "", CMD_REF(data app.db.clear_epoch(branch_name(idx(args, 0)())); } -CMD(set_epoch, "", CMD_REF(database), "BRANCH EPOCH", +CMD(set_epoch, "", CMD_REF(db), "BRANCH EPOCH", N_("Sets the database's epoch"), N_(""), options::opts::none) @@ -318,7 +323,7 @@ CMD(complete, "", CMD_REF(informative), throw usage(execid); } -CMD_HIDDEN(test_migration_step, "", CMD_REF(database), "SCHEMA", +CMD_HIDDEN(test_migration_step, "", CMD_REF(db), "SCHEMA", N_("Runs one step of migration on the specified database"), N_("This command migrates the given database from the specified " "schema in SCHEMA to its successor."), ============================================================ --- commands.cc 4cdd6c02ce00454a314bf17f2a35dd7c5e3b570b +++ commands.cc 64ecb6b65dc7922f9cea68f0016f961dbf3dd267 @@ -45,11 +45,19 @@ CMD_GROUP(__root__, "", NULL, N_(""), N_ // Definition of top-level commands, used to classify the real commands // in logical groups. // +// These top level commands, while part of the final identifiers and defined +// as regular command groups, are handled separately. The user should not +// see them except through the help command. +// +// XXX This is to easily maintain compatibilty with older versions. But +// maybe this should be revised, because exposing the top level category +// (being optional, of course), may not be a bad idea. +// CMD_GROUP(automation, "", CMD_REF(__root__), N_("Commands that aid in scripted execution"), N_(""), options::opts::none); -CMD_GROUP(database, "db", CMD_REF(__root__), +CMD_GROUP(database, "", CMD_REF(__root__), N_("Commands that manipulate the database"), N_(""), options::opts::none); @@ -181,20 +189,20 @@ namespace commands { m_names.insert(onv.begin(), onv.end()); } - command::~command() + command::~command(void) { } command_id - command::ident(utf8 const & name) const + command::ident(void) const { I(this != CMD_REF(__root__)); command_id i; if (parent() != CMD_REF(__root__)) - i = parent()->ident(utf8()); - i.push_back(name().empty() ? primary_name() : name); + i = parent()->ident(); + i.push_back(primary_name()); I(!i.empty()); return i; @@ -316,6 +324,7 @@ namespace commands { map< command_id, command * > command::find_completions(utf8 const & prefix, command_id const & completed) + const { map< command_id, command * > matches; @@ -348,14 +357,11 @@ namespace commands { set< command_id > command::complete_command(command_id const & id, - command_id completed) + command_id completed) const { I(this != CMD_REF(__root__) || !id.empty()); I(!id.empty()); - if (completed.empty() && this != CMD_REF(__root__)) - completed = ident(); - set< command_id > matches; utf8 component = *(id.begin()); @@ -426,29 +432,25 @@ namespace commands command_id complete_command(args_vector const & args) { + // Handle categories early; no completion allowed. + if (CMD_REF(__root__)->find_command(make_command_id(args[0]())) != NULL) + return make_command_id(args[0]()); + command_id id; for (args_vector::const_iterator iter = args.begin(); iter != args.end(); iter++) id.push_back(utf8((*iter)())); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches; - int offset = 0; - if (matches.empty()) + command::children_set const & cs = CMD_REF(__root__)->children(); + for (command::children_set::const_iterator iter = cs.begin(); + iter != cs.end(); iter++) { - command::children_set const & cs = CMD_REF(__root__)->children(); - for (command::children_set::const_iterator iter = cs.begin(); - iter != cs.end(); iter++) - { - // XXX Ugly hack to avoid completion collisions... - if (*iter == CMD_REF(automate)) - continue; + command const * child = *iter; - set< command_id > m2 = (*iter)->complete_command(id); - matches.insert(m2.begin(), m2.end()); - } - - offset = 1; + set< command_id > m2 = child->complete_command(id, child->ident()); + matches.insert(m2.begin(), m2.end()); } if (matches.size() >= 2) @@ -462,7 +464,7 @@ namespace commands iter != matches.end() && tmp.empty(); iter++) { command_id const & id = *iter; - if (id[id.size() - 1]() == args[id.size() - 1 - offset]()) + if (id[id.size() - 1]() == args[id.size() - 2]()) tmp = id; } @@ -614,17 +616,26 @@ namespace commands static void explain_cmd_usage(command_id const & ident, ostream & out) { - I(!ident.empty()); + I(ident.size() >= 1); vector< string > lines; command const * cmd = find_command(ident); - if (cmd->children().size() > 0) - out << F(safe_gettext("Subcommands of '%s %s':")) % - ui.prog_name % join_words(ident) << "\n\n"; + string visibleid = join_words(vector< utf8 >(ident.begin() + 1, + ident.end()))(); + + if (visibleid.empty()) + out << F(safe_gettext("Commands in group '%s':")) % + join_words(ident)() << "\n\n"; else - out << F(safe_gettext("Syntax specific to '%s %s':")) % - ui.prog_name % join_words(ident) << "\n\n"; + { + if (cmd->children().size() > 0) + out << F(safe_gettext("Subcommands of '%s %s':")) % + ui.prog_name % visibleid << "\n\n"; + else + out << F(safe_gettext("Syntax specific to '%s %s':")) % + ui.prog_name % visibleid << "\n\n"; + } // Print command parameters. string params = cmd->params(); @@ -633,7 +644,7 @@ namespace commands { for (vector::const_iterator j = lines.begin(); j != lines.end(); ++j) - out << " " << join_words(ident)() << ' ' << *j << '\n'; + out << " " << visibleid << ' ' << *j << '\n'; out << '\n'; } @@ -645,8 +656,12 @@ namespace commands } // Print command description. - out << F(safe_gettext("Description for '%s %s':")) % - ui.prog_name % join_words(ident) << "\n\n"; + if (visibleid.empty()) + out << F(safe_gettext("Purpose of group '%s':")) % + join_words(ident)() << "\n\n"; + else + out << F(safe_gettext("Description for '%s %s':")) % + ui.prog_name % visibleid << "\n\n"; split_into_lines(cmd->desc(), lines); for (vector::const_iterator j = lines.begin(); j != lines.end(); ++j) @@ -678,11 +693,13 @@ namespace commands if (ident.empty()) { // TODO Wrap long lines in these messages. - out << "Top-level commands:\n\n"; + out << "Command groups:\n\n"; explain_children(CMD_REF(__root__)->children(), out); out << '\n'; out << "For information on a specific command, type " - "'mtn help '.\n"; + "'mtn help [subcommand_name ...]'.\n"; + out << "To see the commands available within a group, type " + "'mtn help '.\n"; out << "Note that you can always abbreviate a command name as " "long as it does not conflict with other names.\n"; out << '\n'; @@ -708,6 +725,11 @@ namespace commands cmd->exec(app, ident, args); return 0; } + else if (cmd->parent() == CMD_REF(__root__)) + { + N(false, + F("command '%s' is invalid; it is a group") % join_words(ident)); + } else { if (args.empty()) @@ -754,7 +776,7 @@ CMD(help, "", CMD_REF(informative), N_(" throw usage(id); } -CMD_HIDDEN(crash, "", CMD_REF(__root__), "{ N | E | I | exception | signal }", +CMD_HIDDEN(crash, "", CMD_REF(debug), "{ N | E | I | exception | signal }", N_("Triggers the specified kind of crash"), N_(""), options::opts::none) @@ -967,11 +989,13 @@ process_commit_message_args(bool & given #ifdef BUILD_UNIT_TESTS #include "unit_tests.hh" -CMD(test1, "alias1", CMD_REF(__root__), "", "", "", options::opts::none) {} -CMD(test2, "alias2", CMD_REF(__root__), "", "", "", options::opts::none) {} -CMD_HIDDEN(test3, "", CMD_REF(__root__), "", "", "", options::opts::none) {} +CMD_GROUP(top, "", CMD_REF(__root__), "", "", options::opts::none); -CMD_GROUP(testg, "aliasg", CMD_REF(__root__), "", "", options::opts::none); +CMD(test1, "alias1", CMD_REF(top), "", "", "", options::opts::none) {} +CMD(test2, "alias2", CMD_REF(top), "", "", "", options::opts::none) {} +CMD_HIDDEN(test3, "", CMD_REF(top), "", "", "", options::opts::none) {} + +CMD_GROUP(testg, "aliasg", CMD_REF(top), "", "", options::opts::none); CMD(testg1, "", CMD_REF(testg), "", "", "", options::opts::none) {} CMD(testg2, "", CMD_REF(testg), "", "", "", options::opts::none) {} CMD_HIDDEN(testg3, "", CMD_REF(testg), "", "", "", options::opts::none) {} @@ -1007,35 +1031,35 @@ UNIT_TEST(commands, complete_command) using commands::complete_command; using commands::make_command_id; + // Single-word identifier, top-level category. + { + command_id id = complete_command(mkargs("top")); + BOOST_CHECK(id == make_command_id("top")); + } + // Single-word identifier. { command_id id = complete_command(mkargs("testg")); - BOOST_CHECK(id == make_command_id("testg")); + BOOST_CHECK(id == make_command_id("top testg")); } // Single-word identifier, non-primary name. { command_id id = complete_command(mkargs("alias1")); - BOOST_CHECK(id == make_command_id("alias1")); + BOOST_CHECK(id == make_command_id("top alias1")); } // Multi-word identifier. { command_id id = complete_command(mkargs("testg testg1")); - BOOST_CHECK(id == make_command_id("testg testg1")); + BOOST_CHECK(id == make_command_id("top testg testg1")); } // Multi-word identifier, non-primary names. { command_id id = complete_command(mkargs("al testg1")); - BOOST_CHECK(id == make_command_id("aliasg testg1")); + BOOST_CHECK(id == make_command_id("top aliasg testg1")); } - - // Single-word identifier, one level deep. - { - command_id id = complete_command(mkargs("testg1")); - BOOST_CHECK(id == make_command_id("testg testg1")); - } } UNIT_TEST(commands, command_complete_command) @@ -1046,21 +1070,21 @@ UNIT_TEST(commands, command_complete_com // Non-existent single-word identifier. { command_id id = make_command_id("foo"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 0); } // Non-existent multi-word identifier. { command_id id = make_command_id("foo bar"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 0); } // Single-word identifier with one match. { command_id id = make_command_id("test1"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 1); BOOST_CHECK(*matches.begin() == make_command_id("test1")); } @@ -1068,7 +1092,7 @@ UNIT_TEST(commands, command_complete_com // Single-word identifier with one match, non-primary name. { command_id id = make_command_id("alias1"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 1); BOOST_CHECK(*matches.begin() == make_command_id("alias1")); } @@ -1076,7 +1100,7 @@ UNIT_TEST(commands, command_complete_com // Single-word identifier with multiple matches. { command_id id = make_command_id("test"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 3); set< command_id > expected; @@ -1089,7 +1113,7 @@ UNIT_TEST(commands, command_complete_com // Single-word identifier with multiple matches, non-primary name. { command_id id = make_command_id("alias"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 3); set< command_id > expected; @@ -1102,7 +1126,7 @@ UNIT_TEST(commands, command_complete_com // Multi-word identifier with one match. { command_id id = make_command_id("testg testg1"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 1); set< command_id > expected; @@ -1113,7 +1137,7 @@ UNIT_TEST(commands, command_complete_com // Multi-word identifier with multiple matches. { command_id id = make_command_id("testg testg"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 2); set< command_id > expected; @@ -1125,7 +1149,7 @@ UNIT_TEST(commands, command_complete_com // Multi-word identifier with multiple matches at different levels. { command_id id = make_command_id("test testg1"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 3); set< command_id > expected; @@ -1138,7 +1162,7 @@ UNIT_TEST(commands, command_complete_com // Multi-word identifier with one match and extra words. { command_id id = make_command_id("testg testg1 foo"); - set< command_id > matches = CMD_REF(__root__)->complete_command(id); + set< command_id > matches = CMD_REF(top)->complete_command(id); BOOST_REQUIRE(matches.size() == 1); set< command_id > expected; @@ -1156,63 +1180,63 @@ UNIT_TEST(commands, command_find_command // Non-existent single-word identifier. { command_id id = make_command_id("foo"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == NULL); } // Non-existent multi-word identifier. { command_id id = make_command_id("foo bar"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == NULL); } // Single-word identifier that could be completed. { command_id id = make_command_id("test"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == NULL); } // Single-word identifier. { command_id id = make_command_id("test1"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == CMD_REF(test1)); } // Hidden single-word identifier. { command_id id = make_command_id("test3"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == CMD_REF(test3)); } // Multi-word identifier that could be completed. { command_id id = make_command_id("testg testg"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == NULL); } // Multi-word identifier. { command_id id = make_command_id("testg testg1"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == CMD_REF(testg1)); } // Hidden multi-word identifier. { command_id id = make_command_id("testg testg3"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == CMD_REF(testg3)); } // Multi-word identifier with extra words. { command_id id = make_command_id("testg testg1 foo"); - command * cmd = CMD_REF(__root__)->find_command(id); + command * cmd = CMD_REF(top)->find_command(id); BOOST_CHECK(cmd == NULL); } } ============================================================ --- monotone.cc 8c79550c27a5c737f2a5415a2586d7a696341d59 +++ monotone.cc 36b847fc599875695adfd6a14288b8253f1aea02 @@ -147,20 +147,13 @@ commands::command_id read_options(option optset = (options::opts::globals() | cmdopts).instantiate(&opts); optset.from_command_line(args, false); - // Remove the command name from the arguments. It is important to - // note that the first component of the identifier is always optional, - // so we must take care about that here. - I(opts.args[0]() != cmd[0]() || opts.args.size() >= cmd.size()); - I(opts.args[0]() == cmd[0]() || opts.args.size() >= cmd.size() - 1); + // Remove the command name from the arguments. Rember that the group + // is not taken into account. + I(opts.args.size() >= cmd.size() - 1); - commands::command_id cmd2 = cmd; - - if (cmd2[0]().find(opts.args[0]()) != 0) - cmd2.erase(cmd2.begin()); - - for (args_vector::size_type i = 0; i < cmd2.size(); i++) + for (args_vector::size_type i = 1; i < cmd.size(); i++) { - I(cmd2[i]().find(opts.args[0]()) == 0); + I(cmd[i]().find(opts.args[0]()) == 0); opts.args.erase(opts.args.begin()); } } @@ -288,6 +281,11 @@ cpp_main(int argc, char ** argv) // merrily down your pipes. std::ostream & usage_stream = (app.opts.help ? cout : cerr); + string visibleid; + if (!u.which.empty()) + visibleid = join_words(vector< utf8 >(u.which.begin() + 1, + u.which.end()))(); + usage_stream << F("Usage: %s [OPTION...] command [ARG...]") % ui.prog_name << "\n\n"; usage_stream << options::opts::globals().instantiate(&app.opts).get_usage_str() << '\n'; @@ -296,7 +294,7 @@ cpp_main(int argc, char ** argv) options::options_type cmd_options = commands::toplevel_command_options(u.which); if (!cmd_options.empty()) { - usage_stream << F("Options specific to '%s %s':") % ui.prog_name % join_words(u.which)() << "\n\n"; + usage_stream << F("Options specific to '%s %s':") % ui.prog_name % visibleid << "\n\n"; usage_stream << cmd_options.instantiate(&app.opts).get_usage_str() << '\n'; } ============================================================ --- tests/schema_migration_error_recovery/__driver__.lua a4b51f336dff083ec53c2199d398f8edb90da941 +++ tests/schema_migration_error_recovery/__driver__.lua 3e15d6854115ab39828211aea9171394cbc6ec5c @@ -8,7 +8,7 @@ function test_one(tag, target, diagnosti db = tag .. ".mtn" check(get(dump)) check(raw_mtn("db", "load", "-d", db), 0, nil, nil, {dump}) - check(raw_mtn("test_migration_step", target, "-d", db), 1, nil, true) + check(raw_mtn("db", "test_migration_step", target, "-d", db), 1, nil, true) check(qgrep(diagnostic, "stderr")) end