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 2013/02/08 13:20:17 UTC

svn commit: r1443984 - in /subversion/trunk/subversion: libsvn_wc/wc-queries.sql libsvn_wc/wc_db.c tests/libsvn_wc/op-depth-test.c

Author: rhuijben
Date: Fri Feb  8 12:20:17 2013
New Revision: 1443984

URL: http://svn.apache.org/r1443984
Log:
When committing update the move-origin location of nodes where the move
source is affected by the commit.

This makes sure that after
svn mv A A2
svn mv A2/B B
svn commit --depth empty A A2

B is still a copy of A2/B, instead of a copy of the old A before the commit.

* subversion/libsvn_wc/wc-queries.sql
  (STMT_SELECT_MOVED_DESCENDANTS): New query.
  (STMT_COMMIT_UPDATE_ORIGIN): New query.

* subversion/libsvn_wc/wc_db.c
  (moved_descendant_commit): New function.
  (descendant_commit): Update comment.
  (commit_node): Update comments. Call moved_descendant_commit.

* subversion/tests/libsvn_wc/op-depth-test.c
  (nested_move_commit): Update comment.
  (test_funcs): Expect nested_move_commit to pass.

Modified:
    subversion/trunk/subversion/libsvn_wc/wc-queries.sql
    subversion/trunk/subversion/libsvn_wc/wc_db.c
    subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c

Modified: subversion/trunk/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc-queries.sql?rev=1443984&r1=1443983&r2=1443984&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/trunk/subversion/libsvn_wc/wc-queries.sql Fri Feb  8 12:20:17 2013
@@ -1536,6 +1536,34 @@ WHERE n.wc_id = ?1
   AND n.op_depth = ?3
   AND n.moved_to IS NOT NULL
 
+-- STMT_SELECT_MOVED_DESCENDANTS
+SELECT n.local_relpath, h.moved_to
+FROM nodes n, nodes h
+WHERE n.wc_id = ?1
+  AND h.wc_id = ?1
+  AND IS_STRICT_DESCENDANT_OF(n.local_relpath, ?2)
+  AND h.local_relpath = n.local_relpath
+  AND n.op_depth = ?3
+  AND h.op_depth = (SELECT MIN(o.op_depth)
+                    FROM nodes o
+                    WHERE o.wc_id = ?1
+                      AND o.local_relpath = n.local_relpath
+                      AND o.op_depth > ?3)
+  AND h.moved_to IS NOT NULL
+
+-- STMT_COMMIT_UPDATE_ORIGIN
+/* Note that the only reason this SUBSTR() trick is valid is that you
+   can move neither the working copy nor the repository root.
+
+   SUBSTR(local_relpath, LENGTH(?2)+1) includes the '/' of the path */
+UPDATE nodes SET repos_id = ?4,
+                 repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1),
+                 revision = ?6
+WHERE wc_id = ?1
+  AND (local_relpath = ?2
+       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
+  AND op_depth = ?3
+
 -- STMT_HAS_LAYER_BETWEEN
 SELECT 1 FROM NODES
 WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 AND op_depth < ?4

Modified: subversion/trunk/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/wc_db.c?rev=1443984&r1=1443983&r2=1443984&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/trunk/subversion/libsvn_wc/wc_db.c Fri Feb  8 12:20:17 2013
@@ -10032,7 +10032,111 @@ determine_repos_info(apr_int64_t *repos_
   return SVN_NO_ERROR;
 }
 
-/* Moves all nodes below PARENT_LOCAL_RELPATH from op-depth OP_DEPTH to
+/* Helper for svn_wc__db_global_commit()
+
+   Makes local_relpath and all its descendants at the same op-depth represent
+   the copy origin repos:repos_relpath@revision.
+
+   This code is only valid to fix-up a move from an old location, to a new
+   location during a commit.
+
+   Assumptions: 
+     * local_relpath is not the working copy root (can't be moved)
+     * repos_relpath is not the repository root (can't be moved)
+   */
+static svn_error_t *
+moved_descendant_commit(svn_wc__db_wcroot_t *wcroot,
+                        const char *local_relpath,
+                        int op_depth,
+                        apr_int64_t repos_id,
+                        const char *repos_relpath,
+                        svn_revnum_t revision,
+                        apr_pool_t *scratch_pool)
+{
+  apr_hash_t *children;
+  apr_pool_t *iterpool;
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+  apr_hash_index_t *hi;
+
+  SVN_ERR_ASSERT(*local_relpath != '\0'
+                 && *repos_relpath != '\0');
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_SELECT_MOVED_DESCENDANTS));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                         local_relpath,
+                                         op_depth));
+
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (! have_row)
+    return svn_error_trace(svn_sqlite__reset(stmt));
+
+  children = apr_hash_make(scratch_pool);
+
+  /* First, obtain all moved children */
+  /* To keep error handling simple, first cache them in a hashtable */
+  while (have_row)
+    {
+      const char *src_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+      const char *to_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
+
+      svn_hash_sets(children, src_relpath, to_relpath);
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  /* Then update them */
+  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                    STMT_COMMIT_UPDATE_ORIGIN));
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (hi = apr_hash_first(scratch_pool, children); hi; hi = apr_hash_next(hi))
+    {
+      const char *src_relpath = svn__apr_hash_index_key(hi);
+      const char *to_relpath = svn__apr_hash_index_val(hi);
+      const char *new_repos_relpath;
+      int to_op_depth = relpath_depth(to_relpath);
+      int affected;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR_ASSERT(to_op_depth > 0);
+
+      new_repos_relpath = svn_relpath_join(
+                            repos_relpath,
+                            svn_relpath_skip_ancestor(local_relpath,
+                                                      src_relpath),
+                            iterpool);
+
+      SVN_ERR(svn_sqlite__bindf(stmt, "isdisr", wcroot->wc_id,
+                                                to_relpath,
+                                                to_op_depth,
+                                                repos_id,
+                                                new_repos_relpath,
+                                                revision));
+      SVN_ERR(svn_sqlite__update(&affected, stmt));
+
+      /* ### The following check should be valid, but triggers
+         copy_tests.py 84: copy a directory with whitespace to one without
+
+         indicating that we don't properly clean up in some other place,
+         or some commit ordering issue ### BH: Looking into this */
+      /* SVN_ERR_ASSERT(affected >= 1); */
+
+      SVN_ERR(moved_descendant_commit(wcroot, to_relpath, to_op_depth,
+                                      repos_id, new_repos_relpath, revision,
+                                      iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
+/* Helper for svn_wc__db_global_commit()
+
+   Moves all nodes below PARENT_LOCAL_RELPATH from op-depth OP_DEPTH to
    op-depth 0 (BASE), setting their presence to 'not-present' if their presence
    wasn't 'normal'. */
 static svn_error_t *
@@ -10205,13 +10309,7 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
 
            1) Remove all shadowed nodes
            2) And remove all nodes that have a base-deleted as lowest layer,
-              because 1) removed that layer
-
-           Possible followup:
-             3) ### Collapse descendants of the current op_depth in layer 0,
-                    to commit a remote copy in one step (but don't touch/use
-                    ACTUAL!!)
-          */
+              because 1) removed that layer */
 
           SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                             STMT_DELETE_SHADOWED_RECURSIVE));
