# # # patch "cmd_automate.cc" # from [4c367f3de01bf1174049b589f95a3addde7866ec] # to [8562d374e86b77324df8a78372b7cfd961120a23] # # patch "cmd_netsync.cc" # from [27ebccae0f902d134ed780bc678b73c954613e43] # to [1c9f724505164da0026f77e4e81010fddc81faad] # # patch "sanity.cc" # from [392f1d3b1f8c9915ccb00933782985843b69b03e] # to [a3fe9554a6c56ec2c3ea2fb82338b5bbfae0ea0c] # # patch "sanity.hh" # from [dcf2a754227ec3554e16ef3aa856d503698d433f] # to [a4d155910fee1e4dff22cbaf0ee5309add304997] # # patch "ui.cc" # from [31589a9e86d23d92cb4f87b310c6eb920d026db6] # to [fb353e177a61d03aef4820424c0541cdb998bb7d] # # patch "ui.hh" # from [2623987665f579dc693dd37483c6a57a6b1bfc93] # to [2f9ec93ac4548f59787a0413e2ac404be702a754] # ============================================================ --- cmd_automate.cc 4c367f3de01bf1174049b589f95a3addde7866ec +++ cmd_automate.cc 8562d374e86b77324df8a78372b7cfd961120a23 @@ -420,6 +420,11 @@ CMD_AUTOMATE(stdio, "", opts = options::opts::globals() | acmd->opts(); opts.instantiate(&app.opts).from_key_value_pairs(params); + + // 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(); + acmd->exec_from_automate(app, id, args, os); } else @@ -430,7 +435,7 @@ CMD_AUTOMATE(stdio, "", os.set_err(2); //Do this instead of printing f.what directly so the output //will be split into properly-sized blocks automatically. - os._M_autobuf.write_out_of_band('e', f.what()); + global_sanity.maybe_write_to_out_of_band_handler('e', f.what()); } os.end_cmd(); } ============================================================ --- cmd_netsync.cc 27ebccae0f902d134ed780bc678b73c954613e43 +++ cmd_netsync.cc 1c9f724505164da0026f77e4e81010fddc81faad @@ -50,7 +50,7 @@ find_key(options & opts, return; rsa_keypair_id key; - + utf8 host(info.client.unparsed); if (!info.client.u.host.empty()) host = utf8(info.client.u.host); @@ -108,7 +108,7 @@ build_client_connection_info(options & o { N(!include_or_exclude_given, F("Include/exclude pattern was given both as part of the URL and as a separate argument.")); - + // Pull include/exclude from the query string char const separator = '/'; char const negate = '-'; @@ -127,7 +127,7 @@ build_client_connection_info(options & o if (begin < query.size()) end = query.find(separator, begin); } - + bool is_exclude = false; if (item.size() >= 1 && item.at(0) == negate) { @@ -143,7 +143,7 @@ build_client_connection_info(options & o is_exclude = true; item.erase(0, string("exclude=").size()); } - + if (is_exclude) excludes.push_back(arg_type(urldecode(item))); else @@ -152,7 +152,7 @@ build_client_connection_info(options & o info.client.include_pattern = globish(includes); info.client.exclude_pattern = globish(excludes); } - + // Maybe set the default values. if (!db.var_exists(default_server_key) || opts.set_default) { @@ -175,7 +175,7 @@ build_client_connection_info(options & o db.set_var(default_exclude_pattern_key, var_value(info.client.exclude_pattern())); } - + info.client.use_argv = lua.hook_get_netsync_connect_command(info.client.u, info.client.include_pattern, @@ -259,6 +259,26 @@ CMD(pull, "pull", "", CMD_REF(network), client_voice, sink_role, info); } +CMD_AUTOMATE(pull, N_("[ADDRESS[:PORTNUMBER] [PATTERN ...]]"), + N_("Pulls branches from a netsync server"), + "", + options::opts::set_default | options::opts::exclude) +{ + database db(app); + key_store keys(app); + project_t project(db); + + netsync_connection_info info; + extract_client_connection_info(app.opts, app.lua, db, keys, + args, info, false); + + if (app.opts.signing_key() == "") + P(F("doing anonymous pull; use -kKEYNAME if you need authentication")); + + run_netsync_protocol(app.opts, app.lua, project, keys, + client_voice, sink_role, info); +} + CMD(sync, "sync", "", CMD_REF(network), N_("[ADDRESS[:PORTNUMBER] [PATTERN ...]]"), N_("Synchronizes branches with a netsync server"), @@ -495,7 +515,7 @@ CMD_NO_WORKSPACE(serve, "serve", "", CMD pid_file pid(app.opts.pidfile); db.ensure_open(); - + netsync_connection_info info; info.server.addrs = app.opts.bind_uris; ============================================================ --- sanity.cc 392f1d3b1f8c9915ccb00933782985843b69b03e +++ sanity.cc a3fe9554a6c56ec2c3ea2fb82338b5bbfae0ea0c @@ -46,7 +46,7 @@ struct sanity::impl std::string gasp_dump; bool already_dumping; std::vector musings; - + void (*out_of_band_function)(char channel, std::string const& text, void *opaque); void *out_of_band_opaque; @@ -143,7 +143,7 @@ sanity::set_debug() inform_log((*i) + "\n"); } -void +void sanity::set_quiet() { I(imp); @@ -241,12 +241,9 @@ sanity::progress(i18n_format const & i18 { string str = do_format(i18nfmt, file, line); - if (imp->out_of_band_function) - { - (*imp->out_of_band_function)('p', str, imp->out_of_band_opaque); - return; - } - + if (maybe_write_to_out_of_band_handler('p', str)) + return; + if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); @@ -266,12 +263,9 @@ sanity::warning(i18n_format const & i18n { string str = do_format(i18nfmt, file, line); - if (imp->out_of_band_function) - { - (*imp->out_of_band_function)('w', str, imp->out_of_band_opaque); - return; - } - + if (maybe_write_to_out_of_band_handler('w', str)) + return; + if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); @@ -426,6 +420,16 @@ void sanity::set_out_of_band_handler(voi imp->out_of_band_opaque= opaque_data; } +bool sanity::maybe_write_to_out_of_band_handler(char channel, std::string const& str) +{ + if (imp->out_of_band_function) + { + (*imp->out_of_band_function)(channel, str, imp->out_of_band_opaque); + return true; + } + return false; +} + template <> void dump(string const & obj, string & out) { @@ -436,10 +440,10 @@ print_var(std::string const & value, cha print_var(std::string const & value, char const * var, char const * file, int const line, char const * func) { - std::cout << (FL("----- begin '%s' (in %s, at %s:%d)\n") + std::cout << (FL("----- begin '%s' (in %s, at %s:%d)\n") % var % func % file % line) << value - << (FL("\n----- end '%s' (in %s, at %s:%d)\n\n") + << (FL("\n----- end '%s' (in %s, at %s:%d)\n\n") % var % func % file % line); } ============================================================ --- sanity.hh dcf2a754227ec3554e16ef3aa856d503698d433f +++ sanity.hh a4d155910fee1e4dff22cbaf0ee5309add304997 @@ -50,10 +50,13 @@ struct sanity { // This takes a bare std::string because we don't want to expose vocab.hh // or paths.hh here. void set_dump_path(std::string const & path); - + // set out of band handler (e.g. for automate stdio) void set_out_of_band_handler(void (*out_of_band_function)(char channel, std::string const& text, void *opaque)=NULL, void *opaque_data=NULL); + // if such an out of band handler is set, this directly writes to it + bool maybe_write_to_out_of_band_handler(char channel, std::string const& str); + // A couple of places need to look at the debug flag to avoid doing // expensive logging if it's off. bool debug_p(); ============================================================ --- ui.cc 31589a9e86d23d92cb4f87b310c6eb920d026db6 +++ ui.cc fb353e177a61d03aef4820424c0541cdb998bb7d @@ -153,6 +153,17 @@ private: unsigned int chars_on_line; }; +struct tick_write_stdio : virtual public tick_writer +{ +public: + tick_write_stdio(); + ~tick_write_stdio(); + void write_ticks(); + void clear_line(); +private: + std::map last_ticks; +}; + struct tick_write_nothing : virtual public tick_writer { public: @@ -425,6 +436,52 @@ void tick_write_dot::clear_line() clog << endl; } + +tick_write_stdio::tick_write_stdio() +{} + +tick_write_stdio::~tick_write_stdio() +{} + +void tick_write_stdio::write_ticks() +{ + I(ui.imp); + string description, tickline; + + for (map::const_iterator i = ui.imp->tickers.begin(); + i != ui.imp->tickers.end(); ++i) + { + std::map::iterator it = + last_ticks.find(i->second->shortname); + // we output each explanation stanza just once and every time the + // total count has been changed + if (it == last_ticks.end() || it->second != i->second->total) + { + description += i->second->shortname + ":" + + i->second->name + ":" + + lexical_cast(i->second->total) + ";"; + + last_ticks.erase(i->second->shortname); + last_ticks[i->second->shortname] = i->second->total; + } + + tickline += i->second->shortname + ":" + lexical_cast(i->second->ticks); + tickline += ";"; + } + + if (!description.empty()) + { + global_sanity.maybe_write_to_out_of_band_handler('T', description); + } + global_sanity.maybe_write_to_out_of_band_handler('t', tickline); +} + +void tick_write_stdio::clear_line() +{ + global_sanity.maybe_write_to_out_of_band_handler('T', ""); + last_ticks.clear(); +} + // user_interface has both constructor/destructor and initialize/ // deinitialize because there's only one of these objects, it's // global, and we don't want global constructors/destructors doing @@ -435,7 +492,7 @@ void user_interface::initialize() void user_interface::initialize() { imp = new user_interface::impl; - + cout.exceptions(ios_base::badbit); #ifdef SYNC_WITH_STDIO_WORKS clog.sync_with_stdio(false); @@ -480,27 +537,48 @@ user_interface::set_tick_write_dot() user_interface::set_tick_write_dot() { I(imp); + if (tick_type == dot) + return; if (imp->t_writer != 0) delete imp->t_writer; imp->t_writer = new tick_write_dot; + tick_type = dot; } void user_interface::set_tick_write_count() { I(imp); + if (tick_type == count) + return; if (imp->t_writer != 0) delete imp->t_writer; imp->t_writer = new tick_write_count; + tick_type = count; } void +user_interface::set_tick_write_stdio() +{ + I(imp); + if (tick_type == stdio) + return; + if (imp->t_writer != 0) + delete imp->t_writer; + imp->t_writer = new tick_write_stdio; + tick_type = stdio; +} + +void user_interface::set_tick_write_nothing() { I(imp); + if (tick_type == none) + return; if (imp->t_writer != 0) delete imp->t_writer; imp->t_writer = new tick_write_nothing; + tick_type = none; } ============================================================ --- ui.hh 2623987665f579dc693dd37483c6a57a6b1bfc93 +++ ui.hh 2f9ec93ac4548f59787a0413e2ac404be702a754 @@ -41,6 +41,7 @@ struct tick_write_dot; struct tick_writer; struct tick_write_count; struct tick_write_dot; +struct tick_write_stdio; struct user_interface { @@ -60,6 +61,7 @@ public: void set_tick_trailer(std::string const & trailer); void set_tick_write_dot(); void set_tick_write_count(); + void set_tick_write_stdio(); void set_tick_write_nothing(); void ensure_clean_line(); void redirect_log_to(system_path const & filename); @@ -73,10 +75,12 @@ private: struct impl; impl * imp; + enum ticker_type {count, dot, stdio, none } tick_type; friend struct ticker; friend struct tick_write_count; friend struct tick_write_dot; + friend struct tick_write_stdio; }; extern struct user_interface ui;