Ping! 
This patch has not been reviewed!

On Tue, Dec 29, 2009 at 07:44:49PM +0100, Daniel Näslund wrote:
> Hi!
> 
> [[[
> 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>
> ]]]
> 
> A big thank you to Bert for putting up with all my questions on IRC.
> 
> My previous patch didn't handle relative externals all that well. And it
> failed to upgrade file externals too. I've added a testcase to this
> patch to prove that this one does things right.
> 
> BUT, the testcase does not check the statustree of the wc after the
> upgrade. I didn't understand how to set up a statustree to check
> against.
> 
> Daniel

> Index: subversion/tests/cmdline/upgrade_tests.py
> ===================================================================
> --- subversion/tests/cmdline/upgrade_tests.py (revision 894319)
> +++ subversion/tests/cmdline/upgrade_tests.py (arbetskopia)
> @@ -139,7 +139,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')
>  
> @@ -216,6 +233,7 @@
>  # list all tests here, starting with None:
>  test_list = [ None,
>                basic_upgrade,
> +              upgrade_with_externals,
>                upgrade_1_5,
>                XFail(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 894319)
> +++ subversion/libsvn_client/cleanup.c        (arbetskopia)
> @@ -33,8 +33,11 @@
>  #include "svn_config.h"
>  #include "svn_dirent_uri.h"
>  #include "client.h"
> +#include "svn_pools.h"
> +#include "svn_props.h"
>  
>  #include "svn_private_config.h"
> +#include "private/svn_wc_private.h"
>  
>  
>  /*** Code. ***/
> @@ -62,6 +65,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}};
>  
>    SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
>    SVN_ERR(svn_wc_upgrade(ctx->wc_ctx, local_abspath,
> @@ -69,5 +76,78 @@
>                           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,
> +                                     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;
>  }

Reply via email to