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"),