You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by as...@apache.org on 2012/11/24 21:29:48 UTC

svn commit: r1413258 [7/33] - in /subversion/branches/compressed-pristines: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/ notes/ notes/directory-index/ subversion/ subve...

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/copy.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/copy.c Sat Nov 24 20:29:11 2012
@@ -244,6 +244,7 @@ do_wc_to_wc_moves_with_locks2(svn_client
                               const char *dst_parent_abspath,
                               svn_boolean_t lock_src,
                               svn_boolean_t lock_dst,
+                              svn_boolean_t allow_mixed_revisions,
                               svn_client_ctx_t *ctx,
                               apr_pool_t *scratch_pool)
 {
@@ -252,11 +253,12 @@ do_wc_to_wc_moves_with_locks2(svn_client
   dst_abspath = svn_dirent_join(dst_parent_abspath, pair->base_name,
                                 scratch_pool);
 
-  SVN_ERR(svn_wc_move(ctx->wc_ctx, pair->src_abspath_or_url,
-                     dst_abspath, FALSE /* metadata_only */,
-                     ctx->cancel_func, ctx->cancel_baton,
-                     ctx->notify_func2, ctx->notify_baton2,
-                     scratch_pool));
+  SVN_ERR(svn_wc__move2(ctx->wc_ctx, pair->src_abspath_or_url,
+                        dst_abspath, FALSE /* metadata_only */,
+                        allow_mixed_revisions,
+                        ctx->cancel_func, ctx->cancel_baton,
+                        ctx->notify_func2, ctx->notify_baton2,
+                        scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -267,17 +269,20 @@ do_wc_to_wc_moves_with_locks1(svn_client
                               const char *dst_parent_abspath,
                               svn_boolean_t lock_src,
                               svn_boolean_t lock_dst,
+                              svn_boolean_t allow_mixed_revisions,
                               svn_client_ctx_t *ctx,
                               apr_pool_t *scratch_pool)
 {
   if (lock_dst)
     SVN_WC__CALL_WITH_WRITE_LOCK(
       do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src,
-                                    lock_dst, ctx, scratch_pool),
+                                    lock_dst, allow_mixed_revisions, ctx,
+                                    scratch_pool),
       ctx->wc_ctx, dst_parent_abspath, FALSE, scratch_pool);
   else
     SVN_ERR(do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src,
-                                          lock_dst, ctx, scratch_pool));
+                                          lock_dst, allow_mixed_revisions,
+                                          ctx, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -287,6 +292,7 @@ do_wc_to_wc_moves_with_locks1(svn_client
 static svn_error_t *
 do_wc_to_wc_moves(const apr_array_header_t *copy_pairs,
                   const char *dst_path,
+                  svn_boolean_t allow_mixed_revisions,
                   svn_client_ctx_t *ctx,
                   apr_pool_t *pool)
 {
@@ -341,13 +347,15 @@ do_wc_to_wc_moves(const apr_array_header
       if (lock_src)
         SVN_WC__CALL_WITH_WRITE_LOCK(
           do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath,
-                                        lock_src, lock_dst, ctx, iterpool),
+                                        lock_src, lock_dst,
+                                        allow_mixed_revisions, ctx, iterpool),
           ctx->wc_ctx, src_parent_abspath,
           FALSE, iterpool);
       else
         SVN_ERR(do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath,
-                                              lock_src, lock_dst, ctx,
-                                              iterpool));
+                                              lock_src, lock_dst,
+                                              allow_mixed_revisions,
+                                              ctx, iterpool));
 
     }
   svn_pool_destroy(iterpool);
@@ -357,18 +365,21 @@ do_wc_to_wc_moves(const apr_array_header
   return svn_error_trace(err);
 }
 
-
+/* Verify that the destinations stored in COPY_PAIRS are valid working copy
+   destinations and set pair->dst_parent_abspath and pair->base_name for each
+   item to the resulting location if they do */
 static svn_error_t *
-verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
-                        svn_boolean_t make_parents,
-                        svn_boolean_t is_move,
-                        svn_client_ctx_t *ctx,
-                        apr_pool_t *pool)
+verify_wc_dsts(const apr_array_header_t *copy_pairs,
+               svn_boolean_t make_parents,
+               svn_boolean_t is_move,
+               svn_client_ctx_t *ctx,
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   int i;
-  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  /* Check that all of our SRCs exist, and all the DSTs don't. */
+  /* Check that DST does not exist, but its parent does */
   for (i = 0; i < copy_pairs->nelts; i++)
     {
       svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
@@ -377,20 +388,52 @@ verify_wc_srcs_and_dsts(const apr_array_
 
       svn_pool_clear(iterpool);
 
-      /* Verify that SRC_PATH exists. */
-      SVN_ERR(svn_io_check_path(pair->src_abspath_or_url, &pair->src_kind,
-                                iterpool));
-      if (pair->src_kind == svn_node_none)
-        return svn_error_createf(
-          SVN_ERR_NODE_UNKNOWN_KIND, NULL,
-          _("Path '%s' does not exist"),
-          svn_dirent_local_style(pair->src_abspath_or_url, pool));
-
       /* If DST_PATH does not exist, then its basename will become a new
          file or dir added to its parent (possibly an implicit '.').
          Else, just error out. */
+      SVN_ERR(svn_wc_read_kind(&dst_kind, ctx->wc_ctx,
+                               pair->dst_abspath_or_url, TRUE /* show_hidden */,
+                               iterpool));
+      if (dst_kind != svn_node_none)
+        {
+          svn_boolean_t is_not_present;
+          svn_boolean_t is_excluded;
+          svn_boolean_t is_server_excluded;
+
+          SVN_ERR(svn_wc__node_is_not_present(&is_not_present, &is_excluded,
+                                              &is_server_excluded, ctx->wc_ctx,
+                                              pair->dst_abspath_or_url,
+                                              iterpool));
+
+          if (is_excluded || is_server_excluded)
+            {
+              return svn_error_createf(
+                  SVN_ERR_WC_OBSTRUCTED_UPDATE,
+                  NULL, _("Path '%s' exists, but is excluded"),
+                  svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
+            }
+
+          if (! is_not_present)
+            {
+              svn_boolean_t is_deleted;
+
+              SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
+                                                     pair->dst_abspath_or_url,
+                                                     scratch_pool));
+
+              if (! is_deleted)
+                return svn_error_createf(
+                            SVN_ERR_ENTRY_EXISTS, NULL,
+                            _("Path '%s' already exists"),
+                            svn_dirent_local_style(pair->dst_abspath_or_url,
+                                                   scratch_pool));
+            }
+        }
+
+      /* Check that there is no unversioned obstruction */
       SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind,
                                 iterpool));
