monotone-commits-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Monotone-commits-diffs] net.venge.monotone.issue-209: f33065689b915304e


From: code
Subject: [Monotone-commits-diffs] net.venge.monotone.issue-209: f33065689b915304ecbc095df537751e12ebd3dd
Date: Sat, 9 Jun 2012 17:32:36 +0200 (CEST)

revision:            f33065689b915304ecbc095df537751e12ebd3dd
date:                2012-06-06T06:47:14
author:              address@hidden
branch:              net.venge.monotone.issue-209
changelog:
handle dropped/modified conflict due to deleted directory.

* doc/monotone.texi: improve discussion of dropped/modified conflict due to 
deleted directory.

* src/cmd_conflicts.cc (show_conflicts): add dropped_modifed_conflict.orphaned
  (set_first_conflict): add dropped_modifed_conflict.orphaned resolutions of 
rename, user_rename

* src/merge_conflict.cc (put_file_resolution): renamed from put_resolution; 
dropped_modified has more fields in the resolution. Add content_user_rename 
case.
  (report_dropped_modified_conflicts, read_dropped_modified_conflict, 
validate_dropped_modified_conflicts): handle conflict.orphaned
  (resolve_dropped_modified_conflicts): add content_user_rename, rename.

* src/merge_roster.cc (image): add content_user_rename
  (dump): add conflict.orphaned, conflict.rename
  (assign_name): set conflict.orphaned

* src/merge_roster.hh (resolve_conflicts::resolution_t): add content_user_rename
  (dropped_modified_conflict): add orphaned, rename

* test/func/(imp)_merge((patch_foo_a),_(delete_foo_)):
* test/func/merge((drop_a),_(rename_a_b,_patch_b)):
* test/func/merge((patch_a),_(drop_a)): deleted; merged with 
resolve_conflicts_dropped_modified

* test/func/resolve_conflicts_dropped_modified/__driver__.lua: test dropped 
directory case (passing). test drop, add vs modify; not passing.

* test/func/resolve_conflicts_dropped_modified/conflicts-orphaned: New file.

* test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved: New 
file.

* test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned: New 
file.

* test/func/update_with_pending_modification/__driver__.lua: change to show 
unresolved conflict.

manifest:
format_version "1"

new_manifest [6457704d6a19512a9b8f4b362ddef41421b5233c]

old_revision [329d1fe78cc665997e872034520b09d0309f98eb]

delete "test/func/(imp)_merge((patch_foo_a),_(delete_foo_))"

delete "test/func/(imp)_merge((patch_foo_a),_(delete_foo_))/__driver__.lua"

delete "test/func/merge((drop_a),_(rename_a_b,_patch_b))"

delete "test/func/merge((drop_a),_(rename_a_b,_patch_b))/__driver__.lua"

delete "test/func/merge((patch_a),_(drop_a))"

delete "test/func/merge((patch_a),_(drop_a))/__driver__.lua"

add_file "test/func/resolve_conflicts_dropped_modified/conflicts-orphaned"
 content [1d2aa9cc3444a9002bca7ba6d74335e943fbed3c]

add_file 
"test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved"
 content [203dc22e1122af927193f34e7186bb650b77302f]

add_file "test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned"
 content [3fd23fd24470d5755be8e083666afadf9f9aad58]

patch "doc/monotone.texi"
 from [3f52411f8776e632a9b6c1d7e5e588bb1cc8b1da]
   to [f22f349d0207a09ae6806f8a57c86991a4143028]

patch "src/cmd_conflicts.cc"
 from [c88107b417e03c5d6b8b916830ba1e9c898f47c8]
   to [a4ebd8012db61009bdc9b24fc677c489b9812661]

patch "src/merge_conflict.cc"
 from [3289a8141136c7f57982a06bd6dfeac3f1251a47]
   to [b2d9fd8f7f7614af23106048c8810ae7e3c2ec60]

patch "src/merge_roster.cc"
 from [4db179b2bb8e140d9ff9bd49f09306c578348759]
   to [d68470addacbe005680b1f66a69f8a9edd4e6ea4]

patch "src/merge_roster.hh"
 from [90740a700bceeecc6f662663246ddbe655f2edcb]
   to [4bd3be5251736b3b0987a2179c6defbcd7d0b188]

patch "test/func/resolve_conflicts_dropped_modified/__driver__.lua"
 from [7f16460e30c39738b2cf25239f1b9522b6c87fa1]
   to [bcfc3ea32eb2bc76edc978567c24731402967120]

