Hi Bert!
You said on IRC that if I adjusted this patch to apply after your
changes and sent it to dev@ you would give a +1. Will you?
I only resolved a variable declaration and added the new parameters to
svn_wc_upgrade(). You added a callback for retrieving the wc root when
upgrading from 1.0. As a external is just as any other wc, I mean that I
don't have to make any special considerations regarding the wc root
fetching.
make check passed.
[[[
Fix issue #3483 - extend svn_client_upgrade() to include externals. I've
done the externals upgrading after wc upgrade is finished. In that way
no errors in the externals will affect the wc.
* subversion/libsvn_client/cleanup.c
(svn_client_upgrade): Get all svn:externals. We need the target_dir so
we have to parse the description. For each target_dir we call
svn_wc_upgrade() which will recursively upgrade the external.
* subversion/tests/cmdline/upgrade_tests.py
(upgrade_with_externals): New. Checks the format of a 1.6 wc upgraded
to wc-ng.
(test_list): Add upgrade with_externals.
* subversion/tests/cmdline/upgrade_tests_data/upgrade_with_extenals.tar.bz2
(...): New. An 1.6 wc with the same structure as those used in
externals_tests.py.
Patch by: Daniel Näslund <daniel{_AT_}longitudo.com>
]]]
Index: subversion/tests/cmdline/upgrade_tests.py
===================================================================
--- subversion/tests/cmdline/upgrade_tests.py (revision 919571)
+++ subversion/tests/cmdline/upgrade_tests.py (arbetskopia)
@@ -141,7 +141,24 @@
expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+def upgrade_with_externals(sbox):
+ "upgrade with externals"
+
+ # Create wc from tarfile, uses the same structure of the wc as the tests
+ # in externals_tests.py.
+ replace_sbox_with_tarfile(sbox, 'upgrade_with_externals.tar.bz2')
+ # Attempt to use the working copy, this should give an error
+ expected_stderr = wc_is_too_old_regex
+ svntest.actions.run_and_verify_svn(None, None, expected_stderr,
+ 'info', sbox.wc_dir)
+ # Now upgrade the working copy
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'upgrade', sbox.wc_dir)
+
+ # Actually check the format number of the upgraded working copy
+ check_format(sbox, get_current_format())
+
def upgrade_1_5_body(sbox, subcommand):
replace_sbox_with_tarfile(sbox, 'upgrade_1_5.tar.bz2')
@@ -328,6 +345,7 @@
# list all tests here, starting with None:
test_list = [ None,
basic_upgrade,
+ upgrade_with_externals,
upgrade_1_5,
update_1_5,
logs_left_1_5,
Index:
subversion/tests/cmdline/upgrade_tests_data/upgrade_with_externals.tar.bz2
===================================================================
Kan inte visa: filen markerad som binär.
svn:mime-type = application/octet-stream
Egenskapsändringar för:
subversion/tests/cmdline/upgrade_tests_data/upgrade_with_externals.tar.bz2
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Index: subversion/libsvn_client/cleanup.c
===================================================================
--- subversion/libsvn_client/cleanup.c (revision 919571)
+++ subversion/libsvn_client/cleanup.c (arbetskopia)
@@ -34,8 +34,11 @@
#include "svn_dirent_uri.h"
#include "svn_pools.h"
#include "client.h"
+#include "svn_pools.h"
+#include "svn_props.h"
#include "svn_private_config.h"
+#include "private/svn_wc_private.h"
/*** Code. ***/
@@ -110,6 +113,10 @@
apr_pool_t *scratch_pool)
{
const char *local_abspath;
+ apr_hash_t *externals;
+ apr_hash_index_t *hi;
+ apr_pool_t *iterpool;
+ svn_opt_revision_t rev = {svn_opt_revision_unspecified, {0}};
struct repos_info_baton info_baton;
info_baton.pool = scratch_pool;
info_baton.ctx = ctx;
@@ -123,5 +130,79 @@
ctx->notify_func2, ctx->notify_baton2,
scratch_pool));
+ /* Now it's time to upgrade the externals too. We do it after the wc
+ upgrade to avoid that errors in the externals causes the wc upgrade to
+ fail. Thanks to caching the performance penalty of walking the wc a
+ second time shouldn't be too severe */
+ SVN_ERR(svn_client_propget3(&externals, SVN_PROP_EXTERNALS, path, &rev,
+ &rev, NULL, svn_depth_infinity, NULL, ctx,
+ scratch_pool));
+
+ iterpool = svn_pool_create(scratch_pool);
+
+ for (hi = apr_hash_first(scratch_pool, externals); hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *key;
+ int i;
+ apr_ssize_t klen;
+ svn_string_t *external_desc;
+ apr_array_header_t *externals_p;
+
+ svn_pool_clear(iterpool);
+ externals_p = apr_array_make(iterpool, 1,
+ sizeof(svn_wc_external_item2_t*));
+
+ apr_hash_this(hi, (void*)&key, &klen, NULL);
+
+ external_desc = apr_hash_get(externals, key, klen);
+
+ SVN_ERR(svn_wc_parse_externals_description3(&externals_p,
+ svn_dirent_dirname(path,
+ iterpool),
+ external_desc->data, TRUE,
+ iterpool));
+ for (i = 0; i < externals_p->nelts; i++)
+ {
+ svn_wc_external_item2_t *item;
+ const char *external_abspath;
+ const char *external_path;
+ svn_node_kind_t kind;
+ svn_error_t *err;
+
+ item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
+
+ /* The key is the path to the dir the svn:externals was set on */
+ external_path = svn_dirent_join(key, item->target_dir, iterpool);
+
+ SVN_ERR(svn_dirent_get_absolute(&external_abspath, external_path,
+ iterpool));
+
+ /* This is hack. We can only send dirs to svn_wc_upgrade(). This
+ way we will get an exception saying that the wc must be
+ upgraded if it's a dir. If it's a file then the lookup is done
+ in an adm_dir belonging to the real wc and since that was
+ updated before the externals no error is returned. */
+ err = svn_wc__node_get_kind(&kind, ctx->wc_ctx, external_abspath,
+ FALSE, iterpool);
+
+ if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
+ {
+ SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, external_abspath,
+ fetch_repos_info, &info_baton,
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2,
+ iterpool));
+ svn_error_clear(err);
+ }
+ else if (err)
+ return svn_error_return(err);
+ else
+ ;
+ }
+ }
+
+ svn_pool_destroy(iterpool);
+
return SVN_NO_ERROR;
}