+
       if (dst_kind != svn_node_none)
         {
           if (is_move
@@ -408,7 +451,7 @@ verify_wc_srcs_and_dsts(const apr_array_
 
               SVN_ERR(svn_path_cstring_from_utf8(&dst,
                                                  pair->dst_abspath_or_url,
-                                                 pool));
+                                                 scratch_pool));
 
               apr_err = apr_filepath_merge(&dst_apr, NULL, dst,
                                            APR_FILEPATH_TRUENAME, iterpool);
@@ -425,7 +468,7 @@ verify_wc_srcs_and_dsts(const apr_array_
                 {
                   /* Ok, we have a single case only rename. Get out of here */
                   svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
-                                   pair->dst_abspath_or_url, pool);
+                                   pair->dst_abspath_or_url, result_pool);
 
                   svn_pool_destroy(iterpool);
                   return SVN_NO_ERROR;
@@ -433,13 +476,14 @@ verify_wc_srcs_and_dsts(const apr_array_
             }
 
           return svn_error_createf(
-                      SVN_ERR_ENTRY_EXISTS, NULL,
-                      _("Path '%s' already exists"),
-                      svn_dirent_local_style(pair->dst_abspath_or_url, pool));
+                            SVN_ERR_ENTRY_EXISTS, NULL,
+                            _("Path '%s' already exists as unversioned node"),
+                            svn_dirent_local_style(pair->dst_abspath_or_url,
+                                                   scratch_pool));
         }
 
       svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
-                       pair->dst_abspath_or_url, pool);
+                       pair->dst_abspath_or_url, result_pool);
 
       /* Make sure the destination parent is a directory and produce a clear
          error message if it is not. */
@@ -465,7 +509,7 @@ verify_wc_srcs_and_dsts(const apr_array_
           return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
                                    _("Path '%s' is not a directory"),
                                    svn_dirent_local_style(
-                                     pair->dst_parent_abspath, pool));
+                                     pair->dst_parent_abspath, scratch_pool));
         }
     }
 
@@ -474,6 +518,43 @@ verify_wc_srcs_and_dsts(const apr_array_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
+                        svn_boolean_t make_parents,
+                        svn_boolean_t is_move,
+                        svn_client_ctx_t *ctx,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  /* Check that all of our SRCs exist. */
+  for (i = 0; i < copy_pairs->nelts; i++)
+    {
+      svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
+                                                    svn_client__copy_pair_t *);
+      svn_pool_clear(iterpool);
+
+      /* Verify that SRC_PATH exists. */
+      SVN_ERR(svn_wc_read_kind(&pair->src_kind, ctx->wc_ctx,
+                               pair->src_abspath_or_url, FALSE, iterpool));
+      if (pair->src_kind == svn_node_none)
+        return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                                 _("Path '%s' does not exist"),
+                                 svn_dirent_local_style(
+                                        pair->src_abspath_or_url,
+                                        scratch_pool));
+    }
+
+  SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, ctx,
+                         result_pool, iterpool));
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Path-specific state used as part of path_driver_cb_baton. */
 typedef struct path_driver_info_t
