Author: rhuijben
Date: Wed May 4 11:03:35 2011
New Revision: 1099411
URL: http://svn.apache.org/viewvc?rev=1099411&view=rev
Log:
In the commit harvester: Stop handling not-present descandants of a copy as
a local operation. Handle them as part of the operation root instead.
This will allow enabling the non-recursive copy commit and it also makes
it easy to resolve issue #3314.
* subversion/libsvn_client/client.h
(svn_client__check_url_kind_t): New typedef.
(svn_client__harvest_committables,
svn_client__get_copy_committables): Add check url kind callback and baton.
* subversion/libsvn_client/commit.c
(check_url_kind_baton): New struct.
(check_url_kind): New function.
(svn_client_commit5): Pass check_url_kind to
svn_client__harvest_committables.
* subversion/libsvn_client/commit_util.c
(harvest_committables): Skip all non-operational deletes.
(handle_descendants_baton): New struct.
(svn_client__harvest_committables): Call handle_descendants over all items.
(copy_committables_baton): Add callback.
(harvest_copy_committables): Call handle_descendants over all items.
(svn_client__get_copy_committables): Store callbacks in baton.
* subversion/libsvn_client/copy.c
(wc_to_repos_copy): Update caller. Just leave a TODO as this issue is less
relevant, because copy is always recursive.
* subversion/tests/cmdline/copy_tests.py
(wc_to_wc_copy_deleted): Expect that the commit notices that these paths
don't exist.
(mixed_rev_copy_del): Remove XFail.
Modified:
subversion/trunk/subversion/libsvn_client/client.h
subversion/trunk/subversion/libsvn_client/commit.c
subversion/trunk/subversion/libsvn_client/commit_util.c
subversion/trunk/subversion/libsvn_client/copy.c
subversion/trunk/subversion/tests/cmdline/copy_tests.py
Modified: subversion/trunk/subversion/libsvn_client/client.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/client.h?rev=1099411&r1=1099410&r2=1099411&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/client.h (original)
+++ subversion/trunk/subversion/libsvn_client/client.h Wed May 4 11:03:35 2011
@@ -777,6 +777,13 @@ typedef struct svn_client__copy_pair_t
*/
+/* Callback for the commit harvester to check if a node exists at the specified
+ url */
+typedef svn_error_t *(*svn_client__check_url_kind_t)(void *baton,
+ svn_node_kind_t *kind,
+ const char *url,
+ apr_pool_t *scratch_pool);
+
/* Recursively crawl a set of working copy paths (DIR_ABSPATH + each
item in the TARGETS array) looking for commit candidates, locking
working copy directories as the crawl progresses. For each
@@ -828,6 +835,8 @@ svn_client__harvest_committables(apr_has
svn_depth_t depth,
svn_boolean_t just_locked,
const apr_array_header_t *changelists,
+ svn_client__check_url_kind_t check_url_func,
+ void *check_url_baton,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -845,11 +854,12 @@ svn_client__harvest_committables(apr_has
svn_error_t *
svn_client__get_copy_committables(apr_hash_t **committables,
const apr_array_header_t *copy_pairs,
+ svn_client__check_url_kind_t check_url_func,
+ void *check_url_baton,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-
/* A qsort()-compatible sort routine for sorting an array of
svn_client_commit_item_t's by their URL member. */
int svn_client__sort_commit_item_urls(const void *a, const void *b);
Modified: subversion/trunk/subversion/libsvn_client/commit.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit.c?rev=1099411&r1=1099410&r2=1099411&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit.c Wed May 4 11:03:35 2011
@@ -1129,6 +1129,39 @@ determine_lock_targets(apr_array_header_
return SVN_NO_ERROR;
}
+/* Baton for check_url_kind */
+struct check_url_kind_baton
+{
+ apr_pool_t *pool;
+ svn_ra_session_t *session;
+ const char *repos_root_url;
+ svn_client_ctx_t *ctx;
+};
+
+/* Implements svn_client__check_url_kind_t for svn_client_commit5 */
+static svn_error_t *
+check_url_kind(void *baton,
+ svn_node_kind_t *kind,
+ const char *url,
+ apr_pool_t *scratch_pool)
+{
+ struct check_url_kind_baton *cukb = baton;
+
+ /* If we don't have a session or can't use the session, get one */
+ if (!cukb->session || !svn_uri_is_ancestor(cukb->repos_root_url, url))
+ {
+ SVN_ERR(svn_client_open_ra_session(&cukb->session, url, cukb->ctx,
+ cukb->pool));
+ SVN_ERR(svn_ra_get_repos_root2(cukb->session, &cukb->repos_root_url,
+ cukb->pool));
+ }
+ else
+ SVN_ERR(svn_ra_reparent(cukb->session, url, scratch_pool));
+
+ return svn_error_return(
+ svn_ra_check_path(cukb->session, "", SVN_INVALID_REVNUM,
+ kind, scratch_pool));
+}
svn_error_t *
svn_client_commit5(const apr_array_header_t *targets,
@@ -1250,17 +1283,29 @@ svn_client_commit5(const apr_array_heade
}
/* Crawl the working copy for commit items. */
- cmt_err = svn_error_return(
- svn_client__harvest_committables(&committables,
- &lock_tokens,
- base_abspath,
- rel_targets,
- depth,
- ! keep_locks,
- changelists,
- ctx,
- pool,
- iterpool));
+ {
+ struct check_url_kind_baton cukb;
+
+ /* Prepare for when we have a copy containing not-present nodes. */
+ cukb.pool = iterpool;
+ cukb.session = NULL; /* ### Can we somehow reuse session? */
+ cukb.repos_root_url = NULL;
+ cukb.ctx = ctx;
+
+ cmt_err = svn_error_return(
+ svn_client__harvest_committables(&committables,
+ &lock_tokens,
+ base_abspath,
+ rel_targets,
+ depth,
+ ! keep_locks,
+ changelists,
+ check_url_kind,
+ &cukb,
+ ctx,
+ pool,
+ iterpool));
+ }
if (cmt_err)
goto cleanup;
Modified: subversion/trunk/subversion/libsvn_client/commit_util.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/commit_util.c?rev=1099411&r1=1099410&r2=1099411&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/commit_util.c (original)
+++ subversion/trunk/subversion/libsvn_client/commit_util.c Wed May 4 11:03:35
2011
@@ -475,6 +475,9 @@ harvest_committables(svn_wc_context_t *w
}
}
+ if (is_deleted && !is_op_root /* && !is_added */)
+ return SVN_NO_ERROR; /* Not an operational delete and not an add. */
+
if (node_relpath == NULL)
SVN_ERR(svn_wc__node_get_repos_relpath(&node_relpath,
wc_ctx, local_abspath,
@@ -722,6 +725,119 @@ harvest_committables(svn_wc_context_t *w
return SVN_NO_ERROR;
}
+/* Baton for handle_descendants */
+struct handle_descendants_baton
+{
+ svn_wc_context_t *wc_ctx;
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
+ svn_client__check_url_kind_t check_url_func;
+ void *check_url_baton;
+};
+
+/* Helper for the commit harvesters */
+static svn_error_t *
+handle_descendants(void *baton,
+ const void *key, apr_ssize_t klen, void *val,
+ apr_pool_t *pool)
+{
+ struct handle_descendants_baton *hdb = baton;
+ apr_array_header_t *commit_items = val;
+ apr_pool_t *iterpool = svn_pool_create(pool);
+ int i;
+
+ for (i = 0; i < commit_items->nelts; i++)
+ {
+ svn_client_commit_item3_t *item =
+ APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
+ const apr_array_header_t *absent_descendants;
+ int j;
+
+ /* Is this a copy operation? */
+ if (!(item->state_flags & SVN_CLIENT_COMMIT_ITEM_ADD)
+ || ! item->copyfrom_url)
+ continue;
+
+ if (hdb->cancel_func)
+ SVN_ERR(hdb->cancel_func(hdb->cancel_baton));
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_wc__get_not_present_descendants(&absent_descendants,
+ hdb->wc_ctx, item->path,
+ iterpool, iterpool));
+
+ for (j = 0; j < absent_descendants->nelts; j++)
+ {
+ int k;
+ svn_boolean_t found_item = FALSE;
+ svn_node_kind_t kind;
+ const char *relpath = APR_ARRAY_IDX(absent_descendants, j,
+ const char *);
+ const char *local_abspath = svn_dirent_join(item->path, relpath,
+ iterpool);
+
+ /* If the path has a commit operation, we do nothing.
+ (It will be deleted by the operation) */
+ for (k = 0; k < commit_items->nelts; k++)
+ {
+ svn_client_commit_item3_t *cmt_item =
+ APR_ARRAY_IDX(commit_items, k, svn_client_commit_item3_t *);
+
+ if (! strcmp(cmt_item->path, local_abspath))
+ {
+ found_item = TRUE;
+ break;
+ }
+ }
+
+ if (found_item)
+ continue; /* We have an explicit delete or replace for this path */
+
+ /* ### Need a sub-iterpool? */
+
+ if (hdb->check_url_func)
+ {
+ const char *from_url = svn_path_url_add_component2(
+ item->copyfrom_url, relpath,
+ iterpool);
+
+ SVN_ERR(hdb->check_url_func(hdb->check_url_baton,
+ &kind, from_url, iterpool));
+
+ if (kind == svn_node_none)
+ continue; /* This node is already deleted */
+ }
+ else
+ kind = svn_node_unknown; /* 'Ok' for a delete of something */
+
+ {
+ /* Add a new commit item that describes the delete */
+ apr_pool_t *result_pool = commit_items->pool;
+ svn_client_commit_item3_t *new_item
+ = svn_client_commit_item3_create(result_pool);
+
+ new_item->path = svn_dirent_join(item->path, relpath,
+ result_pool);
+ new_item->kind = kind;
+ new_item->url = svn_path_url_add_component2(item->url, relpath,
+ result_pool);
+ new_item->revision = SVN_INVALID_REVNUM;
+ new_item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
+ new_item->incoming_prop_changes = apr_array_make(result_pool, 1,
+ sizeof(svn_prop_t *));
+
+ APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *)
+ = new_item;
+ }
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+ return SVN_NO_ERROR;
+}
+
+
/* BATON is an apr_hash_t * of harvested committables. */
static svn_error_t *
@@ -758,6 +874,8 @@ svn_client__harvest_committables(apr_has
svn_depth_t depth,
svn_boolean_t just_locked,
const apr_array_header_t *changelists,
+ svn_client__check_url_kind_t check_url_func,
+ void *check_url_baton,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -766,6 +884,7 @@ svn_client__harvest_committables(apr_has
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_hash_t *changelist_hash = NULL;
svn_wc_context_t *wc_ctx = ctx->wc_ctx;
+ struct handle_descendants_baton hdb;
/* It's possible that one of the named targets has a parent that is
* itself scheduled for addition or replacement -- that is, the
@@ -903,6 +1022,15 @@ svn_client__harvest_committables(apr_has
result_pool, iterpool));
}
+ hdb.wc_ctx = ctx->wc_ctx;
+ hdb.cancel_func = ctx->cancel_func;
+ hdb.cancel_baton = ctx->cancel_baton;
+ hdb.check_url_func = check_url_func;
+ hdb.check_url_baton = check_url_baton;
+
+ SVN_ERR(svn_iter_apr_hash(NULL, *committables,
+ handle_descendants, &hdb, iterpool));
+
/* Make sure that every path in danglers is part of the commit. */
SVN_ERR(svn_iter_apr_hash(NULL,
danglers, validate_dangler, *committables,
@@ -918,6 +1046,8 @@ struct copy_committables_baton
svn_client_ctx_t *ctx;
apr_hash_t *committables;
apr_pool_t *result_pool;
+ svn_client__check_url_kind_t check_url_func;
+ void *check_url_baton;
};
static svn_error_t *
@@ -927,6 +1057,7 @@ harvest_copy_committables(void *baton, v
svn_client__copy_pair_t *pair = *(svn_client__copy_pair_t **)item;
const char *repos_root_url;
const char *commit_relpath;
+ struct handle_descendants_baton hdb;
/* Read the entry for this SRC. */
SVN_ERR_ASSERT(svn_dirent_is_absolute(pair->src_abspath_or_url));
@@ -941,19 +1072,30 @@ harvest_copy_committables(void *baton, v
pool);
/* Handle this SRC. */
- return harvest_committables(btn->ctx->wc_ctx,
- pair->src_abspath_or_url,
- btn->committables, NULL,
- repos_root_url,
- commit_relpath,
- TRUE, /* COPY_MODE_ROOT */
- svn_depth_infinity,
- FALSE, /* JUST_LOCKED */
- NULL,
- FALSE, FALSE, /* skip files, dirs */
- btn->ctx->cancel_func,
- btn->ctx->cancel_baton,
- btn->result_pool, pool);
+ SVN_ERR(harvest_committables(btn->ctx->wc_ctx,
+ pair->src_abspath_or_url,
+ btn->committables, NULL,
+ repos_root_url,
+ commit_relpath,
+ TRUE, /* COPY_MODE_ROOT */
+ svn_depth_infinity,
+ FALSE, /* JUST_LOCKED */
+ NULL,
+ FALSE, FALSE, /* skip files, dirs */
+ btn->ctx->cancel_func,
+ btn->ctx->cancel_baton,
+ btn->result_pool, pool));
+
+ hdb.wc_ctx = btn->ctx->wc_ctx;
+ hdb.cancel_func = btn->ctx->cancel_func;
+ hdb.cancel_baton = btn->ctx->cancel_baton;
+ hdb.check_url_func = btn->check_url_func;
+ hdb.check_url_baton = btn->check_url_baton;
+
+ SVN_ERR(svn_iter_apr_hash(NULL, btn->committables,
+ handle_descendants, &hdb, pool));
+
+ return SVN_NO_ERROR;
}
@@ -961,6 +1103,8 @@ harvest_copy_committables(void *baton, v
svn_error_t *
svn_client__get_copy_committables(apr_hash_t **committables,
const apr_array_header_t *copy_pairs,
+ svn_client__check_url_kind_t check_url_func,
+ void *check_url_baton,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -973,6 +1117,9 @@ svn_client__get_copy_committables(apr_ha
btn.committables = *committables;
btn.result_pool = result_pool;
+ btn.check_url_func = check_url_func;
+ btn.check_url_baton = check_url_baton;
+
/* For each copy pair, harvest the committables for that pair into the
committables hash. */
return svn_iter_apr_array(NULL, copy_pairs,
Modified: subversion/trunk/subversion/libsvn_client/copy.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy.c?rev=1099411&r1=1099410&r2=1099411&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy.c Wed May 4 11:03:35 2011
@@ -1291,8 +1291,10 @@ wc_to_repos_copy(const apr_array_header_
message, ctx, pool));
/* Crawl the working copy for commit items. */
+ /* ### TODO: Pass check_url_func for issue #3314 handling */
SVN_ERR(svn_client__get_copy_committables(&committables,
copy_pairs,
+ NULL, NULL, /* check_url_func */
ctx, pool, pool));
/* The committables are keyed by the repository root */
Modified: subversion/trunk/subversion/tests/cmdline/copy_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/copy_tests.py?rev=1099411&r1=1099410&r2=1099411&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/copy_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/copy_tests.py Wed May 4 11:03:35
2011
@@ -1583,9 +1583,11 @@ def wc_to_wc_copy_deleted(sbox):
copied=None, wc_rev=3)
expected_output = svntest.wc.State(wc_dir, {
'A/B2' : Item(verb='Adding'),
- 'A/B2/E/alpha' : Item(verb='Deleting'),
- 'A/B2/lambda' : Item(verb='Deleting'),
- 'A/B2/F' : Item(verb='Deleting'),
+ # Before the commit processor verified not-present deletes
+ # the output would also contain
+ # 'A/B2/E/alpha' : Item(verb='Deleting'),
+ # 'A/B2/lambda' : Item(verb='Deleting'),
+ # 'A/B2/F' : Item(verb='Deleting'),
})
svntest.actions.run_and_verify_commit(wc_dir,
@@ -4697,7 +4699,6 @@ def copy_over_deleted_dir(sbox):
main.run_svn(None, 'cp', os.path.join(sbox.wc_dir, 'A/D'),
os.path.join(sbox.wc_dir, 'A/B'))
-@XFail()
@Issue(3314)
def mixed_rev_copy_del(sbox):
"""copy mixed-rev and delete children"""