patch "test/func/update_with_pending_modification/__driver__.lua"
 from [03be28a852978808341205ba2e2f713ce8dcaf35]
   to [ac866e80c2aebb3803c42ad8ca275316050b9675]
============================================================
--- doc/monotone.texi	3f52411f8776e632a9b6c1d7e5e588bb1cc8b1da
+++ doc/monotone.texi	f22f349d0207a09ae6806f8a57c86991a4143028
@@ -3489,7 +3489,7 @@ @subheading Dropped/Modified file Confli
 
 @subheading Dropped/Modified file Conflict
 This conflict occurs when a file is dropped in one merge parent,
-and modified on the other.
+and modified in the other.
 
 @command{conflicts} supports resolving this conflict; the possible
 resolutions are to drop the file in the result, keep the modified
@@ -3505,9 +3505,12 @@ @subheading Dropped/Modified file Confli
 
 There is no such thing as a dropped/modified directory; if the
 directory is empty, the only possible change is rename, which is
-ignored. If the directory is not empty, that creates orphaned file
-conflicts.
+ignored.
 
+If the directory is not empty, that creates a special case of
+dropped/modified file conflict; if the file is kept, it must also be
+renamed to an existing directory.
+
 @subheading Invalid Name Conflict
 
 Monotone reserves the name @file{_MTN} in a workspace root directory
@@ -10435,6 +10438,20 @@ @section Automation
    right_file_id [fe6d523f607e2f2fc0f0defad3bda0351a95a337]
 @end verbatim
 
+File orphaned and modified (and possibly renamed):
address@hidden
+        conflict dropped_modified
+   ancestor_name "foo"
+ancestor_file_id [e80910e54d0bdea1b6d295ada320b87aaf9fdc23]
+       left_type "orphaned file"
+      right_type "modified file"
+      right_name "baz"
+   right_file_id [fe6d523f607e2f2fc0f0defad3bda0351a95a337]
address@hidden verbatim
+Orphaned/modified is different from dropped/modified because the
+possible resolutions are different; orphaned requires a rename if the
+file is kept.
+
 Invalid file name (@file{_MTN} in root directory):
 @verbatim
      conflict invalid_name
============================================================
--- src/cmd_conflicts.cc	c88107b417e03c5d6b8b916830ba1e9c898f47c8
+++ src/cmd_conflicts.cc	a4ebd8012db61009bdc9b24fc677c489b9812661
@@ -109,25 +109,52 @@ show_conflicts(database & db, conflicts_
             }
 
           P(F("conflict: file '%s'") % modified_name);