@@ -10225,9 +10323,20 @@ commit_node(svn_wc__db_wcroot_t *wcroot,
           SVN_ERR(svn_sqlite__step_done(stmt));
         }
 
+      /* Note that while these two calls look so similar that they might
+         be integrated, they really affect a different op-depth and
+         completely different nodes (via a different recursion pattern). */
+
+      /* Collapse descendants of the current op_depth in layer 0 */
       SVN_ERR(descendant_commit(wcroot, local_relpath, op_depth,
                                 repos_id, repos_relpath, new_revision,
                                 scratch_pool));
+
+      /* And make the recorded local moves represent moves of the node we just
+         committed. */
+      SVN_ERR(moved_descendant_commit(wcroot, local_relpath, 0,
+                                      repos_id, repos_relpath, new_revision,
+                                      scratch_pool));
     }
 
   /* Update or add the BASE_NODE row with all the new information.  */

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=1443984&r1=1443983&r2=1443984&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_wc/op-depth-test.c Fri Feb  8 12:20:17 2013
@@ -5437,8 +5437,7 @@ nested_move_commit(const svn_test_opts_t
       {3, "A2/B/C",    "base-deleted", NO_COPY_FROM, "C2"},
       {3, "A2/B/C/f",  "base-deleted", NO_COPY_FROM},
 
-      /* Currently these are recorded as a move but still
-         have the copy history from ^/A/B/C@1 */
+      /* These need to have their copyfrom information updated */
       {1, "C2",        "normal",       2, "A2/B/C", MOVED_HERE},
       {1, "C2/f",      "normal",       2, "A2/B/C/f", MOVED_HERE},
       {0}
@@ -6579,7 +6578,7 @@ struct svn_test_descriptor_t test_funcs[
                        "update_prop_mod_into_moved"),
     SVN_TEST_OPTS_PASS(nested_move_update,
                        "nested_move_update"),
-    SVN_TEST_OPTS_XFAIL(nested_move_commit,
+    SVN_TEST_OPTS_PASS(nested_move_commit,
                        "nested_move_commit"),
     SVN_TEST_OPTS_PASS(nested_move_update2,
                        "nested_move_update2"),