Author: rhuijben
Date: Mon Feb 23 13:34:47 2015
New Revision: 1661664

URL: http://svn.apache.org/r1661664
Log:
Fix tree conflict detection in the update editor on unversioned nodes that
exist where there used to be a deleted node.

* subversion/include/svn_wc.h
  (svn_wc_status3_t): Provide kind of what is actually in the working copy,
    to allow status callbacks to see that there is really something else,
    where we just deleted something.

* subversion/libsvn_wc/status.c
  (assemble_status,
   assemble_unversioned): Set actual_kind.

* subversion/libsvn_wc/update_editor.c
  (modcheck_callback): Handle unversioned nodes as a change, even when they
    are in the same place as a delete.

* subversion/tests/cmdline/special_tests.py
  (update_obstructing_symlink): Update expected results: tree conflict!

Modified:
    subversion/trunk/subversion/include/svn_wc.h
    subversion/trunk/subversion/libsvn_wc/status.c
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/cmdline/special_tests.py

Modified: subversion/trunk/subversion/include/svn_wc.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=1661664&r1=1661663&r2=1661664&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_wc.h (original)
+++ subversion/trunk/subversion/include/svn_wc.h Mon Feb 23 13:34:47 2015
@@ -3835,6 +3835,13 @@ typedef struct svn_wc_status3_t
    * @since New in 1.8. */
   svn_boolean_t file_external;
 
+
+  /** The actual kind of the node in the working copy. May differ from kind
+   * on obstructions, deletes, etc. svn_node_unknown if unavailable.
+   *
+   * @since New in 1.9 */
+  svn_node_kind_t actual_kind;
+
   /* NOTE! Please update svn_wc_dup_status3() when adding new fields here. */
 } svn_wc_status3_t;
 

