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 2010/03/04 16:27:02 UTC
svn commit: r919021 - in /subversion/trunk/subversion: include/svn_wc.h
libsvn_client/cleanup.c libsvn_wc/upgrade.c tests/cmdline/upgrade_tests.py
Author: rhuijben
Date: Thu Mar 4 15:27:02 2010
New Revision: 919021
URL: http://svn.apache.org/viewvc?rev=919021&view=rev
Log:
Add support for upgrading Subversion 1.0.0 working copies by adding a
retrieve repository information callback to svn_wc_upgraded().
The Subversion 1.0.0 client format didn't record a repository
root in the working copy so we have to fall back on retrieving this
information via the ra layer. For modern working copies (read: 1.5 and
later) we should never have to fall back on this callback, but when
such a working copy was created by upgrading from a previous version
we might have to do it anyway.
* subversion/include/svn_wc.h
(svn_wc_upgrade_get_repos_info_t): New typedef.
(svn_wc_upgrade): Add callback.
* subversion/libsvn_client/cleanup.c
(includes): Include svn_pools.h.
(repos_info_baton): New struct.
(fetch_repos_info): New function.
(svn_client_upgrade): Pass fetcher to svn_wc_upgrade.
* subversion/libsvn_wc/upgrade.c
(fetch_missing_entry_data): New function.
(upgrade_to_wcng): Update prototype. Remove const from this_dir.
Call fetch_missing_entry_data, before upgrading the entries.
(upgrade_working_copy, svn_wc_upgrade): Pass callback to upgrade_to_wcng.
* subversion/tests/cmdline/upgrade_tests.py
(run_and_verify_status_no_server): Fix error handling to show the real data.
(xml_entries_relocate): New function.
(basic_upgrade_1_0): Relocate the working copy using xml_entries_relocate,
to make the url work for the upgrade callback. Also upgrade sub working
copy (created by a failed svn cp replacement in 1.0.0), to make
check_format() happy. Make expected_status match the working copy.
Use 'svn info' to retrieve some properties that aren't checked by status.
Modified:
subversion/trunk/subversion/include/svn_wc.h
subversion/trunk/subversion/libsvn_client/cleanup.c
subversion/trunk/subversion/libsvn_wc/upgrade.c
subversion/trunk/subversion/tests/cmdline/upgrade_tests.py
Modified: subversion/trunk/subversion/include/svn_wc.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_wc.h?rev=919021&r1=919020&r2=919021&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_wc.h (original)
+++ subversion/trunk/subversion/include/svn_wc.h Thu Mar 4 15:27:02 2010
@@ -6481,6 +6481,22 @@
void *cancel_baton,
apr_pool_t *pool);
+/** Callback for retrieving a repository root for a url from upgrade.
+ *
+ * Called by svn_wc_upgrade() when no repository root and/or repository
+ * uuid are recorded in the working copy. For normal Subversion 1.5 and
+ * later working copies, this callback will not be used.
+ *
+ * @since New in 1.7.
+ */
+typedef svn_error_t * (*svn_wc_upgrade_get_repos_info_t)(
+ const char **repos_root,
+ const char **repos_uuid,
+ void *baton,
+ const char *url,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *result_pool);
+
/**
* Upgrade the working copy at @a local_abspath to the latest metadata
* storage format. @a local_abspath should be an absolute path to the
@@ -6495,11 +6511,17 @@
* the path of the upgraded directory. @a notify_func may be @c NULL
* if this notification is not needed.
*
+ * If the old working copy doesn't contain a repository root and/or
+ * repository uuid, @a repos_info_func (if non-NULL) will be called
+ * with @a repos_info_baton to provide the missing information.
+ *
* @since New in 1.7.
*/
svn_error_t *
svn_wc_upgrade(svn_wc_context_t *wc_ctx,
const char *local_abspath,
+ svn_wc_upgrade_get_repos_info_t repos_info_func,
+ void *repos_info_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
Modified: subversion/trunk/subversion/libsvn_client/cleanup.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/cleanup.c?rev=919021&r1=919020&r2=919021&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/cleanup.c (original)
+++ subversion/trunk/subversion/libsvn_client/cleanup.c Thu Mar 4 15:27:02 2010
@@ -32,11 +32,12 @@
#include "svn_client.h"
#include "svn_config.h"
#include "svn_dirent_uri.h"
+#include "svn_pools.h"
#include "client.h"
#include "svn_private_config.h"
-
+
/*** Code. ***/
svn_error_t *
@@ -55,6 +56,49 @@
return svn_error_return(err);
}
+struct repos_info_baton
+{
+ apr_pool_t *pool;
+ svn_client_ctx_t *ctx;
+ const char *last_repos;
+ const char *last_uuid;
+};
+
+static svn_error_t *
+fetch_repos_info(const char **repos_root,
+ const char **repos_uuid,
+ void *baton,
+ const char *url,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *result_pool)
+{
+ struct repos_info_baton *ri = baton;
+ apr_pool_t *subpool;
+ svn_ra_session_t *ra_session;
+
+ /* The same info is likely to retrieved multiple times (e.g. externals) */
+ if (ri->last_repos && svn_uri_is_child(ri->last_repos, url, NULL))
+ {
+ *repos_root = apr_pstrdup(result_pool, ri->last_repos);
+ *repos_uuid = apr_pstrdup(result_pool, ri->last_uuid);
+ return SVN_NO_ERROR;
+ }
+
+ subpool = svn_pool_create(scratch_pool);
+
+ SVN_ERR(svn_client_open_ra_session(&ra_session, url, ri->ctx, subpool));
+
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, repos_root, result_pool));
+ SVN_ERR(svn_ra_get_uuid2(ra_session, repos_uuid, result_pool));
+
+ /* Store data for further calls */
+ ri->last_repos = apr_pstrdup(ri->pool, *repos_root);
+ ri->last_uuid = apr_pstrdup(ri->pool, *repos_uuid);
+
+ svn_pool_destroy(subpool);
+
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_client_upgrade(const char *path,
@@ -62,9 +106,15 @@
apr_pool_t *scratch_pool)
{
const char *local_abspath;
+ struct repos_info_baton info_baton;
+ info_baton.pool = scratch_pool;
+ info_baton.ctx = ctx;
+ info_baton.last_repos = NULL;
+ info_baton.last_uuid = NULL;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
+ fetch_repos_info, &info_baton,
ctx->cancel_func, ctx->cancel_baton,
ctx->notify_func2, ctx->notify_baton2,
scratch_pool));
Modified: subversion/trunk/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/upgrade.c?rev=919021&r1=919020&r2=919021&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/trunk/subversion/libsvn_wc/upgrade.c Thu Mar 4 15:27:02 2010
@@ -344,6 +344,54 @@
TRUE, scratch_pool));
}
+/* Checks ENTRY to see if it misses critical information. Attempts to
+ retrieve this information from REPOS_INFO_FUNC, passing REPOS_INFO_BATON.
+ Returns a user understandable error using LOCAL_ABSPATH if vital
+ information would not be available after this function returns */
+static svn_error_t *
+fetch_missing_entry_data(svn_wc_entry_t *entry,
+ const char *local_abspath,
+ svn_wc_upgrade_get_repos_info_t repos_info_func,
+ void *repos_info_baton,
+ apr_pool_t *scratch_pool,
+ apr_pool_t *result_pool)
+{
+ const char *repos_root;
+ const char *repos_uuid;
+ if (entry->repos && entry->uuid)
+ return SVN_NO_ERROR; /* We are done here */
+
+ if (!entry->repos && !repos_info_func)
+ return svn_error_createf(
+ SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
+ _("Working copy '%s' can't be upgraded because the repository root is "
+ "not available and can't be retrieved"),
+ svn_dirent_local_style(local_abspath, scratch_pool));
+
+ if (!entry->uuid && !repos_info_func)
+ return svn_error_createf(
+ SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
+ _("Working copy '%s' can't be upgraded because the repository uuid is "
+ "not available and can't be retrieved"),
+ svn_dirent_local_style(local_abspath, scratch_pool));
+
+ if (!entry->url)
+ return svn_error_createf(
+ SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
+ _("Working copy '%s' can't be upgraded because it doesn't have a url"),
+ svn_dirent_local_style(local_abspath, scratch_pool));
+
+ SVN_ERR(repos_info_func(&repos_root, &repos_uuid, repos_info_baton,
+ entry->url, scratch_pool, result_pool));
+
+ if (!entry->repos)
+ entry->repos = repos_root;
+ if (!entry->uuid)
+ entry->uuid = repos_uuid;
+
+ return SVN_NO_ERROR;
+}
+
/* Upgrade the working copy directory represented by DB/DIR_ABSPATH
from OLD_FORMAT to the wc-ng format (SVN_WC__WC_NG_VERSION)'.
@@ -353,13 +401,15 @@
upgrade_to_wcng(svn_wc__db_t *db,
const char *dir_abspath,
int old_format,
+ svn_wc_upgrade_get_repos_info_t repos_info_func,
+ void *repos_info_baton,
apr_pool_t *scratch_pool)
{
const char *logfile_path = svn_wc__adm_child(dir_abspath, SVN_WC__ADM_LOG,
scratch_pool);
svn_node_kind_t logfile_on_disk;
apr_hash_t *entries;
- const svn_wc_entry_t *this_dir;
+ svn_wc_entry_t *this_dir;
svn_sqlite__db_t *sdb;
apr_int64_t repos_id;
apr_int64_t wc_id;
@@ -401,6 +451,10 @@
this_dir = apr_hash_get(entries, SVN_WC_ENTRY_THIS_DIR, APR_HASH_KEY_STRING);
+ SVN_ERR(fetch_missing_entry_data(this_dir, dir_abspath,
+ repos_info_func, repos_info_baton,
+ scratch_pool, apr_hash_pool_get(entries)));
+
/* Create an empty sqlite database for this directory. */
SVN_ERR(svn_wc__db_upgrade_begin(&sdb, &repos_id, &wc_id, dir_abspath,
this_dir->repos, this_dir->uuid,
@@ -1060,6 +1114,8 @@
static svn_error_t *
upgrade_working_copy(svn_wc__db_t *db,
const char *dir_abspath,
+ svn_wc_upgrade_get_repos_info_t repos_info_func,
+ void *repos_info_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -1083,7 +1139,9 @@
/* Upgrade this directory first. */
if (old_format < SVN_WC__WC_NG_VERSION)
- SVN_ERR(upgrade_to_wcng(db, dir_abspath, old_format, iterpool));
+ SVN_ERR(upgrade_to_wcng(db, dir_abspath, old_format,
+ repos_info_func, repos_info_baton,
+ iterpool));
if (notify_func)
notify_func(notify_baton,
@@ -1099,6 +1157,7 @@
svn_pool_clear(iterpool);
SVN_ERR(upgrade_working_copy(db, child_abspath,
+ repos_info_func, repos_info_baton,
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
@@ -1113,6 +1172,8 @@
svn_error_t *
svn_wc_upgrade(svn_wc_context_t *wc_ctx,
const char *local_abspath,
+ svn_wc_upgrade_get_repos_info_t repos_info_func,
+ void *repos_info_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -1142,6 +1203,7 @@
/* Upgrade this directory and/or its subdirectories. */
SVN_ERR(upgrade_working_copy(db, local_abspath,
+ repos_info_func, repos_info_baton,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
Modified: subversion/trunk/subversion/tests/cmdline/upgrade_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/upgrade_tests.py?rev=919021&r1=919020&r2=919021&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/upgrade_tests.py Thu Mar 4 15:27:02 2010
@@ -113,9 +113,9 @@
svntest.tree.compare_trees("status", actual, expected_status.old_tree())
except svntest.tree.SVNTreeError:
svntest.verify.display_trees(None, 'STATUS OUTPUT TREE',
- output_tree, actual)
+ expected_status.old_tree(), actual)
print("ACTUAL STATUS TREE:")
- svvtest.tree.dump_tree_script(actual, wc_dir_name + os.sep)
+ svntest.tree.dump_tree_script(actual, wc_dir + os.sep)
raise
@@ -210,11 +210,38 @@
'(svn:wc:ra_dav:version-url 46 /svn-test-work/local_tmp/repos/!svn/ver/1/iota)',
}
check_dav_cache(sbox.wc_dir, 1, expected_dav_caches)
-
+
+# Poor mans relocate to fix up an 1.0 (xml style) working copy to refer to a
+# valid repository, so svn upgrade can do its work on it
+def xml_entries_relocate(path, from_url, to_url):
+ adm_name = svntest.main.get_admin_name()
+ entries = os.path.join(path, adm_name, 'entries')
+ txt = svntest.main.file_read(entries)
+ txt = txt.replace('url="' + from_url, 'url="' + to_url)
+ os.chmod(entries, 0777)
+ svntest.main.file_write(entries, txt)
+
+ print('Relocated %s' % path)
+
+ for dirent in os.listdir(path):
+ item_path = os.path.join(path, dirent)
+
+ if dirent == svntest.main.get_admin_name():
+ continue
+
+ if os.path.isdir(os.path.join(item_path, adm_name)):
+ xml_entries_relocate(item_path, from_url, to_url)
+
def basic_upgrade_1_0(sbox):
"test upgrading a working copy created with 1.0.0"
+
+ sbox.build(create_wc = False)
replace_sbox_with_tarfile(sbox, 'upgrade_1_0.tar.bz2')
+ url = sbox.repo_url
+
+ xml_entries_relocate(sbox.wc_dir, 'file:///1.0.0/repos', url)
+
# 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,
@@ -224,6 +251,10 @@
# Now upgrade the working copy
svntest.actions.run_and_verify_svn(None, None, [],
'upgrade', sbox.wc_dir)
+ # And the separate working copy below COPIED or check_format() fails
+ svntest.actions.run_and_verify_svn(None, None, [],
+ 'upgrade',
+ os.path.join(sbox.wc_dir, 'COPIED', 'G'))
# Actually check the format number of the upgraded working copy
check_format(sbox, get_current_format())
@@ -231,9 +262,65 @@
# Now check the contents of the working copy
# #### This working copy is not just a basic tree,
# fix with the right data once we get here
- #expected_status = svntest.actions.get_virginal_state(sbox.wc_dir, 1)
- #run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+ expected_status = svntest.wc.State(sbox.wc_dir,
+ {
+ '' : Item(status=' ', wc_rev=7),
+ 'B' : Item(status=' ', wc_rev='7'),
+ 'B/mu' : Item(status=' ', wc_rev='7'),
+ 'B/D' : Item(status=' ', wc_rev='7'),
+ 'B/D/H' : Item(status=' ', wc_rev='7'),
+ 'B/D/H/psi' : Item(status=' ', wc_rev='7'),
+ 'B/D/H/omega' : Item(status=' ', wc_rev='7'),
+ 'B/D/H/zeta' : Item(status='MM', wc_rev='7'),
+ 'B/D/H/chi' : Item(status=' ', wc_rev='7'),
+ 'B/D/gamma' : Item(status=' ', wc_rev='9'),
+ 'B/D/G' : Item(status=' ', wc_rev='7'),
+ 'B/D/G/tau' : Item(status=' ', wc_rev='7'),
+ 'B/D/G/rho' : Item(status=' ', wc_rev='7'),
+ 'B/D/G/pi' : Item(status=' ', wc_rev='7'),
+ 'B/B' : Item(status=' ', wc_rev='7'),
+ 'B/B/lambda' : Item(status=' ', wc_rev='7'),
+ 'MKDIR' : Item(status='A ', wc_rev='0'),
+ 'MKDIR/MKDIR' : Item(status='A ', wc_rev='0'),
+ 'A' : Item(status=' ', wc_rev='7'),
+ 'A/B' : Item(status=' ', wc_rev='7'),
+ 'A/B/lambda' : Item(status=' ', wc_rev='7'),
+ 'A/D' : Item(status=' ', wc_rev='7'),
+ 'A/D/G' : Item(status=' ', wc_rev='7'),
+ 'A/D/G/rho' : Item(status=' ', wc_rev='7'),
+ 'A/D/G/pi' : Item(status=' ', wc_rev='7'),
+ 'A/D/G/tau' : Item(status=' ', wc_rev='7'),
+ 'A/D/H' : Item(status=' ', wc_rev='7'),
+ 'A/D/H/psi' : Item(status=' ', wc_rev='7'),
+ 'A/D/H/omega' : Item(status=' ', wc_rev='7'),
+ 'A/D/H/zeta' : Item(status=' ', wc_rev='7'),
+ 'A/D/H/chi' : Item(status=' ', wc_rev='7'),
+ 'A/D/gamma' : Item(status=' ', wc_rev='7'),
+ 'A/mu' : Item(status=' ', wc_rev='7'),
+ 'iota' : Item(status=' ', wc_rev='7'),
+ 'COPIED' : Item(status=' ', wc_rev='10'),
+ 'DELETED' : Item(status='D ', wc_rev='10'),
+ })
+ run_and_verify_status_no_server(sbox.wc_dir, expected_status)
+ expected_infos = [ {
+ 'Node Kind': 'directory',
+ 'Schedule': 'normal',
+ 'Revision': '7',
+ 'Last Changed Author' : 'Bert',
+ 'Last Changed Rev' : '7'
+ } ]
+ svntest.actions.run_and_verify_info(expected_infos, sbox.wc_dir)
+
+ expected_infos = [ {
+ 'Node Kind': 'directory',
+ 'Schedule': 'delete',
+ 'Revision': '10',
+ 'Last Changed Author' : 'Bert',
+ 'Last Changed Rev' : '10'
+ } ]
+ svntest.actions.run_and_verify_info(expected_infos,
+ os.path.join(sbox.wc_dir, 'DELETED'))
########################################################################
# Run the tests
@@ -245,7 +332,7 @@
XFail(update_1_5),
logs_left_1_5,
upgrade_wcprops,
- XFail(basic_upgrade_1_0)
+ basic_upgrade_1_0
]