# # # patch "CVS_prot" # from [c297cb4303299fc2656ea9798ba43071dc85eed5] # to [ad7cffdca453dd5a7672ea7686208681aee94337] # # patch "commands.cc" # from [8bec6786db5d009451c940b1bfb7df0205df1950] # to [f7ded5246dcb8b206e5028a577a459f5df37d486] # # patch "cvs_sync.cc" # from [b7e181235d9a7f9588cade65ea524cf63d7d3471] # to [2f85976038b9e2ed6de9adc4be3eadd109802e89] # # patch "cvs_sync.hh" # from [566f6de575131364cd5f4ecfd32584243448bd2f] # to [933657a2aee7b745ee0705a253f74cf1ea05f5c2] # ============================================================ --- CVS_prot c297cb4303299fc2656ea9798ba43071dc85eed5 +++ CVS_prot ad7cffdca453dd5a7672ea7686208681aee94337 @@ -1,3 +1,9 @@ +------- migration ------------ + +for i in `mt ls branches` ; do echo $i ; (~/localcvs/mt.cvs/monotone -b$i cvs_migrate >>/tmp/x) ; done + +------------------------------ + commands with a capital letter do not give a response first command must be Root (only as first command) ============================================================ --- commands.cc 8bec6786db5d009451c940b1bfb7df0205df1950 +++ commands.cc f7ded5246dcb8b206e5028a577a459f5df37d486 @@ -3848,6 +3848,11 @@ CMD(cvs_debug, "network", "COMMAND ARG", cvs_sync::debug(idx(args, 0)(), idx(args, 1)(), app); } +CMD(cvs_migrate, "debug", "", "output a migration command to mtn 0.31", OPT_BRANCH_NAME) +{ + if (args.size() != 0) throw usage(name); + cvs_sync::migrate(app); +} CMD(automate, N_("automation"), N_("interface_version\n" ============================================================ --- cvs_sync.cc b7e181235d9a7f9588cade65ea524cf63d7d3471 +++ cvs_sync.cc 2f85976038b9e2ed6de9adc4be3eadd109802e89 @@ -15,6 +15,9 @@ #include #include "stringtok.hh" #include "piece_table.hh" +#include "basic_io.hh" +#include +typedef std::string symbol; #ifdef WIN32 #define sleep(x) _sleep(x) @@ -146,6 +149,14 @@ std::string time_t2human(const time_t &t % tm->tm_sec).str(); } +std::string time_t2monotone(const time_t &t) +{ struct tm *tm; + tm=gmtime(&t); + return (boost::format("%04d-%02d-%02dT%02d:%02d:%02d") % (tm->tm_year+1900) + % (tm->tm_mon+1) % tm->tm_mday % tm->tm_hour % tm->tm_min + % tm->tm_sec).str(); +} + struct cvs_repository::get_all_files_log_cb : rlog_callbacks { cvs_repository &repo; get_all_files_log_cb(cvs_repository &r) : repo(r) {} @@ -1883,3 +1894,88 @@ void cvs_repository::retrieve_modules() piece::reset(); SetServerDir(sd); } + +static std::string escape(std::string const& a) +{ std::string result; + for (std::string::const_iterator i=a.begin();i!=a.end();++i) + { if (*i=='\'') result+="\\'"; + else if (*i=='/') result+="\\/"; + else if (*i=='\\') result+="\\\\"; + else result+=*i; + } + return result; +} + +namespace +{ + namespace syms + { + symbol const set("set"); + symbol const attr("attr"); + symbol const value("value"); + } +} + +static void print_attr(basic_io::printer & pr, std::string const& file, + std::string const& name, std::string const& value) +{ + basic_io::stanza st; + st.push_str_pair(syms::set, file); + st.push_str_pair(syms::attr, name); + st.push_str_pair(syms::value, value); + pr.print_stanza(st); +} + +void cvs_repository::migrate() +{ + I(!edges.empty()); + std::set::const_iterator e=--edges.end(); + I(!e->revision().empty()); // it's already in monotone + // output the revision descriptor + std::string domain="cvs"; + std::cout << "#!/bin/sh\n" + "DATABASE=mtn.db\n" + "OLD_REVISION="<< e->revision() <<"\n" + "REVISION=`mtn -d$DATABASE automate select 'b:" << escape(app.branch_name()) + << "/a:" << escape(e->author) << "/d:" << time_t2monotone(e->time) << "'`\n" + "# remove newline character\n" + "REVISION=`echo $REVISION`\n" + "(echo -n 'l13:put_sync_info40:'$REVISION'"<< domain.size() << ':' + << domain << "' ; cat < &sd=GetServerDir(); + for (std::map::const_iterator i=sd.begin(); + i!=sd.end();++i) + { if (i->first.empty() || i->second!=root+"/"+module+"/") + print_attr(printer, i->first, domain+":path", i->second); + } + cvs_manifest m=get_files(*e); + for (cvs_manifest::const_iterator i=m.begin(); i!=m.end(); ++i) + { print_attr(printer, i->first, domain+":revision", i->second->cvs_version); + if (!i->second->keyword_substitution.empty()) + print_attr(printer, i->first, domain+":keyword", i->second->keyword_substitution); + } + std::cout << str.str().size() << ':' << str.str() << "e\n" + "EOF\n"; +} + +void cvs_sync::migrate(app_state &app) +{ + std::string repository, module, branch; + + std::vector< revision > certs; + + I(!app.branch_name().empty()); + guess_repository(repository, module, branch, certs, app); + I(!repository.empty()); + I(!module.empty()); + cvs_sync::cvs_repository repo(app,repository,module,branch,false); + repo.process_certs(certs); + repo.migrate(); +} ============================================================ --- cvs_sync.hh 566f6de575131364cd5f4ecfd32584243448bd2f +++ cvs_sync.hh 933657a2aee7b745ee0705a253f74cf1ea05f5c2 @@ -170,6 +170,7 @@ public: // semi public interface for pus void prime(); void update(); void commit(); + void migrate(); void process_certs(const std::vector< revision > &certs); bool empty() const { return edges.empty() && files.empty(); } @@ -201,4 +202,5 @@ void takeover(app_state &app, const std: std::string const& branch, app_state &app); void debug(const std::string &command, const std::string &arg, app_state &app); void takeover(app_state &app, const std::string &module); +void migrate(app_state &app); } // end namespace cvs_sync