# # # add_file "automate_ostream_demuxed.hh" # content [705d6844f3b2ce930d27d7a7619707d687fa4df9] # # add_file "network/connection_info.cc" # content [9edab41b536c97a253ea4b55dbe088fb9f09f8c6] # # add_file "network/connection_info.hh" # content [3575b6cdb9fa29dc15b09b43b969ef4b9c73476e] # # patch "Makefile.am" # from [4c0369020e91bd18cb8989ada6ccd7d2e15aa11e] # to [334ee0bb5ce895ec2c47b6153dfb7714febe7964] # # patch "automate_ostream.hh" # from [a7d6900e637ed9f9987da5593a64bbe8f6c15953] # to [b4767dc3d7748882a70f559fabd5c8a48037e3f1] # # patch "cmd_netsync.cc" # from [1bd8e9efedef2a3aeaf92051d9c978b70b59effb] # to [d66b01aa32f79b802747d218cca316e9411be194] # # patch "netcmd.hh" # from [31b755d5604dd28755b7feaf328a12de7e760be5] # to [d866df26f476f548f19a66165c64b0821f898b5a] # # patch "netsync.cc" # from [15644ad53503efe190d6d2191aa58a95ac384101] # to [06420552bf26284f92fbfc19d348948b64cb4f2b] # # patch "network/automate_session.cc" # from [f57baa3e59c7b0a13fe6b09d5c19dbfabd9a906b] # to [502cdaa823c110fdaa6fcf9432a7ccf49c1ddfca] # # patch "network/automate_session.hh" # from [52adb2b5f883e2a1418a03b4906eb8c1b87efeb7] # to [1db9aaf5f363e0ca92826df64c36cc0678b157a0] # # patch "network/session.cc" # from [4ae261e503e22d2b9f4ef980367e3df443c3ba0f] # to [bb67e698a2ddb7f1ebbfde380445dfbf5a76340c] # # patch "tests/serve-automate-single-run/__driver__.lua" # from [723bac05394be3b8628cfe70f6ba863b9ebbd7b1] # to [b2cc73cf028bd61486c8f9ca15fb7ffcded3d8f5] # ============================================================ --- automate_ostream_demuxed.hh 705d6844f3b2ce930d27d7a7619707d687fa4df9 +++ automate_ostream_demuxed.hh 705d6844f3b2ce930d27d7a7619707d687fa4df9 @@ -0,0 +1,121 @@ +// Copyright (C) 2009 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#ifndef __AUTOMATE_OSTREAM_DEMUXED_HH__ +#define __AUTOMATE_OSTREAM_DEMUXED_HH__ + +#include + +#include "automate_ostream.hh" + +template > +class basic_automate_streambuf_demuxed : public std::basic_streambuf<_CharT, _Traits> +{ + typedef _Traits traits_type; + typedef typename _Traits::int_type int_type; + size_t _bufsize; + std::basic_ostream<_CharT, _Traits> *stdout; + std::basic_ostream<_CharT, _Traits> *errout; + bool in_err; +public: + basic_automate_streambuf_demuxed(std::ostream & out, std::ostream & err, + size_t bufsize) : + std::streambuf(), + _bufsize(bufsize), + stdout(&out), + errout(&err), + in_err(false) + { + _CharT * inbuf = new _CharT[_bufsize]; + setp(inbuf, inbuf + _bufsize); + } + + ~basic_automate_streambuf_demuxed() { } + + void set_err(int e) + { + in_err = (e != 0); + } + + void end_cmd() + { + _M_sync(); + } + + virtual int sync() + { + _M_sync(); + return 0; + } + + int_type overflow(int_type c = traits_type::eof()) + { + sync(); + sputc(c); + return 0; + } +private: + void _M_sync() + { + std::basic_ostream<_CharT, _Traits> *str; + str = (in_err ? errout : stdout); + if (!str) + { + setp(this->pbase(), this->pbase() + _bufsize); + return; + } + int num = this->pptr() - this->pbase(); + if (num) + { + (*str) << std::basic_string<_CharT, _Traits>(this->pbase(), num); + setp(this->pbase(), this->pbase() + _bufsize); + str->flush(); + } + } +}; + +template > +struct basic_automate_ostream_demuxed : public basic_automate_ostream<_CharT, _Traits> +{ + typedef basic_automate_streambuf_demuxed<_CharT, _Traits> streambuf_type; + streambuf_type _M_autobuf; + + basic_automate_ostream_demuxed(std::basic_ostream<_CharT, _Traits> &out, + std::basic_ostream<_CharT, _Traits> &err, + size_t blocksize) + : _M_autobuf(out, err, blocksize) + { this->init(&_M_autobuf); } + + virtual ~basic_automate_ostream_demuxed() + {} + + streambuf_type * + rdbuf() const + { return const_cast(&_M_autobuf); } + + virtual void set_err(int e) + { _M_autobuf.set_err(e); } + + virtual void end_cmd() + { _M_autobuf.end_cmd(); } +}; + +typedef basic_automate_streambuf_demuxed automate_streambuf_demuxed; +typedef basic_automate_ostream_demuxed automate_ostream_demuxed; + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- network/connection_info.cc 9edab41b536c97a253ea4b55dbe088fb9f09f8c6 +++ network/connection_info.cc 9edab41b536c97a253ea4b55dbe088fb9f09f8c6 @@ -0,0 +1,49 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#include "base.hh" +#include "network/connection_info.hh" + +netsync_connection_info::Client::Client() : + use_argv(false), + connection_type(netsync_connection), + input_stream(0), + output_stream(0) +{ } + +std::istream & netsync_connection_info::Client::get_input_stream() const +{ + I(input_stream); + return *input_stream; +} + +automate_ostream & netsync_connection_info::Client::get_output_stream() const +{ + I(output_stream); + return *output_stream; +} + +void netsync_connection_info::Client::set_input_stream(std::istream & is) +{ + input_stream = &is; +} + +void netsync_connection_info::Client::set_output_stream(automate_ostream & os) +{ + output_stream = &os; +} + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- network/connection_info.hh 3575b6cdb9fa29dc15b09b43b969ef4b9c73476e +++ network/connection_info.hh 3575b6cdb9fa29dc15b09b43b969ef4b9c73476e @@ -0,0 +1,62 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + +#ifndef __CONNECTION_INFO_HH__ +#define __CONNECTION_INFO_HH__ + +#include +#include + +#include "automate_ostream.hh" +#include "globish.hh" +#include "uri.hh" +#include "vocab.hh" + +struct netsync_connection_info +{ + struct Server + { + std::list addrs; + } server; + enum conn_type + { + netsync_connection, + automate_connection + }; + struct Client + { + globish include_pattern; + globish exclude_pattern; + uri_t uri; + utf8 unparsed; + std::vector argv; + bool use_argv; + conn_type connection_type; + private: + std::istream * input_stream; + automate_ostream * output_stream; + public: + std::istream & get_input_stream() const; + automate_ostream & get_output_stream() const; + void set_input_stream(std::istream & is); + void set_output_stream(automate_ostream & os); + Client(); + } client; +}; + +#endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- Makefile.am 4c0369020e91bd18cb8989ada6ccd7d2e15aa11e +++ Makefile.am 334ee0bb5ce895ec2c47b6153dfb7714febe7964 @@ -39,6 +39,7 @@ MOST_SOURCES = \ rev_types.hh mtn-sanity.cc mtn-sanity.hh ui.cc ui.hh \ app_state.cc app_state.hh \ automate_ostream.hh \ + automate_ostream_demuxed.hh \ automate_reader.hh automate_reader.cc \ botan_pipe_cache.hh \ commands.cc commands.hh $(CMD_SOURCES) \ @@ -62,9 +63,10 @@ MOST_SOURCES = \ enumerator.cc enumerator.hh \ netsync.cc \ network/automate_session.hh network/automate_session.cc \ + network/connection_info.hh network/connection_info.cc \ network/listener_base.hh network/listener_base.cc \ + network/listener.hh network/listener.cc \ network/make_server.hh network/make_server.cc \ - network/listener.hh network/listener.cc \ network/netsync_session.hh network/netsync_session.cc \ network/reactable.hh network/reactable.cc \ network/reactor.hh network/reactor.cc \ ============================================================ --- automate_ostream.hh a7d6900e637ed9f9987da5593a64bbe8f6c15953 +++ automate_ostream.hh b4767dc3d7748882a70f559fabd5c8a48037e3f1 @@ -1,3 +1,13 @@ +// Copyright (C) 2005 and later by various people +// see monotone commit logs for details and authors +// +// This program is made available under the GNU GPL version 2.0 or +// greater. See the accompanying file COPYING for details. +// +// This program is distributed WITHOUT ANY WARRANTY; without even the +// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. + #ifndef __AUTOMATE_OSTREAM_HH__ #define __AUTOMATE_OSTREAM_HH__ @@ -13,20 +23,14 @@ public: int cmdnum; int err; public: - /* - automate_streambuf(size_t bufsize) - : std::streambuf(), _bufsize(bufsize), out(0), cmdnum(0), err(0) - { - char *inbuf = new char[_bufsize]; - setp(inbuf, inbuf + _bufsize); - } - */ basic_automate_streambuf(std::ostream & o, size_t bufsize) : std::streambuf(), _bufsize(bufsize), out(&o), cmdnum(0), err(0) { _CharT *inbuf = new _CharT[_bufsize]; setp(inbuf, inbuf + _bufsize); } + basic_automate_streambuf() + { } ~basic_automate_streambuf() {} @@ -85,21 +89,25 @@ struct basic_automate_ostream : public s basic_automate_ostream(std::basic_ostream<_CharT, _Traits> &out, size_t blocksize) - : std::ostream(NULL), + : std::basic_ostream<_CharT, _Traits>(NULL), _M_autobuf(out, blocksize) { this->init(&_M_autobuf); } - ~basic_automate_ostream() +protected: + basic_automate_ostream() { } +public: + + virtual ~basic_automate_ostream() {} streambuf_type * rdbuf() const { return const_cast(&_M_autobuf); } - void set_err(int e) + virtual void set_err(int e) { _M_autobuf.set_err(e); } - void end_cmd() + virtual void end_cmd() { _M_autobuf.end_cmd(); } }; @@ -107,3 +115,11 @@ typedef basic_automate_ostream aut typedef basic_automate_ostream automate_ostream; #endif + +// Local Variables: +// mode: C++ +// fill-column: 76 +// c-file-style: "gnu" +// indent-tabs-mode: nil +// End: +// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s: ============================================================ --- cmd_netsync.cc 1bd8e9efedef2a3aeaf92051d9c978b70b59effb +++ cmd_netsync.cc d66b01aa32f79b802747d218cca316e9411be194 @@ -11,8 +11,10 @@ #include "base.hh" #include "cmd.hh" +#include "automate_ostream_demuxed.hh" #include "merge_content.hh" #include "netcmd.hh" +#include "network/connection_info.hh" #include "globish.hh" #include "keys.hh" #include "key_store.hh" @@ -261,6 +263,10 @@ CMD_AUTOMATE_NO_STDIO(remote_stdio, info.client.connection_type = netsync_connection_info::automate_connection; + info.client.set_input_stream(std::cin); + automate_ostream os(output, app.opts.automate_stdio_size); + info.client.set_output_stream(os); + run_netsync_protocol(app, app.opts, app.lua, project, keys, client_voice, source_and_sink_role, info); } @@ -383,7 +389,10 @@ CMD_AUTOMATE_NO_STDIO(remote, L(FL("stdio input: %s") % ss.str()); - info.client.stdio_input_stream.rdbuf(ss.rdbuf()); + info.client.set_input_stream(ss); + automate_ostream_demuxed os(output, std::cerr, app.opts.automate_stdio_size); + info.client.set_output_stream(os); + info.client.connection_type = netsync_connection_info::automate_connection; run_netsync_protocol(app, app.opts, app.lua, project, keys, ============================================================ --- netcmd.hh 31b755d5604dd28755b7feaf328a12de7e760be5 +++ netcmd.hh d866df26f476f548f19a66165c64b0821f898b5a @@ -228,30 +228,7 @@ public: }; -struct netsync_connection_info -{ - struct Server - { - std::list addrs; - } server; - enum conn_type - { - netsync_connection, - automate_connection - }; - struct Client - { - globish include_pattern; - globish exclude_pattern; - uri_t uri; - utf8 unparsed; - std::vector argv; - bool use_argv; - conn_type connection_type; - std::istream & stdio_input_stream; - Client() : stdio_input_stream(std::cin) {} - } client; -}; +class netsync_connection_info; void run_netsync_protocol(app_state & app, options & opts, lua_hooks & lua, ============================================================ --- netsync.cc 15644ad53503efe190d6d2191aa58a95ac384101 +++ netsync.cc 06420552bf26284f92fbfc19d348948b64cb4f2b @@ -19,6 +19,7 @@ #include "database.hh" #include "lua.hh" #include "network/automate_session.hh" +#include "network/connection_info.hh" #include "network/listener.hh" #include "network/netsync_session.hh" #include "network/reactor.hh" @@ -133,7 +134,8 @@ call_server(app_state & app, break; case netsync_connection_info::automate_connection: wrapped.reset(new automate_session(app, sess.get(), - info.client.stdio_input_stream)); + &info.client.get_input_stream(), + &info.client.get_output_stream())); break; } sess->set_inner(wrapped); ============================================================ --- network/automate_session.cc f57baa3e59c7b0a13fe6b09d5c19dbfabd9a906b +++ network/automate_session.cc 502cdaa823c110fdaa6fcf9432a7ccf49c1ddfca @@ -28,10 +28,12 @@ automate_session::automate_session(app_s automate_session::automate_session(app_state & app, session * owner, - std::istream & is) : + std::istream * const is, + automate_ostream * const os) : wrapped_session(owner), app(app), input_stream(is), + output_stream(os), command_number(-1), is_done(false) { } @@ -39,7 +41,8 @@ void automate_session::send_command() void automate_session::send_command() { // read an automate command from the stream, then package it up and send it - automate_reader ar(input_stream); + I(input_stream); + automate_reader ar(*input_stream); vector > read_opts; vector read_args; @@ -216,12 +219,11 @@ bool automate_session::do_work(transacti cmd_in->read_automate_packet_cmd(command_num, err_code, last, packet_data); - std::cout<set_err(err_code); + (*output_stream) << packet_data; + if (last) + output_stream->end_cmd(); if (last) send_command(); ============================================================ --- network/automate_session.hh 52adb2b5f883e2a1418a03b4906eb8c1b87efeb7 +++ network/automate_session.hh 1db9aaf5f363e0ca92826df64c36cc0678b157a0 @@ -20,7 +20,8 @@ class automate_session : public wrapped_ class automate_session : public wrapped_session { app_state & app; - std::istream & input_stream; + std::istream * const input_stream; + automate_ostream * const output_stream; typedef commands::command_id command_id; typedef commands::command command; typedef commands::automate automate; @@ -33,10 +34,9 @@ public: void send_command(); public: automate_session(app_state & app, - session * owner); - automate_session(app_state & app, session * owner, - std::istream & is); + std::istream * const is, + automate_ostream * const os); bool do_work(transaction_guard & guard, netcmd const * const in_cmd); ============================================================ --- network/session.cc 4ae261e503e22d2b9f4ef980367e3df443c3ba0f +++ network/session.cc bb67e698a2ddb7f1ebbfde380445dfbf5a76340c @@ -653,7 +653,7 @@ bool session::handle_service_request() their_exclude)); break; case is_automate: - wrapped.reset(new automate_session(app, this, std::cin)); + wrapped.reset(new automate_session(app, this, 0, 0)); break; } ============================================================ --- tests/serve-automate-single-run/__driver__.lua 723bac05394be3b8628cfe70f6ba863b9ebbd7b1 +++ tests/serve-automate-single-run/__driver__.lua b2cc73cf028bd61486c8f9ca15fb7ffcded3d8f5 @@ -10,13 +10,13 @@ check(mtn2("automate", "remote", "--remo server = netsync.start() check(mtn2("automate", "remote", "--remote-stdio-host", server.address, - "interface_version"), 0, true, false) -check(qgrep("^0:2:l:", "stdout")) + "interface_version"), 0, true, true) +check(qgrep("you aren't allowed to do that", "stderr")) server:stop() -check(mtn2("automate", "stdio"), 0, true, false, "l6:leavese") -check(qgrep("^0:0:l:0:", "stdout")) +check(mtn2("automate", "stdio"), 0, true, nil, "l6:leavese") +check(qgrep("[[:xdigit:]]{40}", "stderr")) writefile("allow-automate.lua", "function get_remote_automate_permitted(x, y, z) return true end") @@ -25,15 +25,15 @@ check(mtn2("automate", "remote", "--remo check(mtn2("automate", "remote", "--remote-stdio-host", server.address, "interface_version"), 0, true, false) -check(qgrep("^0:0:l:", "stdout")) +check(qgrep("^[0-9]{2,}\.[0-9]+$", "stdout")) check(mtn2("automate", "remote", "--remote-stdio-host", server.address, "leaves"), 0, true, false) -check(qgrep("^0:0:l:", "stdout")) +check(qgrep("[[:xdigit:]]{40}", "stderr")) check(mtn2("automate", "remote", "--remote-stdio-host", server.address, - "stdio"), 0, true, false) -check(qgrep("can't be run", "stdout")) + "stdio"), 0, true, true) +check(qgrep("can't be run", "stderr")) -- won't work, --revision is no option of automate remote check(mtn2("automate", "remote", "--remote-stdio-host", server.address, @@ -43,8 +43,8 @@ check(mtn2("automate", "remote", "--remo -- 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")) + "get_file_of", "--", "-r", R1, "foo"), 0, true, true) +check(qgrep("wrong argument count", "stderr")) -- finally this should work check(mtn2("automate", "remote", "--remote-stdio-host", server.address,