Hi!
make check passed.
[[[
Fix issue #3390, relative externals not updated during switch.
* subversion/libsvn_client/switch.c
(svn_client__switch_internal): Pass in an external_func to
svn_wc_crawl_revision5().
* subversion/libsvn_client/externals.c
(handle_externals_desc_change): Get the url for parent_dir with
svn_wc__node_get_url(). Does not work for export where the
parent_dir has no url. Then we resort to the old way of adding the
parent_dir to the from_url.
* subversion/tests/cmdline/externals_tests.py
(test_list): Remove XFail from switch_relative_external.
Patch by: Daniel Näslund <daniel{_AT_}longitudo.com>
]]]
When running the update_editor all externals that have changed is
recorded. But in a switch we need to change all relative externals. So I
added an external_func to collect those.
The externals are collected in the same hashtables. There won't be any
problems if the same external is inserted a second time. It will only be
replaced as shown below. (The apr function for inserting new values into
a hashtable).
[[[
358 APR_DECLARE(void) apr_hash_set(apr_hash_t *ht,
359 const void *key,
360 apr_ssize_t klen,
361 const void *val)
362 {
363 apr_hash_entry_t **hep;
364 hep = find_entry(ht, key, klen, val);
365 if (*hep) {
366 if (!val) {
367 /* delete entry */
368 apr_hash_entry_t *old = *hep;
369 *hep = (*hep)->next;
370 old->next = ht->free;
371 ht->free = old;
372 --ht->count;
373 }
373 }
374 else {
375 /* replace entry */
376 (*hep)->val = val;
377 /* check that the collision rate isn't too high */
378 if (ht->count > ht->max) {
379 expand_array(ht);
380 }
381 }
382 }
383 /* else key not present and val==NULL */
384 }
]]]
The reason I had to use the svn_wc__node_get_url() instead of
concanating from_url and parent_dir was because we're using the new
abs_paths crawlers and editors in libsvn_client/switch.c but that update
and export does not use those yet. (Disclaimer: I haven't fully grasped
what's going on inside libsvn_client/export.c. The
svn_delta_get_cancellation_editor() call is just mystery to me).
This is a fix for #3390, things will get tidier (more tidy?) once we're
using abspaths all over the place and have removed the adm_access
batons.
You can't believe all the strange places I've been to solve this. And
it was right under my nose the whole time. If it is indeed the solution
:-) ?
Daniel
Index: subversion/tests/cmdline/externals_tests.py
===================================================================
--- subversion/tests/cmdline/externals_tests.py (revision 889114)
+++ subversion/tests/cmdline/externals_tests.py (arbetskopia)
@@ -1481,7 +1481,7 @@
external_into_path_with_spaces,
binary_file_externals,
XFail(update_lose_file_external),
- XFail(switch_relative_external),
+ switch_relative_external,
export_sparse_wc_with_externals,
relegate_external,
]
Index: subversion/libsvn_client/switch.c
===================================================================
--- subversion/libsvn_client/switch.c (revision 889114)
+++ subversion/libsvn_client/switch.c (arbetskopia)
@@ -256,13 +256,15 @@
PATH. When we call reporter->finish_report, the update_editor
will be driven by svn_repos_dir_delta2.
- We pass NULL for traversal_info because this is a switch, not an
- update, and therefore we don't want to handle any externals
- except the ones directly affected by the switch. */
+ We pass in an external_func for recording all externals. It
+ shouldn't be needed for a switch if it wasn't for the relative
+ externals of type '../path'. All of those must be resolved to
+ the new location. */
err = svn_wc_crawl_revisions5(ctx->wc_ctx, local_abspath, reporter,
report_baton, TRUE, depth, (! depth_is_sticky),
(! server_supports_depth),
- use_commit_times, NULL, NULL,
+ use_commit_times,
+ svn_client__external_info_gatherer, &efb,
ctx->notify_func2, ctx->notify_baton2, pool);
if (err)
Index: subversion/libsvn_client/externals.c
===================================================================
--- subversion/libsvn_client/externals.c (revision 889114)
+++ subversion/libsvn_client/externals.c (arbetskopia)
@@ -556,6 +556,8 @@
const char *url = item->url;
apr_uri_t parent_dir_parsed_uri;
apr_status_t status;
+ const char *my_url;
+ const char *abs_path;
if ((url[0] == '/') && (url[1] == '/'))
{
@@ -1115,6 +1117,9 @@
int i;
svn_wc_external_item2_t *item;
const char *ambient_depth_w;
+ const char *url;
+ const char *abs_parent_dir;
+ svn_error_t *err;
svn_depth_t ambient_depth;
if (cb->is_export)
@@ -1193,19 +1198,31 @@
ib.pool = cb->pool;
ib.iter_pool = svn_pool_create(cb->pool);
- /* Get the URL of the parent directory by appending a portion of
- parent_dir to from_url. from_url is the URL for to_path and
- to_path is a substring of parent_dir, so append any characters in
- parent_dir past strlen(to_path) to from_url (making sure to move
- past a '/' in parent_dir, otherwise svn_path_url_add_component()
- will error. */
- len = strlen(cb->to_path);
- if (ib.parent_dir[len] == '/')
- ++len;
- ib.parent_dir_url = svn_path_url_add_component2(cb->from_url,
- ib.parent_dir + len,
- cb->pool);
+ SVN_ERR(svn_dirent_get_absolute(&abs_parent_dir, ib.parent_dir,
+ cb->pool));
+
+ err = svn_wc__node_get_url(&url, cb->ctx->wc_ctx,
+ abs_parent_dir, cb->pool, cb->pool);
+ ib.parent_dir_url = url;
+
+ if (err)
+ {
+ /* Get the URL of the parent directory by appending a portion of
+ parent_dir to from_url. from_url is the URL for to_path and
+ to_path is a substring of parent_dir, so append any characters in
+ parent_dir past strlen(to_path) to from_url (making sure to move
+ past a '/' in parent_dir, otherwise svn_path_url_add_component()
+ will error. */
+ len = strlen(cb->to_path);
+ if (ib.parent_dir[len] == '/')
+ ++len;
+ ib.parent_dir_url = svn_path_url_add_component2(cb->from_url,
+ ib.parent_dir + len,
+ cb->pool);
+ svn_error_clear(err);
+ }
+
/* We must use a custom version of svn_hash_diff so that the diff
entries are processed in the order they were originally specified
in the svn:externals properties. */