# # # patch "cmd_merging.cc" # from [7c7d8852f134cfdc8834adbb204504ff565538a1] # to [6426802bf8d8ac938a9ae6646a3e3545ce734134] # # patch "cmd_netsync.cc" # from [5f1360b0446a86c6e9fc646141a54e6e5a20dbe8] # to [39a96b273f26950ce8701dd041994f5c0b254877] # # patch "cmd_ws_commit.cc" # from [fe90cd162437b54a69abd9f1d9a42319fffea4e1] # to [f5b0f2b855eb5ebc84c07c9d2a252aad20e57155] # # patch "diff_patch.cc" # from [69b0da5fcfdf80ad434c482841d2d404757c20b3] # to [fd2359b6d78c7fa64d5c380f3ca6c72fe53d68f7] # # patch "diff_patch.hh" # from [86dc0e6ed925b86091b59948fc4a2779c78ca192] # to [c617b890148ef718647145fdd9d106d79c0e2ed9] # # patch "roster_merge.cc" # from [2022593f6ae34b8c306d29440264fbfabcdb07e0] # to [986299e8f70ee379d9d0113f16a65bd051615e8b] # # patch "sanity.hh" # from [199cc212e369ac57a758556faf52d530565b54c6] # to [7c69292b7148dbd84d3f9a8924f791fca9a10682] # # patch "tests/non_content_conflicts/__driver__.lua" # from [aa81cf5de17933a76239a517c094a700efcbc4c8] # to [fc66cec8d78d1c02e6e30824e058a1cce6b7dddd] # ============================================================ --- cmd_merging.cc 7c7d8852f134cfdc8834adbb204504ff565538a1 +++ cmd_merging.cc 6426802bf8d8ac938a9ae6646a3e3545ce734134 @@ -38,30 +38,34 @@ static void using boost::shared_ptr; static void -three_way_merge(roster_t const & ancestor_roster, - roster_t const & left_roster, roster_t const & right_roster, - roster_merge_result & result) +three_way_merge(revision_id const & ancestor_rid, roster_t const & ancestor_roster, + revision_id const & left_rid, roster_t const & left_roster, + revision_id const & right_rid, roster_t const & right_roster, + roster_merge_result & result, + marking_map & left_markings, + marking_map & right_markings) { MM(ancestor_roster); MM(left_roster); MM(right_roster); - // Make some fake rids - revision_id ancestor_rid(fake_id()); MM(ancestor_rid); - revision_id left_rid(fake_id()); MM(left_rid); - revision_id right_rid(fake_id()); MM(right_rid); + MM(ancestor_rid); + MM(left_rid); + MM(right_rid); // Mark up the ANCESTOR marking_map ancestor_markings; MM(ancestor_markings); mark_roster_with_no_parents(ancestor_rid, ancestor_roster, ancestor_markings); // Mark up the LEFT roster - marking_map left_markings; MM(left_markings); + left_markings.clear(); + MM(left_markings); mark_roster_with_one_parent(ancestor_roster, ancestor_markings, left_rid, left_roster, left_markings); // Mark up the RIGHT roster - marking_map right_markings; MM(right_markings); + right_markings.clear(); + MM(right_markings); mark_roster_with_one_parent(ancestor_roster, ancestor_markings, right_rid, right_roster, right_markings); @@ -70,6 +74,9 @@ three_way_merge(roster_t const & ancesto safe_insert(left_uncommon_ancestors, left_rid); safe_insert(right_uncommon_ancestors, right_rid); + P(F("[left] %s") % left_rid); + P(F("[right] %s") % right_rid); + // And do the merge roster_merge(left_roster, left_markings, left_uncommon_ancestors, right_roster, right_markings, right_uncommon_ancestors, @@ -235,25 +242,40 @@ CMD(update, "update", "", CMD_REF(worksp database::roster_t_cp old_roster = parent_cached_roster(parents.begin()).first; MM(*old_roster); - roster_t working_roster; MM(working_roster); - app.work.get_current_roster_shape(working_roster, nis); - app.work.update_current_roster_from_filesystem(working_roster); + shared_ptr working_roster = shared_ptr(new roster_t()); + + MM(*working_roster); + app.work.get_current_roster_shape(*working_roster, nis); + app.work.update_current_roster_from_filesystem(*working_roster); + + revision_t working_rev; + revision_id working_rid; + make_revision_for_workspace(parents, *working_roster, working_rev); + calculate_ident(working_rev, working_rid); + // Get the CHOSEN roster roster_t chosen_roster; MM(chosen_roster); app.db.get_roster(chosen_rid, chosen_roster); + // And finally do the merge roster_merge_result result; - three_way_merge(*old_roster, working_roster, chosen_roster, result); + marking_map left_markings, right_markings; + three_way_merge(old_rid, *old_roster, + working_rid, *working_roster, + chosen_rid, chosen_roster, + result, left_markings, right_markings); roster_t & merged_roster = result.roster; map paths; - get_content_paths(working_roster, paths); + get_content_paths(*working_roster, paths); - content_merge_workspace_adaptor wca(app, old_roster, paths); - resolve_merge_conflicts(working_roster, chosen_roster, + content_merge_workspace_adaptor wca(app, old_rid, old_roster, + left_markings, right_markings, paths); + wca.cache_roster(working_rid, working_roster); + resolve_merge_conflicts(*working_roster, chosen_roster, result, wca, app); // Make sure it worked... @@ -262,7 +284,7 @@ CMD(update, "update", "", CMD_REF(worksp // Now finally modify the workspace cset update; - make_cset(working_roster, merged_roster, update); + make_cset(*working_roster, merged_roster, update); app.work.perform_content_update(update, wca); revision_t remaining; @@ -632,7 +654,7 @@ CMD(merge_into_workspace, "merge_into_wo { revision_id left_id, right_id; database::cached_roster left, right; - roster_t working_roster; + shared_ptr working_roster = shared_ptr(new roster_t()); if (args.size() != 1) throw usage(execid); @@ -643,6 +665,8 @@ CMD(merge_into_workspace, "merge_into_wo // This command cannot be applied to a workspace with more than one parent // (revs can have no more than two parents). + revision_id working_rid; + { parent_map parents; app.work.get_parent_rosters(parents); @@ -650,15 +674,19 @@ CMD(merge_into_workspace, "merge_into_wo F("this command can only be used in a single-parent workspace")); temp_node_id_source nis; - app.work.get_current_roster_shape(working_roster, nis); - app.work.update_current_roster_from_filesystem(working_roster); + app.work.get_current_roster_shape(*working_roster, nis); + app.work.update_current_roster_from_filesystem(*working_roster); - N(parent_roster(parents.begin()) == working_roster, + N(parent_roster(parents.begin()) == *working_roster, F("'%s' can only be used in a workspace with no pending changes") % join_words(execid)()); left_id = parent_id(parents.begin()); left = parent_cached_roster(parents.begin()); + + revision_t working_rev; + make_revision_for_workspace(parents, *working_roster, working_rev); + calculate_ident(working_rev, working_rid); } complete(app, idx(args, 0)(), right_id); @@ -682,9 +710,11 @@ CMD(merge_into_workspace, "merge_into_wo app.db.get_roster(lca_id, lca); map paths; - get_content_paths(working_roster, paths); + get_content_paths(*working_roster, paths); - content_merge_workspace_adaptor wca(app, lca.first, paths); + content_merge_workspace_adaptor wca(app, lca_id, lca.first, + *left.second, *right.second, paths); + wca.cache_roster(working_rid, working_roster); resolve_merge_conflicts(*left.first, *right.first, merge_result, wca, app); // Make sure it worked... @@ -866,10 +896,11 @@ CMD(pluck, "pluck", "", CMD_REF(workspac app.db.get_roster(from_rid, *from_roster); // Get the WORKING roster - roster_t working_roster; MM(working_roster); - app.work.get_current_roster_shape(working_roster, nis); + shared_ptr working_roster = shared_ptr(new roster_t()); + MM(*working_roster); + app.work.get_current_roster_shape(*working_roster, nis); - app.work.update_current_roster_from_filesystem(working_roster); + app.work.update_current_roster_from_filesystem(*working_roster); // Get the FROM->TO cset... cset from_to_to; MM(from_to_to); @@ -883,32 +914,52 @@ CMD(pluck, "pluck", "", CMD_REF(workspac *from_roster, to_true_roster, app); roster_t restricted_roster; - make_restricted_roster(*from_roster, to_true_roster, + make_restricted_roster(*from_roster, to_true_roster, restricted_roster, mask); - + make_cset(*from_roster, restricted_roster, from_to_to); make_cset(restricted_roster, to_true_roster, from_to_to_excluded); } N(!from_to_to.empty(), F("no changes to be applied")); // ...and use it to create the TO roster - roster_t to_roster; MM(to_roster); + shared_ptr to_roster = shared_ptr(new roster_t()); + MM(*to_roster); { - to_roster = *from_roster; - editable_roster_base editable_to_roster(to_roster, nis); + *to_roster = *from_roster; + editable_roster_base editable_to_roster(*to_roster, nis); from_to_to.apply_to(editable_to_roster); } + parent_map parents; + app.work.get_parent_rosters(parents); + + revision_t working_rev; + revision_id working_rid; + make_revision_for_workspace(parents, *working_roster, working_rev); + calculate_ident(working_rev, working_rid); + // Now do the merge roster_merge_result result; - three_way_merge(*from_roster, working_roster, to_roster, result); + marking_map left_markings, right_markings; + three_way_merge(from_rid, *from_roster, + working_rid, *working_roster, + to_rid, *to_roster, + result, left_markings, right_markings); roster_t & merged_roster = result.roster; map paths; - get_content_paths(working_roster, paths); + get_content_paths(*working_roster, paths); - content_merge_workspace_adaptor wca(app, from_roster, paths); - resolve_merge_conflicts(working_roster, to_roster, + content_merge_workspace_adaptor wca(app, from_rid, from_roster, + left_markings, right_markings, paths); + + wca.cache_roster(working_rid, working_roster); + // cache the synthetic to_roster under the to_rid so that the real + // to_roster is not fetched from the db which does not have temporary nids + wca.cache_roster(to_rid, to_roster); + + resolve_merge_conflicts(*working_roster, *to_roster, result, wca, app); I(result.is_clean()); @@ -918,17 +969,15 @@ CMD(pluck, "pluck", "", CMD_REF(workspac // we apply the working to merged cset to the workspace cset update; MM(update); - make_cset(working_roster, merged_roster, update); + make_cset(*working_roster, merged_roster, update); E(!update.empty(), F("no changes were applied")); app.work.perform_content_update(update, wca); P(F("applied changes to workspace")); // and record any remaining changes in _MTN/revision - parent_map parents; revision_t remaining; MM(remaining); - app.work.get_parent_rosters(parents); make_revision_for_workspace(parents, merged_roster, remaining); // small race condition here... ============================================================ --- cmd_netsync.cc 5f1360b0446a86c6e9fc646141a54e6e5a20dbe8 +++ cmd_netsync.cc 39a96b273f26950ce8701dd041994f5c0b254877 @@ -307,7 +307,7 @@ CMD(clone, "clone", "", CMD_REF(network) P(F("setting default branch include pattern to '%s'") % include_pattern); app.db.set_var(default_include_pattern_key, var_value(include_pattern())); } - + if (app.opts.exclude_given) { if (!app.db.var_exists(default_exclude_pattern_key) @@ -317,10 +317,10 @@ CMD(clone, "clone", "", CMD_REF(network) app.db.set_var(default_exclude_pattern_key, var_value(exclude_pattern())); } } - + // make sure we're back in the original dir so that file: URIs work change_current_working_dir(start_dir); - + std::list uris; uris.push_back(addr); @@ -380,11 +380,8 @@ CMD(clone, "clone", "", CMD_REF(network) cset checkout; make_cset(*empty_roster, current_roster, checkout); - map paths; - get_content_paths(*empty_roster, paths); + content_merge_checkout_adaptor wca(app); - content_merge_workspace_adaptor wca(app, empty_roster, paths); - app.work.perform_content_update(checkout, wca, false); app.work.update_any_attrs(); ============================================================ --- cmd_ws_commit.cc fe90cd162437b54a69abd9f1d9a42319fffea4e1 +++ cmd_ws_commit.cc f5b0f2b855eb5ebc84c07c9d2a252aad20e57155 @@ -102,7 +102,7 @@ get_log_message_interactively(revision_t revision_summary(cs, app.opts.branchname, summary); external summary_external; utf8_to_system_best_effort(summary, summary_external); - + utf8 branch_comment = utf8((F("branch \"%s\"\n\n") % app.opts.branchname).str()); external branch_external; utf8_to_system_best_effort(branch_comment, branch_external); @@ -167,7 +167,7 @@ CMD(revert, "revert", "", CMD_REF(worksp temp_node_id_source nis; app.work.get_current_roster_shape(new_roster, nis); } - + node_restriction mask(args_to_paths(args), args_to_paths(app.opts.exclude_patterns), app.opts.depth, @@ -205,15 +205,15 @@ CMD(revert, "revert", "", CMD_REF(worksp // from the new roster *back* to the restricted roster roster_t restricted_roster; - make_restricted_roster(new_roster, old_roster, restricted_roster, + make_restricted_roster(new_roster, old_roster, restricted_roster, mask); - + make_cset(old_roster, restricted_roster, preserved); - - // The preserved cset will be left pending in MTN/revision + // The preserved cset will be left pending in MTN/revision + // if/when reverting through the editable_tree interface use - // make_cset(new_roster, restricted_roster, reverted); + // make_cset(new_roster, restricted_roster, reverted); // to get a cset that gets us back to the restricted roster // from the current workspace roster @@ -617,11 +617,8 @@ CMD(checkout, "checkout", "co", CMD_REF( cset checkout; make_cset(*empty_roster, current_roster, checkout); - map paths; - get_content_paths(*empty_roster, paths); + content_merge_checkout_adaptor wca(app); - content_merge_workspace_adaptor wca(app, empty_roster, paths); - app.work.perform_content_update(checkout, wca, false); app.work.update_any_attrs(); @@ -782,7 +779,7 @@ CMD(attr_set, "set", "", CMD_REF(attr), // format: ('attr', name, value), ('state', [unchanged|changed|added|dropped]) // occurs: zero or more times // -// Error conditions: If the path has no attributes, prints only the +// Error conditions: If the path has no attributes, prints only the // format version, if the file is unknown, escalates CMD_AUTOMATE(get_attributes, N_("PATH"), N_("Prints all attributes for the specified path"), @@ -813,20 +810,20 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), // create the printer basic_io::printer pr; - + // print the format version basic_io::stanza st; st.push_str_pair(basic_io::syms::format_version, "1"); pr.print_stanza(st); - + // the current node holds all current attributes (unchanged and new ones) node_t n = current.get_node(path); - for (full_attr_map_t::const_iterator i = n->attrs.begin(); + for (full_attr_map_t::const_iterator i = n->attrs.begin(); i != n->attrs.end(); ++i) { std::string value(i->second.second()); std::string state; - + // if if the first value of the value pair is false this marks a // dropped attribute if (!i->second.first) @@ -836,16 +833,16 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), // because if it is dropped there as well it was already deleted // in any previous revision I(base.has_node(path)); - + node_t prev_node = base.get_node(path); - + // find the attribute in there full_attr_map_t::const_iterator j = prev_node->attrs.find(i->first); I(j != prev_node->attrs.end()); - + // was this dropped before? then ignore it if (!j->second.first) { continue; } - + state = "dropped"; // output the previous (dropped) value later value = j->second.second(); @@ -856,16 +853,16 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), if (base.has_node(path)) { node_t prev_node = base.get_node(path); - full_attr_map_t::const_iterator j = + full_attr_map_t::const_iterator j = prev_node->attrs.find(i->first); - + // the attribute is new if it either hasn't been found // in the previous roster or has been deleted there if (j == prev_node->attrs.end() || !j->second.first) { state = "added"; } - // check if the attribute's value has been changed + // check if the attribute's value has been changed else if (i->second.second() != j->second.second()) { state = "changed"; @@ -881,14 +878,14 @@ CMD_AUTOMATE(get_attributes, N_("PATH"), state = "added"; } } - + basic_io::stanza st; st.push_str_triple(basic_io::syms::attr, i->first(), value); st.push_str_pair(symbol("state"), state); pr.print_stanza(st); } - - // print the output + + // print the output output.write(pr.buf.data(), pr.buf.size()); } @@ -940,7 +937,7 @@ CMD_AUTOMATE(set_attribute, N_("PATH KEY // 1: file / directory name // 2: attribute key (optional) // Added in: 5.0 -// Purpose: Edits the workspace revision and drops an attribute or all +// Purpose: Edits the workspace revision and drops an attribute or all // attributes of the specified path // // Error conditions: If PATH is unknown in the new roster or the specified @@ -1106,7 +1103,7 @@ CMD(commit, "commit", "ci", CMD_REF(work set heads; app.get_project().get_branch_heads(app.opts.branchname, heads); unsigned int old_head_size = heads.size(); - + { transaction_guard guard(app.db); @@ -1115,7 +1112,7 @@ CMD(commit, "commit", "ci", CMD_REF(work else { L(FL("inserting new revision %s") % restricted_rev_id); - + for (edge_map::const_iterator edge = restricted_rev.edges.begin(); edge != restricted_rev.edges.end(); edge++) ============================================================ --- diff_patch.cc 69b0da5fcfdf80ad434c482841d2d404757c20b3 +++ diff_patch.cc fd2359b6d78c7fa64d5c380f3ca6c72fe53d68f7 @@ -603,7 +603,15 @@ content_merge_database_adaptor::get_vers // content_merge_workspace_adaptor /////////////////////////////////////////////////////////////////////////// + void +content_merge_workspace_adaptor::cache_roster(revision_id const & rid, + boost::shared_ptr roster) +{ + rosters.insert(std::make_pair(rid, roster)); +} + +void content_merge_workspace_adaptor::record_merge(file_id const & left_id, file_id const & right_id, file_id const & merged_id, @@ -624,11 +632,39 @@ content_merge_workspace_adaptor::get_anc revision_id & rid, shared_ptr & anc) { - // When doing an update, the base revision is always the ancestor to - // use for content merging. - anc = base; + // Begin by loading any non-empty file lca roster + if (base->has_node(nid)) + { + rid = lca; + anc = base; + } + else + { + marking_map::const_iterator lmm = left_mm.find(nid); + marking_map::const_iterator rmm = right_mm.find(nid); - // FIXME: return something for rid + MM(left_mm); + MM(right_mm); + + if (lmm == left_mm.end()) + { + I(rmm != right_mm.end()); + rid = rmm->second.birth_revision; + } + else if (rmm == right_mm.end()) + { + I(lmm != left_mm.end()); + rid = lmm->second.birth_revision; + } + else + { + I(lmm->second.birth_revision == rmm->second.birth_revision); + rid = lmm->second.birth_revision; + } + + load_and_cache_roster(rid, rosters, anc, app); + } + I(anc); } void @@ -661,6 +697,37 @@ content_merge_workspace_adaptor::get_ver /////////////////////////////////////////////////////////////////////////// +// content_merge_checkout_adaptor +/////////////////////////////////////////////////////////////////////////// + +void +content_merge_checkout_adaptor::record_merge(file_id const & left_ident, + file_id const & right_ident, + file_id const & merged_ident, + file_data const & left_data, + file_data const & right_data, + file_data const & merged_data) +{ + I(false); +} + +void +content_merge_checkout_adaptor::get_ancestral_roster(node_id nid, + revision_id & rid, + shared_ptr & anc) +{ + I(false); +} + +void +content_merge_checkout_adaptor::get_version(file_id const & ident, + file_data & dat) const +{ + app.db.get_file_version(ident, dat); +} + + +/////////////////////////////////////////////////////////////////////////// // content_merger /////////////////////////////////////////////////////////////////////////// ============================================================ --- diff_patch.hh 86dc0e6ed925b86091b59948fc4a2779c78ca192 +++ diff_patch.hh c617b890148ef718647145fdd9d106d79c0e2ed9 @@ -69,11 +69,11 @@ content_merge_database_adaptor marking_map const & left_mm; marking_map const & right_mm; std::map > rosters; - content_merge_database_adaptor (app_state & app, - revision_id const & left, - revision_id const & right, - marking_map const & left_mm, - marking_map const & right_mm); + content_merge_database_adaptor(app_state & app, + revision_id const & left, + revision_id const & right, + marking_map const & left_mm, + marking_map const & right_mm); void record_merge(file_id const & left_ident, file_id const & right_ident, file_id const & merged_ident, @@ -95,13 +95,25 @@ content_merge_workspace_adaptor { std::map temporary_store; app_state & app; + revision_id const lca; boost::shared_ptr base; + marking_map const & left_mm; + marking_map const & right_mm; + std::map > rosters; std::map content_paths; content_merge_workspace_adaptor(app_state & app, + revision_id const & lca, boost::shared_ptr base, + marking_map const & left_mm, + marking_map const & right_mm, std::map const & paths) - : app(app), base(base), content_paths(paths) + : app(app), lca(lca), base(base), + left_mm(left_mm), right_mm(right_mm), content_paths(paths) {} + + void cache_roster(revision_id const & rid, + boost::shared_ptr roster); + void record_merge(file_id const & left_ident, file_id const & right_ident, file_id const & merged_ident, @@ -117,6 +129,32 @@ content_merge_workspace_adaptor file_data & dat) const; }; +struct +content_merge_checkout_adaptor + : public content_merge_adaptor +{ + app_state & app; + content_merge_checkout_adaptor(app_state & app) + : app(app) + {} + + void record_merge(file_id const & left_ident, + file_id const & right_ident, + file_id const & merged_ident, + file_data const & left_data, + file_data const & right_data, + file_data const & merged_data); + + void get_ancestral_roster(node_id nid, + revision_id & rid, + boost::shared_ptr & anc); + + void get_version(file_id const & ident, + file_data & dat) const; + +}; + + struct content_merger { app_state & app; ============================================================ --- roster_merge.cc 2022593f6ae34b8c306d29440264fbfabcdb07e0 +++ roster_merge.cc 986299e8f70ee379d9d0113f16a65bd051615e8b @@ -30,8 +30,12 @@ dump(divergent_name_conflict const & con { ostringstream oss; oss << "node: " << conflict.nid << "\n" - << "left: " << conflict.left.first << " " << conflict.left.second << "\n" - << "right: " << conflict.right.first << " " << conflict.right.second << "\n"; + << "left\n" + << " parent: " << conflict.left.first << "\n" + << " basename: " << conflict.left.second << "\n" + << "right\n" + << " parent: " << conflict.right.first << "\n" + << " basename: " << conflict.right.second << "\n"; out = oss.str(); } @@ -61,7 +65,8 @@ dump(orphaned_node_conflict const & conf { ostringstream oss; oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << " '" << conflict.parent_name.second << "'\n"; + << "parent: " << conflict.parent_name.first << "\n" + << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -71,7 +76,8 @@ dump(convergent_name_conflict const & co ostringstream oss; oss << "left: " << conflict.left_nid << "\n" << "right: " << conflict.right_nid << "\n" - << "parent: " << conflict.parent_name.first << " '" << conflict.parent_name.second << "'\n"; + << "parent: " << conflict.parent_name.first << "\n" + << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -80,7 +86,8 @@ dump(directory_loop_conflict const & con { ostringstream oss; oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << " '" << conflict.parent_name.second << "'\n"; + << "parent: " << conflict.parent_name.first << "\n" + << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -89,7 +96,8 @@ dump(illegal_name_conflict const & confl { ostringstream oss; oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << " '" << conflict.parent_name.second << "'\n"; + << "parent: " << conflict.parent_name.first << "\n" + << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } ============================================================ --- sanity.hh 199cc212e369ac57a758556faf52d530565b54c6 +++ sanity.hh 7c69292b7148dbd84d3f9a8924f791fca9a10682 @@ -149,7 +149,7 @@ plain_format {} }; -template inline plain_format const & +template inline plain_format const & operator %(plain_format const & f, T const & t) { f.get_stream() << t; @@ -157,7 +157,7 @@ operator %(plain_format const & f, T con return f; } -template inline plain_format const & +template inline plain_format const & operator %(const plain_format & f, T & t) { f.get_stream() << t; @@ -165,7 +165,7 @@ operator %(const plain_format & f, T & t return f; } -template inline plain_format & +template inline plain_format & operator %(plain_format & f, T const & t) { f.get_stream() << t; @@ -173,7 +173,7 @@ operator %(plain_format & f, T const & t return f; } -template inline plain_format & +template inline plain_format & operator %(plain_format & f, T & t) { f.get_stream() << t; @@ -219,13 +219,13 @@ i18n_format explicit i18n_format(const char * localized_pattern) : format_base(localized_pattern, true) {} - + explicit i18n_format(std::string const & localized_pattern) : format_base(localized_pattern, true) {} }; -template inline i18n_format const & +template inline i18n_format const & operator %(i18n_format const & f, T const & t) { f.get_stream() << t; @@ -233,7 +233,7 @@ operator %(i18n_format const & f, T cons return f; } -template inline i18n_format const & +template inline i18n_format const & operator %(i18n_format const & f, T & t) { f.get_stream() << t; @@ -241,7 +241,7 @@ operator %(i18n_format const & f, T & t) return f; } -template inline i18n_format & +template inline i18n_format & operator %(i18n_format & f, T const & t) { f.get_stream() << t; @@ -249,7 +249,7 @@ operator %(i18n_format & f, T const & t) return f; } -template inline i18n_format & +template inline i18n_format & operator %(i18n_format & f, T & t) { f.get_stream() << t; @@ -438,7 +438,7 @@ extern void print_var(std::string const // debugging utility to dump out vars like MM but without requiring a crash extern void print_var(std::string const & value, - std::string const & var, + char const * var, char const * file, int const line, char const * func); ============================================================ --- tests/non_content_conflicts/__driver__.lua aa81cf5de17933a76239a517c094a700efcbc4c8 +++ tests/non_content_conflicts/__driver__.lua fc66cec8d78d1c02e6e30824e058a1cce6b7dddd @@ -16,17 +16,27 @@ commit("divergent") check(mtn("mv", "foo", "bar"), 0, false, false) commit("divergent") +other = base_revision() revert_to(base) check(mtn("mv", "foo", "baz"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: multiple names", "stderr")) + commit("divergent") check(mtn("merge", "--branch", "divergent"), 1, false, true) check(qgrep("conflict: multiple names", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: multiple names", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: multiple names", "stderr")) + -- convergent name conflict (adds) remove("_MTN") @@ -42,17 +52,27 @@ commit("convergent-adds") check(mtn("mv", "xxx", "bar"), 0, false, false) --addfile("bar", "convergent add bar1") commit("convergent-adds") +other = base_revision() revert_to(base) addfile("bar", "convergent add bar2") + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + commit("convergent-adds") check(mtn("merge", "--branch", "convergent-adds"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + -- convergent name conflict (renames) remove("_MTN") @@ -66,17 +86,27 @@ commit("convergent-renames") check(mtn("mv", "foo", "abc"), 0, false, false) commit("convergent-renames") +other = base_revision() revert_to(base) check(mtn("mv", "bar", "abc"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + commit("convergent-renames") check(mtn("merge", "--branch", "convergent-renames"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + -- convergent name conflict (add-rename) remove("_MTN") @@ -89,17 +119,27 @@ commit("convergent-add-rename") check(mtn("mv", "foo", "bar"), 0, false, false) commit("convergent-add-rename") +other = base_revision() revert_to(base) addfile("bar", "convervent add rename bar") + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + commit("convergent-add-rename") check(mtn("merge", "--branch", "convergent-add-rename"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + -- directory loop conflict remove("_MTN") @@ -117,17 +157,27 @@ commit("loop") check(mtn("mv", "foo", "bar"), 0, false, false) commit("loop") +other = base_revision() revert_to(base) check(mtn("mv", "bar", "foo"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: directory loop", "stderr")) + commit("loop") check(mtn("merge", "--branch", "loop"), 1, false, true) check(qgrep("conflict: directory loop", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: directory loop", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: directory loop", "stderr")) + -- orphaned add remove("_MTN") @@ -146,17 +196,28 @@ commit("orphaned-add") check(mtn("mv", "foo/bar", "foo/baz"), 0, false, false) commit("orphaned-add") +other = base_revision() + revert_to(base) remove("foo") check(mtn("drop", "--recursive", "foo"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + commit("orphaned-add") check(mtn("merge", "--branch", "orphaned-add"), 1, false, true) -check(qgrep("orphaned file", "stderr")) +check(qgrep("conflict: orphaned file", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + -- orphaned rename remove("_MTN") @@ -175,18 +236,28 @@ commit("orphaned-rename") commit("orphaned-rename") check(mtn("mv", "foo/bar", "foo/baz"), 0, false, false) commit("orphaned-rename") +other = base_revision() revert_to(base) remove("foo") check(mtn("drop", "--recursive", "foo"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + commit("orphaned-rename") check(mtn("merge", "--branch", "orphaned-rename"), 1, false, true) -check(qgrep("orphaned file", "stderr")) +check(qgrep("conflict: orphaned file", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + -- invalid name add remove("_MTN") @@ -202,16 +273,27 @@ check(indir("invalid", mtn("commit", "-- check(indir("invalid", mtn("pivot_root", "foo", "bar")), 0, true, true) check(indir("invalid", mtn("commit", "--message", "commit")), 0, false, false) +other = indir("invalid", {base_revision})[1]() + mkdir("foo/_MTN") addfile("foo/_MTN/foo", "invalid foo") addfile("foo/_MTN/bar", "invalid bar") + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) + commit("invalid-add") check(mtn("merge", "--branch", "invalid-add"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) + -- invalid name rename remove("_MTN") @@ -229,15 +311,26 @@ check(indir("invalid", mtn("commit", "-- check(mtn("co", "--branch", "invalid-rename", "invalid"), 0, false, false) check(indir("invalid", mtn("pivot_root", "foo", "bar")), 0, true, true) check(indir("invalid", mtn("commit", "--message", "commit")), 0, false, false) +other = indir("invalid", {base_revision})[1]() check(mtn("mv", "bad/_MTN", "foo/_MTN"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) + commit("invalid-rename") check(mtn("merge", "--branch", "invalid-rename"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: invalid name", "stderr")) + + -- missing root conflict remove("_MTN") @@ -254,13 +347,26 @@ check(indir("missing", mtn("commit", "-- --check(indir("missing", mtn("drop", "--recursive", "bar")), 0, true, true) check(indir("missing", mtn("commit", "--message", "commit")), 0, false, false) +other = indir("missing", {base_revision})[1]() + check(mtn("drop", "--recursive", "foo"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: missing root directory", "stderr")) + commit("missing") check(mtn("merge", "--branch", "missing"), 1, false, true) check(qgrep("conflict: missing root directory", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: missing root directory", "stderr")) +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: missing root directory", "stderr")) + + + -- attribute conflict on attached node remove("_MTN") @@ -276,16 +382,29 @@ commit("attribute-attached") check(mtn("attr", "set", "foo", "attr1", "valueX"), 0, false, false) check(mtn("attr", "set", "foo", "attr2", "valueY"), 0, false, false) commit("attribute-attached") +other = base_revision() revert_to(base) check(mtn("attr", "set", "foo", "attr1", "valueZ"), 0, false, false) check(mtn("attr", "drop", "foo", "attr2"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + commit("attribute-attached") check(mtn("merge", "--branch", "attribute-attached"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + + + -- attribute conflict on detached node remove("_MTN") @@ -302,14 +421,24 @@ commit("attribute-detached") check(mtn("attr", "set", "foo", "attr2", "valueY"), 0, false, false) check(mtn("mv", "foo", "bar"), 0, false, false) commit("attribute-detached") +other = base_revision() revert_to(base) check(mtn("attr", "set", "foo", "attr1", "valueZ"), 0, false, false) check(mtn("attr", "drop", "foo", "attr2"), 0, false, false) check(mtn("mv", "foo", "baz"), 0, false, false) + +check(mtn("update"), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + commit("attribute-detached") check(mtn("merge", "--branch", "attribute-detached"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) +check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + +check(mtn("merge_into_workspace", other), 1, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr"))