-          if (conflict.left_nid == the_null_node)
+          if (conflict.orphaned)
             {
-              P(F("dropped on the left"));
-              P(F("modified on the right"));
+              if (conflict.left_nid == the_null_node)
+                {
+                  P(F("orphaned on the left"));
+                  P(F("modified on the right"));
+                }
+              else
+                {
+                  P(F("modified on the left"));
+                  P(F("orphaned on the right"));
+                }
             }
           else
             {
-              P(F("modified on the left"));
-              P(F("dropped on the right"));
+              if (conflict.left_nid == the_null_node)
+                {
+                  P(F("dropped on the left"));
+                  P(F("modified on the right"));
+                }
+              else
+                {
+                  P(F("modified on the left"));
+                  P(F("dropped on the right"));
+                }
             }
 
           switch (show_case)
             {
             case first:
-              P(F("possible resolutions:"));
-              P(F("resolve_first drop"));
-              P(F("resolve_first keep"));
-              P(F("resolve_first user \"name\""));
-              return;
+              if (conflict.orphaned)
+                {
+                  P(F("possible resolutions:"));
+                  P(F("resolve_first drop"));
+                  P(F("resolve_first rename"));
+                  P(F("resolve_first user_rename \"new_content_name\" \"new_file_name\""));
+                  return;
+                }
+              else
+                {
+                  P(F("possible resolutions:"));
+                  P(F("resolve_first drop"));
+                  P(F("resolve_first keep"));
+                  P(F("resolve_first user \"name\""));
+                  return;
+                }
 
             case remaining:
               break;
@@ -427,16 +454,35 @@ set_first_conflict(database & db,
               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;
                 }
               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::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.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.resolution.first  = resolve_conflicts::content_user_rename;
+                  conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+                  conflict.rename = resolve_conflicts::new_file_path(idx(args,2)());
+                }
               else
                 {
                   E(false, origin::user,
============================================================
--- src/merge_conflict.cc	3289a8141136c7f57982a06bd6dfeac3f1251a47
+++ src/merge_conflict.cc	b2d9fd8f7f7614af23106048c8810ae7e3c2ec60
@@ -397,9 +397,9 @@ static void
 enum side_t {left_side, right_side};
 
 static void
-put_resolution(basic_io::stanza & st,
-               side_t side,
-               resolve_conflicts::file_resolution_t const & resolution)
+put_file_resolution(basic_io::stanza & st,
+                    side_t side,
+                    resolve_conflicts::file_resolution_t const & resolution)
 {
   // We output any resolution for any conflict; only valid resolutions
   // should get into the data structures. To enforce that, when reading
@@ -424,6 +424,20 @@ put_resolution(basic_io::stanza & st,
         }
       break;
 
+    case resolve_conflicts::content_user_rename:
+      switch (side)
+        {
+        case left_side:
+          st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+          break;
+
+        case right_side:
+          st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+          break;
+        }
+      // value for rename is put by caller
+      break;
+
     case resolve_conflicts::content_internal:
       st.push_symbol(syms::resolved_internal);
       break;
@@ -519,7 +533,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_resolution (st, left_side, conflict.resolution);
+  put_file_resolution (st, left_side, conflict.resolution);
 }
 
 static void
@@ -985,7 +999,7 @@ roster_merge_result::report_orphaned_nod
 
       if (basic_io)
         {
-          put_resolution (st, left_side, conflict.resolution);
+          put_file_resolution (st, left_side, conflict.resolution);
           put_stanza (st, output);
         }
     }
@@ -1104,7 +1118,14 @@ roster_merge_result::report_dropped_modi
 
           if (conflict.left_nid == the_null_node)
             {
-              st.push_str_pair(syms::left_type, "dropped file");
+              if (conflict.orphaned)
+                {
+                   st.push_str_pair(syms::left_type, "orphaned file");
+                }
+              else
+                {
+                  st.push_str_pair(syms::left_type, "dropped file");
+                }
             }
           else
             {
@@ -1116,7 +1137,14 @@ roster_merge_result::report_dropped_modi
 
           if (conflict.right_nid == the_null_node)
             {
-              st.push_str_pair(syms::right_type, "dropped file");
+              if (conflict.orphaned)
+                {
+                  st.push_str_pair(syms::right_type, "orphaned file");
+                }
+              else
+                {
+                  st.push_str_pair(syms::right_type, "dropped file");
+                }
             }
           else
             {
@@ -1126,7 +1154,26 @@ roster_merge_result::report_dropped_modi
               st.push_binary_pair(syms::right_file_id, fid.inner());
             }
 
-          put_resolution (st, left_side, conflict.resolution);
+          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;
+
+                case resolve_conflicts::content_user_rename:
+                  st.push_str_pair(syms::resolved_rename_left, conflict.rename->as_external());
+                  break;
+
+                default:
+                  // FIXME: debugging
+                  E(false, origin::user, F("conflict.resolution.first: %s") % conflict.resolution.first);
+                  I(false);
+                }
+            }
           put_stanza(st, output);
         }
       else
@@ -1134,13 +1181,27 @@ roster_merge_result::report_dropped_modi
           P(F("conflict: file '%s' from revision %s") % ancestor_name % lca_rid);
           if (conflict.left_nid == the_null_node)
             {
-              P(F("dropped on the left"));
+              if (conflict.orphaned)
+                {
+                  P(F("orphaned on the left"));
+                }
+              else
+                {
+                  P(F("dropped on the left"));
+                }
               P(F("modified on the right, named %s") % modified_name);
             }
           else
             {
               P(F("modified on the left, named %s") % modified_name);
-              P(F("dropped on the right"));
+              if (conflict.orphaned)
+                {
+                  P(F("orphaned on the right"));
+                }
+              else
+                {
+                  P(F("dropped on the right"));
+                }
             }
         }
     }
@@ -1320,8 +1381,8 @@ roster_merge_result::report_duplicate_na
 
       if (basic_io)
         {
-          put_resolution (st, left_side, conflict.left_resolution);
-          put_resolution (st, right_side, conflict.right_resolution);
+          put_file_resolution (st, left_side, conflict.left_resolution);
+          put_file_resolution (st, right_side, conflict.right_resolution);
           put_stanza(st, output);
         }
     }
