You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2011/05/12 01:55:47 UTC

svn commit: r1102143 - in /subversion/trunk/subversion: libsvn_wc/update_editor.c tests/cmdline/switch_tests.py

Author: rhuijben
Date: Wed May 11 23:55:47 2011
New Revision: 1102143

URL: http://svn.apache.org/viewvc?rev=1102143&view=rev
Log:
Make the add part of the update in the issue #3879 test added in r1101833
continue under the installed tree conflict for the deletion. Update the
existing tree conflict to report an incoming replacement.

* subversion/libsvn_wc/update_editor.c
  (dir_baton): Add optional hash for deletion tree conflicts.
  (check_tree_conflict): Implement result + scratch pool pattern.
  (delete_entry): Create tree conflict in parent directory pool and store
    it there for reuse when adding a new node in its place.

  (add_directory): When we see a conflict, check if we just introduced it
    ourself by deleting an older node. If so, update the tree conflict and
    continue as a shadowed addition. Update caller.
  (open_directory): Update caller.

  (add_file): When we see a conflict, check if we just introduced it ourself
    by deleting an older node. If so, update the tree conflict and continue
    as a shadowed addition. Update caller.
  (open_file): Update caller.
  (close_file): Update caller.

* subversion/tests/cmdline/switch_tests.py
  (failed_anchor_is_target): Assume that we just continue below the tree
    conflict, where we used to skip the add part of the replacement.

Modified:
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/cmdline/switch_tests.py

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1102143&r1=1102142&r2=1102143&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Wed May 11 23:55:47 2011
@@ -294,6 +294,14 @@ struct dir_baton
      marked as deleted. */
   svn_boolean_t shadowed;
 
+  /* If not NULL, contains a mapping of const char* basenames of children that have been
+     deleted to their svn_wc_conflict_description2_t* tree conflicts. We store this hash
+     to allow replacements      to continue under a just installed tree conflict.
+
+     The add after the delete will then update the tree conflicts information and
+     reinstall it. */
+  apr_hash_t *deletion_conflicts;
+
   /* Set if an unversioned dir of the same name already existed in
      this directory. */
   svn_boolean_t obstruction_found;
@@ -1302,7 +1310,8 @@ create_tree_conflict(svn_wc_conflict_des
  * Simply put, that's the URL obtained from the node's dir_baton->new_relpath
  * or file_baton->new_relpath (but it's more complex for a delete).
  *
- * All allocations are made in POOL.
+ * The tree conflict is allocated in RESULT_POOL. Temporary allocations use
+ * SCRACTH_POOl.
  */
 static svn_error_t *
 check_tree_conflict(svn_wc_conflict_description2_t **pconflict,
@@ -1314,7 +1323,8 @@ check_tree_conflict(svn_wc_conflict_desc
                     svn_wc_conflict_action_t action,
                     svn_node_kind_t their_node_kind,
                     const char *their_relpath,
-                    apr_pool_t *pool)
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
 {
   svn_wc_conflict_reason_t reason = SVN_WC_CONFLICT_REASON_NONE;
   svn_boolean_t locally_replaced = FALSE;
@@ -1341,8 +1351,7 @@ check_tree_conflict(svn_wc_conflict_desc
                                              NULL, NULL, NULL, NULL, NULL,
                                              NULL, NULL, NULL,
                                              eb->db, local_abspath,
-                                             pool,
-                                             pool));
+                                             scratch_pool, scratch_pool));
             if (base_status != svn_wc__db_status_not_present)
               locally_replaced = TRUE;
           }
@@ -1399,7 +1408,7 @@ check_tree_conflict(svn_wc_conflict_desc
         SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes,
                                     eb->db, local_abspath,
                                     eb->cancel_func, eb->cancel_baton,
-                                    pool));
+                                    scratch_pool));
 
         if (modified)
           {
@@ -1453,7 +1462,8 @@ check_tree_conflict(svn_wc_conflict_desc
    * to record it. */
   return svn_error_return(create_tree_conflict(pconflict, eb, local_abspath,
                                                reason, action, their_node_kind,
-                                               their_relpath, pool, pool));
+                                               their_relpath,
+                                               result_pool, scratch_pool));
 }
 
 
@@ -1657,7 +1667,7 @@ delete_entry(const char *path,
       SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
                                   status, kind, TRUE,
                                   svn_wc_conflict_action_delete, svn_node_none,
-                                  repos_relpath, scratch_pool));
+                                  repos_relpath, pb->pool, scratch_pool));
     }
 
   if (tree_conflict != NULL)
