You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ph...@apache.org on 2013/01/18 14:56:30 UTC

svn commit: r1435138 - in /subversion/trunk/subversion: libsvn_wc/update_editor.c libsvn_wc/wc-queries.sql libsvn_wc/wc.h libsvn_wc/wc_db_update_move.c tests/cmdline/update_tests.py tests/libsvn_wc/op-depth-test.c

Author: philip
Date: Fri Jan 18 13:56:30 2013
New Revision: 1435138

URL: http://svn.apache.org/viewvc?rev=1435138&view=rev
Log:
Handle delete conflicts during move-update by raising tree-conflicts
and converting modified trees to copies.

* subversion/libsvn_wc/wc_db_update_move.c
  (tc_editor_delete): Handle delete conflicts.
  (get_info): Return correct enum type.

* subversion/libsvn_wc/wc.h
  (svn_wc__node_has_local_mods): New.

* subversion/libsvn_wc/update_editor.c
  (node_has_local_mods): Renamed to ...
  (svn_wc__node_has_local_mods): ... this, made non-static.
  (check_tree_conflict): Adjust call.

* subversion/libsvn_wc/wc-queries.sql
  (STMT_DELETE_WORKING_OP_DEPTH_ABOVE, STMT_UPDATE_OP_DEPTH_RECURSIVE): New.

* subversion/tests/libsvn_wc/op-depth-test.c
  (move_update_delete_mods): New test.
  (test_funcs): Add new test.

* subversion/tests/cmdline/update_tests.py
  (update_moved_dir_leaf_del, update_moved_dir_file_add): Do non-recursive
   resolves, expect delete-delete conflicts.

Modified:
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/libsvn_wc/wc-queries.sql
    subversion/trunk/subversion/libsvn_wc/wc.h
    subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c
    subversion/trunk/subversion/tests/cmdline/update_tests.py
    subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Fri Jan 18 13:56:30 2013
@@ -1322,14 +1322,14 @@ modcheck_callback(void *baton,
  * is set to true and all the local modifications were deletes then set
  * *ALL_EDITS_ARE_DELETES to true, set it to false otherwise.  LOCAL_ABSPATH
  * may be a file or a directory. */
-static svn_error_t *
-node_has_local_mods(svn_boolean_t *modified,
-                    svn_boolean_t *all_edits_are_deletes,
-                    svn_wc__db_t *db,
-                    const char *local_abspath,
-                    svn_cancel_func_t cancel_func,
-                    void *cancel_baton,
-                    apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__node_has_local_mods(svn_boolean_t *modified,
+                            svn_boolean_t *all_edits_are_deletes,
+                            svn_wc__db_t *db,
+                            const char *local_abspath,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            apr_pool_t *scratch_pool)
 {
   modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE };
   svn_error_t *err;
@@ -1496,10 +1496,10 @@ check_tree_conflict(svn_skel_t **pconfli
          * not visit the subdirectories of a directory that it wants to delete.
          * Therefore, we need to start a separate crawl here. */
 
-        SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes,
-                                    eb->db, local_abspath,
-                                    eb->cancel_func, eb->cancel_baton,
-                                    scratch_pool));
+        SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_mods_are_deletes,
+                                            eb->db, local_abspath,
+                                            eb->cancel_func, eb->cancel_baton,
+                                            scratch_pool));
 
         if (modified)
           {

Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Fri Jan 18 13:56:30 2013
@@ -226,6 +226,12 @@ WHERE wc_id = ?1 
   AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
   AND op_depth = ?3
 
+-- STMT_DELETE_WORKING_OP_DEPTH_ABOVE
+DELETE FROM nodes
+WHERE wc_id = ?1 
+  AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+  AND op_depth > ?3
+
 -- STMT_SELECT_LOCAL_RELPATH_OP_DEPTH
 SELECT local_relpath
 FROM nodes
@@ -885,6 +891,12 @@ WHERE wc_id = ?1
  AND IS_STRICT_DESCENDANT_OF(local_relpath, ?2)
  AND op_depth = ?3
 
+-- STMT_UPDATE_OP_DEPTH_RECURSIVE
+UPDATE nodes SET op_depth = ?4, moved_here = NULL
+WHERE wc_id = ?1
+ AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+ AND op_depth = ?3
+
 -- STMT_DOES_NODE_EXIST
 SELECT 1 FROM nodes WHERE wc_id = ?1 AND local_relpath = ?2
 LIMIT 1

Modified: subversion/trunk/subversion/libsvn_wc/wc.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc.h?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc.h (original)
+++ subversion/trunk/subversion/libsvn_wc/wc.h Fri Jan 18 13:56:30 2013
@@ -783,6 +783,15 @@ svn_wc__revert_internal(svn_wc__db_t *db
                         void *notify_baton,
                         apr_pool_t *scratch_pool);
 
+svn_error_t *
+svn_wc__node_has_local_mods(svn_boolean_t *modified,
+                            svn_boolean_t *all_edits_are_deletes,
+                            svn_wc__db_t *db,
+                            const char *local_abspath,
+                            svn_cancel_func_t cancel_func,
+                            void *cancel_baton,
+                            apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db_update_move.c Fri Jan 18 13:56:30 2013
@@ -843,6 +843,52 @@ tc_editor_delete(void *baton,
                               svn_wc_conflict_action_delete,
                               scratch_pool));
 
+  if (!is_conflicted)
+    {
+      svn_boolean_t is_modified, is_all_deletes;
+
+      SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes, b->db,
+                                          svn_dirent_join(b->wcroot->abspath,
+                                                          relpath,
+                                                          scratch_pool),
+                                          NULL, NULL, scratch_pool));
+      if (is_modified)
+        {
+          /* No conflict means no NODES rows at the relpath op-depth
+             so it's easy to convert the modified tree into a copy. */
+          SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+                                            STMT_UPDATE_OP_DEPTH_RECURSIVE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath,
+                                    op_depth, relpath_depth(relpath)));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+
+          SVN_ERR(mark_tree_conflict(b, relpath,
+                                     /* ### kinds? */
+                                     svn_node_dir, svn_node_dir,
+                                     svn_wc_conflict_reason_edited,
+                                     svn_wc_conflict_action_delete, NULL,
+                                     scratch_pool));
+          is_conflicted = TRUE;
+        }
+      else if (is_all_deletes)
+        {
+          SVN_ERR(mark_tree_conflict(b, relpath,
+                                     /* ### kinds? */
+                                     svn_node_dir, svn_node_dir,
+                                     svn_wc_conflict_reason_deleted,
+                                     svn_wc_conflict_action_delete, NULL,
+                                     scratch_pool));
+
+          SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
+                                          STMT_DELETE_WORKING_OP_DEPTH_ABOVE));
+          SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
+                                    op_depth));
+          SVN_ERR(svn_sqlite__step_done(stmt));
+
+          is_conflicted = TRUE;
+        }
+    }
+
   /* Deleting the ROWS is valid so long as we update the parent before
      committing the transaction. */
   SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