@@ -1865,6 +1926,11 @@ read_dropped_modified_conflict(basic_io:
     {
       // no more data for left
     }
+  else if (tmp == "orphaned file")
+    {
+      // no more data for left
+      conflict.orphaned = true;
+    }
   else
     {
       // modified file
@@ -1880,6 +1946,11 @@ read_dropped_modified_conflict(basic_io:
     {
       // no more data for right
     }
+  else if (tmp == "orphaned file")
+    {
+      // no more data for right
+      conflict.orphaned = true;
+    }
   else
     {
       // modified file
@@ -1898,6 +1969,8 @@ read_dropped_modified_conflict(basic_io:
         }
       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;
           pars.sym();
         }
@@ -1907,7 +1980,24 @@ read_dropped_modified_conflict(basic_io:
           pars.sym();
           conflict.resolution.second = 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 = new_optimal_path(tmp, false);
+            }
         }
+      else if (pars.symp (syms::resolved_rename_left))
+        {
+          E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+
+          conflict.resolution.first = resolve_conflicts::rename;
+          pars.sym();
+          conflict.resolution.second = new_optimal_path(pars.token, false);
+          pars.str();
+        }
       else
         E(false, origin::user,
           F(conflict_resolution_not_supported_msg) % pars.token % "dropped_modified");
@@ -1958,6 +2048,7 @@ validate_dropped_modified_conflicts(basi
         F(conflicts_mismatch_msg));
 
       merge_conflict.resolution = file_conflict.resolution;
+      merge_conflict.rename     = file_conflict.rename;
 
       if (pars.tok.in.lookahead != EOF)
         pars.esym (syms::conflict);
@@ -2586,6 +2677,34 @@ roster_merge_result::resolve_orphaned_no
   orphaned_node_conflicts.clear();
 }
 
+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)
+{
+  // See comments in keep below on why we drop first
+  roster.drop_detached_node(nid);
+
+  file_data result_data;
+  data result_raw_data;
+  file_id result_fid;
+  read_data(*conflict.resolution.second, result_raw_data);
+
+  result_data = file_data(result_raw_data);
+  calculate_ident(result_data, result_fid);
+
+  nid = roster.create_file_node(result_fid, nis);
+
+  // User could specify no changes
+  if (result_fid != modified_fid)
+    {
+      adaptor.record_file(result_fid, result_data);
+    }
+}
+
 void
 roster_merge_result::resolve_dropped_modified_conflicts(lua_hooks & lua,
                                                         roster_t const & left_roster,
@@ -2632,33 +2751,32 @@ roster_merge_result::resolve_dropped_mod
           P(F("replacing content of '%s' with '%s'") %
             modified_name % conflict.resolution.second->as_external());
 
-          {
-            // See comments in keep below on why we drop first
-            roster.drop_detached_node(nid);
+          resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
+          attach_node(lua, roster, nid, modified_name);
+          break;
 
-            file_data result_data;
-            data result_raw_data;
-            file_id result_fid;
-            read_data(*conflict.resolution.second, result_raw_data);
+        case resolve_conflicts::content_user_rename:
+          I(conflict.rename != 0);
+          P(F("replacing content of '%s' (renamed to '%s') with '%s'") %
+            modified_name % conflict.rename->as_external() % conflict.resolution.second->as_external());
 
-            result_data = file_data(result_raw_data);
-            calculate_ident(result_data, result_fid);
+          resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
+          attach_node(lua, roster, nid, file_path_internal (conflict.rename->as_internal()));
+          break;
 
-            nid = roster.create_file_node(result_fid, nis);
+        case resolve_conflicts::drop:
+          P(F("dropping '%s'") % modified_name);
 
-            // User could specify no changes
-            if (result_fid != modified_fid)
-              {
-                adaptor.record_file(result_fid, result_data);
-              }
-            attach_node(lua, roster, nid, modified_name);
-          }
+          roster.drop_detached_node(nid);
           break;
 
-        case resolve_conflicts::drop:
-          P(F("dropping '%s'") % modified_name);
+        case resolve_conflicts::rename:
+          P(F("renaming '%s' to '%s'") % modified_name % conflict.resolution.second->as_external());
 
+          // 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;
 
         case resolve_conflicts::keep:
============================================================
--- src/merge_roster.cc	4db179b2bb8e140d9ff9bd49f09306c578348759
+++ src/merge_roster.cc	d68470addacbe005680b1f66a69f8a9edd4e6ea4
@@ -42,6 +42,8 @@ image(resolve_conflicts::resolution_t re
       return "keep";
     case resolve_conflicts::rename:
       return "rename";
+    case resolve_conflicts::content_user_rename:
+      return "content_user_rename";
     }
   I(false); // keep compiler happy
 }
