You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2011/07/06 13:41:50 UTC

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

Author: julianfoad
Date: Wed Jul  6 11:41:49 2011
New Revision: 1143357

URL: http://svn.apache.org/viewvc?rev=1143357&view=rev
Log:
Fix and test for a bug in switching a directory to a file.  The repository
URL was not updated in the WC metadata, so 'svn status' did not show it as
switched and further operations involving the repository would not work.
This dir-to-file kind of switch was not checked by the test suite except in
switch_tests.py 9 which has always been XFAIL.

* subversion/libsvn_wc/update_editor.c
  (make_file_baton): When calculating the new repository relpath, account
    for switches in the same way as is done in make_dir_baton().
  (set_target_revision): Remove a useless comment.

* subversion/tests/cmdline/svntest/wc.py
  (State.remove): Tweak the doc string.
  (State.remove_subtree): New function.
  (State.subtree): Remove the limitation that the subtree path could only be
    a single path element.

* subversion/tests/cmdline/switch_tests.py
  (different_node_kind): New test function.
  (test_list): Add it.

Modified:
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/cmdline/svntest/wc.py
    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=1143357&r1=1143356&r2=1143357&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/trunk/subversion/libsvn_wc/update_editor.c Wed Jul  6 11:41:49 2011
@@ -773,6 +773,7 @@ make_file_baton(struct file_baton **f_p,
                 svn_boolean_t adding,
                 apr_pool_t *scratch_pool)
 {
+  struct edit_baton *eb = pb->edit_baton;
   apr_pool_t *file_pool = svn_pool_create(pb->pool);
 
   struct file_baton *f = apr_pcalloc(file_pool, sizeof(*f));
@@ -785,17 +786,35 @@ make_file_baton(struct file_baton **f_p,
   SVN_ERR(path_join_under_root(&f->local_abspath,
                                pb->local_abspath, f->name, file_pool));
 
-  /* Figure out the new_URL for this file. */
-  if (adding || pb->edit_baton->switch_relpath)
-    f->new_relpath = svn_relpath_join(pb->new_relpath, f->name, file_pool);
-  else
+  /* Figure out the new URL for this file. */
+  if (eb->switch_relpath)
     {
-      SVN_ERR(svn_wc__db_scan_base_repos(&f->new_relpath, NULL, NULL,
-                                         pb->edit_baton->db,
-                                         f->local_abspath,
-                                         file_pool, scratch_pool));
+      /* Handle switches... */
 
-      SVN_ERR_ASSERT(f->new_relpath);
+      /* This file has a parent directory. If there is
+         no grandparent, then we may have anchored at the parent,
+         and self is the target. If we match the target, then set
+         NEW_RELPATH to the SWITCH_RELPATH.
+
+         Otherwise, we simply extend NEW_RELPATH from the parent.  */
+      if (pb->parent_baton == NULL
+          && strcmp(eb->target_basename, f->name) == 0)
+        f->new_relpath = eb->switch_relpath;
+      else
+        f->new_relpath = svn_relpath_join(pb->new_relpath, f->name,
+                                          file_pool);
+    }
+  else  /* must be an update */
+    {
+      if (adding)
+        f->new_relpath = svn_relpath_join(pb->new_relpath, f->name, file_pool);
+      else
+        {
+          SVN_ERR(svn_wc__db_scan_base_repos(&f->new_relpath, NULL, NULL,
+                                             eb->db, f->local_abspath,
+                                             file_pool, scratch_pool));
+          SVN_ERR_ASSERT(f->new_relpath);
+        }
     }
 
   f->pool              = file_pool;
@@ -1046,7 +1065,6 @@ set_target_revision(void *edit_baton,
 {
   struct edit_baton *eb = edit_baton;
 
-  /* Stashing a target_revision in the baton */
   *(eb->target_revision) = target_revision;
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/tests/cmdline/svntest/wc.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svntest/wc.py?rev=1143357&r1=1143356&r2=1143357&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svntest/wc.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svntest/wc.py Wed Jul  6 11:41:49 2011
@@ -135,10 +135,18 @@ class State:
       self.desc[path] = item
 
   def remove(self, *paths):
-    "Remove a path from the state (the path must exist)."
+    "Remove PATHS from the state (the paths must exist)."
     for path in paths:
       del self.desc[to_relpath(path)]
 
+  def remove_subtree(self, *paths):
+    "Remove PATHS recursively from the state (the paths must exist)."
+    for subtree_path in paths:
+      subtree_path = to_relpath(subtree_path)
+      for path, item in self.desc.items():
+        if path == subtree_path or path[:len(subtree_path) + 1] == subtree_path + '/':
+          del self.desc[path]
+
   def copy(self, new_root=None):
     """Make a deep copy of self.  If NEW_ROOT is not None, then set the
     copy's wc_dir NEW_ROOT instead of to self's wc_dir."""
@@ -180,13 +188,12 @@ class State:
 
   def subtree(self, subtree_path):
     """Return a State object which is a deep copy of the sub-tree
-    identified by SUBTREE_PATH (which is assumed to contain only one
-    element rooted at the tree of this State object's WC_DIR)."""
+    beneath SUBTREE_PATH (which is assumed to be rooted at the tree of
+    this State object's WC_DIR).  Exclude SUBTREE_PATH itself."""
     desc = { }
     for path, item in self.desc.items():
-      path_elements = path.split("/")
-      if len(path_elements) > 1 and path_elements[0] == subtree_path:
-        desc["/".join(path_elements[1:])] = item.copy()
+      if path[:len(subtree_path) + 1] == subtree_path + '/':
+        desc[path[len(subtree_path) + 1:]] = item.copy()
     return State(self.wc_dir, desc)
 
   def write_to_disk(self, target_dir):

Modified: subversion/trunk/subversion/tests/cmdline/switch_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/switch_tests.py?rev=1143357&r1=1143356&r2=1143357&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/switch_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/switch_tests.py Wed Jul  6 11:41:49 2011
@@ -2856,6 +2856,56 @@ def up_to_old_rev_with_subtree_switched_
   # Now update the WC to r1.
   svntest.actions.run_and_verify_svn(None, None, [], 'up', '-r1', wc_dir)
 
+def different_node_kind(sbox):
+  "switch to a different node kind"
+  sbox.build(read_only = True)
+  os.chdir(sbox.wc_dir)
+  sbox.wc_dir = ''
+
+  pristine_disk = svntest.main.greek_state
+  pristine_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
+  expected_disk = pristine_disk.copy()
+  expected_status = pristine_status.copy()
+
+  def switch_to_dir(sbox, rel_url, rel_path):
+    full_url = sbox.repo_url + '/' + rel_url
+    full_path = sbox.ospath(rel_path)
+    expected_disk.remove(rel_path)
+    expected_disk.add({ rel_path : pristine_disk.desc[rel_url] })
+    expected_disk.add_state(rel_path, pristine_disk.subtree(rel_url))
+    expected_status.tweak(rel_path, switched='S')
+    expected_status.add_state(rel_path, pristine_status.subtree(rel_url))
+    svntest.actions.run_and_verify_switch(sbox.wc_dir, full_path, full_url,
+                                          None, expected_disk, expected_status,
+                                          None, None, None, None, None, False,
+                                          '--ignore-ancestry')
+    svntest.actions.run_and_verify_svn(None, None, [], 'info', full_path)
+    if not os.path.isdir(full_path):
+      raise svntest.Failure
+
+  def switch_to_file(sbox, rel_url, rel_path):
+    full_url = sbox.repo_url + '/' + rel_url
+    full_path = sbox.ospath(rel_path)
+    expected_disk.remove_subtree(rel_path)
+    expected_disk.add({ rel_path : pristine_disk.desc[rel_url] })
+    expected_status.remove_subtree(rel_path)
+    expected_status.add({ rel_path : pristine_status.desc[rel_url] })
+    expected_status.tweak(rel_path, switched='S')
+    svntest.actions.run_and_verify_switch(sbox.wc_dir, full_path, full_url,
+                                          None, expected_disk, expected_status,
+                                          None, None, None, None, None, False,
+                                          '--ignore-ancestry')
+    svntest.actions.run_and_verify_svn(None, None, [], 'info', full_path)
+    if not os.path.isfile(full_path):
+      raise svntest.Failure
+
+  # Switch two files to dirs and two dirs to files.
+  # 'A/C' is an empty dir; 'A/D/G' is a non-empty dir.
+  switch_to_dir(sbox, 'A/C', 'iota')
+  switch_to_dir(sbox, 'A/D/G', 'A/D/gamma')
+  switch_to_file(sbox, 'iota', 'A/C')
+  switch_to_file(sbox, 'A/D/gamma', 'A/D/G')
+
 ########################################################################
 # Run the tests
 
@@ -2895,6 +2945,7 @@ test_list = [ None,
               tree_conflicts_on_switch_3,
               copy_with_switched_subdir,
               up_to_old_rev_with_subtree_switched_to_root,
+              different_node_kind,
               ]
 
 if __name__ == '__main__':