@@ -1666,6 +1676,11 @@ delete_entry(const char *path,
        * node as skipped, to allow a replacement to continue doing at least
        * a bit of its work (possibly adding a not present node, for the
        * next update) */
+      if (!pb->deletion_conflicts)
+        pb->deletion_conflicts = apr_hash_make(pb->pool);
+
+      apr_hash_set(pb->deletion_conflicts, apr_pstrdup(pb->pool, base),
+                   APR_HASH_KEY_STRING, tree_conflict);
 
       SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db,
                                               local_abspath,
@@ -1683,7 +1698,6 @@ delete_entry(const char *path,
            * To prepare the "accept mine" resolution for the tree conflict,
            * we must schedule the existing content for re-addition as a copy
            * of what it was, but with its local modifications preserved. */
-
           SVN_ERR(svn_wc__db_temp_op_make_copy(eb->db, local_abspath,
                                                scratch_pool));
 
@@ -1874,8 +1888,33 @@ add_directory(const char *path,
 
   /* Is this path a conflict victim? */
   if (conflicted)
-    SVN_ERR(node_already_conflicted(&conflicted, eb->db,
-                                    db->local_abspath, pool));
+    {
+      if (pb->deletion_conflicts)
+        tree_conflict = apr_hash_get(pb->deletion_conflicts, db->name,
+                                     APR_HASH_KEY_STRING);
+
+      if (tree_conflict)
+        {
+          /* So this deletion wasn't just a deletion, it is actually a
+             replacement. Luckily we still have the conflict so we can
+             just update it. */
+
+          /* ### What else should we update? */
+          tree_conflict->action = svn_wc_conflict_action_replace;
+
+          SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db, db->local_abspath,
+                                                  tree_conflict, pool));
+
+          /* And now stop checking for conflicts here and just perform
+             a shadowed update */
+          tree_conflict = NULL; /* No direct notification */
+          db->shadowed = TRUE; /* Just continue */
+          conflicted = FALSE; /* No skip */
+        }
+      else
+        SVN_ERR(node_already_conflicted(&conflicted, eb->db,
+                                        db->local_abspath, pool));
+    }
 
   /* Now the "usual" behaviour if already conflicted. Skip it. */
   if (conflicted)
@@ -1960,7 +1999,8 @@ add_directory(const char *path,
                                       db->local_abspath,
                                       status, wc_kind, FALSE,
                                       svn_wc_conflict_action_add,
-                                      svn_node_dir, db->new_relpath, pool));
+                                      svn_node_dir, db->new_relpath,
+                                      pool, pool));
         }
 
       if (tree_conflict == NULL)
@@ -2022,8 +2062,6 @@ add_directory(const char *path,
 
   if (tree_conflict != NULL)
     {
-      /* Queue this conflict in the parent so that its descendants
-         are skipped silently. */
       SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db, db->local_abspath,
                                               tree_conflict, pool));
 
@@ -2152,7 +2190,7 @@ open_directory(const char *path,
     SVN_ERR(check_tree_conflict(&tree_conflict, eb, db->local_abspath,
                                 status, wc_kind, TRUE,
                                 svn_wc_conflict_action_edit, svn_node_dir,
-                                db->new_relpath, pool));
+                                db->new_relpath, pool, pool));
 
   /* Remember the roots of any locally deleted trees. */
   if (tree_conflict != NULL)
@@ -2754,8 +2792,34 @@ add_file(const char *path,
 
   /* Is this path a conflict victim? */
   if (conflicted)
-    SVN_ERR(node_already_conflicted(&conflicted, eb->db,
-                                    fb->local_abspath, scratch_pool));
+    if (conflicted)
+    {
+      if (pb->deletion_conflicts)
+        tree_conflict = apr_hash_get(pb->deletion_conflicts, fb->name,
+                                     APR_HASH_KEY_STRING);
+
+      if (tree_conflict)
+        {
+          /* So this deletion wasn't just a deletion, it is actually a
+             replacement. Luckily we still have the conflict so we can
+             just update it. */
+
+          /* ### What else should we update? */
+          tree_conflict->action = svn_wc_conflict_action_replace;
+
+          SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db, fb->local_abspath,
+                                                  tree_conflict, pool));
+
+          /* And now stop checking for conflicts here and just perform
+             a shadowed update */
+          tree_conflict = NULL; /* No direct notification */
+          fb->shadowed = TRUE; /* Just continue */
+          conflicted = FALSE; /* No skip */
+        }
+      else
+        SVN_ERR(node_already_conflicted(&conflicted, eb->db,
+                                        fb->local_abspath, pool));
+    }
 
   /* Now the usual conflict handling: skip. */
   if (conflicted)
@@ -2843,7 +2907,7 @@ add_file(const char *path,
                                       status, wc_kind, FALSE,
                                       svn_wc_conflict_action_add,
                                       svn_node_file, fb->new_relpath,
-                                      scratch_pool));
+                                      scratch_pool, scratch_pool));
         }
 
       if (tree_conflict == NULL)
@@ -3008,7 +3072,7 @@ open_file(const char *path,
     SVN_ERR(check_tree_conflict(&tree_conflict, eb, fb->local_abspath,
                                 status, wc_kind, TRUE,
                                 svn_wc_conflict_action_edit, svn_node_file,
-                                fb->new_relpath, scratch_pool));
+                                fb->new_relpath, scratch_pool, scratch_pool));
 
   /* Is this path the victim of a newly-discovered tree conflict? */
   if (tree_conflict != NULL)
@@ -3754,8 +3818,8 @@ close_file(void *file_baton,
                                       svn_wc__db_status_added,
                                       svn_wc__db_kind_file, TRUE,
                                       svn_wc_conflict_action_add,
-                                      svn_node_file,
-                                      fb->new_relpath, scratch_pool));
+                                      svn_node_file, fb->new_relpath,
+                                      scratch_pool, scratch_pool));
           SVN_ERR_ASSERT(tree_conflict != NULL);
           SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db,
                                                   fb->local_abspath,

Modified: subversion/trunk/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/switch_tests.py?rev=1102143&r1=1102142&r2=1102143&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/switch_tests.py Wed May 11 23:55:47 2011
@@ -794,7 +794,7 @@ def failed_anchor_is_target(sbox):
 
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('A/D/H', switched='S', wc_rev=2)
-  expected_status.tweak('A/D/H/psi', status='A ', copied='+',
+  expected_status.tweak('A/D/H/psi', status='R ', copied='+',
                         wc_rev='-', treeconflict='C')
   expected_status.remove('A/D/H/chi', 'A/D/H/omega')
   expected_status.add({