# # # add_dir "tests/serve-automate-single-run" # # add_file "tests/serve-automate-single-run/__driver__.lua" # content [723bac05394be3b8628cfe70f6ba863b9ebbd7b1] # # patch "cmd_netsync.cc" # from [f5c7f34fb92c0b808a6c8e6fadf24022f122c36c] # to [1bd8e9efedef2a3aeaf92051d9c978b70b59effb] # # patch "netcmd.hh" # from [f4e7e7874dcfd14ad78d9a9c9d803930d6cc17c8] # to [31b755d5604dd28755b7feaf328a12de7e760be5] # # patch "netsync.cc" # from [8fe90f10954441c004634552f77f2861cf4e6df0] # to [15644ad53503efe190d6d2191aa58a95ac384101] # # patch "network/automate_session.cc" # from [0248881838d553ea7132b68180d1367758f94487] # to [f57baa3e59c7b0a13fe6b09d5c19dbfabd9a906b] # # patch "network/automate_session.hh" # from [40b95850da8cb9d9dec39b7384db141b1023bb84] # to [52adb2b5f883e2a1418a03b4906eb8c1b87efeb7] # # patch "network/session.cc" # from [1994ca2bf271f581a99502da7858864044e5b041] # to [4ae261e503e22d2b9f4ef980367e3df443c3ba0f] # # patch "options_list.hh" # from [556f0e2b7f83c5baece9886bcf2ef842ef2fc29e] # to [8bc3f3aa0f02d498748398dcf0b7969734492b4d] # ============================================================ --- tests/serve-automate-single-run/__driver__.lua 723bac05394be3b8628cfe70f6ba863b9ebbd7b1 +++ tests/serve-automate-single-run/__driver__.lua 723bac05394be3b8628cfe70f6ba863b9ebbd7b1 @@ -0,0 +1,54 @@ +include("common/netsync.lua") + +mtn_setup() +netsync.setup() + +addfile("foo", "bar") +commit() +R1 = base_revision() + +server = netsync.start() + +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "interface_version"), 0, true, false) +check(qgrep("^0:2:l:", "stdout")) + +server:stop() + +check(mtn2("automate", "stdio"), 0, true, false, "l6:leavese") +check(qgrep("^0:0:l:0:", "stdout")) + +writefile("allow-automate.lua", + "function get_remote_automate_permitted(x, y, z) return true end") + +server = netsync.start({"--rcfile=allow-automate.lua"}) + +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "interface_version"), 0, true, false) +check(qgrep("^0:0:l:", "stdout")) + +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "leaves"), 0, true, false) +check(qgrep("^0:0:l:", "stdout")) + +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "stdio"), 0, true, false) +check(qgrep("can't be run", "stdout")) + +-- won't work, --revision is no option of automate remote +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "get_file_of", "-r", R1, "foo"), 1, false, false) + +-- this doesn't work either because we can't use the option machinery +-- to distinguish valid from invalid options on the _server_, so we expect +-- all options arguments to be directly written after the option +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "get_file_of", "--", "-r", R1, "foo"), 0, true, false) +check(qgrep("wrong argument count", "stdout")) + +-- finally this should work +check(mtn2("automate", "remote", "--remote-stdio-host", server.address, + "get_file_of", "--", "-r".. R1, "foo"), 0, true, false) +check(qgrep("bar", "stdout")) + +server:stop() ============================================================ --- cmd_netsync.cc f5c7f34fb92c0b808a6c8e6fadf24022f122c36c +++ cmd_netsync.cc 1bd8e9efedef2a3aeaf92051d9c978b70b59effb @@ -265,6 +265,131 @@ CMD_AUTOMATE_NO_STDIO(remote_stdio, client_voice, source_and_sink_role, info); } +// shamelessly copied and adapted from option.cc +static void +parse_options_from_args(args_vector & args, + std::vector > & opts) +{ + bool seen_dashdash = false; + for (args_vector::size_type i = 0; i < args.size(); ) + { + string name; + arg_type arg; + + if (idx(args,i)() == "--" || seen_dashdash) + { + if (!seen_dashdash) + { + seen_dashdash = true; + } + ++i; + continue; + } + else if (idx(args,i)().substr(0,2) == "--") + { + string::size_type equals = idx(args,i)().find('='); + bool has_arg; + if (equals == string::npos) + { + name = idx(args,i)().substr(2); + has_arg = false; + } + else + { + name = idx(args,i)().substr(2, equals-2); + has_arg = true; + } + + if (has_arg) + { + arg = arg_type(idx(args,i)().substr(equals+1), origin::user); + } + } + else if (idx(args,i)().substr(0,1) == "-") + { + name = idx(args,i)().substr(1,1); + bool has_arg = idx(args,i)().size() > 2; + + if (has_arg) + { + arg = arg_type(idx(args,i)().substr(2), origin::user); + } + } + else + { + ++i; + continue; + } + + opts.push_back(std::pair(name, arg)); + args.erase(args.begin() + i); + } +} + +CMD_AUTOMATE_NO_STDIO(remote, + N_("COMMAND [ARGS]"), + N_("Executes COMMAND on a remote server"), + "", + options::opts::remote_stdio_host | + options::opts::max_netsync_version | + options::opts::min_netsync_version) +{ + E(args.size() >= 1, origin::user, + F("wrong argument count")); + + database db(app); + key_store keys(app); + project_t project(db); + + netsync_connection_info info; + info.client.unparsed = app.opts.remote_stdio_host; + parse_uri(info.client.unparsed(), info.client.uri, origin::user); + + info.client.use_argv = + app.lua.hook_get_netsync_connect_command(info.client.uri, + info.client.include_pattern, + info.client.exclude_pattern, + global_sanity.debug_p(), + info.client.argv); + app.opts.use_transport_auth = app.lua.hook_use_transport_auth(info.client.uri); + if (app.opts.use_transport_auth) + { + find_key(app.opts, db, keys, app.lua, project, info, true); + } + + args_vector cleaned_args(args); + std::vector > opts; + parse_options_from_args(cleaned_args, opts); + + std::stringstream ss; + if (opts.size() > 0) + { + ss << 'o'; + for (unsigned int i=0; i < opts.size(); ++i) + { + ss << opts.at(i).first.size() << ':' << opts.at(i).first; + ss << opts.at(i).second().size() << ':' << opts.at(i).second(); + } + ss << 'e' << ' '; + } + + ss << 'l'; + for (args_vector::size_type i=0; i #include +#include #include "globish.hh" #include "merkle_tree.hh" @@ -229,7 +230,7 @@ struct netsync_connection_info struct netsync_connection_info { - struct + struct Server { std::list addrs; } server; @@ -238,7 +239,7 @@ struct netsync_connection_info netsync_connection, automate_connection }; - struct + struct Client { globish include_pattern; globish exclude_pattern; @@ -247,6 +248,8 @@ struct netsync_connection_info std::vector argv; bool use_argv; conn_type connection_type; + std::istream & stdio_input_stream; + Client() : stdio_input_stream(std::cin) {} } client; }; ============================================================ --- netsync.cc 8fe90f10954441c004634552f77f2861cf4e6df0 +++ netsync.cc 15644ad53503efe190d6d2191aa58a95ac384101 @@ -132,7 +132,8 @@ call_server(app_state & app, info.client.exclude_pattern)); break; case netsync_connection_info::automate_connection: - wrapped.reset(new automate_session(app, sess.get())); + wrapped.reset(new automate_session(app, sess.get(), + info.client.stdio_input_stream)); break; } sess->set_inner(wrapped); ============================================================ --- network/automate_session.cc 0248881838d553ea7132b68180d1367758f94487 +++ network/automate_session.cc f57baa3e59c7b0a13fe6b09d5c19dbfabd9a906b @@ -27,17 +27,19 @@ automate_session::automate_session(app_s CMD_FWD_DECL(automate); automate_session::automate_session(app_state & app, - session * owner) : + session * owner, + std::istream & is) : wrapped_session(owner), app(app), + input_stream(is), command_number(-1), is_done(false) { } void automate_session::send_command() { - // read an automate command on stdin, then package it up and send it - automate_reader ar(std::cin); + // read an automate command from the stream, then package it up and send it + automate_reader ar(input_stream); vector > read_opts; vector read_args; ============================================================ --- network/automate_session.hh 40b95850da8cb9d9dec39b7384db141b1023bb84 +++ network/automate_session.hh 52adb2b5f883e2a1418a03b4906eb8c1b87efeb7 @@ -20,6 +20,7 @@ class automate_session : public wrapped_ class automate_session : public wrapped_session { app_state & app; + std::istream & input_stream; typedef commands::command_id command_id; typedef commands::command command; typedef commands::automate automate; @@ -33,6 +34,9 @@ public: public: automate_session(app_state & app, session * owner); + automate_session(app_state & app, + session * owner, + std::istream & is); bool do_work(transaction_guard & guard, netcmd const * const in_cmd); ============================================================ --- network/session.cc 1994ca2bf271f581a99502da7858864044e5b041 +++ network/session.cc 4ae261e503e22d2b9f4ef980367e3df443c3ba0f @@ -304,7 +304,7 @@ bool session::do_work(transaction_guard } I(project.db.public_key_exists(remote_peer_key_id)); - + // save their identity received_remote_key = true; } @@ -653,7 +653,7 @@ bool session::handle_service_request() their_exclude)); break; case is_automate: - wrapped.reset(new automate_session(app, this)); + wrapped.reset(new automate_session(app, this, std::cin)); break; } ============================================================ --- options_list.hh 556f0e2b7f83c5baece9886bcf2ef842ef2fc29e +++ options_list.hh 8bc3f3aa0f02d498748398dcf0b7969734492b4d @@ -140,6 +140,16 @@ OPT(min_netsync_version, "min-netsync-ve } #endif +OPT(remote_stdio_host, "remote-stdio-host", + utf8, , + gettext_noop("sets the host (and optionally the port) for a " + "remote netsync action")) +#ifdef option_bodies +{ + remote_stdio_host = utf8(arg, origin::user); +} +#endif + OPT(branch, "branch,b", branch_name, , gettext_noop("select branch cert for operation")) #ifdef option_bodies