Author: kotkov
Date: Thu Mar  2 11:10:34 2023
New Revision: 1907965

URL: http://svn.apache.org/viewvc?rev=1907965&view=rev
Log:
Fix an issue where calling `svn upgrade` without arguments for a 1.15-format
working copy resulted in an error:

  $ svn checkout --compatible-version=1.15 wc
  $ svn upgrade wc
  $ svn: E155021: Working copy '…' is already at version 1.15 (format 32)
    and cannot be downgraded to version 1.8 (format 31)

To fix it, we start to distinguish cases where the `--compatible-version`
argument (or the corresponding API parameter) have or have not been specified
explicitly.  If the working copy already has a supported format newer than
the resolved target format, the behavior is as follows:

- If the format version wasn't specified explicitly, meaning the default
  version should be used, the upgrade is no-op and the working copy is left
  at its current format.

- If the format version was specified explicitly, meaning that a concrete
  format version should be used, the upgrade results in an error.

* subversion/include/svn_client.h
  (svn_client_upgrade2): Add the `result_format_version_p` out parameter.
   Rename `wc_format_version` to `target_format_version`.  Adjust docstring.
  (svn_client_upgrade): Adjust docstring.

* subversion/include/private/svn_wc_private.h
  (svn_wc__upgrade): Add the `result_format_p` out parameter.  Adjust docstring.

* subversion/libsvn_client/upgrade.c
  (upgrade_internal): Add the `result_format_p` out parameter.
   Rename `wc_format` to `target_format`.
  (upgrade_external_item): Adjust calling site of upgrade_internal().
  (svn_client_upgrade2): Fill in the resulting format version.
   Fail on downgrade attempts if a format version was passed explicitly.

* subversion/libsvn_client/deprecated.c
  (svn_client_upgrade): Adjust calling site of svn_client_upgrade2().

* subversion/libsvn_wc/upgrade.c
  (svn_wc__upgrade_sdb): Don't check for downgrade attempts here.
   Allow the upgrade to be a no-op by removing corresponding assertions from
   this function and also …
  (svn_wc__update_schema): …here, …
  (svn_wc__upgrade): …and here.  Fill in the resulting format value.

* subversion/libsvn_wc/deprecated.c
  (svn_wc_upgrade): Adjust calling site of svn_wc__upgrade().

* subversion/svn/upgrade-cmd.c
  (svn_cl__upgrade): Use the information about the resulting format version
   to re-implement the "working copy may be upgraded further" message, and
   issue it on a per-wc basis.

* subversion/tests/cmdline/upgrade_tests.py
  (upgrade_latest_format): No longer fails.  Check the resulting format of
   the working copy.

* subversion/tests/cmdline/externals_tests.py
  (switch_relative_externals): Remove Wimp() marker, because the corresponding
   issue is now solved.