Modified: subversion/trunk/subversion/libsvn_wc/status.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/status.c?rev=1661664&r1=1661663&r2=1661664&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/status.c (original)
+++ subversion/trunk/subversion/libsvn_wc/status.c Mon Feb 23 13:34:47 2015
@@ -378,9 +378,6 @@ assemble_status(svn_wc_status3_t **statu
   svn_boolean_t copied = FALSE;
   svn_boolean_t conflicted;
   const char *moved_from_abspath = NULL;
-  svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
-                                ? dirent->filesize
-                                : SVN_INVALID_FILESIZE;
 
   /* Defaults for two main variables. */
   enum svn_wc_status_kind node_status = svn_wc_status_normal;
@@ -644,7 +641,21 @@ assemble_status(svn_wc_status3_t **statu
         stat->kind = svn_node_unknown;
     }
   stat->depth = info->depth;
-  stat->filesize = filesize;
+  if (dirent)
+    {
+      stat->filesize = (dirent->kind == svn_node_file)
+                            ? dirent->filesize
+                            : SVN_INVALID_FILESIZE;
+      stat->actual_kind = dirent->special ? svn_node_symlink
+                                          : dirent->kind;
+    }
+  else
+    {
+      stat->filesize = SVN_INVALID_FILESIZE;
+      stat->actual_kind = ignore_text_mods ? svn_node_unknown
+                                           : svn_node_none;
+    }
+
   stat->node_status = node_status;
   stat->text_status = text_status;
   stat->prop_status = prop_status;
@@ -733,9 +744,20 @@ assemble_unversioned(svn_wc_status3_t **
   /*stat->versioned = FALSE;*/
   stat->kind = svn_node_unknown; /* not versioned */
   stat->depth = svn_depth_unknown;
-  stat->filesize = (dirent && dirent->kind == svn_node_file)
-                        ? dirent->filesize
-                        : SVN_INVALID_FILESIZE;
+  if (dirent)
+    {
+      stat->actual_kind = dirent->special ? svn_node_symlink
+                                           : dirent->kind;
+      stat->filesize = (dirent->kind == svn_node_file)
+                            ? dirent->filesize
+                            : SVN_INVALID_FILESIZE;
+    }
+  else
+    {
+       stat->actual_kind = svn_node_none;
+       stat->filesize = SVN_INVALID_FILESIZE;
+    }
+
   stat->node_status = svn_wc_status_none;
   stat->text_status = svn_wc_status_none;
   stat->prop_status = svn_wc_status_none;

Modified: subversion/trunk/subversion/libsvn_wc/update_editor.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/update_editor.c?rev=1661664&r1=1661663&r2=1661664&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Mon Feb 23 13:34:47 
2015
@@ -1332,14 +1332,21 @@ modcheck_callback(void *baton,
       case svn_wc_status_incomplete:
       case svn_wc_status_ignored:
       case svn_wc_status_none:
-      case svn_wc_status_unversioned:
       case svn_wc_status_external:
         break;
 
       case svn_wc_status_deleted:
         mb->found_mod = TRUE;
+        if (status->actual_kind != svn_node_none
+            && status->actual_kind != svn_node_unknown)
+          {
+            /* The delete is obstructed by something unversioned */
+            mb->found_not_delete = TRUE;
+            return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+          }
         break;
 
+      case svn_wc_status_unversioned:
       case svn_wc_status_missing:
       case svn_wc_status_obstructed:
         mb->found_mod = TRUE;

Modified: subversion/trunk/subversion/tests/cmdline/special_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/special_tests.py?rev=1661664&r1=1661663&r2=1661664&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/special_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/special_tests.py Mon Feb 23 
13:34:47 2015
@@ -617,19 +617,55 @@ def update_obstructing_symlink(sbox):
 
   sbox.build()
   wc_dir = sbox.wc_dir
-  mu_path = os.path.join(wc_dir, 'A', 'mu')
-  mu_url = sbox.repo_url + '/A/mu'
-  iota_path = os.path.join(wc_dir, 'iota')
-
-  # delete A/mu and replace it with a symlink
-  svntest.main.run_svn(None, 'rm', mu_path)
-  sbox.simple_add_symlink(iota_path, 'mu')
+  mu_path = sbox.ospath('A/mu')
 
-  svntest.main.run_svn(None, 'rm', mu_url,
-                       '-m', 'log msg')
+  # delete mu and replace it with an (not-added) symlink
+  sbox.simple_rm('A/mu')
+  sbox.simple_symlink(sbox.ospath('iota'), 'A/mu')
 
-  svntest.main.run_svn(None,
-                       'up', wc_dir)
+  # delete pi and replace it with an added symlink
+  sbox.simple_rm('A/D/G/pi')
+  sbox.simple_add_symlink(sbox.ospath('iota'), 'A/D/G/pi')
+
+  if not os.path.exists(mu_path):
+      raise svntest.Failure("mu should be there")
+
+  # Now remove mu and pi in the repository
+  svntest.main.run_svn(None, 'rm', '-m', 'log msg',
+                       sbox.repo_url + '/A/mu',
+                       sbox.repo_url + '/A/D/G/pi')
+
+  # We expect tree conflicts
+  expected_output = svntest.wc.State(wc_dir, {
+    'A/mu':         Item(status='  ', treeconflict='C'),
+    'A/D/G/pi':     Item(status='  ', treeconflict='C')
+  })
+
+  expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
+  expected_status.tweak('A/mu', status='? ', treeconflict='C',
+                        wc_rev=None)
+
+  expected_status.tweak('A/D/G/pi', status='A ',treeconflict='C',
+                        wc_rev='-')
+
+  svntest.actions.run_and_verify_update(wc_dir,
+                                        expected_output, None,
+                                        expected_status)
+
+  expected_info = [
+    {
+      'Path': re.escape(sbox.ospath('A/D/G/pi')),
+      'Tree conflict': 'local file replace, incoming file delete or move.*'
+    },
+    {
+      'Path': re.escape(sbox.ospath('A/mu')),
+      'Tree conflict': 'local file delete, incoming file delete or move.*'
+    }
+  ]
+
+  svntest.actions.run_and_verify_info(expected_info,
+                                      sbox.ospath('A/D/G/pi'),
+                                      sbox.ospath('A/mu'))
 
   # check that the symlink is still there
   if not os.path.exists(mu_path):


Reply via email to