# # patch "ChangeLog" # from [f36da866416989a6399a2f6d9797b129547c6b9c] # to [9df88607ee3b9fde1203282405f9fee132ba61d3] # # patch "change_set.cc" # from [002e0964b7401655ae7ab7fe308cb82be578e89a] # to [8c37c6f09b401fcf164561e83f7c0f6e04d6358d] # # patch "lua.cc" # from [40cea21efcbbbcb98eb2c502cf971b10ab76e521] # to [06b516d959c5061c34107be35a5673217de796b8] # # patch "lua.hh" # from [38945dd7ac35f3f1ef7d4027ad1874f8b3716e26] # to [62639d2342ef3924e4077b614bef6b5fd7a57358] # # patch "pcdv.cc" # from [e5afc13109510eba3626bacb2c335c5ea9b479e4] # to [109b9384a6d250b492e7704aa2e3a9e1b2be001f] # # patch "pcdv.hh" # from [17325b49d29d3b78d11828c7355867d975d63229] # to [8c7faa78892b3ec390925c665c00cd50df87181c] # # patch "std_hooks.lua" # from [b6bde98342f50a4bd4f89e236849bdea43399397] # to [350e0f8222b1e2174ff85844718d6aaf1477ab25] # ======================================================================== --- ChangeLog f36da866416989a6399a2f6d9797b129547c6b9c +++ ChangeLog 9df88607ee3b9fde1203282405f9fee132ba61d3 @@ -1,5 +1,10 @@ 2005-08-22 Timothy Brownawell + * tree merger: Allow tree conflicts to be resolved by the user. + New lua hook resolve_path_conflicts. + +2005-08-22 Timothy Brownawell + * commands.cc: remove tree merger from the pcdv test driver 2005-08-22 Timothy Brownawell @@ -139,49 +144,6 @@ Will be moved to a more appropriate home once it works (currenty has insane memory usage). -2005-08-20 Matthew Gregan - - * revision.hh: Delete doubled line of text in comment. - -2005-08-20 Benoît Dejean - - * monotone.cc (cpp_main): setlocale(LC_ALL). - * commands.cc (dropkey): Unify warning into a single string. - -2005-08-20 Nathaniel Smith - - * contrib/monoprof.sh (test_commit): Kernel tarball unpacks to - linux-$KVER/, not $KVER/. - -2005-08-19 Nathaniel Smith - - * contrib/monoprof.sh (SETUP): Put netsync hooks in the default - hook file. - -2005-08-19 Nathaniel Smith - - * contrib/monoprof.sh: Give a sensible error message if $DATADIR - doesn't exist. - -2005-08-20 Matt Johnston - - * database.cc (put_revision): uncomment check_sane_history call - (was accidentally committed commented out) - -2005-08-19 Nathaniel Smith - - * monotone.texi (Tutorial): Tweak wording, use --db at more - appropriate places. - -2005-08-19 Matthew Gregan - - * tests/t_crlf.at: Adjust expected line count to accomodate diff - output change. - * commands.cc (CMD(diff)): Include base revision ID in diff output - header when diffing against working copy. Useful to identify what - revision a patch was created against. - * std_hooks.lua (ignore_file): Ignore Visual SourceSafe junk. - 2005-08-18 Timothy Brownawell * std_hooks.lua: accept_testresult_change now only cares about ======================================================================== --- change_set.cc 002e0964b7401655ae7ab7fe308cb82be578e89a +++ change_set.cc 8c37c6f09b401fcf164561e83f7c0f6e04d6358d @@ -1904,11 +1904,19 @@ } tree_state -merge_trees(tree_state l, tree_state r) +merge_trees(tree_state l, tree_state r, app_state & app) { std::vector conf(l.conflict(r)); MM(conf); std::set res; + if (!conf.empty()) + { + data c, r; + write_path_conflicts(conf, c); + app.lua.hook_resolve_path_conflicts(c, r); + read_path_resolutions(r, res); + } +/* for (std::vector::const_iterator i = conf.begin(); i != conf.end(); ++i) { @@ -1917,6 +1925,7 @@ if (i->type == path_conflict::collision) W(F("Filename collision, suturing...")); } +*/ std::vector lr; lr.push_back(l); lr.push_back(r); @@ -2075,7 +2084,7 @@ tree_state r = k->second; // do the merge - tree_state m = merge_trees(l, r); + tree_state m = merge_trees(l, r, app); // calculate outputs calculate_itempaths(a, l, r, m, paths, itx); @@ -2238,7 +2247,7 @@ tree_state changes = merge_trees(treevec, chvec, itx, "changes"); // merge - tree_state result = merge_trees(left, changes); + tree_state result = merge_trees(left, changes, app); // calculate outputs std::vector paths; ======================================================================== --- lua.cc 40cea21efcbbbcb98eb2c502cf971b10ab76e521 +++ lua.cc 06b516d959c5061c34107be35a5673217de796b8 @@ -1336,3 +1336,18 @@ ll.call(4, 0); return ll.ok(); } + +bool +lua_hooks::hook_resolve_path_conflicts(data const & orig, + data & result) +{ + string res; + bool ok = Lua(st) + .func("resolve_path_conflicts") + .push_str(orig()) + .call(1,1) + .extract_str(res) + .ok(); + result = res; + return ok; +} ======================================================================== --- lua.hh 38945dd7ac35f3f1ef7d4027ad1874f8b3716e26 +++ lua.hh 62639d2342ef3924e4077b614bef6b5fd7a57358 @@ -135,6 +135,9 @@ rsa_keypair_id const & kid, cert_name const & name, cert_value const & value); + + bool hook_resolve_path_conflicts(data const & orig, + data & result); }; #endif // __LUA_HH__ ======================================================================== --- pcdv.cc e5afc13109510eba3626bacb2c335c5ea9b479e4 +++ pcdv.cc 109b9384a6d250b492e7704aa2e3a9e1b2be001f @@ -1,7 +1,8 @@ #include #include #include #include +#include #include "sanity.hh" #include "pcdv.hh" @@ -1562,6 +1563,7 @@ apply_sutures(); tree_state merged(mash(other)); std::vector out; + MM(out); std::map > m; // splits, merge(mv a b, mv a c) @@ -1583,10 +1585,21 @@ std::set left(j->second.current_names()), right(k->second.current_names()); - I(left.size() == 1); - I(right.size() == 1); - c.lnames.push_back(get_full_name(*left.begin())); - c.rnames.push_back(other.get_full_name(*right.begin())); + I((left.size() == 1 && right.size() == 1) || left == right); + if (left.size() == 1) + { + c.lnames.push_back(get_full_name(*left.begin())); + c.rnames.push_back(other.get_full_name(*right.begin())); + } + else + { + E(left.size() == 2, F("Item has too many names.")); + std::set::const_iterator + k = left.begin(); + c.lnames.push_back(get_full_name(*k)); + ++k; + c.rnames.push_back(get_full_name(*k)); + } out.push_back(c); } for (std::set::const_iterator @@ -1794,6 +1807,7 @@ std::set const & res, std::string const & revision) { + MM(res); tree_state merged(mash(revs)); merged.apply_sutures(); @@ -1807,6 +1821,7 @@ i != res.end(); ++i) { file_path fp(i->second); + P(F("Item %1% resolved to '%2%'") % i->first % i->second); splitpath sp; split_path(fp, sp); sorted.insert(make_pair(sp.size(), make_pair(i->first, sp))); @@ -1814,6 +1829,8 @@ typedef int fpid; interner cit; std::map names; + fpid rootid = cit.intern(file_path()()); + names.insert(make_pair(rootid, -1)); typedef std::pair::iterator, bool> nir; int lastlevel = 0; for (std::multimap >::const_iterator @@ -1854,7 +1871,7 @@ splitpath sp(i->second.second); unsigned int s = resolved.size(); resolved.insert(id); - std::map::const_iterator + std::map::iterator j = merged.states->find(id); I(j != merged.states->end()); item_status it = j->second; @@ -1884,9 +1901,6 @@ std::map::const_iterator k = names.find(pd); I(k != names.end()); - std::map::iterator - j = merged.states->find(k->second); - I(j != merged.states->end()); j->second = item_status(j->second.rename(merged.itx->intern(revision), k->second, name)); if (fp == file_path()) @@ -1906,8 +1920,15 @@ { if (resolved.find(j->first) == resolved.end()) { - file_path fp(merged.get_full_name(j->second)); resolved.insert(j->first); + std::set + x(j->second.current_names()); + if (x.size() != 1) + continue;// not resolved, so ignore + int d; + file_path fp(merged.try_get_full_name(*x.begin(), d)); + if (d == -1) + continue;// not resolved, so ignore if (fp == file_path()) continue; fpid f(cit.intern(fp())); @@ -2038,19 +2059,63 @@ void dump(path_conflict const & obj, std::string & out) { - out = "##########"; + out = "##########\n"; out+=(F("#Type: %1%\n") % ((obj.type == path_conflict::collision)?"Collision":"Split")).str(); for (unsigned int j = 0; j < obj.items.size(); ++j) { - out+=(F("Item %1%:\n") % idx(obj.items, j)).str(); - out+=(F("#\tLname: %1%\n") % idx(obj.lnames, j)).str(); - out+=(F("#\tRname: %1%\n") % idx(obj.rnames, j)).str(); + out+=(F("Item %1%: ''\n") % idx(obj.items, j)).str(); + out+=(F("#\tLname: '%1%'\n") % idx(obj.lnames, j)).str(); + out+=(F("#\tRname: '%1%'\n") % idx(obj.rnames, j)).str(); } - out+=(F("#Name: %1%\n") % obj.name).str(); + out+=(F("#Name: '%1%'\n") % obj.name).str(); } void +dump(std::set const & obj, std::string & out) +{ + out.clear(); + for (std::set::const_iterator i = obj.begin(); + i != obj.end(); ++i) + out += (F("Item %1%: '%2%'\n") % i->first % i->second).str(); +} + +void +read_path_resolution(data const & in, path_conflict::resolution & obj) +{ + boost::regex pat("Item ([[:digit:]]+)\\: '(.*)'"); + boost::smatch m; + N(boost::regex_match(in(), m, pat), F("Malformed resolution.")); + I(m.size() == 3);// 2 parentheses + the expr itself + std::string idstr(m[1].first, m[1].second); + MM(idstr); + obj.first = boost::lexical_cast(idstr); + obj.second = std::string(m[2].first, m[2].second); +} + +void +split_into_lines(std::string const & in, + std::vector & out); + +void +read_path_resolutions(data const & in, + std::set & obj) +{ + std::vector lines; + split_into_lines(in(), lines); + for (std::vector::const_iterator i = lines.begin(); + i != lines.end(); ++i) + { + if (i->size() && (*i)[0] != '#') + { + path_conflict::resolution r; + read_path_resolution(data(*i), r); + obj.insert(r); + } + } +} + +void dump(std::vector const & obj, std::string & out) { out.clear(); @@ -2063,7 +2128,15 @@ } } +void +write_path_conflicts(std::vector const & pc, data & dat) +{ + std::string s; + dump(pc, s); + dat = data(s); +} + ///////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////// /////////////////////////// Tests /////////////////////////////////// ======================================================================== --- pcdv.hh 17325b49d29d3b78d11828c7355867d975d63229 +++ pcdv.hh 8c7faa78892b3ec390925c665c00cd50df87181c @@ -338,9 +338,22 @@ dump(path_conflict const & obj, std::string & out); void +read_path_resolution(data const & in, path_conflict::resolution & obj); + +void +read_path_resolutions(data const & in, + std::set & obj); + +void dump(std::vector const & obj, std::string & out); void +dump(std::set const & obj, std::string & out); + +void +write_path_conflicts(std::vector const & pc, data & dat); + +void dirmerge_test(); #endif ======================================================================== --- std_hooks.lua b6bde98342f50a4bd4f89e236849bdea43399397 +++ std_hooks.lua 350e0f8222b1e2174ff85844718d6aaf1477ab25 @@ -671,3 +671,34 @@ os.remove (old_file); os.remove (new_file); end + + +function resolve_path_conflicts(conflicts) + local exe = "vi" + local visual = os.getenv("VISUAL") + if (visual ~= nil) then exe = visual end + local editor = os.getenv("EDITOR") + if (editor ~= nil) then exe = editor end + + local tmp, tname = temp_file() + if (tmp == nil) then return nil end + tmp:write(conflicts) + io.close(tmp) + + if (execute(exe, tname) ~= 0) then + os.remove(tname) + return nil + end + + tmp = io.open(tname, "r") + if (tmp == nil) then os.remove(tname); return nil end + local res = "" + local line = tmp:read() + while(line ~= nil) do + res = res .. line .. "\n" + line = tmp:read() + end + io.close(tmp) + os.remove(tname) + return res +end