Modified:
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/deprecated.c
    subversion/trunk/subversion/libsvn_client/upgrade.c
    subversion/trunk/subversion/libsvn_wc/deprecated.c
    subversion/trunk/subversion/libsvn_wc/upgrade.c
    subversion/trunk/subversion/svn/upgrade-cmd.c
    subversion/trunk/subversion/tests/cmdline/externals_tests.py
    subversion/trunk/subversion/tests/cmdline/upgrade_tests.py

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Thu Mar  2 
11:10:34 2023
@@ -2290,6 +2290,9 @@ svn_wc__ensure_adm(svn_wc_context_t *wc_
  * format indicated by @a target_format.  @a local_abspath should be
  * an absolute path to the root of the working copy.
  *
+ * If @a result_format_p is non-NULL, it will be set to the resulting
+ * format of the working copy after the upgrade.
+ *
  * If @a cancel_func is non-NULL, invoke it with @a cancel_baton at
  * various points during the operation.  If it returns an error
  * (typically #SVN_ERR_CANCELLED), return that error immediately.
@@ -2306,7 +2309,8 @@ svn_wc__ensure_adm(svn_wc_context_t *wc_
  * @since New in 1.15.
  */
 svn_error_t *
-svn_wc__upgrade(svn_wc_context_t *wc_ctx,
+svn_wc__upgrade(int *result_format_p,
+                svn_wc_context_t *wc_ctx,
                 const char *local_abspath,
                 int target_format,
                 svn_wc_upgrade_get_repos_info_t repos_info_func,

Modified: subversion/trunk/subversion/include/svn_client.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Thu Mar  2 11:10:34 2023
@@ -4403,12 +4403,27 @@ svn_client_cleanup(const char *dir,
 /**
  * Recursively upgrade a working copy and nested externals working
  * copies from any older format to a WC metadata storage
- * format supported by Subversion @a wc_format_version.
+ * format supported by Subversion @a target_format_version.
  *
- * If @a wc_format_version is @c NULL, the default version is used.
+ * If @a target_format_version is @c NULL, the default version is used.
+ *
+ * If the working copy already has a supported format newer than
+ * @a target_format_version, the behavior is as follows:
+ *
+ * - If @a target_format_version is @c NULL, meaning the default version
+ *   should be used, the upgrade is no-op and the working copy is left
+ *   at its current format.
+ *
+ * - If @a target_format_version is not @c NULL, meaning that a specific
+ *   format version should be used, the upgrade results in an error.
  *
  * @a wcroot_dir is the path to the WC root.
  *
+ * If @a result_format_version_p is not @c NULL, it will be set to the
+ * resulting format version of the upgraded working copy, allocated from
+ * @a result_pool.  If this information is not required, @a result_pool
+ * may be passed as @c NULL.
+ *
  * @see svn_client_default_wc_version(),
  * svn_client_get_wc_formats_supported().
  *
@@ -4417,13 +4432,16 @@ svn_client_cleanup(const char *dir,
  * @since New in 1.15.
  */
 svn_error_t *
-svn_client_upgrade2(const char *wcroot_dir,
-                    const svn_version_t *wc_format_version,
+svn_client_upgrade2(const svn_version_t **result_format_version_p,
+                    const char *wcroot_dir,
+                    const svn_version_t *target_format_version,
                     svn_client_ctx_t *ctx,
+                    apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool);
 
 /**
- * Like svn_client_upgrade2(), but with @a wc_format_version set to @c NULL.
+ * Like svn_client_upgrade2(), but with @a result_format_version_p,
+ * @a target_format_version and @a result_pool set to @c NULL.
  *
  * @since New in 1.7.
  * @deprecated Provided for backward compatibility with the 1.14 API.

Modified: subversion/trunk/subversion/libsvn_client/deprecated.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/deprecated.c?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_client/deprecated.c Thu Mar  2 11:10:34 
2023
@@ -3287,5 +3287,6 @@ svn_client_upgrade(const char *path,
                    svn_client_ctx_t *ctx,
                    apr_pool_t *scratch_pool)
 {
-  return svn_error_trace(svn_client_upgrade2(path, NULL, ctx, scratch_pool));
+  return svn_error_trace(svn_client_upgrade2(NULL, path, NULL, ctx,
+                                             NULL, scratch_pool));
 }

Modified: subversion/trunk/subversion/libsvn_client/upgrade.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/upgrade.c?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/upgrade.c (original)
+++ subversion/trunk/subversion/libsvn_client/upgrade.c Thu Mar  2 11:10:34 2023
@@ -99,8 +99,9 @@ upgrade_externals_from_properties(svn_cl
                                   apr_pool_t *scratch_pool);
 
 static svn_error_t *
-upgrade_internal(const char *path,
-                 int wc_format,
+upgrade_internal(int *result_format_p,
+                 const char *path,
+                 int target_format,
                  svn_client_ctx_t *ctx,
                  apr_pool_t *scratch_pool)
 {
@@ -118,7 +119,8 @@ upgrade_internal(const char *path,
                              _("'%s' is not a local path"), path);
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
-  SVN_ERR(svn_wc__upgrade(ctx->wc_ctx, local_abspath, wc_format,
+  SVN_ERR(svn_wc__upgrade(result_format_p, ctx->wc_ctx,
+                          local_abspath, target_format,
                           fetch_repos_info, &info_baton,
                           ctx->cancel_func, ctx->cancel_baton,
                           ctx->notify_func2, ctx->notify_baton2,
@@ -156,8 +158,9 @@ upgrade_internal(const char *path,
 
           if (kind == svn_node_dir)
             {
-              svn_error_t *err = upgrade_internal(ext_abspath, wc_format,
-                                                  ctx, iterpool);
+              svn_error_t *err = upgrade_internal(NULL, ext_abspath,
+                                                  target_format, ctx,
+                                                  iterpool);
 
               if (err)
                 {
@@ -181,8 +184,9 @@ upgrade_internal(const char *path,
       /* Upgrading from <= 1.6, or no svn:properties defined.
          (There is no way to detect the difference from libsvn_client :( ) */
 
-      SVN_ERR(upgrade_externals_from_properties(ctx, local_abspath, wc_format,
-                                                &info_baton, scratch_pool));
+      SVN_ERR(upgrade_externals_from_properties(ctx, local_abspath,
+                                                target_format, &info_baton,
+                                                scratch_pool));
     }
 
   SVN_ERR(svn_client__textbase_sync(NULL, local_abspath, FALSE, TRUE, ctx,
@@ -192,23 +196,54 @@ upgrade_internal(const char *path,
 }
 
 svn_error_t *
-svn_client_upgrade2(const char *path,
-                    const svn_version_t *wc_format_version,
+svn_client_upgrade2(const svn_version_t **result_format_version_p,
+                    const char *path,
+                    const svn_version_t *target_format_version,
                     svn_client_ctx_t *ctx,
+                    apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
-  int wc_format;
+  int result_format;
+  int target_format;
+  svn_boolean_t fail_on_downgrade;
 
-  if (!wc_format_version)
+  if (target_format_version)
     {
-      SVN_ERR(svn_client_default_wc_version(&wc_format_version, ctx,
+      SVN_ERR(svn_wc__format_from_version(&target_format,
+                                          target_format_version,
+                                          scratch_pool));
+      /* Fail on downgrade attempts if format version was passed explicitly. */
+      fail_on_downgrade = TRUE;
+    }
+  else
+    {
+      const svn_version_t *default_version;
+
+      SVN_ERR(svn_client_default_wc_version(&default_version, ctx,
                                             scratch_pool, scratch_pool));
+      SVN_ERR(svn_wc__format_from_version(&target_format, default_version,
+                                          scratch_pool));
+      fail_on_downgrade = FALSE;
     }
 
-  SVN_ERR(svn_wc__format_from_version(&wc_format,
-                                      wc_format_version,
-                                      scratch_pool));
-  SVN_ERR(upgrade_internal(path, wc_format, ctx, scratch_pool));
+  SVN_ERR(upgrade_internal(&result_format, path, target_format,
+                           ctx, scratch_pool));
+
+  if (fail_on_downgrade && result_format > target_format)
+    return svn_error_createf(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
+                             _("Working copy '%s' is already at version %s "
+                               "(format %d) and cannot be downgraded to "
+                               "version %s (format %d)"),
+                             svn_dirent_local_style(path, scratch_pool),
+                             svn_wc__version_string_from_format(result_format),
+                             result_format,
+                             svn_wc__version_string_from_format(target_format),
+                             target_format);
+
+  if (result_format_version_p)
+    *result_format_version_p = svn_client_wc_version_from_format(
+                                 result_format, result_pool);
+
   return SVN_NO_ERROR;
 }
 
@@ -362,7 +397,8 @@ upgrade_external_item(svn_client_ctx_t *
     {
       svn_error_clear(err);
 
-      SVN_ERR(upgrade_internal(external_abspath, wc_format, ctx, 
scratch_pool));
+      SVN_ERR(upgrade_internal(NULL, external_abspath, wc_format, ctx,
+                               scratch_pool));
     }
   else if (err)
     return svn_error_trace(err);

Modified: subversion/trunk/subversion/libsvn_wc/deprecated.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/deprecated.c?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/deprecated.c (original)
+++ subversion/trunk/subversion/libsvn_wc/deprecated.c Thu Mar  2 11:10:34 2023
@@ -5179,7 +5179,8 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
                void *notify_baton,
                apr_pool_t *scratch_pool)
 {
-  return svn_wc__upgrade(wc_ctx, local_abspath, SVN_WC__DEFAULT_VERSION,
+  return svn_wc__upgrade(NULL, wc_ctx, local_abspath,
+                         SVN_WC__DEFAULT_VERSION,
                          repos_info_func, repos_info_baton,
                          cancel_func, cancel_baton,
                          notify_func, notify_baton,

Modified: subversion/trunk/subversion/libsvn_wc/upgrade.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/upgrade.c?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/trunk/subversion/libsvn_wc/upgrade.c Thu Mar  2 11:10:34 2023
@@ -1765,18 +1765,6 @@ svn_wc__upgrade_sdb(int *result_format,
                                                     scratch_pool),
                              start_format);
 
-  if (start_format > target_format)
-    return svn_error_createf(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
-                             _("Working copy '%s' is already at version %s "
-                               "(format %d) and cannot be downgraded to "
-                               "version %s (format %d)"),
-                             svn_dirent_local_style(wcroot_abspath,
-                                                    scratch_pool),
-                             svn_wc__version_string_from_format(start_format),
-                             start_format,
-                             svn_wc__version_string_from_format(target_format),
-                             target_format);
-
   if (target_format < SVN_WC__SUPPORTED_VERSION)
     return svn_error_createf(SVN_ERR_WC_UNSUPPORTED_FORMAT, NULL,
                              _("Working copy version %s (format %d) "
@@ -1802,17 +1790,6 @@ svn_wc__upgrade_sdb(int *result_format,
       svn_wc__db_install_schema_statistics(sdb, scratch_pool),
       sdb);
 
-#ifdef SVN_DEBUG
-  if (*result_format != start_format)
-    {
-      int schema_version;
-      SVN_ERR(svn_sqlite__read_schema_version(&schema_version, sdb, 
scratch_pool));
-
-      /* If this assertion fails the schema isn't updated correctly */
-      SVN_ERR_ASSERT(schema_version == *result_format);
-    }
-#endif
-
   /* Zap anything that might be remaining or escaped our notice.  */
   wipe_obsolete_files(wcroot_abspath, scratch_pool);
 
@@ -1855,7 +1832,6 @@ svn_wc__update_schema(int *result_format
 #undef UPDATE_TO_FORMAT
     }
 
-  SVN_ERR_ASSERT(*result_format == target_format);
   return SVN_NO_ERROR;
 }
 
@@ -2023,7 +1999,8 @@ is_old_wcroot(const char *local_abspath,
 }
 
 svn_error_t *
-svn_wc__upgrade(svn_wc_context_t *wc_ctx,
+svn_wc__upgrade(int *result_format_p,
+                svn_wc_context_t *wc_ctx,
                 const char *local_abspath,
                 int target_format,
                 svn_wc_upgrade_get_repos_info_t repos_info_func,
@@ -2072,8 +2049,6 @@ svn_wc__upgrade(svn_wc_context_t *wc_ctx
       /* Auto-upgrade worked! */
       SVN_ERR(svn_wc__db_close(db));
 
-      SVN_ERR_ASSERT(result_format == target_format);
-
       if (bumped_format && notify_func)
         {
           svn_wc_notify_t *notify;
@@ -2085,6 +2060,8 @@ svn_wc__upgrade(svn_wc_context_t *wc_ctx
           notify_func(notify_baton, notify, scratch_pool);
         }
 
+      if (result_format_p)
+        *result_format_p = result_format;
       return SVN_NO_ERROR;
     }
 
@@ -2183,6 +2160,8 @@ svn_wc__upgrade(svn_wc_context_t *wc_ctx
   SVN_ERR(svn_io_remove_dir2(data.root_abspath, FALSE, NULL, NULL,
                              scratch_pool));
 
+  if (result_format_p)
+    *result_format_p = target_format;
   return SVN_NO_ERROR;
 }
 

Modified: subversion/trunk/subversion/svn/upgrade-cmd.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/upgrade-cmd.c?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/upgrade-cmd.c (original)
+++ subversion/trunk/subversion/svn/upgrade-cmd.c Thu Mar  2 11:10:34 2023
@@ -52,11 +52,8 @@ svn_cl__upgrade(apr_getopt_t *os,
   apr_array_header_t *targets;
   apr_pool_t *iterpool;
   int i;
-  const svn_version_t *default_version;
   const svn_version_t *latest_version;
 
-  SVN_ERR(svn_client_default_wc_version(&default_version, ctx,
-                                        scratch_pool, scratch_pool));
   latest_version = svn_client_latest_wc_version(scratch_pool);
 
   SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
@@ -75,31 +72,34 @@ svn_cl__upgrade(apr_getopt_t *os,
   for (i = 0; i < targets->nelts; i++)
     {
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
+      const svn_version_t *result_format_version;
 
       svn_pool_clear(iterpool);
       SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
-      SVN_ERR(svn_client_upgrade2(target,
+      SVN_ERR(svn_client_upgrade2(&result_format_version, target,
                                   opt_state->compatible_version,
-                                  ctx, scratch_pool));
-    }
-  svn_pool_destroy(iterpool);
+                                  ctx, iterpool, iterpool));
 
-  /* Remind the user they can upgrade further if:
-   *   - the user did not specify compatible-version explicitly
-   *   - a higher version is available. */
-  if (! opt_state->compatible_version
-      && ! svn_version__at_least(default_version,
-                                 latest_version->major, latest_version->minor, 
0)
-      && ! opt_state->quiet)
-    {
-      const char *msg
-        = _("svn: The target working copies are already at version %d.%d; "
-            "the highest version supported by this client can be "
-            "specified with '--compatible-version=%d.%d'.\n");
-      SVN_ERR(svn_cmdline_printf(scratch_pool, msg,
-                                 default_version->major, 
default_version->minor,
-                                 latest_version->major, 
latest_version->minor));
+      /* Remind the user they can upgrade further if:
+       *   - the user did not specify compatible-version explicitly
+       *   - a higher version is available. */
+      if (! opt_state->compatible_version
+          && ! svn_version__at_least(result_format_version,
+                                     latest_version->major,
+                                     latest_version->minor, 0)
+          && ! opt_state->quiet)
+        {
+          SVN_ERR(svn_cmdline_printf(
+                    iterpool,
+                    _("svn: The target working copy '%s' is at version %d.%d; "
+                      "the highest version supported by this client can be "
+                      "specified with '--compatible-version=%d.%d'.\n"),
+                    svn_dirent_local_style(target, iterpool),
+                    result_format_version->major, result_format_version->minor,
+                    latest_version->major, latest_version->minor));
+        }
     }
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/tests/cmdline/externals_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/externals_tests.py?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/externals_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/externals_tests.py Thu Mar  2 
11:10:34 2023
@@ -3431,7 +3431,6 @@ def update_deletes_file_external(sbox):
 
 
 @Issue(4519)
-@Wimp("May trigger an existing issue, see 
upgrade_tests.py:upgrade_latest_format()")
 def switch_relative_externals(sbox):
   "switch relative externals"
 

Modified: subversion/trunk/subversion/tests/cmdline/upgrade_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/upgrade_tests.py?rev=1907965&r1=1907964&r2=1907965&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/upgrade_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/upgrade_tests.py Thu Mar  2 
11:10:34 2023
@@ -1583,7 +1583,6 @@ def upgrade_1_0_with_externals(sbox):
      })
   run_and_verify_status_no_server(sbox.wc_dir, expected_status)
 
-@XFail()
 @SkipUnless(lambda: svntest.main.options.wc_format_version is None)
 def upgrade_latest_format(sbox):
   "upgrade latest format without arguments"
@@ -1599,11 +1598,13 @@ def upgrade_latest_format(sbox):
                                           [],
                                           '--compatible-version',
                                           latest_ver)
-  # XFAIL:
+  # This used to fail with the following error:
   # svn: E155021: Working copy '...' is already at version 1.15 (format 32)
   # and cannot be downgraded to version 1.8 (format 31)
   svntest.actions.run_and_verify_svn(None, [], 'upgrade', sbox.wc_dir)
 
+  check_format(sbox, svntest.main.wc_format(latest_ver))
+
 def upgrade_compatible_version_arg(sbox):
   "upgrade with compatible-version from arg"
 


Reply via email to