@@ -1066,8 +1147,8 @@ repos_to_repos_copy(const apr_array_head
   cb_baton.is_move = is_move;
 
   /* Call the path-based editor driver. */
-  err = svn_delta_path_driver(editor, edit_baton, SVN_INVALID_REVNUM, paths,
-                              path_driver_cb_func, &cb_baton, pool);
+  err = svn_delta_path_driver2(editor, edit_baton, paths, TRUE,
+                               path_driver_cb_func, &cb_baton, pool);
   if (err)
     {
       /* At least try to abort the edit (and fs txn) before throwing err. */
@@ -1601,86 +1682,24 @@ repos_to_wc_copy_locked(const apr_array_
                         apr_pool_t *scratch_pool)
 {
   int i;
-  const char *src_uuid = NULL, *dst_uuid = NULL;
   svn_boolean_t same_repositories;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   /* We've already checked for physical obstruction by a working file.
      But there could also be logical obstruction by an entry whose
      working file happens to be missing.*/
-  for (i = 0; i < copy_pairs->nelts; i++)
-    {
-      svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
-                                                    svn_client__copy_pair_t *);
-      svn_node_kind_t kind;
-      svn_boolean_t is_excluded;
-      svn_boolean_t is_server_excluded;
-
-      svn_pool_clear(iterpool);
-
-      SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, pair->dst_abspath_or_url,
-                               FALSE, iterpool));
-      if (kind == svn_node_none)
-        continue;
-
-      /* ### TODO(#2843): Rework these error report. Maybe we can
-         ### simplify the conditions? */
-
-      /* Hidden by client exclusion */
-      SVN_ERR(svn_wc__node_is_status_excluded(&is_excluded, ctx->wc_ctx,
-                                              pair->dst_abspath_or_url,
-                                              iterpool));
-      if (is_excluded)
-        {
-          return svn_error_createf
-            (SVN_ERR_ENTRY_EXISTS,
-             NULL, _("'%s' is already under version control"),
-             svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
-        }
-
-      /* Hidden by server exclusion (not authorized) */
-      SVN_ERR(svn_wc__node_is_status_server_excluded(&is_server_excluded,
-                                                     ctx->wc_ctx,
-                                                     pair->dst_abspath_or_url,
-                                                     iterpool));
-      if (is_server_excluded)
-        {
-          return svn_error_createf
-            (SVN_ERR_ENTRY_EXISTS,
-             NULL, _("'%s' is already under version control"),
-             svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
-        }
-
-      /* Working file missing to something other than being scheduled
-         for addition or in "deleted" state. */
-      if (kind != svn_node_dir)
-        {
-          svn_boolean_t is_deleted;
-          svn_boolean_t is_not_present;
-
-          SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
-                                                 pair->dst_abspath_or_url,
-                                                 iterpool));
-          SVN_ERR(svn_wc__node_is_status_not_present(&is_not_present,
-                                                     ctx->wc_ctx,
-                                                     pair->dst_abspath_or_url,
-                                                     iterpool));
-          if ((! is_deleted) && (! is_not_present))
-            return svn_error_createf
-              (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
-               _("Entry for '%s' exists (though the working file is missing)"),
-               svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
-        }
-    }
+  SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, ctx,
+                         scratch_pool, iterpool));
 
   /* Decide whether the two repositories are the same or not. */
   {
     svn_error_t *src_err, *dst_err;
     const char *parent;
     const char *parent_abspath;
+    const char *src_uuid, *dst_uuid;
 
     /* Get the repository uuid of SRC_URL */
-    src_err = svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool);
+    src_err = svn_ra_get_uuid2(ra_session, &src_uuid, iterpool);
     if (src_err && src_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
       return svn_error_trace(src_err);
 
@@ -1695,7 +1714,7 @@ repos_to_wc_copy_locked(const apr_array_
     SVN_ERR(svn_dirent_get_absolute(&parent_abspath, parent, scratch_pool));
     dst_err = svn_client_get_repos_root(NULL /* root_url */, &dst_uuid,
                                         parent_abspath, ctx,
-                                        scratch_pool, scratch_pool);
+                                        iterpool, iterpool);
     if (dst_err && dst_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
       return dst_err;
 
@@ -1705,7 +1724,6 @@ repos_to_wc_copy_locked(const apr_array_
        copy-history is attempted. */
     if (src_err || dst_err || (! src_uuid) || (! dst_uuid))
       same_repositories = FALSE;
-
     else
       same_repositories = (strcmp(src_uuid, dst_uuid) == 0);
   }
@@ -1856,6 +1874,7 @@ static svn_error_t *
 try_copy(const apr_array_header_t *sources,
          const char *dst_path_in,
          svn_boolean_t is_move,
+         svn_boolean_t allow_mixed_revisions,
          svn_boolean_t make_parents,
          svn_boolean_t ignore_externals,
          const apr_hash_t *revprop_table,
@@ -2141,12 +2160,13 @@ try_copy(const apr_array_header_t *sourc
   if ((! srcs_are_urls) && (! dst_is_url))
     {
       SVN_ERR(verify_wc_srcs_and_dsts(copy_pairs, make_parents, is_move,
-                                      ctx, pool));
+                                      ctx, pool, pool));
 
       /* Copy or move all targets. */
       if (is_move)
-        return svn_error_trace(do_wc_to_wc_moves(copy_pairs, dst_path_in, ctx,
-                                                 pool));
+        return svn_error_trace(do_wc_to_wc_moves(copy_pairs, dst_path_in,
+                                                 allow_mixed_revisions,
+                                                 ctx, pool));
       else
         return svn_error_trace(do_wc_to_wc_copies(copy_pairs, ctx, pool));
     }
@@ -2195,6 +2215,7 @@ svn_client_copy6(const apr_array_header_
 
   err = try_copy(sources, dst_path,
                  FALSE /* is_move */,
+                 TRUE /* allow_mixed_revisions */,
                  make_parents,
                  ignore_externals,
                  revprop_table,
@@ -2226,6 +2247,7 @@ svn_client_copy6(const apr_array_header_
                                                        subpool)
                          : svn_dirent_join(dst_path, src_basename, subpool),
                      FALSE /* is_move */,
+                     TRUE /* allow_mixed_revisions */,
                      make_parents,
                      ignore_externals,
                      revprop_table,
@@ -2240,10 +2262,11 @@ svn_client_copy6(const apr_array_header_
 
 
 svn_error_t *
-svn_client_move6(const apr_array_header_t *src_paths,
+svn_client_move7(const apr_array_header_t *src_paths,
                  const char *dst_path,
                  svn_boolean_t move_as_child,
                  svn_boolean_t make_parents,
+                 svn_boolean_t allow_mixed_revisions,
                  const apr_hash_t *revprop_table,
                  svn_commit_callback2_t commit_callback,
                  void *commit_baton,
@@ -2277,6 +2300,7 @@ svn_client_move6(const apr_array_header_
 
   err = try_copy(sources, dst_path,
                  TRUE /* is_move */,
+                 allow_mixed_revisions,
                  make_parents,
                  FALSE,
                  revprop_table,
@@ -2307,6 +2331,7 @@ svn_client_move6(const apr_array_header_
                                                        src_basename, pool)
                          : svn_dirent_join(dst_path, src_basename, pool),
                      TRUE /* is_move */,
+                     allow_mixed_revisions,
                      make_parents,
                      FALSE,
                      revprop_table,

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/ctx.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/ctx.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/ctx.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/ctx.c Sat Nov 24 20:29:11 2012
@@ -76,9 +76,12 @@ call_conflict_func(svn_wc_conflict_resul
 }
 
 svn_error_t *
-svn_client_create_context(svn_client_ctx_t **ctx,
-                          apr_pool_t *pool)
+svn_client_create_context2(svn_client_ctx_t **ctx,
+                           apr_hash_t *cfg_hash,
+                           apr_pool_t *pool)
 {
+  svn_config_t *cfg_config;
+                                   
   *ctx = apr_pcalloc(pool, sizeof(svn_client_ctx_t));
 
   (*ctx)->notify_func2 = call_notify_func;
@@ -87,8 +90,23 @@ svn_client_create_context(svn_client_ctx
   (*ctx)->conflict_func2 = call_conflict_func;
   (*ctx)->conflict_baton2 = *ctx;
 
-  SVN_ERR(svn_wc_context_create(&(*ctx)->wc_ctx, NULL /* config */, pool,
+  (*ctx)->config = cfg_hash;
+
+  if (cfg_hash)
+    cfg_config = apr_hash_get(cfg_hash, SVN_CONFIG_CATEGORY_CONFIG,
+                              APR_HASH_KEY_STRING);
+  else
+    cfg_config = NULL;
+
+  SVN_ERR(svn_wc_context_create(&(*ctx)->wc_ctx, cfg_config, pool,
                                 pool));
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_client_create_context(svn_client_ctx_t **ctx,
+                          apr_pool_t *pool)
+{
+  return svn_client_create_context2(ctx, NULL, pool);
+}

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/delete.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/delete.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/delete.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/delete.c Sat Nov 24 20:29:11 2012
@@ -206,9 +206,8 @@ single_repos_delete(svn_ra_session_t *ra
                                     pool));
 
   /* Call the path-based editor driver. */
-  err = svn_delta_path_driver(editor, edit_baton, SVN_INVALID_REVNUM,
-                              relpaths, path_driver_cb_func,
-                              (void *)editor, pool);
+  err = svn_delta_path_driver2(editor, edit_baton, relpaths, TRUE,
+                               path_driver_cb_func, (void *)editor, pool);
 
   if (err)
     {

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/deprecated.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/deprecated.c Sat Nov 24 20:29:11 2012
@@ -699,6 +699,25 @@ svn_client_copy(svn_client_commit_info_t
 }
 
 svn_error_t *
+svn_client_move6(const apr_array_header_t *src_paths,
+                 const char *dst_path,
+                 svn_boolean_t move_as_child,
+                 svn_boolean_t make_parents,
+                 const apr_hash_t *revprop_table,
+                 svn_commit_callback2_t commit_callback,
+                 void *commit_baton,
+                 svn_client_ctx_t *ctx,
+                 apr_pool_t *pool)
+{
+  return svn_error_trace(svn_client_move7(src_paths, dst_path,
+                                          move_as_child, make_parents,
+                                          TRUE, /* allow_mixed_revisions */
+                                          revprop_table,
+                                          commit_callback, commit_baton,
+                                          ctx, pool));
+}
+
+svn_error_t *
 svn_client_move5(svn_commit_info_t **commit_info_p,
                  const apr_array_header_t *src_paths,
                  const char *dst_path,
@@ -1712,6 +1731,26 @@ svn_client_revprop_set(const char *propn
 }
 
 svn_error_t *
+svn_client_propget4(apr_hash_t **props,
+                    const char *propname,
+                    const char *target,
+                    const svn_opt_revision_t *peg_revision,
+                    const svn_opt_revision_t *revision,
+                    svn_revnum_t *actual_revnum,
+                    svn_depth_t depth,
+                    const apr_array_header_t *changelists,
+                    svn_client_ctx_t *ctx,
+                    apr_pool_t *result_pool,
+                    apr_pool_t *scratch_pool)
+{
+  return svn_error_trace(svn_client_propget5(props, NULL, propname, target,
+                                             peg_revision, revision,
+                                             actual_revnum, depth,
+                                             changelists, ctx,
+                                             result_pool, scratch_pool));
+}
+
+svn_error_t *
 svn_client_propget3(apr_hash_t **props,
                     const char *propname,
                     const char *path_or_url,
@@ -1851,6 +1890,70 @@ svn_client_proplist_item_dup(const svn_c
   return new_item;
 }
 
+/* Baton for use with wrap_proplist_receiver */
+struct proplist_receiver_wrapper_baton {
+  void *baton;
+  svn_proplist_receiver_t receiver;
+};
+
+/* This implements svn_client_proplist_receiver2_t */
+static svn_error_t *
+proplist_wrapper_receiver(void *baton,
+                          const char *path,
+                          apr_hash_t *prop_hash,
+                          apr_array_header_t *inherited_props,
+                          apr_pool_t *pool)
+{
+  struct proplist_receiver_wrapper_baton *plrwb = baton;
+
+  if (plrwb->receiver)
+    return plrwb->receiver(plrwb->baton, path, prop_hash, pool);
+
+  return SVN_NO_ERROR;
+}
+
+static void
+wrap_proplist_receiver(svn_proplist_receiver2_t *receiver2,
+                       void **receiver2_baton,
+                       svn_proplist_receiver_t receiver,
+                       void *receiver_baton,
+                       apr_pool_t *pool)
+{
+  struct proplist_receiver_wrapper_baton *plrwb = apr_palloc(pool,
+                                                             sizeof(*plrwb));
+
+  /* Set the user provided old format callback in the baton. */
+  plrwb->baton = receiver_baton;
+  plrwb->receiver = receiver;
+
+  *receiver2_baton = plrwb;
+  *receiver2 = proplist_wrapper_receiver;
+}
+
+svn_error_t *
+svn_client_proplist3(const char *target,
+                     const svn_opt_revision_t *peg_revision,
+                     const svn_opt_revision_t *revision,
+                     svn_depth_t depth,
+                     const apr_array_header_t *changelists,
+                     svn_proplist_receiver_t receiver,
+                     void *receiver_baton,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *pool)
+{
+
+  svn_proplist_receiver2_t receiver2;
+  void *receiver2_baton;
+
+  wrap_proplist_receiver(&receiver2, &receiver2_baton, receiver, receiver_baton,
+                         pool);
+
+  return svn_error_trace(svn_client_proplist4(target, peg_revision, revision,
+                                              depth, changelists, FALSE,
+                                              receiver2, receiver2_baton,
+                                              ctx, pool, pool));
+}
+
 /* Receiver baton used by proplist2() */
 struct proplist_receiver_baton {
   apr_array_header_t *props;

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/diff.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/diff.c Sat Nov 24 20:29:11 2012
@@ -1044,6 +1044,9 @@ diff_content_changed(const char *path,
                                        subpool, subpool));
       SVN_ERR(svn_stream_copy3(stream, svn_stream_disown(errstream, subpool),
                                NULL, NULL, subpool));
+
+      /* We have a printed a diff for this path, mark it as visited. */
+      mark_path_as_visited(diff_cmd_baton, path);
     }
   else   /* use libsvn_diff to generate the diff  */
     {

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/externals.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/externals.c Sat Nov 24 20:29:11 2012
@@ -475,12 +475,16 @@ switch_file_external(const char *local_a
        ### We can't enable this now, because that would move the external
        ### information into the wrong working copy */
     const char *definition_abspath = svn_dirent_dirname(local_abspath,subpool);
+    apr_array_header_t *inherited_props;
 
     /* Open an RA session to 'source' URL */
     SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &switch_loc,
                                               url, dir_abspath,
                                               peg_revision, revision,
                                               ctx, subpool));
+    /* Get the external file's iprops. */
+    SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props, "",
+                                       switch_loc->rev, subpool, subpool));
 
     SVN_ERR(svn_ra_reparent(ra_session, svn_uri_dirname(url, subpool),
                             subpool));
@@ -492,6 +496,7 @@ switch_file_external(const char *local_a
                                              switch_loc->url,
                                              switch_loc->repos_root_url,
                                              switch_loc->repos_uuid,
+                                             inherited_props,
                                              use_commit_times,
                                              diff3_cmd, preserved_exts,
                                              definition_abspath /* def */,

Added: subversion/branches/compressed-pristines/subversion/libsvn_client/iprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/iprops.c?rev=1413258&view=auto
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/iprops.c (added)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/iprops.c Sat Nov 24 20:29:11 2012
@@ -0,0 +1,183 @@
+/*
+ * iprops.c:  wrappers around wc inherited property functionality
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+/* ==================================================================== */
+
+
+
+/*** Includes. ***/
+
+#include "svn_error.h"
+#include "svn_pools.h"
+#include "svn_wc.h"
+#include "svn_ra.h"
+
+#include "client.h"
+#include "svn_private_config.h"
+
+#include "private/svn_wc_private.h"
+
+
+/*** Code. ***/
+
+/* Determine if ABSPATH needs an inherited property cache (i.e. it is a WC
+   root that is not also the repository root or it is switched).  If it does,
+   then set *NEEDS_CACHE to true, set it to false otherwise. */
+static svn_error_t *
+need_to_cache_iprops(svn_boolean_t *needs_cache,
+                     const char *abspath,
+                     svn_client_ctx_t *ctx,
+                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t is_wc_root;
+  svn_error_t *err;
+
+  /* Our starting assumption. */
+  *needs_cache = FALSE;
+
+  err = svn_wc_is_wc_root2(&is_wc_root, ctx->wc_ctx, abspath,
+                           scratch_pool);
+
+  /* ABSPATH can't need a cache if it doesn't exist. */
+  if (err)
+    {
+      if (err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          is_wc_root = FALSE;
+        }
+      else
+        {
+          return svn_error_trace(err);
+        }
+    }
+
+  if (is_wc_root)
+    {
+      const char *child_repos_relpath;
+
+      /* We want to cache the inherited properties for WC roots, unless that
+         root points to the root of the repository, then there in nowhere to
+         inherit properties from. */
+      SVN_ERR(svn_wc__node_get_repos_relpath(&child_repos_relpath,
+                                             ctx->wc_ctx, abspath,
+                                             scratch_pool, scratch_pool));
+      if (child_repos_relpath[0] != '\0')
+        *needs_cache = TRUE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__get_inheritable_props(apr_hash_t **wcroot_iprops,
+                                  const char *local_abspath,
+                                  svn_revnum_t revision,
+                                  svn_depth_t depth,
+                                  svn_ra_session_t *ra_session,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  *wcroot_iprops = apr_hash_make(result_pool);
+
+  /* If we don't have a base revision for LOCAL_ABSPATH then it can't
+     possibly be a working copy root, nor can it contain any WC roots
+     in the form of switched subtrees.  So there is nothing to cache. */
+  if (SVN_IS_VALID_REVNUM(revision))
+    {
+      apr_hash_t *iprop_paths;
+      apr_hash_index_t *hi;
+      const char *old_session_url = NULL;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+      SVN_ERR(svn_wc__get_cached_iprop_children(&iprop_paths, depth,
+                                                ctx->wc_ctx, local_abspath,
+                                                scratch_pool, iterpool));
+
+      /* If we are in the midst of a checkout or an update that is bringing in
+         an external, then svn_wc__get_cached_iprop_children won't return
+         LOCAL_ABSPATH in IPROPS_PATHS because the former has no cached iprops
+         yet.  So make sure LOCAL_ABSPATH is present if it's a WC root. */
+      if (!apr_hash_get(iprop_paths, local_abspath, APR_HASH_KEY_STRING))
+        {
+          svn_boolean_t needs_cached_iprops;
+
+          SVN_ERR(need_to_cache_iprops(&needs_cached_iprops, local_abspath,
+                                       ctx, iterpool));
+          if (needs_cached_iprops)
+            {
+              const char *target_abspath = apr_pstrdup(scratch_pool,
+                                                       local_abspath);
+              apr_hash_set(iprop_paths, target_abspath, 
+                           APR_HASH_KEY_STRING, target_abspath);
+            }
+        }
+
+      for (hi = apr_hash_first(scratch_pool, iprop_paths);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *child_abspath = svn__apr_hash_index_key(hi);
+          const char *url;
+          apr_array_header_t *inherited_props;
+
+          svn_pool_clear(iterpool);
+          SVN_ERR(svn_wc__node_get_url(&url, ctx->wc_ctx, child_abspath,
+                                       iterpool, iterpool));
+          if (ra_session)
+            {
+              if (old_session_url)
+                SVN_ERR(svn_ra_reparent(ra_session, url, scratch_pool));
+              else
+                SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                                          ra_session, url,
+                                                          scratch_pool));
+            }
+          else
+            {
+              SVN_ERR(svn_client__open_ra_session_internal(&ra_session,
+                                                           NULL, url,
+                                                           NULL, NULL,
+                                                           FALSE, TRUE,
+                                                           ctx,
+                                                           scratch_pool));
+            }
+
+          SVN_ERR(svn_ra_get_inherited_props(ra_session, &inherited_props,
+                                             "", revision, result_pool,
+                                             scratch_pool));
+          apr_hash_set(*wcroot_iprops,
+                       apr_pstrdup(result_pool, child_abspath),
+                       APR_HASH_KEY_STRING,
+                       inherited_props);
+        }
+
+      if (old_session_url)
+        SVN_ERR(svn_ra_reparent(ra_session, old_session_url,
+                                iterpool));
+      svn_pool_destroy(iterpool);
+    }
+
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/merge.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/merge.c Sat Nov 24 20:29:11 2012
@@ -1607,8 +1607,8 @@ merge_file_changed(svn_wc_notify_state_t
      way svn_wc_merge5() can do the merge. */
   if (wc_kind != svn_node_file || is_deleted)
     {
-      const char *moved_to_abspath;
-      svn_error_t *err;
+      svn_boolean_t moved_away;
+      svn_wc_conflict_reason_t reason;
 
       /* Maybe the node is excluded via depth filtering? */
 
@@ -1638,44 +1638,23 @@ merge_file_changed(svn_wc_notify_state_t
       /* This is use case 4 described in the paper attached to issue
        * #2282.  See also notes/tree-conflicts/detection.txt
        */
-      err = svn_wc__node_was_moved_away(&moved_to_abspath, NULL,
-                                        ctx->wc_ctx, local_abspath,
-                                        scratch_pool, scratch_pool);
-      if (err)
-        {
-          if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-            {
-              svn_error_clear(err);
-              moved_to_abspath = NULL;
-            }
-          else
-            return svn_error_trace(err);
-        }
-
-      if (moved_to_abspath)
-        {
-          /* File has been moved away locally -- apply incoming
-           * changes at the new location. */
-          local_abspath = moved_to_abspath;
-        }
+      SVN_ERR(check_moved_away(&moved_away, ctx->wc_ctx,
+                               local_abspath, scratch_pool));
+      if (moved_away)
+        reason = svn_wc_conflict_reason_moved_away;
+      else if (is_deleted)
+        reason = svn_wc_conflict_reason_deleted;
       else
-        {
-          svn_wc_conflict_reason_t reason;
-
-          if (is_deleted)
-            reason = svn_wc_conflict_reason_deleted;
-          else
-            reason = svn_wc_conflict_reason_missing;
-          SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
-                                svn_wc_conflict_action_edit, reason));
-          if (tree_conflicted)
-            *tree_conflicted = TRUE;
-          if (content_state)
-            *content_state = svn_wc_notify_state_missing;
-          if (prop_state)
-            *prop_state = svn_wc_notify_state_missing;
-          return SVN_NO_ERROR;
-        }
+        reason = svn_wc_conflict_reason_missing;
+      SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
+                            svn_wc_conflict_action_edit, reason));
+      if (tree_conflicted)
+        *tree_conflicted = TRUE;
+      if (content_state)
+        *content_state = svn_wc_notify_state_missing;
+      if (prop_state)
+        *prop_state = svn_wc_notify_state_missing;
+      return SVN_NO_ERROR;
     }
 
   /* ### TODO: Thwart attempts to merge into a path that has
@@ -1904,7 +1883,7 @@ merge_file_added(svn_wc_notify_state_t *
             svn_revnum_t copyfrom_rev;
             svn_stream_t *new_contents, *new_base_contents;
             apr_hash_t *new_base_props, *new_props;
-            const svn_wc_conflict_description2_t *existing_conflict;
+            svn_boolean_t existing_tree_conflict;
             svn_error_t *err;
 
             /* If this is a merge from the same repository as our
@@ -1941,10 +1920,9 @@ merge_file_added(svn_wc_notify_state_t *
                                                  scratch_pool, scratch_pool));
               }
 
-            err = svn_wc__get_tree_conflict(&existing_conflict,
-                                            merge_b->ctx->wc_ctx,
-                                            mine_abspath, merge_b->pool,
-                                            merge_b->pool);
+            err = svn_wc_conflicted_p3(NULL, NULL, &existing_tree_conflict,
+                                       merge_b->ctx->wc_ctx, mine_abspath,
+                                       merge_b->pool);
 
             if (err)
               {
@@ -1952,10 +1930,10 @@ merge_file_added(svn_wc_notify_state_t *
                   return svn_error_trace(err);
 
                 svn_error_clear(err);
-                existing_conflict = FALSE;
+                existing_tree_conflict = FALSE;
               }
 
-            if (existing_conflict)
+            if (existing_tree_conflict)
               {
                 svn_boolean_t moved_here;
                 svn_wc_conflict_reason_t reason;
@@ -2747,7 +2725,7 @@ merge_dir_closed(svn_wc_notify_state_t *
   merge_cmd_baton_t *merge_b = baton;
 
   if (merge_b->dry_run)
-    svn_hash__clear(merge_b->dry_run_deletions, scratch_pool);
+    SVN_ERR(svn_hash__clear(merge_b->dry_run_deletions, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -5753,11 +5731,16 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
   svn_opt_revision_t working_revision = { svn_opt_revision_working, { 0 } };
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_hash_index_t *hi;
+  apr_hash_t *externals;
 
-  SVN_ERR(svn_client_propget4(subtrees_with_mergeinfo, SVN_PROP_MERGEINFO,
-                              target_abspath, &working_revision,
-                              &working_revision, NULL, depth, NULL,
-                              ctx, result_pool, scratch_pool));
+  SVN_ERR(svn_client_propget5(subtrees_with_mergeinfo, NULL,
+                              SVN_PROP_MERGEINFO, target_abspath,
+                              &working_revision, &working_revision, NULL,
+                              depth, NULL, ctx, result_pool, scratch_pool));
+
+  SVN_ERR(svn_wc__externals_defined_below(&externals, ctx->wc_ctx,
+                                          target_abspath, scratch_pool,
+                                          scratch_pool));
 
   /* Convert property values to svn_mergeinfo_t. */
   for (hi = apr_hash_first(scratch_pool, *subtrees_with_mergeinfo);
@@ -5769,6 +5752,15 @@ get_wc_explicit_mergeinfo_catalog(apr_ha
       svn_mergeinfo_t mergeinfo;
       svn_error_t *err;
 
+      /* svn_client_propget5 picks up file externals with
+         mergeinfo, but we don't want those. */
+      if (apr_hash_get(externals, wc_path, APR_HASH_KEY_STRING))
+        {
+          apr_hash_set(*subtrees_with_mergeinfo, wc_path,
+                       APR_HASH_KEY_STRING, NULL);
+          continue;
+        }
+
       svn_pool_clear(iterpool);
 
       err = svn_mergeinfo_parse(&mergeinfo, mergeinfo_string->data,
@@ -11159,57 +11151,6 @@ typedef struct source_and_target_t
   svn_client__pathrev_t *yca;
 } source_and_target_t;
 
-/* "Open" the source and target branches of a merge.  That means:
- *   - find out their exact repository locations (resolve WC paths and
- *     non-numeric revision numbers),
- *   - check the branches are suitably related,
- *   - establish RA session(s) to the repo,
- *   - check the WC for suitability (throw an error if unsuitable)
- *
- * Record this information and return it in a new "merge context" object.
- */
-static svn_error_t *
-open_source_and_target(source_and_target_t **source_and_target,
-                       const char *source_path_or_url,
-                       const svn_opt_revision_t *source_peg_revision,
-                       const char *target_abspath,
-                       svn_boolean_t allow_mixed_rev,
-                       svn_boolean_t allow_local_mods,
-                       svn_boolean_t allow_switched_subtrees,
-                       svn_client_ctx_t *ctx,
-                       apr_pool_t *session_pool,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
-{
-  source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
-
-  /* Target */
-  SVN_ERR(open_target_wc(&s_t->target, target_abspath,
-                         allow_mixed_rev, allow_local_mods, allow_switched_subtrees,
-                         ctx, result_pool, scratch_pool));
-  SVN_ERR(svn_client_open_ra_session(&s_t->target_ra_session,
-                                     s_t->target->loc.url,
-                                     ctx, session_pool));
-
-  /* Source */
-  SVN_ERR(svn_client__ra_session_from_path2(
-            &s_t->source_ra_session, &s_t->source,
-            source_path_or_url, NULL, source_peg_revision, source_peg_revision,
-            ctx, result_pool));
-
-  *source_and_target = s_t;
-  return SVN_NO_ERROR;
-}
-
-/* "Close" any resources that were acquired in the S_T structure. */
-static svn_error_t *
-close_source_and_target(source_and_target_t *s_t,
-                        apr_pool_t *scratch_pool)
-{
-  /* close s_t->source_/target_ra_session */
-  return SVN_NO_ERROR;
-}
-
 /* Set *INTERSECTION_P to the intersection of BRANCH_HISTORY with the
  * revision range OLDEST_REV to YOUNGEST_REV (inclusive).
  *
@@ -11474,10 +11415,10 @@ find_base_on_target(svn_client__pathrev_
   return SVN_NO_ERROR;
 }
 
-/* The body of svn_client__find_symmetric_merge(), which see.
+/* The body of svn_client_find_automatic_merge(), which see.
  */
 static svn_error_t *
-find_symmetric_merge(svn_client__pathrev_t **base_p,
+find_automatic_merge(svn_client__pathrev_t **base_p,
                      svn_client__pathrev_t **mid_p,
                      source_and_target_t *s_t,
                      svn_client_ctx_t *ctx,
@@ -11494,14 +11435,23 @@ find_symmetric_merge(svn_client__pathrev
                                           svn_mergeinfo_inherited,
                                           FALSE /* squelch_incapable */,
                                           scratch_pool));
-  SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(&s_t->target_mergeinfo,
-                                                NULL /* inherited */,
-                                                NULL /* from_repos */,
-                                                FALSE /* repos_only */,
-                                                svn_mergeinfo_inherited,
-                                                s_t->target_ra_session,
-                                                s_t->target->abspath,
-                                                ctx, scratch_pool));
+  if (! s_t->target->abspath)
+    SVN_ERR(svn_client__get_repos_mergeinfo(&s_t->target_mergeinfo,
+                                            s_t->target_ra_session,
+                                            s_t->target->loc.url,
+                                            s_t->target->loc.rev,
+                                            svn_mergeinfo_inherited,
+                                            FALSE /* squelch_incapable */,
+                                            scratch_pool));
+  else
+    SVN_ERR(svn_client__get_wc_or_repos_mergeinfo(&s_t->target_mergeinfo,
+                                                  NULL /* inherited */,
+                                                  NULL /* from_repos */,
+                                                  FALSE /* repos_only */,
+                                                  svn_mergeinfo_inherited,
+                                                  s_t->target_ra_session,
+                                                  s_t->target->abspath,
+                                                  ctx, scratch_pool));
 
   /* Get the location-history of each branch. */
   s_t->source_branch.tip = s_t->source;
@@ -11545,42 +11495,99 @@ find_symmetric_merge(svn_client__pathrev
   return SVN_NO_ERROR;
 }
 
+/* Details of an automatic merge. */
+struct svn_client_automatic_merge_t
+{
+  svn_client__pathrev_t *yca, *base, *mid, *right, *target;
+  svn_boolean_t allow_mixed_rev, allow_local_mods, allow_switched_subtrees;
+};
+
 svn_error_t *
-svn_client__find_symmetric_merge(svn_client__symmetric_merge_t **merge_p,
+svn_client_find_automatic_merge_no_wc(
+                                 svn_client_automatic_merge_t **merge_p,
                                  const char *source_path_or_url,
                                  const svn_opt_revision_t *source_revision,
-                                 const char *target_wcpath,
-                                 svn_boolean_t allow_mixed_rev,
-                                 svn_boolean_t allow_local_mods,
-                                 svn_boolean_t allow_switched_subtrees,
+                                 const char *target_path_or_url,
+                                 const svn_opt_revision_t *target_revision,
                                  svn_client_ctx_t *ctx,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
+  source_and_target_t *s_t = apr_palloc(scratch_pool, sizeof(*s_t));
+  svn_client__pathrev_t *target_loc;
+  svn_client_automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+
+  /* Source */
+  SVN_ERR(svn_client__ra_session_from_path2(
+            &s_t->source_ra_session, &s_t->source,
+            source_path_or_url, NULL, source_revision, source_revision,
+            ctx, result_pool));
+
+  /* Target */
+  SVN_ERR(svn_client__ra_session_from_path2(
+            &s_t->target_ra_session, &target_loc,
+            target_path_or_url, NULL, target_revision, target_revision,
+            ctx, result_pool));
+  s_t->target = apr_palloc(scratch_pool, sizeof(*s_t->target));
+  s_t->target->kind = svn_node_none;
+  s_t->target->abspath = NULL;  /* indicate the target is not a WC */
+  s_t->target->loc = *target_loc;
+
+  SVN_ERR(find_automatic_merge(&merge->base, &merge->mid, s_t,
+                               ctx, result_pool, scratch_pool));
+
+  merge->right = s_t->source;
+  merge->target = &s_t->target->loc;
+  merge->yca = s_t->yca;
+  *merge_p = merge;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client_find_automatic_merge(svn_client_automatic_merge_t **merge_p,
+                                const char *source_path_or_url,
+                                const svn_opt_revision_t *source_revision,
+                                const char *target_wcpath,
+                                svn_boolean_t allow_mixed_rev,
+                                svn_boolean_t allow_local_mods,
+                                svn_boolean_t allow_switched_subtrees,
+                                svn_client_ctx_t *ctx,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
   const char *target_abspath;
-  source_and_target_t *s_t;
-  svn_client__symmetric_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+  source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
+  svn_client_automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
 
   SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_wcpath, scratch_pool));
 
-  /* Open RA sessions to the source and target trees.  We're not going
-   * to check the target WC for mixed-rev, local mods or switched
-   * subtrees yet.  After we find out what kind of merge is required,
-   * then if a reintegrate-like merge is required we'll do the stricter
-   * checks, in do_symmetric_merge_locked(). */
-  SVN_ERR(open_source_and_target(&s_t, source_path_or_url, source_revision,
-                                 target_abspath,
-                                 TRUE /*allow_mixed_rev*/,
-                                 TRUE /*allow_local_mods*/,
-                                 TRUE /*allow_switched_subtrees*/,
-                                 ctx, result_pool, result_pool, scratch_pool));
+  /* "Open" the target WC.  We're not going to check the target WC for
+   * mixed-rev, local mods or switched subtrees yet.  After we find out
+   * what kind of merge is required, then if a reintegrate-like merge is
+   * required we'll do the stricter checks, in do_automatic_merge_locked(). */
+  SVN_ERR(open_target_wc(&s_t->target, target_abspath,
+                         TRUE /*allow_mixed_rev*/,
+                         TRUE /*allow_local_mods*/,
+                         TRUE /*allow_switched_subtrees*/,
+                         ctx, result_pool, scratch_pool));
+
+  /* Open RA sessions to the source and target trees. */
+  SVN_ERR(svn_client_open_ra_session(&s_t->target_ra_session,
+                                     s_t->target->loc.url,
+                                     ctx, result_pool));
+  /* ### check for null URL (i.e. added path) here, like in reintegrate? */
+  SVN_ERR(svn_client__ra_session_from_path2(
+            &s_t->source_ra_session, &s_t->source,
+            source_path_or_url, NULL, source_revision, source_revision,
+            ctx, result_pool));
 
   /* Check source is in same repos as target. */
   SVN_ERR(check_same_repos(s_t->source, source_path_or_url,
                            &s_t->target->loc, target_wcpath,
                            TRUE /* strict_urls */, scratch_pool));
 
-  SVN_ERR(find_symmetric_merge(&merge->base, &merge->mid, s_t,
+  SVN_ERR(find_automatic_merge(&merge->base, &merge->mid, s_t,
                                ctx, result_pool, scratch_pool));
   merge->yca = s_t->yca;
   merge->right = s_t->source;
@@ -11590,12 +11597,12 @@ svn_client__find_symmetric_merge(svn_cli
 
   *merge_p = merge;
 
-  SVN_ERR(close_source_and_target(s_t, scratch_pool));
+  /* TODO: Close the source and target sessions here? */
 
   return SVN_NO_ERROR;
 }
 
-/* The body of svn_client__do_symmetric_merge(), which see.
+/* The body of svn_client_do_automatic_merge(), which see.
  *
  * Five locations are inputs: YCA, BASE, MID, RIGHT, TARGET, as shown
  * depending on whether the base is on the source branch or the target
@@ -11623,7 +11630,7 @@ svn_client__find_symmetric_merge(svn_cli
  * eliminate already-cherry-picked revisions from the source.
  */
 static svn_error_t *
-do_symmetric_merge_locked(const svn_client__symmetric_merge_t *merge,
+do_automatic_merge_locked(const svn_client_automatic_merge_t *merge,
                           const char *target_abspath,
                           svn_depth_t depth,
                           svn_boolean_t force,
@@ -11713,7 +11720,7 @@ do_symmetric_merge_locked(const svn_clie
          gaps that are older than the base that we calculated (which is
          for the root path of the merge).
 
-         An improvement would be to change find_symmetric_merge() to
+         An improvement would be to change find_automatic_merge() to
          find the base for each sutree, and then here use the oldest base
          among all subtrees. */
       merge_source_t source;
@@ -11742,15 +11749,15 @@ do_symmetric_merge_locked(const svn_clie
 }
 
 svn_error_t *
-svn_client__do_symmetric_merge(const svn_client__symmetric_merge_t *merge,
-                               const char *target_wcpath,
-                               svn_depth_t depth,
-                               svn_boolean_t force,
-                               svn_boolean_t record_only,
-                               svn_boolean_t dry_run,
-                               const apr_array_header_t *merge_options,
-                               svn_client_ctx_t *ctx,
-                               apr_pool_t *pool)
+svn_client_do_automatic_merge(const svn_client_automatic_merge_t *merge,
+                              const char *target_wcpath,
+                              svn_depth_t depth,
+                              svn_boolean_t force,
+                              svn_boolean_t record_only,
+                              svn_boolean_t dry_run,
+                              const apr_array_header_t *merge_options,
+                              svn_client_ctx_t *ctx,
+                              apr_pool_t *pool)
 {
   const char *target_abspath, *lock_abspath;
 
@@ -11759,16 +11766,43 @@ svn_client__do_symmetric_merge(const svn
 
   if (!dry_run)
     SVN_WC__CALL_WITH_WRITE_LOCK(
-      do_symmetric_merge_locked(merge,
+      do_automatic_merge_locked(merge,
                                 target_abspath, depth,
                                 force, record_only, dry_run,
                                 merge_options, ctx, pool),
       ctx->wc_ctx, lock_abspath, FALSE /* lock_anchor */, pool);
   else
-    SVN_ERR(do_symmetric_merge_locked(merge,
+    SVN_ERR(do_automatic_merge_locked(merge,
                                 target_abspath, depth,
                                 force, record_only, dry_run,
                                 merge_options, ctx, pool));
 
   return SVN_NO_ERROR;
 }
+
+svn_boolean_t
+svn_client_automatic_merge_is_reintegrate_like(
+        const svn_client_automatic_merge_t *merge)
+{
+  return merge->mid != NULL;
+}
+
+svn_error_t *
+svn_client__automatic_merge_get_locations(
+                                svn_client__pathrev_t **yca,
+                                svn_client__pathrev_t **base,
+                                svn_client__pathrev_t **right,
+                                svn_client__pathrev_t **target,
+                                const svn_client_automatic_merge_t *merge,
+                                apr_pool_t *result_pool)
+{
+  if (yca)
+    *yca = svn_client__pathrev_dup(merge->yca, result_pool);
+  if (base)
+    *base = svn_client__pathrev_dup(merge->base, result_pool);
+  if (right)
+    *right = svn_client__pathrev_dup(merge->right, result_pool);
+  if (target)
+    *target = svn_client__pathrev_dup(merge->target, result_pool);
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/compressed-pristines/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_client/mergeinfo.c?rev=1413258&r1=1413257&r2=1413258&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_client/mergeinfo.c Sat Nov 24 20:29:11 2012
@@ -1572,6 +1572,44 @@ logs_for_mergeinfo_rangelist(const char 
 
   return SVN_NO_ERROR;
 }
+
+/* Set *OUT_MERGEINFO to a shallow copy of MERGEINFO with each source path
+   converted to a (URI-encoded) URL based on REPOS_ROOT_URL. *OUT_MERGEINFO
+   is declared as 'apr_hash_t *' because its key do not obey the rules of
+   'svn_mergeinfo_t'.
+
+   Allocate *OUT_MERGEINFO and the new keys in RESULT_POOL.  Use
+   SCRATCH_POOL for any temporary allocations. */
+static svn_error_t *
+mergeinfo_relpaths_to_urls(apr_hash_t **out_mergeinfo,
+                           svn_mergeinfo_t mergeinfo,
+                           const char *repos_root_url,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  *out_mergeinfo = NULL;
+  if (mergeinfo)
+    {
+      apr_hash_index_t *hi;
+      apr_hash_t *full_path_mergeinfo = apr_hash_make(result_pool);
+
+      for (hi = apr_hash_first(scratch_pool, mergeinfo);
+           hi; hi = apr_hash_next(hi))
+        {
+          const char *key = svn__apr_hash_index_key(hi);
+          void *val = svn__apr_hash_index_val(hi);
+
+          apr_hash_set(full_path_mergeinfo,
+                       svn_path_url_add_component2(repos_root_url, key + 1,
+                                                   result_pool),
+                       APR_HASH_KEY_STRING, val);
+        }
+      *out_mergeinfo = full_path_mergeinfo;
+    }
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** Public APIs ***/
 
@@ -1614,8 +1652,8 @@ svn_client_mergeinfo_get_merged(apr_hash
       mergeinfo = NULL;
     }
 
-  SVN_ERR(svn_mergeinfo__relpaths_to_urls(mergeinfo_p, mergeinfo,
-                                          repos_root, pool, pool));
+  SVN_ERR(mergeinfo_relpaths_to_urls(mergeinfo_p, mergeinfo,
+                                     repos_root, pool, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1729,7 +1767,10 @@ svn_client_mergeinfo_log2(svn_boolean_t 
         }
     }
 
-  /* Open RA sessions to the repository for the source and target.
+  /* Fetch the location history as mergeinfo, for the source branch
+   * (between the given start and end revisions), and, if we're finding
+   * merged revisions, then also for the entire target branch.
+   *
    * ### TODO: As the source and target must be in the same repository, we
    * should share a single session, tracking the two URLs separately. */
   {