@@ -1047,7 +1093,7 @@ get_info(apr_hash_t **props,
   if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
     {
       svn_error_clear(err);
-      *kind = svn_node_none;
+      *kind = svn_kind_none;
     }
   else
     SVN_ERR(err);

Modified: subversion/trunk/subversion/tests/cmdline/update_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/update_tests.py?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/update_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/update_tests.py Fri Jan 18 13:56:30 2013
@@ -5462,14 +5462,15 @@ def update_moved_dir_leaf_del(sbox):
                                         None, None, None,
                                         None, None, 1)
 
-  # Now resolve the conflict, using --accept=mine-conflict.
-  # This should apply the update to A/B/E2, deleting A/B/E2/alpha.
+  # Now resolve the conflict, using --accept=mine-conflict applying
+  # the update to A/B/E2 causing a delete-delete conflict
   svntest.actions.run_and_verify_svn("resolve failed", None, [],
                                      'resolve',
-                                     '--recursive',
-                                     '--accept=mine-conflict', wc_dir)
+                                     '--accept=mine-conflict',
+                                     sbox.ospath('A/B/E'))
   expected_status.tweak('A/B/E', treeconflict=None)
-  expected_status.remove('A/B/E2/alpha')
+  expected_status.tweak('A/B/E2/alpha', status='? ', treeconflict='C',
+                        copied=None, wc_rev=None)
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 @XFail()
@@ -5581,8 +5582,8 @@ def update_moved_dir_file_add(sbox):
   # This should apply the update to A/B/E2, adding A/B/E2/foo.
   svntest.actions.run_and_verify_svn("resolve failed", None, [],
                                      'resolve',
-                                     '--recursive',
-                                     '--accept=mine-conflict', wc_dir)
+                                     '--accept=mine-conflict',
+                                     sbox.ospath('A/B/E'))
   # the incoming file should auto-merge
   expected_status.tweak('A/B/E', treeconflict=None)
   expected_status.add({
@@ -5697,15 +5698,15 @@ def update_moved_dir_file_move(sbox):
 
   # The incoming change is a delete as we don't yet track server-side
   # moves.  Resolving the tree-conflict as "mine-conflict" applies the
-  # delete to the move destination.  This is effectively accepting the
-  # move from the server.
+  # delete to the move destination creating a delete-delete conflict.
   svntest.actions.run_and_verify_svn("resolve failed", None, [],
                                      'resolve',
-                                     '--recursive',
-                                     '--accept=mine-conflict', wc_dir)
+                                     '--accept=mine-conflict',
+                                     sbox.ospath('A/B/E'))
 
   expected_status.tweak('A/B/E', treeconflict=None)
-  expected_status.remove('A/B/E2/alpha')
+  expected_status.tweak('A/B/E2/alpha', status='? ', treeconflict='C',
+                        copied=None, wc_rev=None)
   svntest.actions.run_and_verify_status(wc_dir, expected_status)
 
 

Modified: subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c?rev=1435138&r1=1435137&r2=1435138&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Fri Jan 18 13:56:30 2013
@@ -5624,6 +5624,72 @@ move_update_conflicts(const svn_test_opt
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+move_update_delete_mods(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  svn_test__sandbox_t b;
+
+  SVN_ERR(svn_test__sandbox_create(&b, "move_update_delete_mods", opts, pool));
+
+  SVN_ERR(sbox_wc_mkdir(&b, "A"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/C"));
+  SVN_ERR(sbox_wc_mkdir(&b, "A/B/D"));
+  sbox_file_write(&b, "A/B/C/f", "r1 content\n");
+  SVN_ERR(sbox_wc_add(&b, "A/B/C/f"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_delete(&b, "A/B/C"));
+  SVN_ERR(sbox_wc_delete(&b, "A/B/D"));
+  SVN_ERR(sbox_wc_commit(&b, ""));
+  SVN_ERR(sbox_wc_update(&b, "", 1));
+
+  SVN_ERR(sbox_wc_move(&b, "A/B", "B2"));
+  sbox_file_write(&b, "B2/C/f", "modified content\n");
+  SVN_ERR(sbox_wc_delete(&b, "B2/D"));
+  {
+    nodes_row_t nodes[] = {
+      {0, "",        "normal",       1, ""},
+      {0, "A",       "normal",       1, "A"},
+      {0, "A/B",     "normal",       1, "A/B"},
+      {0, "A/B/C",   "normal",       1, "A/B/C"},
+      {0, "A/B/C/f", "normal",       1, "A/B/C/f"},
+      {0, "A/B/D",   "normal",       1, "A/B/D"},
+      {2, "A/B",     "base-deleted",  NO_COPY_FROM, "B2"},
+      {2, "A/B/C",   "base-deleted",  NO_COPY_FROM},
+      {2, "A/B/C/f", "base-deleted",  NO_COPY_FROM},
+      {2, "A/B/D",   "base-deleted",  NO_COPY_FROM},
+      {1, "B2",      "normal",       1, "A/B", MOVED_HERE},
+      {1, "B2/C",    "normal",       1, "A/B/C", MOVED_HERE},
+      {1, "B2/C/f",  "normal",       1, "A/B/C/f", MOVED_HERE},
+      {1, "B2/D",    "normal",       1, "A/B/D", MOVED_HERE},
+      {2, "B2/D",    "base-deleted", NO_COPY_FROM},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(sbox_wc_update(&b, "A", 2));
+  SVN_ERR(sbox_wc_resolve(&b, "A/B", svn_wc_conflict_choose_mine_conflict));
+  {
+    nodes_row_t nodes[] = {
+      {0, "",        "normal",       1, ""},
+      {0, "A",       "normal",       2, "A"},
+      {0, "A/B",     "normal",       2, "A/B"},
+      {2, "A/B",     "base-deleted",  NO_COPY_FROM, "B2"},
+      {1, "B2",      "normal",       2, "A/B", MOVED_HERE},
+      {2, "B2/C",    "normal",       1, "A/B/C"},
+      {2, "B2/C/f",  "normal",       1, "A/B/C/f"},
+      {0}
+    };
+    SVN_ERR(check_db_rows(&b, "", nodes));
+  }
+
+  SVN_ERR(check_tree_conflict_repos_path(&b, "B2/C", "A/B/C", "A/B/C"));
+  SVN_ERR(check_tree_conflict_repos_path(&b, "B2/D", "A/B/D", "A/B/D"));
+
+  return SVN_NO_ERROR;
+}
+
 
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
@@ -5731,5 +5797,7 @@ struct svn_test_descriptor_t test_funcs[
                        "nested_move_update2"),
     SVN_TEST_OPTS_PASS(move_update_conflicts,
                        "move_update_conflicts"),
+    SVN_TEST_OPTS_PASS(move_update_delete_mods,
+                       "move_update_delete_mods"),
     SVN_TEST_NULL
   };