@@ -94,10 +96,12 @@ dump(dropped_modified_conflict const & c
   ostringstream oss;
   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 << " name: " << conflict.resolution.second;
+      oss << " new_content_name: " << conflict.resolution.second;
+      oss << " rename: " << conflict.rename;
     }
   oss << "\n";
   out = oss.str();
@@ -435,14 +439,33 @@ namespace
       }
     else
       {
+        // We need this in two places
+        std::vector<dropped_modified_conflict>::iterator dropped_modified =
+          find(result.dropped_modified_conflicts.begin(),
+               result.dropped_modified_conflicts.end(),
+               nid);
+
         // orphan:
         if (!result.roster.has_node(parent))
           {
-            orphaned_node_conflict c;
-            c.nid = nid;
-            c.parent_name = make_pair(parent, name);
-            result.orphaned_node_conflicts.push_back(c);
-            return;
+            // If the orphaned node is due to the parent directory being
+            // dropped, and the orphaned node is modified, then it already
+            // has a dropped_modified conflict; add the orphaned information
+            // to that.
+
+            if (result.dropped_modified_conflicts.end() != dropped_modified)
+              {
+                dropped_modified->orphaned = true;
+                return;
+              }
+            else
+              {
+                orphaned_node_conflict c;
+                c.nid = nid;
+                c.parent_name = make_pair(parent, name);
+                result.orphaned_node_conflicts.push_back(c);
+                return;
+              }
           }
 
         dir_t p = downcast_to_dir_t(result.roster.get_node_for_update(parent));
@@ -490,10 +513,7 @@ namespace
             return;
           }
 
