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
              ]