# # # patch "cmd_automate.cc" # from [cbb4b35759dc496636ca64ba63496f917b2cd7ea] # to [998cb92fdee6c695cd586dda3edc848f755dda8c] # # patch "sanity.cc" # from [7e4d028499e1899cddb4cbc6a91349c5e9e90721] # to [91dae4dd5cae11526178289c8a037eaff75b209f] # # patch "sanity.hh" # from [9b631056da3997a94b2310e7f10d65c219fa5312] # to [da312b526f8e0413e785e884a3207540ecbad92c] # # patch "ui.cc" # from [c1706a9c8cc139e1489b06515156c1171c0b071d] # to [e14df1817ba0aa50275c9228faa4a0b7f2fb83eb] # # patch "ui.hh" # from [5c9d5db3978343c279096c8aee2b51f8408feb4d] # to [5084fd606932e38f97f934cba2ad063e9c14b936] # ============================================================ --- cmd_automate.cc cbb4b35759dc496636ca64ba63496f917b2cd7ea +++ cmd_automate.cc 998cb92fdee6c695cd586dda3edc848f755dda8c @@ -15,6 +15,7 @@ #include "cmd.hh" #include "app_state.hh" #include "ui.hh" +#include "key_store.hh" #include "lua.hh" #include "lua_hooks.hh" #include "database.hh" @@ -315,6 +316,20 @@ public: out->flush(); } } + void write_out_of_band(char type, std::string const& data) + { + unsigned chunksize = _bufsize; + size_t length = data.size(), offset = 0; + do + { + if (offset+chunksize>length) + chunksize = length-offset; + (*out) << cmdnum << ':' << err << ':' << type << ':' + << chunksize << ':' << data.substr(offset, chunksize); + offset+= chunksize; + } while (offsetflush(); + } int_type overflow(int_type c = traits_type::eof()) { @@ -347,6 +362,11 @@ struct automate_ostream : public std::os { _M_autobuf.end_cmd(); } }; +static void out_of_band_to_automate_streambuf(char channel, std::string const& text, void *opaque) +{ + reinterpret_cast(opaque)->write_out_of_band(channel, text); +} + CMD_AUTOMATE(stdio, "", N_("Automates several commands in one run"), "", @@ -367,6 +387,8 @@ CMD_AUTOMATE(stdio, "", automate_reader ar(std::cin); vector > params; vector cmdline; + global_sanity.set_out_of_band_handler(&out_of_band_to_automate_streambuf, + &os._M_autobuf); while (true) { command const * cmd = 0; @@ -422,6 +444,10 @@ CMD_AUTOMATE(stdio, "", options::options_type opts; opts = options::opts::globals() | cmd->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(); } // FIXME: we need to re-package and rethrow this special exception // since it is not based on informative_failure @@ -458,6 +484,7 @@ CMD_AUTOMATE(stdio, "", } os.end_cmd(); } + global_sanity.set_out_of_band_handler(); } LUAEXT(mtn_automate, ) ============================================================ --- sanity.cc 7e4d028499e1899cddb4cbc6a91349c5e9e90721 +++ sanity.cc 91dae4dd5cae11526178289c8a037eaff75b209f @@ -75,6 +75,9 @@ struct sanity::impl bool already_dumping; std::vector musings; + void (*out_of_band_function)(char channel, std::string const& text, void *opaque); + void *out_of_band_opaque; + impl() : debug(false), quiet(false), reallyquiet(false), logbuf(0xffff), already_dumping(false) @@ -279,6 +282,9 @@ sanity::progress(i18n_format const & i18 { string str = do_format(i18nfmt, file, line); + if (maybe_write_to_out_of_band_handler('p', str)) + return; + if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); @@ -298,6 +304,9 @@ sanity::warning(i18n_format const & i18n { string str = do_format(i18nfmt, file, line); + if (maybe_write_to_out_of_band_handler('w', str)) + return; + if (str.size() > constants::log_line_sz) { str.resize(constants::log_line_sz); @@ -439,6 +448,22 @@ sanity::gasp() imp->already_dumping = false; } +void sanity::set_out_of_band_handler(void (*out_of_band_function)(char, std::string const&, void *), void *opaque_data) +{ + imp->out_of_band_function= out_of_band_function; + 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) { ============================================================ --- sanity.hh 9b631056da3997a94b2310e7f10d65c219fa5312 +++ sanity.hh da312b526f8e0413e785e884a3207540ecbad92c @@ -69,6 +69,12 @@ struct sanity { // 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 c1706a9c8cc139e1489b06515156c1171c0b071d +++ ui.cc e14df1817ba0aa50275c9228faa4a0b7f2fb83eb @@ -66,13 +66,14 @@ ticker::ticker(string const & tickname, }; ticker::ticker(string const & tickname, string const & s, size_t mod, - bool kilocount) : + bool kilocount, bool skip_display) : ticks(0), mod(mod), total(0), previous_total(0), kilocount(kilocount), use_total(false), + may_skip_display(skip_display), keyname(tickname), name(_(tickname.c_str())), shortname(s), @@ -154,6 +155,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: @@ -236,6 +248,12 @@ void tick_write_count::write_ticks() { ticker * tick = i->second; + // if the display of this ticker has no great importance, i.e. multiple + // other tickers should be displayed at the same time, skip its display + // to save space on terminals + if (tick->may_skip_display) + continue; + if ((tick->count_size == 0 && tick->kilocount) || (tick->use_total && tick->previous_total != tick->total)) @@ -428,6 +446,69 @@ 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 headers, sizes, 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()) + { + headers += i->second->shortname + ":" + i->second->name + ";"; + sizes += i->second->shortname + "=" + lexical_cast(i->second->total) + ";"; + last_ticks[i->second->shortname] = i->second->total; + } + else + if (it->second != i->second->total) + { + sizes += i->second->shortname + "=" + lexical_cast(i->second->total) + ";"; + last_ticks[i->second->shortname] = i->second->total; + } + + tickline += i->second->shortname + "#" + lexical_cast(i->second->ticks) + ";"; + } + + if (!headers.empty()) + { + global_sanity.maybe_write_to_out_of_band_handler('t', headers); + } + if (!sizes.empty()) + { + global_sanity.maybe_write_to_out_of_band_handler('t', sizes); + } + + I(!tickline.empty()); + global_sanity.maybe_write_to_out_of_band_handler('t', tickline); +} + +void tick_write_stdio::clear_line() +{ + std::map::iterator it; + std::string out; + + for (it = last_ticks.begin(); it != last_ticks.end(); it++) + { + out += it->first + ";"; + } + + global_sanity.maybe_write_to_out_of_band_handler('t', out); + 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 @@ -478,27 +559,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 5c9d5db3978343c279096c8aee2b51f8408feb4d +++ ui.hh 5084fd606932e38f97f934cba2ad063e9c14b936 @@ -29,12 +29,13 @@ struct ticker size_t previous_total; bool kilocount; bool use_total; + bool may_skip_display; std::string keyname; std::string name; // translated name std::string shortname; size_t count_size; ticker(std::string const & n, std::string const & s, size_t mod = 64, - bool kilocount=false); + bool kilocount=false, bool skip_display=false); void set_total(size_t tot) { use_total = true; total = tot; } void set_count_size(size_t csiz) { count_size = csiz; } void operator++(); @@ -45,6 +46,7 @@ struct tick_write_dot; struct tick_writer; struct tick_write_count; struct tick_write_dot; +struct tick_write_stdio; struct user_interface { @@ -65,6 +67,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); @@ -77,10 +80,12 @@ private: struct impl; impl * imp; + enum ticker_type { count=1, 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;