-        if (result.dropped_modified_conflicts.end() !=
-            find(result.dropped_modified_conflicts.begin(),
-                 result.dropped_modified_conflicts.end(),
-                 nid))
+        if (result.dropped_modified_conflicts.end() != dropped_modified)
           {
             // conflict already entered, just don't attach
             return;
============================================================
--- src/merge_roster.hh	90740a700bceeecc6f662663246ddbe655f2edcb
+++ src/merge_roster.hh	4bd3be5251736b3b0987a2179c6defbcd7d0b188
@@ -29,7 +29,7 @@ namespace resolve_conflicts
 
 namespace resolve_conflicts
 {
-  enum resolution_t {none, content_user, content_internal, drop, keep, rename};
+  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;
 
@@ -95,9 +95,19 @@ struct dropped_modified_conflict
 struct dropped_modified_conflict
 {
   node_id left_nid, right_nid; // the dropped side is the null node, modified is valid.
+
+  bool orphaned; // if true, the dropped side is due to a dropped parent directory
+
   resolve_conflicts::file_resolution_t resolution;
+  boost::shared_ptr<any_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.
 
-  dropped_modified_conflict(node_id left_nid, node_id right_nid) : left_nid(left_nid), right_nid(right_nid)
+  dropped_modified_conflict(node_id left_nid, node_id right_nid) :
+    left_nid(left_nid),
+    right_nid(right_nid),
+    orphaned(false)
   {resolution.first = resolve_conflicts::none;}
 
   bool operator==(node_id n) {return left_nid == n || right_nid == n;}
============================================================
--- test/func/(imp)_merge((patch_foo_a),_(delete_foo_))/__driver__.lua	7369a583460c9839c752d40173538c32ea635a0a
+++ /dev/null	
@@ -1,24 +0,0 @@
-
-mtn_setup()
-
-mkdir("foo")
-addfile("foo/a", "blah blah")
-commit()
-base = base_revision()
-
-check(mtn("drop", "--bookkeep-only", "--recursive", "foo"), 0, false, false)
-commit()
-
-remove("foo")
-revert_to(base)
-
-writefile("foo/a", "some other stuff")
-commit()
-
-check(mtn("--branch=testbranch", "merge"), 0, false, false)
-
-check(mtn("checkout", "--revision", base, "test_dir"), 0, false, false)
-check(indir("test_dir", mtn("update", "--branch=testbranch")), 0, false, false)
-
-check(not exists("test_dir/foo/a"))
-check(not exists("test_dir/bar/a"))
============================================================
--- test/func/merge((drop_a),_(rename_a_b,_patch_b))/__driver__.lua	7c6a662fa620c7515804cb6e5e513549429015c5
+++ /dev/null	
@@ -1,27 +0,0 @@
-
-mtn_setup()
-
-writefile("original", "some stuff here")
-
-check(mtn("add", "original"), 0, false, false)
-commit()
-base = base_revision()
-
--- drop it
-check(mtn("drop", "--bookkeep-only", "original"), 0, false, false)
-commit()
-
-revert_to(base)
-
--- patch and rename it
-rename("original", "different")
-check(mtn("rename", "--bookkeep-only", "original", "different"), 0, false, false)
-append("different", "more\n")
-commit()
-
-check(mtn("merge"), 0, false, false)
-check(mtn("checkout", "-b", "testbranch", "clean"), 0, false, false)
-
--- check that the file doesn't exist
-check(not exists("clean/original"))
-check(not exists("clean/different"))
============================================================
--- test/func/merge((patch_a),_(drop_a))/__driver__.lua	336ee81dc87b3f5843cfcbc94b0e2c899f965523
+++ /dev/null	
@@ -1,27 +0,0 @@
-
-mtn_setup()
-
-writefile("base", "foo blah")
-writefile("left", "bar blah")
-
-copy("base", "testfile")
-check(mtn("add", "testfile"), 0, false, false)
-commit()
-base = base_revision()
-
-copy("left", "testfile")
-commit()
-left = base_revision()
-
-revert_to(base)
-
-check(mtn("drop", "testfile"), 0, false, false)
-commit()
-
-check(mtn("merge"), 0, false, true)
-
--- check that we're warned about the changes being dropped...
-
-check(qgrep("content changes to the file", "stderr"))
-check(qgrep(left, "stderr"))
-
============================================================
--- test/func/resolve_conflicts_dropped_modified/__driver__.lua	7f16460e30c39738b2cf25239f1b9522b6c87fa1
+++ test/func/resolve_conflicts_dropped_modified/__driver__.lua	bcfc3ea32eb2bc76edc978567c24731402967120
@@ -8,6 +8,8 @@ mtn_setup()
 -- Six conflicts to test the three possible resolutions, with drop on
 -- both left and right. Number in file name is the node number (helps
 -- in debugging; node 1 is the root directory).
+--
+-- The case of a modified file in a dropped directory is tested below.
 
 addfile("file_2", "file_2 base") -- modify/rename left, drop right; drop
 addfile("file_3", "file_3 base") -- drop left, modify/rename right; drop
@@ -166,12 +168,7 @@ check(not qgrep("warning", "stderr"))
 check(qgrep("replacing content of 'file_7_renamed' with '_MTN/resolutions/file_7_resolved", "stderr"))
 check(not qgrep("warning", "stderr"))
 
--- There is no such thing as a dropped/modified directory; if the
--- directory is empty, the only possible change is rename, which is
--- ignored. If the directory is not empty, that creates orphaned file
--- conflicts.
---
--- Similarly, if a file is renamed (without other change) and dropped,
+-- If a file is renamed (without other change) and dropped,
 -- the change is ignored:
 
 addfile("file_8", "file_8 base") -- rename left, drop right
@@ -191,4 +188,123 @@ check(qgrep("0 conflicts", "stderr"))
 check(mtn("show_conflicts", left_2, right_2), 0, nil, true)
 check(qgrep("0 conflicts", "stderr"))
 
+-- There is no such thing as a dropped/modified directory; if the
+-- directory is empty, the only possible change is rename, which is
+-- ignored.
+--
+-- If the directory is not empty, that creates a dropped/modified file
+-- conflict (not an orphaned file conflict, although that would also
+-- make sense). This used to be the test
+-- "(imp)_merge((patch_foo_a),_(delete_foo_))"
+--
+-- We create three potential conflicts; one ignored, three with different resolutions:
+
+adddir("dir1") -- empty, dropped and renamed (not a conflict; just dropped)
+mkdir("dir2")  -- not empty, dropped, contents modified
+addfile("dir2/file_9", "file_9 base") -- resolved by rename
+addfile("dir2/file_10", "file_10 base") -- resolved by user_rename
+addfile("dir2/file_11", "file_11 base") -- resolved by drop
+commit("testbranch", "base 3")
+base_3 = base_revision()
+
+check(mtn("mv", "dir1", "dir3"), 0, false, false)
+
+writefile("dir2/file_9", "file_9 left")
+writefile("dir2/file_10", "file_10 left")
+writefile("dir2/file_11", "file_11 left")
+commit("testbranch", "left 3")
+left_3 = base_revision()
+
+revert_to(base_3)
+
+check(mtn("drop", "dir1", "--no-recursive"), 0, false, false)
+
+check(mtn("drop", "--recursive", "dir2"), 0, false, false)
+
+commit("testbranch", "right 3")
+right_3 = base_revision()
+
+check(mtn("show_conflicts", left_3, right_3), 0, nil, true)
+canonicalize("stderr")
+check(samefilestd("show_conflicts-orphaned", "stderr"))
+
+-- Show these conflicts can be resolved
+check(mtn("conflicts", "store", left_3, right_3), 0, nil, true)
+
+canonicalize("_MTN/conflicts")
+check(samefilestd("conflicts-orphaned", "_MTN/conflicts"))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'dir2/file_10'",
+ "mtn: modified on the left",
+ "mtn: orphaned on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first drop",
+ "mtn: resolve_first rename",
+ "mtn: resolve_first user_rename \"new_content_name\" \"new_file_name\""}))
+
+mkdir("_MTN")
+mkdir("_MTN/resolutions")
+writefile("_MTN/resolutions/file_10", "file_10 user")
+check(mtn("conflicts", "resolve_first", "user_rename", "_MTN/resolutions/file_10", "file_10"), 0, nil, true)
+
+check(mtn("conflicts", "resolve_first", "drop"), 0, nil, nil)
+
+check(mtn("conflicts", "resolve_first", "rename", "file_9"), 0, nil, nil)
+
+check(samefilestd("conflicts-orphaned-resolved", "_MTN/conflicts"))
+
+check(mtn("explicit_merge", "--resolve-conflicts", left_3, right_3, "testbranch"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: [left]  5ac4e947066417642f5404b9a54d4d8487bda002",
+ "mtn: [right] d542a5d8e86dc29448a27449688d6f4fffcec72b",
+ "mtn: replacing content of 'dir2/file_10' (renamed to 'file_10') with '_MTN/resolutions/file_10'",
+ "mtn: dropping 'dir2/file_11'",
+ "mtn: renaming 'dir2/file_9' to 'file_9'",
+ "mtn: [merged] 202584446f5184430d1f8320eb702a5f81134505"}))
+
+ 
+-- A special case; drop then re-add vs modify. This used to be the test
+-- "merge((patch_a),_(drop_a,_add_a))"
+addfile("file_10", "file_10 base")
+commit("testbranch", "base 4")
+base_4 = base_revision()
+
+writefile("file_10", "file_10 left")
+commit("testbranch", "left 4")
+left_4 = base_revision()
+
+revert_to(base_4)
+
+check(mtn("drop", "file_10"), 0, false, false)
+commit("testbranch", "right 4a")
+
+addfile("file_10", "file_10 right re-add")
+commit("testbranch", "right 4b")
+right_4 = base_revision()
+
+check(mtn("show_conflicts", left_4, right_4), 0, nil, true)
+check(qgrep("mtn: conflict: file 'file_10'", "stderr"))
+check(qgrep("mtn: modified on the left", "stderr"))
+check(qgrep("mtn: dropped on the right", "stderr"))
+check(qgrep("mtn: 1 conflict with supported resolutions.", "stderr"))
+
+-- FIXME: Show this conflict can't be resolved by keep; two new nodes with same name
+check(mtn("conflicts", "store", left_4, right_4), 0, nil, true)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_10'",
+ "mtn: modified on the left",
+ "mtn: dropped on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first drop",
+ "mtn: resolve_first keep",
+ "mtn: resolve_first user \"name\""}))
+
+check(mtn("conflicts", "resolve_first", "keep"), 0, nil, true)
+
+check(mtn("explicit_merge", "--resolve-conflicts", left_4, right_4, "testbranch"), 0, nil)
+
 -- end of file
