# # # patch "cmd.cc" # from [cccdf8eb731992378caa5b1b6e571871a6c4f860] # to [79983ff3293f63d2626d4a8f73ffe90ad18cda4b] # # patch "cmd_automate.cc" # from [500220a163b7270354d416076438587ce598e1b1] # to [a95cf1406ece9ee3bf8f1d316a8da35e66f7e7ee] # # patch "commands.hh" # from [8b4b67bd3366d9ecab8c17851c6007edecac5c03] # to [7307dae6bcaa384018604f6a7571a32267d4aed5] # # patch "network/automate_session.cc" # from [76973e2e4c7495c703110c1500f20a9a966eea2a] # to [1a373ea42046cead616d7a44968a2ea29eaed197] # ============================================================ --- cmd.cc cccdf8eb731992378caa5b1b6e571871a6c4f860 +++ cmd.cc 79983ff3293f63d2626d4a8f73ffe90ad18cda4b @@ -10,6 +10,7 @@ #include "base.hh" #include "cmd.hh" + #include "lua.hh" #include "app_state.hh" #include "work.hh" @@ -26,6 +27,7 @@ using std::ostream; using std::string; using std::vector; using std::ostream; +using std::set; // // Definition of top-level commands, used to classify the real commands @@ -82,6 +84,9 @@ CMD_GROUP(user, "user", "", CMD_REF(__ro N_("Commands defined by the user"), ""); + +CMD_FWD_DECL(automate); + template<> void dump(size_t const & in, std::string & out) { out = boost::lexical_cast(in); @@ -166,6 +171,66 @@ namespace commands { } } + void automate_stdio_shared_setup(app_state & app, + vector const & cmdline, + vector > const & params, + command_id & id, + automate const * & acmd) + { + args_vector args; + for (vector::const_iterator i = cmdline.begin(); + i != cmdline.end(); ++i) + { + args.push_back(arg_type(*i, origin::user)); + id.push_back(utf8(*i, origin::user)); + } + + set< command_id > matches = + CMD_REF(automate)->complete_command(id); + + if (matches.empty()) + { + E(false, origin::network, + F("no completions for this command")); + } + else if (matches.size() > 1) + { + E(false, origin::network, + F("multiple completions possible for this command")); + } + + id = *matches.begin(); + + command const * cmd = CMD_REF(automate)->find_command(id); + I(cmd != NULL); + + acmd = dynamic_cast< automate const * >(cmd); + I(acmd != NULL); + + E(acmd->can_run_from_stdio(), origin::network, + F("sorry, that can't be run remotely or over stdio")); + + + 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)); + commands::reapply_options(app, + app.reset_info.cmd, + commands::command_id() /* doesn't matter */, + cmd, my_id_for_hook, 2, + args, + ¶ms); + + // disable user prompts, f.e. for password decryption + app.opts.non_interactive = true; + + + // set a fixed ticker type regardless what the user wants to + // see, because anything else would screw the stdio-encoded output + ui.set_tick_write_stdio(); + } + // monotone.cc calls this function after option processing. void process(app_state & app, command_id const & ident, args_vector const & args) ============================================================ --- cmd_automate.cc 500220a163b7270354d416076438587ce598e1b1 +++ cmd_automate.cc a95cf1406ece9ee3bf8f1d316a8da35e66f7e7ee @@ -237,8 +237,7 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", automate const * acmd = 0; command_id id; - // FIXME: what follows is largely duplicated - // in network/automate_session.cc::do_work() + // this should match what's in network/automate_session.cc::do_work() // // stdio decoding errors should be noted with errno 1, // errno 2 is reserved for errors from the commands itself @@ -247,58 +246,8 @@ CMD_AUTOMATE_NO_STDIO(stdio, "", if (!ar.get_command(params, cmdline)) break; - args_vector args; - vector::iterator i = cmdline.begin(); - for (; i != cmdline.end(); ++i) - { - args.push_back(arg_type(*i, origin::user)); - id.push_back(utf8(*i, origin::user)); - } - - set< command_id > matches = - CMD_REF(automate)->complete_command(id); - - if (matches.empty()) - { - E(false, origin::user, - F("no completions for this command")); - } - else if (matches.size() > 1) - { - E(false, origin::user, - F("multiple completions possible for this command")); - } - - id = *matches.begin(); - - command const * cmd = CMD_REF(automate)->find_command(id); - I(cmd != NULL); - - acmd = dynamic_cast< automate const * >(cmd); - I(acmd != NULL); - - E(acmd->can_run_from_stdio(), origin::network, - F("sorry, that can't be run remotely or over stdio")); - - - 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)); - commands::reapply_options(app, - app.reset_info.cmd, - commands::command_id() /* doesn't matter */, - cmd, my_id_for_hook, 2, - args, - ¶ms); - - // disable user prompts, f.e. for password decryption - app.opts.non_interactive = true; - - - // set a fixed ticker type regardless what the user wants to - // see, because anything else would screw the stdio-encoded output - ui.set_tick_write_stdio(); + commands::automate_stdio_shared_setup(app, cmdline, params, + id, acmd); } // FIXME: we need to re-package and rethrow this special exception // since it is not based on informative_failure ============================================================ --- commands.hh 8b4b67bd3366d9ecab8c17851c6007edecac5c03 +++ commands.hh 7307dae6bcaa384018604f6a7571a32267d4aed5 @@ -22,6 +22,7 @@ namespace commands { namespace commands { typedef std::vector< utf8 > command_id; class command; + class automate; command_id make_command_id(std::string const & path); void explain_usage(command_id const & cmd, bool show_hidden, std::ostream & out); @@ -38,6 +39,15 @@ namespace commands { args_vector const & subcmd_cmdline = args_vector(), std::vector > const * const separate_params = 0); + // really no good place to put this + // used by 'automate stdio' and automate_session::do_work + void automate_stdio_shared_setup(app_state & app, + std::vector const & cmdline, + std::vector > + const & params, + command_id & id, + /* reference-to-pointer here is intentional */ + automate const * & acmd); void process(app_state & app, command_id const & ident, args_vector const & args); options::options_type command_options(command_id const & ident); ============================================================ --- network/automate_session.cc 76973e2e4c7495c703110c1500f20a9a966eea2a +++ network/automate_session.cc 1a373ea42046cead616d7a44968a2ea29eaed197 @@ -27,7 +27,6 @@ using boost::lexical_cast; using boost::shared_ptr; using boost::lexical_cast; -CMD_FWD_DECL(automate); automate_session::automate_session(app_state & app, session * owner, @@ -170,59 +169,9 @@ bool automate_session::do_work(transacti origin::user, F("Sorry, you aren't allowed to do that.")); - args_vector args; - for (vector::iterator i = cmdline.begin(); - i != cmdline.end(); ++i) - { - args.push_back(arg_type(*i, origin::user)); - id.push_back(utf8(*i, origin::user)); - } + commands::automate_stdio_shared_setup(app, cmdline, params, + id, acmd); - set< command_id > matches = - CMD_REF(automate)->complete_command(id); - - if (matches.empty()) - { - E(false, origin::network, - F("no completions for this command")); - } - else if (matches.size() > 1) - { - E(false, origin::network, - F("multiple completions possible for this command")); - } - - id = *matches.begin(); - - command const * cmd = CMD_REF(automate)->find_command(id); - I(cmd != NULL); - - acmd = dynamic_cast< automate const * >(cmd); - I(acmd != NULL); - - E(acmd->can_run_from_stdio(), origin::network, - F("sorry, that can't be run remotely or over stdio")); - - - 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)); - commands::reapply_options(app, - app.reset_info.cmd, - commands::command_id() /* doesn't matter */, - cmd, my_id_for_hook, 2, - args, - ¶ms); - - // disable user prompts, f.e. for password decryption - app.opts.non_interactive = true; - - - // set a fixed ticker type regardless what the user wants to - // see, because anything else would screw the stdio-encoded output - ui.set_tick_write_stdio(); - L(FL("Executing %s for remote peer %s") % join_words(id) % get_peer()); }