# # # patch "cmd.cc" # from [5c36b7cff092295b30e91930ffb401fc6a4510a1] # to [a7d3e349b9b0c4ca20d77df537c999320984d441] # # patch "cmd_automate.cc" # from [e03b031b0762fe400b75f75d00fbcd1aaab0a11a] # to [906e9fb69e5c187eff0e0c02a058dfb41300434f] # # patch "cmd_merging.cc" # from [ed3530c95d77f9ec3d2f9a1fdcfabca9bc05e10c] # to [a2062506e548919fa80e08aaf6e657cdcffb01e3] # # patch "cmd_ws_commit.cc" # from [950ec8b23cc87441c3de37a0f8f743e992542f6c] # to [c3f3acf71cb7b80f6c810f68003e267b90a79382] # # patch "commands.hh" # from [cd142f8a073ac9e2af690f05d18fb765274cf413] # to [a8a38db021714abcdbbe8dea95f345eab1c5b557] # # patch "monotone.cc" # from [18c066704f5ac41ee05a1cdd4373d1f8ce2cbd94] # to [0bc3fbe00872cfca1526f2cc193b9bd6e144d819] # # patch "option_reset_info.hh" # from [4a2fb29c93c1332bcfac55a34e79158b35f6ab02] # to [a11b67e3d5c52197a2228224b8927b2d27471b3a] # ============================================================ --- cmd.cc 5c36b7cff092295b30e91930ffb401fc6a4510a1 +++ cmd.cc a7d3e349b9b0c4ca20d77df537c999320984d441 @@ -85,21 +85,80 @@ namespace commands { namespace commands { void remove_command_name_from_args(command_id const & ident, - args_vector & args) + args_vector & args, + size_t invisible_length) { - I(ident.empty() || args.size() >= ident.size() - 1); - for (args_vector::size_type i = 1; i < ident.size(); i++) + I(ident.empty() || args.size() >= ident.size() - invisible_length); + for (args_vector::size_type i = invisible_length; i < ident.size(); i++) { I(ident[i]().find(args[0]()) == 0); args.erase(args.begin()); } } + void reapply_options(app_state & app, + command const * cmd, + command_id const & cmd_ident, + command const * subcmd, + command_id const & subcmd_full_ident, + size_t subcmd_invisible_length, + args_vector const & subcmd_cmdline) + { + I(cmd); + options::opts::all_options().instantiate(&app.opts).reset(); + + option::concrete_option_set optset + = (options::opts::globals() | cmd->opts()) + .instantiate(&app.opts); + + optset.from_command_line(app.reset_info.default_args, false); + + if (subcmd) + { + args_vector subcmd_defaults; + app.lua.hook_get_default_command_options(subcmd_full_ident, + subcmd_defaults); + (options::opts::globals() | subcmd->opts()) + .instantiate(&app.opts) + .from_command_line(subcmd_defaults, false); + } + + // at this point we process the data from _MTN/options if + // the command needs it. + if ((subcmd ? subcmd : cmd)->use_workspace_options()) + { + workspace::check_format(); + workspace::get_options(app.opts); + } + + optset.from_command_line(app.reset_info.cmdline_args, false); + + if (subcmd) + { + app.opts.args.clear(); + (options::opts::globals() | subcmd->opts()) + .instantiate(&app.opts) + /* the first argument here is only ever modified if the second is 'true' */ + .from_command_line(const_cast(subcmd_cmdline), false); + remove_command_name_from_args(subcmd_full_ident, app.opts.args, + subcmd_invisible_length); + } + else + { + remove_command_name_from_args(cmd_ident, app.opts.args); + } + } + // monotone.cc calls this function after option processing. void process(app_state & app, command_id const & ident, args_vector const & args) { + static bool process_called(false); + I(!process_called); + process_called = true; + command const * cmd = CMD_REF(__root__)->find_command(ident); + app.reset_info.cmd = cmd; string visibleid = join_words(vector< utf8 >(ident.begin() + 1, ident.end()))(); @@ -112,7 +171,7 @@ namespace commands { if (!cmd->is_leaf()) { // args used in the command name have not been stripped yet - remove_command_name_from_args(app.reset_info.cmd, app.opts.args); + remove_command_name_from_args(ident, app.opts.args); E(!args.empty(), origin::user, F("no subcommand specified for '%s'") % visibleid); @@ -124,26 +183,8 @@ namespace commands { L(FL("executing command '%s'") % visibleid); - options::opts::all_options().instantiate(&app.opts).reset(); + reapply_options(app, cmd, ident); - option::concrete_option_set optset - = (options::opts::globals() - | commands::command_options(app.reset_info.cmd)) - .instantiate(&app.opts); - - optset.from_command_line(app.reset_info.default_args, false); - - // at this point we process the data from _MTN/options if - // the command needs it. - if (cmd->use_workspace_options()) - { - workspace::check_format(); - workspace::get_options(app.opts); - } - - optset.from_command_line(app.reset_info.cmdline_args, false); - remove_command_name_from_args(app.reset_info.cmd, app.opts.args); - cmd->exec(app, ident, args); } ============================================================ --- cmd_automate.cc e03b031b0762fe400b75f75d00fbcd1aaab0a11a +++ cmd_automate.cc 906e9fb69e5c187eff0e0c02a058dfb41300434f @@ -436,53 +436,20 @@ LUAEXT(mtn_automate, ) I(cmd != NULL); - // reset and recalcualte the options - options::opts::all_options().instantiate(&app_p->opts).reset(); + commands::command_id my_id_for_hook = id; + my_id_for_hook.insert(my_id_for_hook.begin(), utf8("automate", origin::internal)); + // group name + my_id_for_hook.insert(my_id_for_hook.begin(), utf8("automation", origin::internal)); - option::concrete_option_set orig_optset - = (options::opts::globals() - | commands::command_options(app_p->reset_info.cmd)) - .instantiate(&app_p->opts); - orig_optset.from_command_line(app_p->reset_info.default_args, false); + commands::reapply_options(*app_p, + app_p->reset_info.cmd, commands::command_id() /*doesn't matter*/, + cmd, my_id_for_hook, 2, + args); - // get default options for the current (sub-)command here - option::concrete_option_set my_optset - = (options::opts::globals() | cmd->opts()) - .instantiate(&app_p->opts); - args_vector my_defaults; - { - command_id my_id_for_hook = id; - my_id_for_hook.insert(my_id_for_hook.begin(), utf8("automate", origin::internal)); - // group name - my_id_for_hook.insert(my_id_for_hook.begin(), utf8("automation", origin::internal)); - app_p->lua.hook_get_default_command_options(my_id_for_hook, my_defaults); - } - my_optset.from_command_line(my_defaults, false); - - if (cmd->use_workspace_options()) - { - // Re-read the ws options file, rather than just copying - // the options from the previous apts.opts object, because - // the file may have changed due to user activity. - workspace::check_format(); - workspace::get_options(app_p->opts); - } - - orig_optset.from_command_line(app_p->reset_info.cmdline_args, false); - - // now add our given options and clean the arg list - app_p->opts.args.clear(); - my_optset.from_command_line(args, false); - I(app_p->opts.args.size() >= id.size()); - for (commands::command_id::size_type i = 0; i < id.size(); i++) - app_p->opts.args.erase(app_p->opts.args.begin()); - - // disable user prompts, f.e. for password decryption + // disable user prompts, for example for password decryption app_p->opts.non_interactive = true; - // done recalculating options - args_vector & parsed_args = app_p->opts.args; commands::automate const * acmd ============================================================ --- cmd_merging.cc ed3530c95d77f9ec3d2f9a1fdcfabca9bc05e10c +++ cmd_merging.cc a2062506e548919fa80e08aaf6e657cdcffb01e3 @@ -571,20 +571,6 @@ CMD(merge, "merge", "", CMD_REF(tree), " updater.maybe_do_update(); } -CMD(propagate, "propagate", "", CMD_REF(tree), - N_("SOURCE-BRANCH DEST-BRANCH"), - N_("Merges from one branch to another asymmetrically"), - "", - options::opts::date | options::opts::author | options::opts::messages | - options::opts::resolve_conflicts_opts) -{ - if (args.size() != 2) - throw usage(execid); - args_vector a = args; - a.push_back(arg_type()); - process(app, make_command_id("tree merge_into_dir"), a); -} - // This is a special merge operator, but very useful for people // maintaining "slightly disparate but related" trees. It does a one-way // merge; less powerful than putting things in the same branch and also @@ -611,12 +597,9 @@ CMD(propagate, "propagate", "", CMD_REF( // If dir is not the empty string, rename the root of N1 to have the name // 'dir' in the merged tree. (ie, it has name "basename(dir)", and its // parent node is "N2.get_node(dirname(dir))") -CMD(merge_into_dir, "merge_into_dir", "", CMD_REF(tree), - N_("SOURCE-BRANCH DEST-BRANCH DIR"), - N_("Merges one branch into a subdirectory in another branch"), - "", - options::opts::date | options::opts::author | options::opts::messages | - options::opts::resolve_conflicts_opts | options::opts::maybe_auto_update) +void perform_merge_into_dir(app_state & app, + commands::command_id const & execid, + args_vector const & args) { database db(app); key_store keys(app); @@ -767,6 +750,30 @@ CMD(merge_into_dir, "merge_into_dir", "" updater.maybe_do_update(); } +CMD(propagate, "propagate", "", CMD_REF(tree), + N_("SOURCE-BRANCH DEST-BRANCH"), + N_("Merges from one branch to another asymmetrically"), + "", + options::opts::date | options::opts::author | options::opts::messages | + options::opts::resolve_conflicts_opts) +{ + if (args.size() != 2) + throw usage(execid); + args_vector a = args; + a.push_back(arg_type()); + perform_merge_into_dir(app, make_command_id("tree merge_into_dir"), a); +} + +CMD(merge_into_dir, "merge_into_dir", "", CMD_REF(tree), + N_("SOURCE-BRANCH DEST-BRANCH DIR"), + N_("Merges one branch into a subdirectory in another branch"), + "", + options::opts::date | options::opts::author | options::opts::messages | + options::opts::resolve_conflicts_opts | options::opts::maybe_auto_update) +{ + perform_merge_into_dir(app, execid, args); +} + CMD(merge_into_workspace, "merge_into_workspace", "", CMD_REF(tree), N_("OTHER-REVISION"), N_("Merges a revision into the current workspace's base revision"), ============================================================ --- cmd_ws_commit.cc 950ec8b23cc87441c3de37a0f8f743e992542f6c +++ cmd_ws_commit.cc c3f3acf71cb7b80f6c810f68003e267b90a79382 @@ -1418,7 +1418,7 @@ void perform_commit(app_state & app, database & db, workspace & work, project_t & project, - command_id const & execid, + commands::command_id const & execid, vector const & paths) { key_store keys(app); ============================================================ --- commands.hh cd142f8a073ac9e2af690f05d18fb765274cf413 +++ commands.hh a8a38db021714abcdbbe8dea95f345eab1c5b557 @@ -21,12 +21,21 @@ namespace commands { namespace commands { typedef std::vector< utf8 > command_id; + class command; command_id make_command_id(std::string const & path); void explain_usage(command_id const & cmd, bool show_hidden, std::ostream & out); command_id complete_command(args_vector const & args); void remove_command_name_from_args(command_id const & ident, - args_vector & args); + args_vector & args, + size_t invisible_length = 1); + void reapply_options(app_state & app, + command const * cmd, + command_id const & cmd_ident, + command const * subcmd = 0, + command_id const & subcmd_full_ident = command_id(), + size_t subcmd_invisible_length = 1, + args_vector const & subcmd_cmdline = args_vector()); void process(app_state & app, command_id const & ident, args_vector const & args); options::options_type command_options(command_id const & ident); ============================================================ --- monotone.cc 18c066704f5ac41ee05a1cdd4373d1f8ce2cbd94 +++ monotone.cc 0bc3fbe00872cfca1526f2cc193b9bd6e144d819 @@ -214,15 +214,16 @@ cpp_main(int argc, char ** argv) // this needs to be after the hooks are loaded, because new // command names may have been added with the alias_command() // lua extension function + commands::command_id cmd_id; if (!app.opts.args.empty()) { - app.reset_info.cmd = commands::complete_command(app.opts.args); - I(!app.reset_info.cmd.empty()); + cmd_id = commands::complete_command(app.opts.args); + I(!cmd_id.empty()); } // check if the user specified default arguments for this command - if (!app.reset_info.cmd.empty()) - app.lua.hook_get_default_command_options(app.reset_info.cmd, + if (!cmd_id.empty()) + app.lua.hook_get_default_command_options(cmd_id, app.reset_info.default_args); if (workspace::found) @@ -244,18 +245,18 @@ cpp_main(int argc, char ** argv) // stop here if they asked for help if (app.opts.help) - throw usage(app.reset_info.cmd); + throw usage(cmd_id); // main options processed, now invoke the // sub-command w/ remaining args - if (app.reset_info.cmd.empty()) + if (cmd_id.empty()) throw usage(commands::command_id()); // as soon as a command requires a workspace, this is set to true workspace::used = false; - commands::process(app, app.reset_info.cmd, app.opts.args); + commands::process(app, cmd_id, app.opts.args); workspace::maybe_set_options(app.opts, app.lua); ============================================================ --- option_reset_info.hh 4a2fb29c93c1332bcfac55a34e79158b35f6ab02 +++ option_reset_info.hh a11b67e3d5c52197a2228224b8927b2d27471b3a @@ -14,13 +14,15 @@ #include "option.hh" -typedef std::vector< utf8 > command_id; +namespace commands { + class command; +} struct option_reset_info { args_vector default_args; args_vector cmdline_args; - command_id cmd; + commands::command const * cmd; }; #endif // __OPTION_RESET_INFO_HH__