[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Monotone-commits-diffs] net.venge.monotone.issue-209: d4a22d4d54c5ab65e
From: |
code |
Subject: |
[Monotone-commits-diffs] net.venge.monotone.issue-209: d4a22d4d54c5ab65e491cd43f0f12a3b96b45c78 |
Date: |
Mon, 23 Jul 2012 11:01:12 +0200 (CEST) |
revision: d4a22d4d54c5ab65e491cd43f0f12a3b96b45c78
date: 2012-07-16T11:51:51
author: address@hidden
branch: net.venge.monotone.issue-209
changelog:
restructure dropped_modified conflicts to handle duplicate_name; first draft.
compiles, but not complete; commited for backup
* doc/monotone.texi (Conflicts): add user_rename conflict resolution
* src/merge_roster.hh: restructure dropped_modified conflicts to handle
duplicate_name; store rename in file_resolution_t.
* src/cmd_conflicts.cc:
* src/merge_conflict.cc:
* src/merge_content.cc:
* src/merge_roster.cc: dropped_modified conflicts handle duplicate_name
* test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2: new
test case that shows duplicate_name/dropped_modified
manifest:
format_version "1"
new_manifest [e25b70e5808ad7e5c4103889103497defff9578f]
old_revision [d6e8f82dc157a9aa5b10b2f11106067683e6f93d]
add_dir "test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2"
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/__driver__.lua"
content [46e918155fe50737229d3c2cb31899cf204ef9fd]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2"
content [bb23f1fbf87e4f1dcb8aa7c4c3fcb90e1fc84fed]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2_resolved"
content [954b8dfc7ee161c1ca809b61d03ad8fd12bfb539]
patch "doc/monotone.texi"
from [d1225486c4df3ec2023d0e303aac65b8ff10a54e]
to [0f1e2230272b68614efad33648dbf436e0d6f729]
patch "src/cmd_conflicts.cc"
from [e1b7feca5acd314d85498cabedf888f5293bf30e]
to [c4c2c75feb32cce46f146e05aba424c038152ded]
patch "src/merge_conflict.cc"
from [34fbc891bc8455202d9c0d0a495beb690fd8a5a0]
to [d653ef4d1d748fa833b2500eed77ecc0107d48fb]
patch "src/merge_content.cc"
from [662433acaf08fc1f3f3417389a9bc3b3d2bd9bf1]
to [6a1d7ad7184f88674a585f5065e965f15294f7dc]
patch "src/merge_roster.cc"
from [5fbc50c114df22f4753f444aa137c06ea0f06195]
to [b4de8ec7db2c60b3ebb777bfa58d9e0d8986558d]
patch "src/merge_roster.hh"
from [34d382b0ad333fa0f052e8640a88c1ece03caaa9]
to [63eab7b216f8839626f9d9d04dc8e58c3eed90bf]
============================================================
--- doc/monotone.texi d1225486c4df3ec2023d0e303aac65b8ff10a54e
+++ doc/monotone.texi 0f1e2230272b68614efad33648dbf436e0d6f729
@@ -1,4 +1,4 @@
-0\input texinfo @c -*-texinfo-*-
+\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename monotone.info
@settitle monotone documentation
@@ -5232,6 +5232,16 @@ @subheading Conflict resolutions
@command{resolved_rename_right @var{filename}} conflict resolution in
the conflicts file.
address@hidden user_rename @var{contents_file} @var{rename_file}
+The file contents are replaced by the contents of the specified file,
+and renamed.
+
+This inserts a @command{resolved_user_left @var{contents_file}} or
address@hidden @var{contents_file}} conflict resolution
+in the conflicts file, and a @command{resolved_rename_left
address@hidden or @command{resolved_rename_right
address@hidden conflict resolution.
+
@item keep
The file is kept in the merge.
============================================================
--- src/cmd_conflicts.cc e1b7feca5acd314d85498cabedf888f5293bf30e
+++ src/cmd_conflicts.cc c4c2c75feb32cce46f146e05aba424c038152ded
@@ -60,7 +60,7 @@ show_conflicts(database & db, conflicts_
{
orphaned_node_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
file_path name;
if (conflicts.left_roster->has_node(conflict.nid))
@@ -90,83 +90,102 @@ show_conflicts(database & db, conflicts_
{
dropped_modified_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none ||
+ conflict.right_resolution.resolution == resolve_conflicts::none)
{
- node_id nid;
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- // left side dropped, right side modified
- nid = conflict.right_nid;
+ case resolve_conflicts::left_side:
conflicts.right_roster->get_name(conflict.right_nid, modified_name);
- }
- else
- {
- // left side modified, right side dropped
- nid = conflict.left_nid;
+ break;
+
+ case resolve_conflicts::right_side:
conflicts.left_roster->get_name(conflict.left_nid, modified_name);
+ break;
}
P(F("conflict: file '%s'") % modified_name);
if (conflict.orphaned)
{
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
P(F("orphaned on the left"));
P(F("modified on the right"));
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left"));
P(F("orphaned on the right"));
}
}
else
{
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- if (conflict.recreated == the_null_node)
+ case resolve_conflicts::left_side:
+ if (conflict.left_nid == the_null_node)
P(F("dropped on the left"));
else
- P(F("dropped and recreated on the left"));
+ {
+ // we can't distinguish duplicate name from recreated
+ P(F("dropped and recreated on the left"));
+ }
P(F("modified on the right"));
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left"));
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
P(F("dropped on the right"));
else
- P(F("dropped and recreated on the right"));
+ {
+ P(F("dropped and recreated on the right"));
+ }
}
}
- switch (show_case)
- {
- case first:
- P(F("possible resolutions:"));
+ if (show_case == remaining) return;
- if (conflict.recreated == the_null_node)
- P(F("resolve_first drop"));
+ P(F("possible resolutions:"));
- if (conflict.orphaned)
+ if (conflict.left_nid == the_null_node || conflict.right_nid == the_null_node)
+ {
+ // only one file involved; only need one resolution
+ P(F("resolve_first drop"));
+ P(F("resolve_first rename"));
+ P(F("resolve_first user_rename \"new_content_name\" \"new_file_name\""));
+
+ if (!conflict.orphaned)
{
- P(F("resolve_first rename"));
- P(F("resolve_first user_rename \"new_content_name\" \"new_file_name\""));
- return;
- }
- else
- {
P(F("resolve_first keep"));
P(F("resolve_first user \"name\""));
- return;
}
+ return;
+ }
+ else
+ {
+ // recreated or repeated duplicate name; need two resolutions
+ P(F("resolve_first_left drop"));
+ P(F("resolve_first_right drop"));
- case remaining:
- break;
+ P(F("resolve_first_left rename"));
+ P(F("resolve_first_right rename"));
+ P(F("resolve_first_left user_rename \"new_content_name\" \"new_file_name\""));
+ P(F("resolve_first_right user_rename \"new_content_name\" \"new_file_name\""));
+
+ if (!conflict.orphaned)
+ {
+ P(F("resolve_first_left keep"));
+ P(F("resolve_first_right keep"));
+ P(F("resolve_first_left user \"name\""));
+ P(F("resolve_first_right user \"name\""));
+ }
+ return;
}
}
}
@@ -177,8 +196,8 @@ show_conflicts(database & db, conflicts_
{
duplicate_name_conflict & conflict = *i;
- if (conflict.left_resolution.first == resolve_conflicts::none ||
- conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none ||
+ conflict.right_resolution.resolution == resolve_conflicts::none)
{
file_path left_name;
conflicts.left_roster->get_name(conflict.left_nid, left_name);
@@ -189,7 +208,7 @@ show_conflicts(database & db, conflicts_
case first:
P(F("possible resolutions:"));
- if (conflict.left_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
P(F("resolve_first_left drop"));
P(F("resolve_first_left keep"));
@@ -197,7 +216,7 @@ show_conflicts(database & db, conflicts_
P(F("resolve_first_left user \"name\""));
}
- if (conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
P(F("resolve_first_right drop"));
P(F("resolve_first_right keep"));
@@ -218,7 +237,7 @@ show_conflicts(database & db, conflicts_
{
file_content_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
file_path name;
conflicts.left_roster->get_name(conflict.nid, name);
@@ -330,48 +349,58 @@ static void
} // do_interactive_merge
static void
-set_duplicate_name_conflict(resolve_conflicts::file_resolution_t & resolution,
- resolve_conflicts::file_resolution_t const & other_resolution,
- args_vector const & args)
+set_resolution(resolve_conflicts::file_resolution_t & resolution,
+ resolve_conflicts::file_resolution_t const & other_resolution,
+ args_vector const & args)
{
if ("drop" == idx(args, 0)())
{
E(args.size() == 1, origin::user, F("too many arguments"));
- resolution.first = resolve_conflicts::drop;
+ resolution.resolution = resolve_conflicts::drop;
}
else if ("keep" == idx(args, 0)())
{
E(args.size() == 1, origin::user, F("too many arguments"));
- E(other_resolution.first == resolve_conflicts::none ||
- other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::none ||
+ other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename ||
+ other_resolution.resolution == resolve_conflicts::content_user_rename,
origin::user,
- F("other resolution must be 'drop' or 'rename'"));
- resolution.first = resolve_conflicts::keep;
+ F("other resolution must be 'drop', 'rename', or 'user_rename'"));
+ resolution.resolution = resolve_conflicts::keep;
}
else if ("rename" == idx(args, 0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- resolution.first = resolve_conflicts::rename;
- resolution.second = resolve_conflicts::new_file_path(idx(args,1)());
+ resolution.resolution = resolve_conflicts::rename;
+ resolution.rename = file_path_external(utf8(idx(args,1)(), origin::user));
}
else if ("user" == idx(args, 0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- E(other_resolution.first == resolve_conflicts::none ||
- other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::none ||
+ other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename ||
+ other_resolution.resolution == resolve_conflicts::content_user_rename,
origin::user,
- F("other resolution must be 'drop' or 'rename'"));
+ F("other resolution must be 'drop', 'rename', or 'user_rename'"));
- resolution.first = resolve_conflicts::content_user;
- resolution.second = new_optimal_path(idx(args,1)(), false);
+ resolution.resolution = resolve_conflicts::content_user;
+ resolution.content = new_optimal_path(idx(args,1)(), false);
}
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+
+ resolution.resolution = resolve_conflicts::content_user_rename;
+ resolution.content = new_optimal_path(idx(args,1)(), false);
+ resolution.rename = file_path_external(utf8(idx(args,2)(), origin::user));
+ }
else
E(false, origin::user,
F(conflict_resolution_not_supported_msg) % idx(args,0) % "duplicate_name");
-} //set_duplicate_name_conflict
+} // set_resolution
static void
set_first_conflict(database & db,
@@ -384,6 +413,48 @@ set_first_conflict(database & db,
if (side != neither)
{
+ for (std::vector<dropped_modified_conflict>::iterator i = conflicts.result.dropped_modified_conflicts.begin();
+ i != conflicts.result.dropped_modified_conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict & conflict = *i;
+
+ // here we only allow two resolutions; single resolutions are handled below
+
+ switch (side)
+ {
+ case left:
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
+ {
+ E(conflict.left_nid != the_null_node, origin::user,
+ F("must specify resolve_first (not _left or _right)"));
+
+ if ("keep" == idx(args,0)())
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ set_resolution(conflict.left_resolution, conflict.right_resolution, args);
+ return;
+ }
+ break;
+ case right:
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
+ {
+ E(conflict.right_nid != the_null_node, origin::user,
+ F("must specify resolve_first (not _left or _right)"));
+
+ if ("keep" == idx(args,0)())
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ set_resolution(conflict.right_resolution, conflict.left_resolution, args);
+ return;
+ }
+ break;
+ case neither:
+ // can't get here
+ break;
+ }
+ }
+
for (std::vector<duplicate_name_conflict>::iterator i = conflicts.result.duplicate_name_conflicts.begin();
i != conflicts.result.duplicate_name_conflicts.end();
++i)
@@ -393,17 +464,17 @@ set_first_conflict(database & db,
switch (side)
{
case left:
- if (conflict.left_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
- set_duplicate_name_conflict(conflict.left_resolution, conflict.right_resolution, args);
+ set_resolution(conflict.left_resolution, conflict.right_resolution, args);
return;
}
break;
case right:
- if (conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
- set_duplicate_name_conflict(conflict.right_resolution, conflict.left_resolution, args);
+ set_resolution(conflict.right_resolution, conflict.left_resolution, args);
return;
}
break;
@@ -422,20 +493,20 @@ set_first_conflict(database & db,
{
orphaned_node_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
if ("drop" == idx(args,0)())
{
E(args.size() == 1, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::drop;
+ conflict.resolution.resolution = resolve_conflicts::drop;
}
else if ("rename" == idx(args,0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::rename;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ conflict.resolution.resolution = resolve_conflicts::rename;
+ conflict.resolution.content = new_optimal_path(idx(args,1)(), false);
}
else
{
@@ -452,53 +523,104 @@ set_first_conflict(database & db,
{
dropped_modified_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ // Here we only allow single resolutions; two resolutions are handled above
+
+ switch (conflict.dropped_side)
{
- if ("drop" == idx(args,0)())
+ case resolve_conflicts::left_side:
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
- E(args.size() == 1, origin::user, F("wrong number of arguments"));
- E(conflict.recreated == the_null_node, origin::user, F("recreated files may not be dropped"));
+ if ("drop" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::drop;
- }
- else if ("keep" == idx(args,0)())
- {
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
+ }
+ else if ("keep" == idx(args,0)())
+ {
E(args.size() == 1, origin::user, F("wrong number of arguments"));
E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
- conflict.resolution.first = resolve_conflicts::keep;
+ conflict.left_resolution.resolution = resolve_conflicts::keep;
+ }
+ else if ("user" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ conflict.left_resolution.resolution = resolve_conflicts::content_user;
+ conflict.left_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("rename" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
+ conflict.left_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ conflict.left_resolution.content = new_optimal_path(idx(args,1)(), false);
+ conflict.left_resolution.rename = file_path_external(utf8(idx(args,2)(), origin::user));
+ }
+ else
+ {
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
+ }
+ return;
}
- else if ("user" == idx(args,0)())
+ break;
+ case resolve_conflicts::right_side:
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
- E(args.size() == 2, origin::user, F("wrong number of arguments"));
+ if ("drop" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ }
+ else if ("keep" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
- conflict.resolution.first = resolve_conflicts::content_user;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
- }
- else if ("rename" == idx(args,0)())
- {
- E(args.size() == 2, origin::user, F("wrong number of arguments"));
- E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+ conflict.right_resolution.resolution = resolve_conflicts::keep;
+ }
+ else if ("user" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
- conflict.resolution.first = resolve_conflicts::rename;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
- }
- else if ("user_rename" == idx(args,0)())
- {
- E(args.size() == 3, origin::user, F("wrong number of arguments"));
- E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
+ conflict.right_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("rename" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::content_user_rename;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
- conflict.rename = file_path_external(utf8(idx(args,2)(), origin::user));
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
+ conflict.right_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ conflict.right_resolution.content = new_optimal_path(idx(args,1)(), false);
+ conflict.right_resolution.rename = file_path_external(utf8(idx(args,2)(), origin::user));
+ }
+ else
+ {
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
+ }
+ return;
}
- else
- {
- E(false, origin::user,
- F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
- }
- return;
+ break;
}
}
@@ -508,7 +630,7 @@ set_first_conflict(database & db,
{
file_content_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
if ("interactive" == idx(args,0)())
{
@@ -543,8 +665,8 @@ set_first_conflict(database & db,
if (do_interactive_merge(db, lua, conflicts, conflict.nid,
conflict.ancestor, conflict.left, conflict.right, result_path))
{
- conflict.resolution.first = resolve_conflicts::content_user;
- conflict.resolution.second = boost::shared_ptr<any_path>(new bookkeeping_path(result_path));
+ conflict.resolution.resolution = resolve_conflicts::content_user;
+ conflict.resolution.content = boost::shared_ptr<any_path>(new bookkeeping_path(result_path));
P(F("interactive merge result saved in '%s'") % result_path.as_internal());
}
else
@@ -554,8 +676,8 @@ set_first_conflict(database & db,
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::content_user;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ conflict.resolution.resolution = resolve_conflicts::content_user;
+ conflict.resolution.content = new_optimal_path(idx(args,1)(), false);
}
else
{
============================================================
--- src/merge_conflict.cc 34fbc891bc8455202d9c0d0a495beb690fd8a5a0
+++ src/merge_conflict.cc d653ef4d1d748fa833b2500eed77ecc0107d48fb
@@ -1,4 +1,4 @@
-// Copyright (C) 2005 Nathaniel Smith <address@hidden>
+// Copyright (C) 2005, 2012 Nathaniel Smith <address@hidden>
// 2008, 2009, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
@@ -86,11 +86,9 @@ namespace resolve_conflicts
namespace resolve_conflicts
{
- shared_ptr<any_path>
- new_file_path(string path)
+ file_path file_path_external(string path)
{
- return shared_ptr<any_path>
- (new file_path(file_path_external(utf8(path, origin::user))));
+ return file_path_external(utf8(path, origin::user));
};
}
@@ -396,11 +394,9 @@ put_attr_conflict (basic_io::stanza & st
}
}
-enum side_t {left_side, right_side};
-
static void
-put_file_resolution(basic_io::stanza & st,
- side_t side,
+put_file_resolution(basic_io::stanza & st,
+ resolve_conflicts::side_t side,
resolve_conflicts::file_resolution_t const & resolution)
{
// We output any resolution for any conflict; only valid resolutions
@@ -408,7 +404,7 @@ put_file_resolution(basic_io::stanza & s
// resolutions from files we check that the resolution is valid for the
// conflict. Hence there is no read_resolution.
- switch (resolution.first)
+ switch (resolution.resolution)
{
case resolve_conflicts::none:
break;
@@ -416,12 +412,12 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::content_user:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_user_left, resolution.content->as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_user_right, resolution.content->as_external());
break;
}
break;
@@ -429,15 +425,16 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::content_user_rename:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_user_left, resolution.content->as_external());
+ st.push_str_pair(syms::resolved_rename_left, resolution.rename.as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_user_right, resolution.content->as_external());
+ st.push_str_pair(syms::resolved_rename_right, resolution.rename.as_external());
break;
}
- // value for rename is put by caller
break;
case resolve_conflicts::content_internal:
@@ -447,12 +444,12 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::rename:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_rename_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_rename_left, resolution.rename.as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_rename_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_rename_right, resolution.rename.as_external());
break;
}
break;
@@ -460,11 +457,11 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::drop:
switch (side)
{
- case left_side:
+ case resolve_conflicts::left_side:
st.push_symbol(syms::resolved_drop_left);
break;
- case right_side:
+ case resolve_conflicts::right_side:
st.push_symbol(syms::resolved_drop_right);
break;
}
@@ -473,11 +470,11 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::keep:
switch (side)
{
- case left_side:
+ case resolve_conflicts::left_side:
st.push_symbol(syms::resolved_keep_left);
break;
- case right_side:
+ case resolve_conflicts::right_side:
st.push_symbol(syms::resolved_keep_right);
break;
}
@@ -535,7 +532,7 @@ put_content_conflict (basic_io::stanza &
st.push_file_pair(syms::left_name, left_name);
st.push_file_pair(syms::right_name, right_name);
}
- put_file_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.resolution);
}
static void
@@ -1001,7 +998,7 @@ roster_merge_result::report_orphaned_nod
if (basic_io)
{
- put_file_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.resolution);
put_stanza (st, output);
}
}
@@ -1101,21 +1098,21 @@ roster_merge_result::report_dropped_modi
node_id nid;
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- // left side dropped, right side modified
+ case resolve_conflicts::left_side:
I(!roster.is_attached(conflict.right_nid));
nid = conflict.right_nid;
right_roster.get_name(conflict.right_nid, modified_name);
- }
- else
- {
- // left side modified, right side dropped
+ break;
+
+ case resolve_conflicts::right_side:
I(!roster.is_attached(conflict.left_nid));
nid = conflict.left_nid;
left_roster.get_name(conflict.left_nid, modified_name);
+ break;
}
shared_ptr<roster_t const> lca_roster;
@@ -1137,8 +1134,9 @@ roster_merge_result::report_dropped_modi
db_adaptor.db.get_file_content (db_adaptor.lca, nid, fid);
st.push_binary_pair(syms::ancestor_file_id, fid.inner());
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
if (conflict.orphaned)
{
st.push_str_pair(syms::left_type, "orphaned file");
@@ -1147,7 +1145,7 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.left_nid == the_null_node)
{
st.push_str_pair(syms::left_type, "dropped file");
push_dropped_details(db_adaptor, syms::left_rev, syms::left_name, syms::left_file_id,
@@ -1157,21 +1155,18 @@ roster_merge_result::report_dropped_modi
{
st.push_str_pair(syms::left_type, "recreated file");
st.push_str_pair(syms::left_name, modified_name.as_external());
- db_adaptor.db.get_file_content (db_adaptor.left_rid, conflict.recreated, fid);
+ db_adaptor.db.get_file_content (db_adaptor.left_rid, conflict.left_nid, fid);
st.push_binary_pair(syms::left_file_id, fid.inner());
}
}
- }
- else
- {
+
st.push_str_pair(syms::left_type, "modified file");
st.push_str_pair(syms::left_name, modified_name.as_external());
db_adaptor.db.get_file_content (db_adaptor.left_rid, nid, fid);
st.push_binary_pair(syms::left_file_id, fid.inner());
- }
+ break;
- if (conflict.right_nid == the_null_node)
- {
+ case resolve_conflicts::right_side:
if (conflict.orphaned)
{
st.push_str_pair(syms::right_type, "orphaned file");
@@ -1180,7 +1175,7 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
{
st.push_str_pair(syms::right_type, "dropped file");
push_dropped_details(db_adaptor, syms::right_rev, syms::right_name, syms::right_file_id,
@@ -1190,59 +1185,44 @@ roster_merge_result::report_dropped_modi
{
st.push_str_pair(syms::right_type, "recreated file");
st.push_str_pair(syms::right_name, modified_name.as_external());
- db_adaptor.db.get_file_content (db_adaptor.right_rid, conflict.recreated, fid);
+ db_adaptor.db.get_file_content (db_adaptor.right_rid, conflict.right_nid, fid);
st.push_binary_pair(syms::right_file_id, fid.inner());
}
}
- }
- else
- {
+
st.push_str_pair(syms::right_type, "modified file");
st.push_str_pair(syms::right_name, modified_name.as_external());
db_adaptor.db.get_file_content (db_adaptor.right_rid, nid, fid);
st.push_binary_pair(syms::right_file_id, fid.inner());
+ break;
}
- put_file_resolution (st, left_side, conflict.resolution);
- if (conflict.orphaned)
- {
- switch (conflict.resolution.first)
- {
- case resolve_conflicts::none:
- case resolve_conflicts::rename:
- case resolve_conflicts::drop:
- break;
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.left_resolution);
+ put_file_resolution (st, resolve_conflicts::right_side, conflict.right_resolution);
- case resolve_conflicts::content_user_rename:
- st.push_str_pair(syms::resolved_rename_left, conflict.rename.as_external());
- break;
-
- default:
- I(false);
- }
- }
put_stanza(st, output);
}
else
{
P(F("conflict: file '%s' from revision %s") % ancestor_name % lca_rid);
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
if (conflict.orphaned)
{
P(F("orphaned on the left"));
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.left_nid == the_null_node)
P(F("dropped on the left"));
else
P(F("dropped and recreated on the left"));
}
P(F("modified on the right, named %s") % modified_name);
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left, named %s") % modified_name);
if (conflict.orphaned)
{
@@ -1250,43 +1230,45 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
P(F("dropped on the right"));
else
P(F("dropped and recreated on the right"));
}
+ break;
}
- // We can have a resolution from a mtn:resolve_conflict attribute.
- switch (conflict.resolution.first)
+ // We can have a resolution from a mtn:resolve_conflict attribute
+ // (so far, that only supports drop).
+ switch (conflict.left_resolution.resolution)
{
case resolve_conflicts::none:
- break;
-
case resolve_conflicts::content_user:
- P(F("resolution: user file '%s'") % conflict.resolution.second->as_external());
- break;
-
case resolve_conflicts::content_user_rename:
- P(F("resolution: user '%s' rename '%s'") %
- conflict.resolution.second->as_external() %
- conflict.rename.as_external());
- break;
-
case resolve_conflicts::rename:
- P(F("resolution: rename '%s'") % conflict.resolution.second->as_external());
+ case resolve_conflicts::keep:
+ case resolve_conflicts::content_internal:
+ I(false);
break;
case resolve_conflicts::drop:
- P(F("resolution: drop"));
+ P(F("left_resolution: drop"));
break;
-
+ }
+ switch (conflict.right_resolution.resolution)
+ {
+ case resolve_conflicts::none:
+ case resolve_conflicts::content_user:
+ case resolve_conflicts::content_user_rename:
+ case resolve_conflicts::rename:
case resolve_conflicts::keep:
- P(F("resolution: keep"));
+ case resolve_conflicts::content_internal:
+ I(false);
break;
- default:
- I(false);
+ case resolve_conflicts::drop:
+ P(F("right_resolution: drop"));
+ break;
}
}
}
@@ -1466,8 +1448,8 @@ roster_merge_result::report_duplicate_na
if (basic_io)
{
- put_file_resolution (st, left_side, conflict.left_resolution);
- put_file_resolution (st, right_side, conflict.right_resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.left_resolution);
+ put_file_resolution (st, resolve_conflicts::right_side, conflict.right_resolution);
put_stanza(st, output);
}
}
@@ -1643,9 +1625,9 @@ roster_merge_result::report_file_content
{
basic_io::stanza st;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
if (auto_merge_succeeds(lua, conflict, adaptor, left_roster, right_roster))
- conflict.resolution.first = resolve_conflicts::content_internal;
+ conflict.resolution.resolution = resolve_conflicts::content_internal;
st.push_str_pair(syms::conflict, syms::content);
put_content_conflict (st, left_roster, right_roster, adaptor, conflict);
@@ -1886,14 +1868,14 @@ read_orphaned_node_conflict(basic_io::pa
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ conflict.resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_rename_left))
{
- conflict.resolution.first = resolve_conflicts::rename;
+ conflict.resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, true);
+ conflict.resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else
@@ -1994,10 +1976,12 @@ static void
} // read_multiple_name_conflicts
static void
-read_dropped_modified_conflict(basic_io::parser & pars,
+read_dropped_modified_conflict(basic_io::parser & pars,
dropped_modified_conflict & conflict,
- roster_t const & left_roster,
- roster_t const & right_roster)
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ roster_t const & right_roster)
{
string tmp;
@@ -2009,28 +1993,38 @@ read_dropped_modified_conflict(basic_io:
if (tmp == "dropped file")
{
- pars.esym(syms::left_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::left_side;
+
+ pars.esym(syms::left_rev); pars.hex(tmp);
+ conflict.left_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::left_name); pars.str();
pars.esym(syms::left_file_id); pars.hex();
}
else if (tmp == "orphaned file")
{
- pars.esym(syms::left_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::left_side;
+ conflict.orphaned = true;
+
+ pars.esym(syms::left_rev); pars.hex(tmp);
+ conflict.left_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::left_name); pars.str();
pars.esym(syms::left_file_id); pars.hex();
-
- conflict.orphaned = true;
}
else if (tmp == "recreated file")
{
+ conflict.dropped_side = resolve_conflicts::left_side;
+ conflict.left_rid = left_rid;
+
pars.esym(syms::left_name); pars.str(tmp);
- conflict.recreated = left_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.left_nid = left_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::left_file_id); pars.hex();
}
else if (tmp == "modified file")
{
+ conflict.left_rid = left_rid;
+
pars.esym(syms::left_name); pars.str(tmp);
- conflict.left_nid = left_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.left_nid = left_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::left_file_id); pars.hex();
}
else
@@ -2041,70 +2035,109 @@ read_dropped_modified_conflict(basic_io:
if (tmp == "dropped file")
{
- pars.esym(syms::right_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::right_side;
+
+ pars.esym(syms::right_rev); pars.hex(tmp);
+ conflict.right_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::right_name); pars.str();
pars.esym(syms::right_file_id); pars.hex();
}
else if (tmp == "orphaned file")
{
- pars.esym(syms::right_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::right_side;
+ conflict.orphaned = true;
+
+ pars.esym(syms::right_rev); pars.hex(tmp);
+ conflict.right_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::right_name); pars.str();
pars.esym(syms::right_file_id); pars.hex();
-
- conflict.orphaned = true;
}
else if (tmp == "recreated file")
{
+ conflict.dropped_side = resolve_conflicts::right_side;
+ conflict.right_rid = right_rid;
+
pars.esym(syms::right_name); pars.str(tmp);
- conflict.recreated = right_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.right_nid = right_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::right_file_id); pars.hex();
}
else if (tmp == "modified file")
{
+ conflict.dropped_side = resolve_conflicts::right_side;
+ conflict.right_rid = right_rid;
+
pars.esym(syms::right_name); pars.str(tmp);
- conflict.right_nid = right_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.right_nid = right_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::right_file_id); pars.hex();
}
else
I(false);
- // check for a resolution
- if ((!pars.symp (syms::conflict)) && pars.tok.in.lookahead != EOF)
+ // check for resolutions
+ while ((!pars.symp (syms::conflict)) && pars.tok.in.lookahead != EOF)
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
+ else if (pars.symp (syms::resolved_drop_right))
+ {
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ pars.sym();
+ }
else if (pars.symp (syms::resolved_keep_left))
{
E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
- conflict.resolution.first = resolve_conflicts::keep;
+ conflict.left_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
+ else if (pars.symp (syms::resolved_keep_right))
+ {
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::keep;
+ pars.sym();
+ }
+ else if (pars.symp (syms::resolved_rename_left))
+ {
+ if (conflict.left_resolution.resolution == resolve_conflicts::content_user)
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
+ pars.sym();
+ conflict.left_resolution.rename = resolve_conflicts::file_path_external(pars.token);
+ pars.str();
+ }
+ else if (pars.symp (syms::resolved_rename_right))
+ {
+ if (conflict.right_resolution.resolution == resolve_conflicts::content_user)
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
+ pars.sym();
+ conflict.right_resolution.rename = resolve_conflicts::file_path_external(pars.token);
+ pars.str();
+ }
else if (pars.symp (syms::resolved_user_left))
{
- conflict.resolution.first = resolve_conflicts::content_user;
+ if (conflict.left_resolution.resolution == resolve_conflicts::rename)
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.left_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, false);
+ conflict.left_resolution.content = new_optimal_path(pars.token, false);
pars.str();
-
- if (conflict.orphaned)
- {
- pars.esym (syms::resolved_rename_left);
- conflict.resolution.first = resolve_conflicts::content_user_rename;
- pars.str(tmp);
- conflict.rename = file_path_external_ws(utf8(tmp, origin::user));
- }
}
- else if (pars.symp (syms::resolved_rename_left))
+ else if (pars.symp (syms::resolved_user_right))
{
- E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
-
- conflict.resolution.first = resolve_conflicts::rename;
+ if (conflict.right_resolution.resolution == resolve_conflicts::rename)
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, false);
+ conflict.left_resolution.content = new_optimal_path(pars.token, false);
pars.str();
}
else
@@ -2114,18 +2147,20 @@ static void
} // read_dropped_modified_conflict
static void
-read_dropped_modified_conflicts(basic_io::parser & pars,
- std::vector<dropped_modified_conflict> & conflicts,
- roster_t const & left_roster,
- roster_t const & right_roster)
+read_dropped_modified_conflicts(basic_io::parser & pars,
+ std::vector<dropped_modified_conflict> & conflicts,
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ roster_t const & right_roster)
{
while (pars.tok.in.lookahead != EOF && pars.symp(syms::dropped_modified))
{
- dropped_modified_conflict conflict(the_null_node, the_null_node);
+ dropped_modified_conflict conflict;
pars.sym();
- read_dropped_modified_conflict(pars, conflict, left_roster, right_roster);
+ read_dropped_modified_conflict(pars, conflict, left_rid, left_roster, right_rid, right_roster);
conflicts.push_back(conflict);
@@ -2133,11 +2168,14 @@ read_dropped_modified_conflicts(basic_io
pars.esym (syms::conflict);
}
} // read_dropped_modified_conflicts
+
static void
-validate_dropped_modified_conflicts(basic_io::parser & pars,
+validate_dropped_modified_conflicts(basic_io::parser & pars,
std::vector<dropped_modified_conflict> & conflicts,
- roster_t const & left_roster,
- roster_t const & right_roster)
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ roster_t const & right_roster)
{
for (std::vector<dropped_modified_conflict>::iterator i = conflicts.begin();
i != conflicts.end();
@@ -2148,17 +2186,19 @@ validate_dropped_modified_conflicts(basi
pars.esym(syms::dropped_modified);
- read_dropped_modified_conflict(pars, file_conflict, left_roster, right_roster);
+ read_dropped_modified_conflict(pars, file_conflict, left_rid, left_roster, right_rid, right_roster);
// Note that we do not confirm the file ids.
- E(merge_conflict.left_nid == file_conflict.left_nid &&
- merge_conflict.right_nid == file_conflict.right_nid &&
- merge_conflict.recreated == file_conflict.recreated,
+ E(merge_conflict.dropped_side == file_conflict.dropped_side &&
+ merge_conflict.left_nid == file_conflict.left_nid &&
+ merge_conflict.right_nid == file_conflict.right_nid,
origin::user,
F(conflicts_mismatch_msg));
- merge_conflict.resolution = file_conflict.resolution;
- merge_conflict.rename = file_conflict.rename;
+ merge_conflict.left_rid = file_conflict.left_rid;
+ merge_conflict.right_rid = file_conflict.right_rid;
+ merge_conflict.left_resolution = file_conflict.left_resolution;
+ merge_conflict.right_resolution = file_conflict.right_resolution;
if (pars.tok.in.lookahead != EOF)
pars.esym (syms::conflict);
@@ -2185,50 +2225,50 @@ read_duplicate_name_conflict(basic_io::p
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.left_resolution.first = resolve_conflicts::drop;
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_drop_right))
{
- conflict.right_resolution.first = resolve_conflicts::drop;
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_keep_left))
{
- conflict.left_resolution.first = resolve_conflicts::keep;
+ conflict.left_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
else if (pars.symp (syms::resolved_keep_right))
{
- conflict.right_resolution.first = resolve_conflicts::keep;
+ conflict.right_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
else if (pars.symp (syms::resolved_rename_left))
{
- conflict.left_resolution.first = resolve_conflicts::rename;
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.left_resolution.second = resolve_conflicts::new_file_path(pars.token);
+ conflict.left_resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else if (pars.symp (syms::resolved_rename_right))
{
- conflict.right_resolution.first = resolve_conflicts::rename;
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.right_resolution.second = resolve_conflicts::new_file_path(pars.token);
+ conflict.right_resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else if (pars.symp (syms::resolved_user_left))
{
- conflict.left_resolution.first = resolve_conflicts::content_user;
+ conflict.left_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.left_resolution.second = new_optimal_path(pars.token, true);
+ conflict.left_resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else if (pars.symp (syms::resolved_user_right))
{
- conflict.right_resolution.first = resolve_conflicts::content_user;
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.right_resolution.second = new_optimal_path(pars.token, true);
+ conflict.right_resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else
@@ -2433,14 +2473,14 @@ read_file_content_conflict(basic_io::par
{
if (pars.symp (syms::resolved_internal))
{
- conflict.resolution.first = resolve_conflicts::content_internal;
+ conflict.resolution.resolution = resolve_conflicts::content_internal;
pars.sym();
}
else if (pars.symp (syms::resolved_user_left))
{
- conflict.resolution.first = resolve_conflicts::content_user;
+ conflict.resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, true);
+ conflict.resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else
@@ -2506,7 +2546,9 @@ read_conflict_file_core(basic_io::parser
static void
read_conflict_file_core(basic_io::parser pars,
+ revision_id left_rid,
roster_t const & left_roster,
+ revision_id right_rid,
roster_t const & right_roster,
roster_merge_result & result,
bool validate)
@@ -2533,7 +2575,8 @@ read_conflict_file_core(basic_io::parser
// order as non-validate, below.
validate_orphaned_node_conflicts(pars, result.orphaned_node_conflicts, left_roster, right_roster);
- validate_dropped_modified_conflicts(pars, result.dropped_modified_conflicts, left_roster, right_roster);
+ validate_dropped_modified_conflicts
+ (pars, result.dropped_modified_conflicts, left_rid, left_roster, right_rid, right_roster);
validate_duplicate_name_conflicts(pars, result.duplicate_name_conflicts, left_roster, right_roster);
validate_file_content_conflicts(pars, result.file_content_conflicts, left_roster, right_roster);
}
@@ -2546,7 +2589,8 @@ read_conflict_file_core(basic_io::parser
read_directory_loop_conflicts(pars, result.directory_loop_conflicts, left_roster, right_roster);
read_orphaned_node_conflicts(pars, result.orphaned_node_conflicts, left_roster, right_roster);
read_multiple_name_conflicts(pars, result.multiple_name_conflicts, left_roster, right_roster);
- read_dropped_modified_conflicts(pars, result.dropped_modified_conflicts, left_roster, right_roster);
+ read_dropped_modified_conflicts
+ (pars, result.dropped_modified_conflicts, left_rid, left_roster, right_rid, right_roster);
read_duplicate_name_conflicts(pars, result.duplicate_name_conflicts, left_roster, right_roster);
read_attribute_conflicts(pars, result.attribute_conflicts, left_roster, right_roster);
read_file_content_conflicts(pars, result.file_content_conflicts, left_roster, right_roster);
@@ -2596,7 +2640,7 @@ roster_merge_result::read_conflict_file(
db.get_roster(left_rid, left_roster, left_marking);
db.get_roster(right_rid, right_roster, right_marking);
- read_conflict_file_core(pars, left_roster, right_roster, *this, false);
+ read_conflict_file_core(pars, left_rid, left_roster, right_rid, right_roster, *this, false);
}
// else no conflicts
@@ -2694,9 +2738,12 @@ parse_resolve_conflicts_opts (options co
pars.sym();
pars.hex(temp);
+ read_conflict_file_core (pars, left_rid, left_roster, right_rid, right_roster, result, true);
+ }
+ else
+ {
// if there is no ancestor revision, then left is an ancestor of
// right, or vice versa, and there can be no conflicts.
- read_conflict_file_core (pars, left_roster, right_roster, result, true);
}
}
else
@@ -2761,7 +2808,7 @@ roster_merge_result::resolve_orphaned_no
right_roster.get_name(conflict.nid, name);
}
- switch (conflict.resolution.first)
+ switch (conflict.resolution.resolution)
{
case resolve_conflicts::drop:
if (is_dir_t(roster.get_node(conflict.nid)))
@@ -2775,9 +2822,8 @@ roster_merge_result::resolve_orphaned_no
break;
case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % name % *conflict.resolution.second);
- attach_node
- (lua, roster, conflict.nid, file_path_internal (conflict.resolution.second->as_internal()));
+ P(F("renaming '%s' to '%s'") % name % conflict.resolution.rename);
+ attach_node (lua, roster, conflict.nid, conflict.resolution.rename);
break;
case resolve_conflicts::none:
@@ -2794,34 +2840,102 @@ roster_merge_result::resolve_orphaned_no
orphaned_node_conflicts.clear();
}
+static node_id
+create_new_node(roster_t const & parent_roster,
+ node_id const & parent_nid,
+ roster_t & result_roster,
+ boost::shared_ptr<any_path> new_content,
+ content_merge_adaptor & adaptor,
+ temp_node_id_source & nis)
+{
+ file_path parent_name;
+ file_id parent_fid;
+ file_data parent_data;
+
+ parent_roster.get_file_details(parent_nid, parent_fid, parent_name);
+ adaptor.get_version(parent_fid, parent_data);
+
+ P(F("replacing content of '%s' with '%s'") % parent_name % new_content->as_external());
+
+ // FIXME: factor out 'history lost' msg
+ P(F("history for '%s' will be lost; see user manual Merge Conflicts section") % parent_name);
+
+ data result_raw_data;
+ read_data(*new_content, result_raw_data);
+
+ file_data result_data = file_data(result_raw_data);
+ file_id result_fid;
+ calculate_ident(result_data, result_fid);
+
+ // User could specify no changes in content
+ if (result_fid != parent_fid)
+ {
+ adaptor.record_file(parent_fid, result_fid, parent_data, result_data);
+ }
+
+ return result_roster.create_file_node(result_fid, nis);
+}
+
static void
-resolve_dropped_modified_user(roster_t & roster,
- node_id & nid,
- file_id modified_fid,
- dropped_modified_conflict const conflict,
- content_merge_adaptor & adaptor,
- temp_node_id_source & nis)
+replace_content(roster_t const & parent_roster,
+ node_id const & nid,
+ roster_t & result_roster,
+ boost::shared_ptr<any_path> new_content,
+ content_merge_adaptor & adaptor)
{
- // See comments in keep below on why we drop first
- roster.drop_detached_node(nid);
+ file_path parent_name;
+ file_id parent_fid;
- file_data result_data;
+ parent_roster.get_file_details(nid, parent_fid, parent_name);
+
+ P(F("replacing content of '%s' with '%s'") % parent_name % new_content->as_external());
+
+ file_data parent_data;
+ adaptor.get_version(parent_fid, parent_data);
+
data result_raw_data;
+ read_data(*new_content, result_raw_data);
+
+ file_data result_data = file_data(result_raw_data);
file_id result_fid;
- read_data(*conflict.resolution.second, result_raw_data);
+ calculate_ident(result_data, result_fid);
- result_data = file_data(result_raw_data);
- calculate_ident(result_data, result_fid);
+ file_t result_node = downcast_to_file_t(result_roster.get_node_for_update(nid));
+ result_node->content = result_fid;
- nid = roster.create_file_node(result_fid, nis);
+ // User could specify no changes in content
+ if (result_fid != parent_fid)
+ {
+ adaptor.record_file(parent_fid, result_fid, parent_data, result_data);
+ }
+}
- // User could specify no changes
- if (result_fid != modified_fid)
+static void
+error_extra_left(node_id left_nid, node_id right_nid, roster_t const & right_roster)
+{
+ if (left_nid == the_null_node)
{
- adaptor.record_file(result_fid, result_data);
+ file_path right_name;
+ file_id right_fid;
+ right_roster.get_file_details(right_nid, right_fid, right_name);
+ E(false, origin::user,
+ F("extra left_resolution provided for dropped_modifed '%s'") % right_name);
}
}
+static void
+error_extra_right(node_id left_nid, node_id right_nid, roster_t const & left_roster)
+{
+ if (right_nid == the_null_node)
+ {
+ file_path left_name;
+ file_id left_fid;
+ left_roster.get_file_details(left_nid, left_fid, left_name);
+ E(false, origin::user,
+ F("extra right_resolution provided for dropped_modifed '%s'") % left_name);
+ }
+}
+
void
roster_merge_result::resolve_dropped_modified_conflicts(lua_hooks & lua,
roster_t const & left_roster,
@@ -2833,8 +2947,6 @@ roster_merge_result::resolve_dropped_mod
MM(right_roster);
MM(this->roster); // New roster
- // Conflict node is absent in the new roster
-
for (std::vector<dropped_modified_conflict>::const_iterator i = dropped_modified_conflicts.begin();
i != dropped_modified_conflicts.end();
++i)
@@ -2842,107 +2954,93 @@ roster_merge_result::resolve_dropped_mod
dropped_modified_conflict const & conflict = *i;
MM(conflict);
- node_id nid;
- file_path modified_name;
- file_id modified_fid;
- file_path recreated_name;
- file_id recreated_fid;
+ file_path left_name;
+ file_id left_fid;
+ file_path right_name;
+ file_id right_fid;
- if (conflict.left_nid == the_null_node)
+ switch (conflict.left_resolution.resolution)
{
- nid = conflict.right_nid;
- right_roster.get_file_details(nid, modified_fid, modified_name);
-
- if (conflict.recreated != the_null_node)
+ case resolve_conflicts::none:
+ if (conflict.left_nid != the_null_node)
{
- roster.get_file_details(conflict.recreated, recreated_fid, recreated_name);
+ // FIXME: use left_name here if it's not too hard
+ right_roster.get_file_details(conflict.right_nid, right_fid, right_name);
+ E(false, origin::user,
+ F("no left_resolution provided for dropped_modifed '%s'") % right_name);
}
- }
- else
- {
- nid = conflict.left_nid;
- left_roster.get_file_details(nid, modified_fid, modified_name);
+ break;
- if (conflict.recreated != the_null_node)
+ case resolve_conflicts::content_user:
+ switch (conflict.dropped_side)
{
- roster.get_file_details(conflict.recreated, recreated_fid, recreated_name);
- }
- }
+ case resolve_conflicts::left_side:
+ error_extra_left(conflict.left_nid, conflict.right_nid, right_roster);
- switch (conflict.resolution.first)
- {
- case resolve_conflicts::none:
- E(false, origin::user,
- F("no resolution provided for dropped_modifed '%s'") % modified_name);
- break;
+ // recreated; replace the contents of the recreated node
+ replace_content(left_roster, conflict.left_nid, roster, conflict.left_resolution.content, adaptor);
+ break;
- case resolve_conflicts::content_user:
- P(F("replacing content of '%s' with '%s'") %
- modified_name % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ case resolve_conflicts::right_side:
+ error_extra_right(conflict.left_nid, conflict.right_nid, left_roster);
- if (conflict.recreated == the_null_node)
- {
- resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
- attach_node(lua, roster, nid, modified_name);
- }
- else
- {
+ // modified; drop and create a new node
// See comments in keep below on why we drop first
- roster.drop_detached_node(nid);
+ roster.drop_detached_node(conflict.left_nid);
- file_id result_fid;
- file_data parent_data, result_data;
- data result_raw_data;
- adaptor.get_version(recreated_fid, parent_data);
+ node_id new_nid = create_new_node
+ (left_roster, conflict.left_nid, roster, conflict.left_resolution.content, adaptor, nis);
- read_data(*conflict.resolution.second, result_raw_data);
+ attach_node(lua, roster, new_nid, left_name);
- result_data = file_data(result_raw_data);
- calculate_ident(result_data, result_fid);
-
- file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.recreated));
- result_node->content = result_fid;
-
- adaptor.record_file(recreated_fid, result_fid, parent_data, result_data);
+ break;
}
break;
- case resolve_conflicts::content_user_rename:
- I(conflict.rename.as_external().length() != 0);
- P(F("replacing content of '%s' (renamed to '%s') with '%s'") %
- modified_name % conflict.rename.as_external() % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ case resolve_conflicts::content_internal:
+ I(false);
- resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
- attach_node(lua, roster, nid, file_path_internal (conflict.rename.as_internal()));
- break;
+ case resolve_conflicts::drop:
+ switch (conflict.dropped_side)
+ {
+ case resolve_conflicts::left_side:
+ error_extra_left(conflict.left_nid, conflict.right_nid, right_roster);
- case resolve_conflicts::drop:
- P(F("dropping '%s'") % modified_name);
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("dropping '%s'") % left_name);
- roster.drop_detached_node(nid);
- break;
+ roster.drop_detached_node(conflict.left_nid);
+ break;
- case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % modified_name % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ case resolve_conflicts::right_side:
+ error_extra_right(conflict.left_nid, conflict.right_nid, left_roster);
- // See comment in keep below on why we drop first.
- roster.drop_detached_node(nid);
- nid = roster.create_file_node(modified_fid, nis);
- attach_node (lua, roster, nid, file_path_internal (conflict.resolution.second->as_internal()));
- break;
+ right_roster.get_file_details(conflict.right_nid, right_fid, right_name);
+ P(F("dropping '%s'") % right_name);
+ roster.drop_detached_node(conflict.right_nid);
+ break;
+ }
+
case resolve_conflicts::keep:
- if (conflict.recreated == the_null_node)
+ switch (conflict.dropped_side)
{
- P(F("keeping '%s'") % modified_name);
+ case resolve_conflicts::left_side:
+ error_extra_left(conflict.left_nid, conflict.right_nid, right_roster);
+
+ // recreated; keep the recreated contents
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("keeping '%s'") % left_name);
+ attach_node(lua, roster, conflict.left_nid, left_name);
+ break;
+
+ case resolve_conflicts::right_side:
+ // modified; keep the modified contents
+
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("keeping '%s'") % left_name);
P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ left_name);
// We'd like to just attach_node here, but that violates a
// fundamental design principle of mtn; nodes are born once,
@@ -2953,35 +3051,72 @@ roster_merge_result::resolve_dropped_mod
// the same contents. That loses history; 'mtn log <path>'
// will end here, not showing the history of the original
// node.
- roster.drop_detached_node(nid);
- nid = roster.create_file_node(modified_fid, nis);
- attach_node (lua, roster, nid, modified_name);
+ roster.drop_detached_node(conflict.left_nid);
+ node_id nid = roster.create_file_node(left_fid, nis);
+ attach_node (lua, roster, nid, left_name);
+ break;
}
- else
+
+ case resolve_conflicts::rename:
+ switch (conflict.dropped_side)
{
- P(F("keeping '%s' from %s") % modified_name % ((conflict.left_nid == the_null_node) ? "right" : "left"));
+ case resolve_conflicts::left_side:
+ error_extra_left(conflict.left_nid, conflict.right_nid, right_roster);
+
+ // recreated; rename the recreated contents
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("renaming '%s' to '%s'") % left_name % conflict.left_resolution.rename.as_external());
+ attach_node(lua, roster, conflict.left_nid, conflict.left_resolution.rename);
+ break;
+
+ case resolve_conflicts::right_side:
+ error_extra_right(conflict.left_nid, conflict.right_nid, left_roster);
+
+ // modified; drop, create new node with the modified contents, rename
+ // See comment in keep above on why we drop first.
+ roster.drop_detached_node(conflict.left_nid);
+
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("renaming '%s' to '%s'") % left_name % conflict.left_resolution.rename.as_external());
P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ left_name);
- roster.drop_detached_node(nid);
+ node_id new_nid = roster.create_file_node(left_fid, nis);
+ attach_node (lua, roster, new_nid, conflict.left_resolution.rename);
+ break;
+ }
- // keep the modified content, not the recreated content
- file_data parent_data, result_data;
- adaptor.get_version(recreated_fid, parent_data);
+ case resolve_conflicts::content_user_rename:
+ switch (conflict.dropped_side)
+ {
+ case resolve_conflicts::left_side:
+ error_extra_left(conflict.left_nid, conflict.right_nid, right_roster);
- adaptor.get_version(modified_fid, result_data);
+ // recreated; rename and replace the recreated contents
+ replace_content(left_roster, conflict.left_nid, roster, conflict.left_resolution.content, adaptor);
- file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.recreated));
- result_node->content = modified_fid;
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("renaming '%s' to '%s'") % left_name % conflict.left_resolution.rename.as_external());
- adaptor.record_file(recreated_fid, modified_fid, parent_data, result_data);
- }
- break;
+ attach_node (lua, roster, conflict.left_nid, conflict.left_resolution.rename);
+ break;
- default:
- I(false);
+ case resolve_conflicts::right_side:
+ // modified; drop, rename and replace the modified contents
+ node_id nid = create_new_node
+ (left_roster, conflict.left_nid, roster, conflict.left_resolution.content, adaptor, nis);
+
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ P(F("renaming '%s' to '%s'") % left_name % conflict.left_resolution.rename.as_external());
+
+ attach_node(lua, roster, conflict.left_nid, conflict.left_resolution.rename);
+ break;
+ }
}
+ // FIXME: handle right_resolution; factor out resolve_dropped_modified_one_side
+ // add inconsistent left/right resolution checks
+
} // end for
dropped_modified_conflicts.clear();
@@ -2997,23 +3132,23 @@ resolve_duplicate_name_one_side(lua_hook
content_merge_adaptor & adaptor,
roster_t & result_roster)
{
- switch (resolution.first)
+ switch (resolution.resolution)
{
case resolve_conflicts::content_user:
{
- E(other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename,
origin::user,
F("inconsistent left/right resolutions for '%s'") % name);
- P(F("replacing content of '%s' with '%s'") % name % resolution.second->as_external());
+ P(F("replacing content of '%s' with '%s'") % name % resolution.content->as_external());
file_id result_fid;
file_data parent_data, result_data;
data result_raw_data;
adaptor.get_version(fid, parent_data);
- read_data(*resolution.second, result_raw_data);
+ read_data(*resolution.content, result_raw_data);
result_data = file_data(result_raw_data);
calculate_ident(result_data, result_fid);
@@ -3039,8 +3174,8 @@ resolve_duplicate_name_one_side(lua_hook
break;
case resolve_conflicts::keep:
- E(other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename,
origin::user,
F("inconsistent left/right resolutions for '%s'") % name);
@@ -3049,9 +3184,8 @@ resolve_duplicate_name_one_side(lua_hook
break;
case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % name % *resolution.second);
- attach_node
- (lua, result_roster, nid, file_path_internal (resolution.second->as_internal()));
+ P(F("renaming '%s' to '%s'") % name % resolution.rename);
+ attach_node (lua, result_roster, nid, resolution.rename);
break;
case resolve_conflicts::none:
@@ -3146,7 +3280,7 @@ roster_merge_result::resolve_file_conten
left_roster.get_name(conflict.nid, left_name);
right_roster.get_name(conflict.nid, right_name);
- switch (conflict.resolution.first)
+ switch (conflict.resolution.resolution)
{
case resolve_conflicts::content_internal:
case resolve_conflicts::none:
@@ -3168,7 +3302,7 @@ roster_merge_result::resolve_file_conten
case resolve_conflicts::content_user:
{
P(F("replacing content of '%s', '%s' with '%s'") %
- left_name % right_name % conflict.resolution.second->as_external());
+ left_name % right_name % conflict.resolution.content->as_external());
file_id result_id;
file_data left_data, right_data, result_data;
@@ -3176,7 +3310,7 @@ roster_merge_result::resolve_file_conten
adaptor.get_version(conflict.left, left_data);
adaptor.get_version(conflict.right, right_data);
- read_data(*conflict.resolution.second, result_raw_data);
+ read_data(*conflict.resolution.content, result_raw_data);
result_data = file_data(result_raw_data);
calculate_ident(result_data, result_id);
============================================================
--- src/merge_content.cc 662433acaf08fc1f3f3417389a9bc3b3d2bd9bf1
+++ src/merge_content.cc 6a1d7ad7184f88674a585f5065e965f15294f7dc
@@ -189,8 +189,9 @@ content_merge_database_adaptor::get_drop
set<revision_id> parents;
db.get_revision_parents(rev_id, parents);
- for (set<revision_id>::iterator i = parents.begin(); i != parents.end(); i++)
+ while (parents.begin() != parents.end())
{
+ set<revision_id>::iterator i = parents.begin();
roster_t roster;
marking_map marking_map;
@@ -203,6 +204,7 @@ content_merge_database_adaptor::get_drop
}
else
{
+ parents.erase (i);
set<revision_id> more_parents;
db.get_revision_parents(*i, more_parents);
parents.insert(more_parents.begin(), more_parents.end());
============================================================
--- src/merge_roster.cc 5fbc50c114df22f4753f444aa137c06ea0f06195
+++ src/merge_roster.cc b4de8ec7db2c60b3ebb777bfa58d9e0d8986558d
@@ -49,6 +49,21 @@ image(resolve_conflicts::resolution_t re
I(false); // keep compiler happy
}
+static string
+image(resolve_conflicts::file_resolution_t res)
+{
+ if (res.resolution == resolve_conflicts::none)
+ return string("");
+ else
+ {
+ ostringstream oss;
+ oss << "resolution: " << image(res.resolution) << " "
+ << "content: " << res.content << " "
+ << "rename: " << res.rename << "\n";
+ return oss.str();
+ }
+}
+
template <> void
dump(invalid_name_conflict const & conflict, string & out)
{
@@ -98,12 +113,8 @@ dump(dropped_modified_conflict const & c
oss << "dropped_modified_conflict on node: " <<
conflict.left_nid == the_null_node ? conflict.right_nid : conflict.left_nid;
oss << " orphaned: " << conflict.orphaned;
- if (conflict.resolution.first != resolve_conflicts::none)
- {
- oss << " resolution: " << image(conflict.resolution.first);
- oss << " new_content_name: " << conflict.resolution.second;
- oss << " rename: " << conflict.rename;
- }
+ oss << " left_resolution: " << image(conflict.left_resolution);
+ oss << " right_resolution: " << image(conflict.left_resolution);
oss << "\n";
out = oss.str();
}
@@ -115,19 +126,10 @@ dump(duplicate_name_conflict const & con
oss << "duplicate_name_conflict between left node: " << conflict.left_nid << " "
<< "and right node: " << conflict.right_nid << " "
<< "parent: " << conflict.parent_name.first << " "
- << "basename: " << conflict.parent_name.second;
-
- if (conflict.left_resolution.first != resolve_conflicts::none)
- {
- oss << " left_resolution: " << image(conflict.left_resolution.first);
- oss << " left_name: " << conflict.left_resolution.second;
- }
- if (conflict.right_resolution.first != resolve_conflicts::none)
- {
- oss << " right_resolution: " << image(conflict.right_resolution.first);
- oss << " right_name: " << conflict.right_resolution.second;
- }
- oss << "\n";
+ << "basename: " << conflict.parent_name.second << " "
+ << "left_resolution: " << " "
+ << "right_resolution: "
+ << "\n";
out = oss.str();
}
@@ -147,12 +149,7 @@ dump(file_content_conflict const & confl
{
ostringstream oss;
oss << "file_content_conflict on node: " << conflict.nid;
-
- if (conflict.resolution.first != resolve_conflicts::none)
- {
- oss << " resolution: " << image(conflict.resolution.first);
- oss << " name: " << conflict.resolution.second;
- }
+ oss << " resolution: " << image(conflict.resolution);
oss << "\n";
out = oss.str();
}
@@ -374,7 +371,7 @@ namespace
switch (present_in)
{
case left_side:
- conflict = dropped_modified_conflict(n->self, the_null_node);
+ conflict = dropped_modified_conflict(n->self, the_null_node);
break;
case right_side:
conflict = dropped_modified_conflict(the_null_node, n->self);
@@ -385,7 +382,15 @@ namespace
{
if (i->second.second == typecast_vocab<attr_value>(utf8("drop")))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ switch (present_in)
+ {
+ case left_side:
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
+ break;
+ case right_side:
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ break;
+ }
}
else
{
@@ -796,21 +801,65 @@ roster_merge(roster_t const & left_paren
{
dropped_modified_conflict & conflict = result.dropped_modified_conflicts[i];
+ // If the file name was recreated it may now subject to a
+ // duplicate_name conflict (see
+ // test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2).
+ // In which case modified_name will be present in the other parent,
+ // but not in the result.
+
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ bool duplicate_name = false;
+
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
right_parent.get_name(conflict.right_nid, modified_name);
- }
- else
- {
+
+ if (left_parent.has_node (modified_name))
+ {
+ conflict.left_nid = left_parent.get_node(modified_name)->self;
+ duplicate_name = true;
+ }
+ else if (result.roster.has_node(modified_name))
+ {
+ // recreated
+ conflict.left_nid = result.roster.get_node(modified_name)->self;
+ }
+ break;
+
+ case resolve_conflicts::right_side:
left_parent.get_name(conflict.left_nid, modified_name);
+
+ if (right_parent.has_node (modified_name))
+ {
+ conflict.right_nid = right_parent.get_node(modified_name)->self;
+ duplicate_name = false;
+ }
+
+ else if (result.roster.has_node(modified_name))
+ {
+ // recreated
+ conflict.right_nid = result.roster.get_node(modified_name)->self;
+ }
+ break;
}
- if (result.roster.has_node(modified_name))
+ if (duplicate_name)
{
- conflict.recreated = result.roster.get_node(modified_name)->self;
+ // delete the duplicate name conflict; it will be handled by dropped_modified.
+ for (std::vector<duplicate_name_conflict>::iterator i = result.duplicate_name_conflicts.begin();
+ i != result.duplicate_name_conflicts.end();
+ ++i)
+ {
+ duplicate_name_conflict & dn_conf = *i;
+ if (dn_conf.left_nid == conflict.left_nid || dn_conf.right_nid == conflict.right_nid)
+ {
+ result.duplicate_name_conflicts.erase(i);
+ break;
+ }
+ }
}
- }
+ } // end dropped_modified loop
// now check for the possible global problems
if (!result.roster.has_root())
============================================================
--- src/merge_roster.hh 34d382b0ad333fa0f052e8640a88c1ece03caaa9
+++ src/merge_roster.hh 63eab7b216f8839626f9d9d04dc8e58c3eed90bf
@@ -31,10 +31,25 @@ namespace resolve_conflicts
{
enum resolution_t {none, content_user, content_internal, drop, keep, rename, content_user_rename};
- typedef std::pair<resolve_conflicts::resolution_t, boost::shared_ptr<any_path> > file_resolution_t;
+ enum side_t {left_side, right_side};
- boost::shared_ptr<any_path> new_file_path(std::string path);
+ struct file_resolution_t
+ {
+ resolution_t resolution;
+ boost::shared_ptr<any_path> content;
+ file_path rename;
+ file_resolution_t() :
+ resolution(none),
+ content(),
+ rename()
+ {}
+ };
+
+ // For filename read from conflicts file; converts path to utf8. basic_io
+ // parser should return utf8 in the first place.
+ file_path file_path_external(std::string path);
+
}
// renaming the root dir allows these:
@@ -94,34 +109,55 @@ struct dropped_modified_conflict
// roster, with null parent and name fields.
struct dropped_modified_conflict
{
- node_id left_nid, right_nid; // the dropped side is the null node, modified is valid.
+ // A dropped_modified conflict can be the result of a repeated
+ // duplicate_name conflict (see
+ // ../test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2)
+ //
+ // If the user has recreated the dropped node, that also looks like a
+ // duplicate name conflict.
+ //
+ // In either case both nids are non-null.
+ //
+ // Dropped_modified can also be due to a dropped directory, in which case
+ // this looks like an orphaned_node conflict.
+ //
+ // If the resolution for the dropped node is 'keep', we need the revision
+ // that contains the node id, which is an ancestor of the merge parent.
+ // That information is also useful for an external front end, that wants to
+ // retreive the file contents for a merge tool.
- bool orphaned; // if true, the dropped side is due to a dropped parent directory
+ resolve_conflicts::side_t dropped_side;
- node_id recreated; // by user, or in a previous drop/modified resolution
+ // If nid is set, it is in corresponding merge parent.
+ node_id left_nid, right_nid;
- resolve_conflicts::file_resolution_t resolution;
- file_path rename;
- // if orphaned is true, the resolutions are 'drop' and 'user rename'; the
- // latter requires two paths; content in resolution->second, filename in
- // rename.
+ bool orphaned; // if true, the dropped side is due to a dropped parent directory
+ // read_dropped_modified sets rid for dropped, non-recreated file FIXME: can we use this?
+ revision_id left_rid, right_rid;
+ resolve_conflicts::file_resolution_t left_resolution, right_resolution;
+
dropped_modified_conflict(node_id left_nid, node_id right_nid) :
left_nid(left_nid),
right_nid(right_nid),
orphaned(false),
- recreated(the_null_node)
- // rename is implicitly null
- {resolution.first = resolve_conflicts::none;}
+ left_rid(),
+ right_rid(),
+ left_resolution(),
+ right_resolution()
+ {dropped_side = (left_nid == the_null_node ? resolve_conflicts::right_side : resolve_conflicts::left_side);}
dropped_modified_conflict() :
left_nid(the_null_node),
right_nid(the_null_node),
orphaned(false),
- recreated(the_null_node)
- // rename is implicitly null
- {resolution.first = resolve_conflicts::none;}
+ left_rid(),
+ right_rid(),
+ left_resolution(),
+ right_resolution()
+ {}
+ // for find
bool operator==(node_id n) {return left_nid == n || right_nid == n;}
};
@@ -147,9 +183,10 @@ struct duplicate_name_conflict
// it may be a bookkeeping or system path if resolution is 'user'.
resolve_conflicts::file_resolution_t left_resolution, right_resolution;
- duplicate_name_conflict ()
- {left_resolution.first = resolve_conflicts::none;
- right_resolution.first = resolve_conflicts::none;};
+ duplicate_name_conflict() {};
+
+ // for find
+ bool operator==(node_id n) {return left_nid == n || right_nid == n;}
};
// nodes with attribute conflicts are left attached in the resulting tree (unless
@@ -174,12 +211,15 @@ struct file_content_conflict
file_id ancestor, left, right; // ancestor is set only when reading in a conflicts file
resolve_conflicts::file_resolution_t resolution;
- file_content_conflict () :
- nid(the_null_node)
- {resolution.first = resolve_conflicts::none;};
+ file_content_conflict() :
+ nid(the_null_node),
+ resolution()
+ {};
file_content_conflict(node_id nid) :
- nid(nid) {resolution.first = resolve_conflicts::none;};
+ nid(nid),
+ resolution()
+ {};
};
template <> void dump(invalid_name_conflict const & conflict, std::string & out);
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/__driver__.lua 46e918155fe50737229d3c2cb31899cf204ef9fd
@@ -0,0 +1,119 @@
+-- Show a problematic use case involving a dropped_modified conflict,
+-- and how it can be resolved with the 'mtn:resolve_conflict'
+-- attribute.
+--
+-- There is an upstream branch, and a local branch. The local branch
+-- adds a file that the upstream branch adopts. The next merge from
+-- upstream to local encounters a duplicate_name conflict; if we
+-- resolve that the wrong way (keep local instead of upstream), on the
+-- next merge we get a dropped_modified conflict.
+--
+-- In the meantime, we've edited the file locally, illustrating that
+-- the dropped_modified conflict code needs to search thru history for
+-- the rev last containing the dropped node id (this was a bug in an
+-- earlier implementation).
+
+mtn_setup()
+
+addfile("file_1", "file_1 base")
+commit("testbranch", "base")
+base = base_revision()
+
+writefile("file_1", "file_1 upstream 1")
+
+commit("testbranch", "upstream 1")
+upstream_1 = base_revision()
+
+revert_to(base)
+
+addfile("file_2", "file_2 local")
+
+commit("testbranch", "local 1")
+local_1 = base_revision()
+
+revert_to(upstream_1)
+
+addfile("file_2", "file_2 upstream 1")
+
+commit("testbranch", "upstream 2")
+upstream_2 = base_revision()
+
+check(mtn("show_conflicts", upstream_2, local_1), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: [right] 3cae692a68fa6710b1db5e73e3e876994c175925",
+ "mtn: [ancestor] 736498437fa91538540dc5fbad750cbc1472d793",
+ "mtn: conflict: duplicate name 'file_2' for the directory ''",
+ "mtn: added as a new file on the left",
+ "mtn: added as a new file on the right",
+ "mtn: 1 conflict with supported resolutions."}))
+
+check(mtn("conflicts", "store", upstream_2, local_1), 0, nil, true)
+
+-- We should keep upstream, and drop local, but we get it backwards
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, true)
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, true)
+
+check(mtn("explicit_merge", "--resolve-conflicts", upstream_2, local_1, "testbranch"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: [right] 3cae692a68fa6710b1db5e73e3e876994c175925",
+ "mtn: dropping 'file_2'",
+ "mtn: keeping 'file_2'",
+ "mtn: [merged] fce2fe3c327a294209ad695e0658275f104fe12a"}))
+
+check(mtn("update"), 0, nil, true)
+
+-- One more local mod
+writefile("file_2", "file_2 local 2")
+commit("testbranch", "local 2")
+local_2 = base_revision()
+
+-- round 2; upstream modifies the file again, and we try to merge
+revert_to(upstream_2)
+
+writefile("file_2", "file_2 upstream 2")
+
+commit("testbranch", "upstream 3")
+upstream_3 = base_revision()
+
+check(mtn("show_conflicts", upstream_3, local_2), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 48b18ebc7b70733133539384e49a2eedb82e32b2",
+ "mtn: [right] 650057e8a81bd41991dc5ff10b2d60343f1032ae",
+ "mtn: [ancestor] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: conflict: file 'file_2' from revision 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: modified on the left, named file_2",
+ "mtn: dropped and recreated on the right",
+ "mtn: 1 conflict with supported resolutions."}))
+
+check(mtn("conflicts", "store", upstream_3, local_2), 0, nil, true)
+check(samefilestd("conflicts_3_2", "_MTN/conflicts"))
+
+-- 'keep' is ambiguous here, so it gives an error
+check(mtn("conflicts", "resolve_first", "keep"), 1, nil, true)
+check(qgrep("ambiguous; use 'keep_left' or 'keep_right'", "stderr"))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: conflict: file 'file_2' from revision 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: modified on the left, named file_2",
+ "mtn: dropped and recreated on the right",
+ "mtn: modified on the left",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first keep_left",
+ "mtn: resolve_first keep_right",
+ "mtn: resolve_first user_left \"name\"",
+ "mtn: resolve_first user_right \"name\""}))
+
+-- We want to keep the upstream node to avoid future conflicts
+check(mtn("conflicts", "resolve_first", "keep_left"), 0, nil, true)
+check(samefilestd("conflicts_3_2_resolved", "_MTN/conflicts"))
+
+check(mtn("explicit_merge", "--resolve-conflicts", upstream_3, local_2, "testbranch"), 0, nil, true)
+check(qgrep("mtn: dropping 'file_2'", "stderr"))
+
+check(mtn("update"), 0, nil, true)
+check(samelines("file_2", {"file_2 upstream 2"}))
+
+-- end of file
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2 bb23f1fbf87e4f1dcb8aa7c4c3fcb90e1fc84fed
@@ -0,0 +1,13 @@
+ left [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ right [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "modified file"
+ left_name "file_2"
+ left_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
+ right_type "recreated file"
+ right_name "file_2"
+ right_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2_resolved 954b8dfc7ee161c1ca809b61d03ad8fd12bfb539
@@ -0,0 +1,14 @@
+ left [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ right [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "modified file"
+ left_name "file_2"
+ left_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
+ right_type "recreated file"
+ right_name "file_2"
+ right_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
+resolved_keep_left
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone.issue-209: d4a22d4d54c5ab65e491cd43f0f12a3b96b45c78,
code <=