============================================================
--- /dev/null	
+++ test/func/resolve_conflicts_dropped_modified/conflicts-orphaned	1d2aa9cc3444a9002bca7ba6d74335e943fbed3c
@@ -0,0 +1,27 @@
+    left [5ac4e947066417642f5404b9a54d4d8487bda002]
+   right [d542a5d8e86dc29448a27449688d6f4fffcec72b]
+ancestor [70ef90574731a834d932669e77be7f89662e9097]
+
+        conflict dropped_modified
+   ancestor_name "dir2/file_10"
+ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
+       left_type "modified file"
+       left_name "dir2/file_10"
+    left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
+      right_type "orphaned file"
+
+        conflict dropped_modified
+   ancestor_name "dir2/file_11"
+ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
+       left_type "modified file"
+       left_name "dir2/file_11"
+    left_file_id [ea74c930ce75ac43380f520f9cdd4e85f56ed049]
+      right_type "orphaned file"
+
+        conflict dropped_modified
+   ancestor_name "dir2/file_9"
+ancestor_file_id [6259d1132e063364597e6ee84a431b432f0e9cf9]
+       left_type "modified file"
+       left_name "dir2/file_9"
+    left_file_id [d1c21ac76fd433b5f1daead0438938b45f9e13a8]
+      right_type "orphaned file"
============================================================
--- /dev/null	
+++ test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved	203dc22e1122af927193f34e7186bb650b77302f
@@ -0,0 +1,31 @@
+    left [5ac4e947066417642f5404b9a54d4d8487bda002]
+   right [d542a5d8e86dc29448a27449688d6f4fffcec72b]
+ancestor [70ef90574731a834d932669e77be7f89662e9097]
+
+            conflict dropped_modified
+       ancestor_name "dir2/file_10"
+    ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
+           left_type "modified file"
+           left_name "dir2/file_10"
+        left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
+          right_type "orphaned file"
+  resolved_user_left "_MTN/resolutions/file_10"
+resolved_rename_left "file_10"
+
+          conflict dropped_modified
+     ancestor_name "dir2/file_11"
+  ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
+         left_type "modified file"
+         left_name "dir2/file_11"
+      left_file_id [ea74c930ce75ac43380f520f9cdd4e85f56ed049]
+        right_type "orphaned file"
+resolved_drop_left 
+
+            conflict dropped_modified
+       ancestor_name "dir2/file_9"
+    ancestor_file_id [6259d1132e063364597e6ee84a431b432f0e9cf9]
+           left_type "modified file"
+           left_name "dir2/file_9"
+        left_file_id [d1c21ac76fd433b5f1daead0438938b45f9e13a8]
+          right_type "orphaned file"
+resolved_rename_left "file_9"
============================================================
--- /dev/null	
+++ test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned	3fd23fd24470d5755be8e083666afadf9f9aad58
@@ -0,0 +1,13 @@
+mtn: [left]     5ac4e947066417642f5404b9a54d4d8487bda002
+mtn: [right]    d542a5d8e86dc29448a27449688d6f4fffcec72b
+mtn: [ancestor] 70ef90574731a834d932669e77be7f89662e9097
+mtn: conflict: file 'dir2/file_10' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_10
+mtn: orphaned on the right
+mtn: conflict: file 'dir2/file_11' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_11
+mtn: orphaned on the right
+mtn: conflict: file 'dir2/file_9' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_9
+mtn: orphaned on the right
+mtn: 3 conflicts with supported resolutions.
============================================================
--- test/func/update_with_pending_modification/__driver__.lua	03be28a852978808341205ba2e2f713ce8dcaf35
+++ test/func/update_with_pending_modification/__driver__.lua	ac866e80c2aebb3803c42ad8ca275316050b9675
@@ -1,3 +1,4 @@
+-- Test the case of update where there is a dropped/modified conflict
 
 mtn_setup()
 
@@ -5,28 +6,25 @@ commit()
 addfile("file1", "contents of file1")
 commit()
 
--- store the newly created revision id
 REV1=base_revision()
 
--- check(mtn("--branch", "testbranch", "co", "codir"), 0, false, false)
--- writefile("codir/file2", "contents of file2")
-
--- add another file and commit
+-- add another file, then change it
 addfile("file2", "contents of file2")
 commit()
 
--- change that new file
 writefile("file2", "new contents of file2")
 
--- .. and upadte to the previous revision, which didn't have file2.
--- At the moment, this simply drops file2 and all changes to it.
---
--- See bug #15058
+-- update to the previous revision, which didn't have file2. This
+-- looks like file2 is dropped on one side (in rev 1), and modified on
+-- the other (the workspace), so we get a dropped/modified conflict.
 
-xfail(mtn("update", "-r", REV1), 1, true, true)
+check(mtn("update", "-r", REV1), 1, true, true)
+check(qgrep("mtn: conflict: file 'file2'"), "stderr")
+check(qgrep("mtn: modified on the left, named file2"), "stderr")
+check(qgrep("mtn: dropped on the right"), "stderr")
+check(qgrep("mtn: misuse: merge failed due to unresolved conflicts"), "stderr")
 
--- IMO, the correct curse of action should be to fail updating due to
--- a conflict.
-check(exists("file2"))
-check(samelines("file2", {"new contents of file2"}))
+-- Since this is a workspace merge, we can't resolve the conflict; the
+-- modified file must be committed first.
 
+-- end of file

reply via email to

[Prev in Thread] Current Thread [Next in Thread]