subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hwri...@apache.org
Subject svn commit: r1329209 [10/38] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/vim/ contrib/server-side/mod_dontdothat/ notes/ notes/a...
Date Mon, 23 Apr 2012 12:33:03 GMT
Modified: subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.c Mon Apr 23 12:32:48 2012
@@ -38,10 +38,12 @@
 #include "svn_client.h"
 #include "svn_hash.h"
 
+#include "private/svn_opt_private.h"
 #include "private/svn_mergeinfo_private.h"
 #include "private/svn_wc_private.h"
 #include "private/svn_ra_private.h"
 #include "private/svn_fspath.h"
+#include "private/svn_client_private.h"
 #include "client.h"
 #include "mergeinfo.h"
 #include "svn_private_config.h"
@@ -67,6 +69,16 @@ svn_client__merge_path_dup(const svn_cli
   return new;
 }
 
+svn_client__merge_path_t *
+svn_client__merge_path_create(const char *abspath,
+                              apr_pool_t *pool)
+{
+  svn_client__merge_path_t *result = apr_pcalloc(pool, sizeof(*result));
+
+  result->abspath = apr_pstrdup(pool, abspath);
+  return result;
+}
+
 svn_error_t *
 svn_client__parse_mergeinfo(svn_mergeinfo_t *mergeinfo,
                             svn_wc_context_t *wc_ctx,
@@ -136,13 +148,56 @@ svn_client__record_wc_mergeinfo(const ch
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_client__record_wc_mergeinfo_catalog(apr_hash_t *result_catalog,
+                                        svn_client_ctx_t *ctx,
+                                        apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  if (apr_hash_count(result_catalog))
+    {
+      int i;
+      apr_array_header_t *sorted_cat =
+        svn_sort__hash(result_catalog, svn_sort_compare_items_as_paths,
+                       scratch_pool);
+      for (i = 0; i < sorted_cat->nelts; i++)
+        {
+          svn_sort__item_t elt = APR_ARRAY_IDX(sorted_cat, i,
+                                               svn_sort__item_t);
+          svn_error_t *err;
+
+          svn_pool_clear(iterpool);
+          err = svn_client__record_wc_mergeinfo(elt.key, elt.value, TRUE,
+                                                ctx, iterpool);
+
+          if (err && err->apr_err == SVN_ERR_ENTRY_NOT_FOUND)
+            {
+              /* PATH isn't just missing, it's not even versioned as far
+                 as this working copy knows.  But it was included in
+                 MERGES, which means that the server knows about it.
+                 Likely we don't have access to the source due to authz
+                 restrictions.  For now just clear the error and
+                 continue... */
+              svn_error_clear(err);
+            }
+          else
+            {
+              SVN_ERR(err);
+            }
+        }
+    }
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 /*-----------------------------------------------------------------------*/
 
 /*** Retrieving mergeinfo. ***/
 
 svn_error_t *
 svn_client__get_wc_mergeinfo(svn_mergeinfo_t *mergeinfo,
-                             svn_boolean_t *inherited,
+                             svn_boolean_t *inherited_p,
                              svn_mergeinfo_inheritance_t inherit,
                              const char *local_abspath,
                              const char *limit_abspath,
@@ -156,6 +211,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
   svn_mergeinfo_t wc_mergeinfo;
   svn_revnum_t base_revision;
   apr_pool_t *iterpool;
+  svn_boolean_t inherited;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
   if (limit_abspath)
@@ -238,7 +294,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
                                                 scratch_pool));
 
           /* Look in LOCAL_ABSPATH's parent for inherited mergeinfo if
-             LOCAL_ABSPATH's has no base revision because it is an uncommitted
+             LOCAL_ABSPATH has no base revision because it is an uncommitted
              addition, or if its base revision falls within the inclusive
              range of its parent's last changed revision to the parent's base
              revision; otherwise stop looking for inherited mergeinfo. */
@@ -258,7 +314,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
   if (svn_path_is_empty(walk_relpath))
     {
       /* Mergeinfo is explicit. */
-      *inherited = FALSE;
+      inherited = FALSE;
       *mergeinfo = wc_mergeinfo;
     }
   else
@@ -266,7 +322,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
       /* Mergeinfo may be inherited. */
       if (wc_mergeinfo)
         {
-          *inherited = TRUE;
+          inherited = TRUE;
           SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(mergeinfo,
                                                          wc_mergeinfo,
                                                          walk_relpath,
@@ -275,7 +331,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
         }
       else
         {
-          *inherited = FALSE;
+          inherited = FALSE;
           *mergeinfo = NULL;
         }
     }
@@ -285,7 +341,7 @@ svn_client__get_wc_mergeinfo(svn_mergein
 
   /* Remove non-inheritable mergeinfo and paths mapped to empty ranges
      which may occur if WCPATH's mergeinfo is not explicit. */
-  if (*inherited
+  if (inherited
       && apr_hash_count(*mergeinfo)) /* Nothing to do for empty mergeinfo. */
     {
       SVN_ERR(svn_mergeinfo_inheritable2(mergeinfo, *mergeinfo, NULL,
@@ -294,6 +350,9 @@ svn_client__get_wc_mergeinfo(svn_mergein
       svn_mergeinfo__remove_empty_rangelists(*mergeinfo, result_pool);
     }
 
+  if (inherited_p)
+    *inherited_p = inherited;
+
   return SVN_NO_ERROR;
 }
 
@@ -324,7 +383,8 @@ svn_client__get_wc_mergeinfo_catalog(svn
     {
       if (walked_path)
         *walked_path = "";
-      *inherited = FALSE;
+      if (inherited)
+        *inherited = FALSE;
       return SVN_NO_ERROR;
     }
 
@@ -405,7 +465,7 @@ svn_client__get_wc_mergeinfo_catalog(svn
 svn_error_t *
 svn_client__get_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
                                 svn_ra_session_t *ra_session,
-                                const char *rel_path,
+                                const char *url,
                                 svn_revnum_t rev,
                                 svn_mergeinfo_inheritance_t inherit,
                                 svn_boolean_t squelch_incapable,
@@ -417,7 +477,7 @@ svn_client__get_repos_mergeinfo(svn_merg
 
   SVN_ERR(svn_client__get_repos_mergeinfo_catalog(&tgt_mergeinfo_cat,
                                                   ra_session,
-                                                  rel_path, rev, inherit,
+                                                  url, rev, inherit,
                                                   squelch_incapable, FALSE,
                                                   pool, pool));
 
@@ -437,7 +497,7 @@ svn_client__get_repos_mergeinfo(svn_merg
 svn_error_t *
 svn_client__get_repos_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
                                         svn_ra_session_t *ra_session,
-                                        const char *rel_path,
+                                        const char *url,
                                         svn_revnum_t rev,
                                         svn_mergeinfo_inheritance_t inherit,
                                         svn_boolean_t squelch_incapable,
@@ -448,13 +508,18 @@ svn_client__get_repos_mergeinfo_catalog(
   svn_error_t *err;
   svn_mergeinfo_t repos_mergeinfo_cat;
   apr_array_header_t *rel_paths = apr_array_make(scratch_pool, 1,
-                                                 sizeof(rel_path));
+                                                 sizeof(const char *));
+  const char *old_session_url;
 
-  APR_ARRAY_PUSH(rel_paths, const char *) = rel_path;
+  APR_ARRAY_PUSH(rel_paths, const char *) = "";
 
   /* Fetch the mergeinfo. */
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
+                                            ra_session, url, scratch_pool));
   err = svn_ra_get_mergeinfo(ra_session, &repos_mergeinfo_cat, rel_paths,
                              rev, inherit, include_descendants, result_pool);
+  err = svn_error_compose_create(
+          err, svn_ra_reparent(ra_session, old_session_url, scratch_pool));
   if (err)
     {
       if (squelch_incapable && err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE)
@@ -474,11 +539,9 @@ svn_client__get_repos_mergeinfo_catalog(
   else
     {
       const char *session_relpath;
-      const char *session_url;
 
-      SVN_ERR(svn_ra_get_session_url(ra_session, &session_url, scratch_pool));
       SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &session_relpath,
-                                               session_url, scratch_pool));
+                                               url, scratch_pool));
 
       if (session_relpath[0] == '\0')
         *mergeinfo_cat = repos_mergeinfo_cat;
@@ -534,7 +597,7 @@ svn_client__get_wc_or_repos_mergeinfo(sv
 svn_error_t *
 svn_client__get_wc_or_repos_mergeinfo_catalog(
   svn_mergeinfo_catalog_t *target_mergeinfo_catalog,
-  svn_boolean_t *inherited,
+  svn_boolean_t *inherited_p,
   svn_boolean_t *from_repos,
   svn_boolean_t include_descendants,
   svn_boolean_t repos_only,
@@ -565,7 +628,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
      a URL and without that we cannot get accurate mergeinfo for
      TARGET_WCPATH. */
   SVN_ERR(svn_wc__node_get_origin(NULL, &target_rev, &repos_relpath,
-                                  &repos_root, NULL,
+                                  &repos_root, NULL, NULL,
                                   ctx->wc_ctx, local_abspath, FALSE,
                                   scratch_pool, scratch_pool));
 
@@ -576,8 +639,9 @@ svn_client__get_wc_or_repos_mergeinfo_ca
 
   if (!repos_only)
     {
+      svn_boolean_t inherited;
       SVN_ERR(svn_client__get_wc_mergeinfo_catalog(&target_mergeinfo_cat_wc,
-                                                   inherited,
+                                                   &inherited,
                                                    include_descendants,
                                                    inherit,
                                                    local_abspath,
@@ -586,11 +650,13 @@ svn_client__get_wc_or_repos_mergeinfo_ca
                                                    ctx,
                                                    result_pool,
                                                    scratch_pool));
+      if (inherited_p)
+        *inherited_p = inherited;
 
       /* If we want LOCAL_ABSPATH's inherited mergeinfo, were we able to
          get it from the working copy?  If not, then we must ask the
          repository. */
-      if (! ((*inherited)
+      if (! (inherited
              || (inherit == svn_mergeinfo_explicit)
              || (repos_relpath
                  && target_mergeinfo_cat_wc
@@ -620,16 +686,9 @@ svn_client__get_wc_or_repos_mergeinfo_ca
           if (!apr_hash_get(original_props, SVN_PROP_MERGEINFO,
                             APR_HASH_KEY_STRING))
             {
-              const char *session_url = NULL;
               apr_pool_t *sesspool = NULL;
 
-              if (ra_session)
-                {
-                  SVN_ERR(svn_client__ensure_ra_session_url(&session_url,
-                                                            ra_session,
-                                                            url, result_pool));
-                }
-              else
+              if (! ra_session)
                 {
                   sesspool = svn_pool_create(scratch_pool);
                   SVN_ERR(svn_client__open_ra_session_internal(
@@ -639,7 +698,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
 
               SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
                         &target_mergeinfo_cat_repos, ra_session,
-                        "", target_rev, inherit,
+                        url, target_rev, inherit,
                         TRUE, include_descendants,
                         result_pool, scratch_pool));
 
@@ -648,7 +707,8 @@ svn_client__get_wc_or_repos_mergeinfo_ca
                                   repos_relpath,
                                   APR_HASH_KEY_STRING))
                 {
-                  *inherited = TRUE;
+                  if (inherited_p)
+                    *inherited_p = TRUE;
                   if (from_repos)
                     *from_repos = TRUE;
                 }
@@ -660,11 +720,6 @@ svn_client__get_wc_or_repos_mergeinfo_ca
                 {
                   svn_pool_destroy(sesspool);
                 }
-              else if (session_url)
-                {
-                  SVN_ERR(svn_ra_reparent(ra_session, session_url,
-                                          result_pool));
-                }
             }
         }
     }
@@ -693,24 +748,26 @@ svn_client__get_wc_or_repos_mergeinfo_ca
 
 svn_error_t *
 svn_client__get_history_as_mergeinfo(svn_mergeinfo_t *mergeinfo_p,
-                                     svn_boolean_t *has_rev_zero_history,
-                                     svn_revnum_t peg_revnum,
-                                     svn_revnum_t range_youngest,
-                                     svn_revnum_t range_oldest,
-                                     svn_ra_session_t *ra_session,
-                                     svn_client_ctx_t *ctx,
-                                     apr_pool_t *pool)
+                                      svn_boolean_t *has_rev_zero_history,
+                                      const svn_client__pathrev_t *pathrev,
+                                      svn_revnum_t range_youngest,
+                                      svn_revnum_t range_oldest,
+                                      svn_ra_session_t *ra_session,
+                                      svn_client_ctx_t *ctx,
+                                      apr_pool_t *pool)
 {
   apr_array_header_t *segments;
 
   /* Fetch the location segments for our URL@PEG_REVNUM. */
   if (! SVN_IS_VALID_REVNUM(range_youngest))
-    range_youngest = peg_revnum;
+    range_youngest = pathrev->rev;
   if (! SVN_IS_VALID_REVNUM(range_oldest))
     range_oldest = 0;
-  SVN_ERR(svn_client__repos_location_segments(&segments, ra_session, "",
-                                              peg_revnum, range_youngest,
-                                              range_oldest, ctx, pool));
+
+  SVN_ERR(svn_client__repos_location_segments(&segments, ra_session,
+                                              pathrev->url, pathrev->rev,
+                                              range_youngest, range_oldest,
+                                              ctx, pool));
 
   if (has_rev_zero_history)
     {
@@ -756,7 +813,7 @@ should_elide_mergeinfo(svn_boolean_t *el
                        svn_mergeinfo_t parent_mergeinfo,
                        svn_mergeinfo_t child_mergeinfo,
                        const char *path_suffix,
-                       apr_pool_t *pool)
+                       apr_pool_t *scratch_pool)
 {
   /* Easy out: No child mergeinfo to elide. */
   if (child_mergeinfo == NULL)
@@ -781,20 +838,18 @@ should_elide_mergeinfo(svn_boolean_t *el
       /* Both CHILD_MERGEINFO and PARENT_MERGEINFO are non-NULL and
          non-empty. */
       svn_mergeinfo_t path_tweaked_parent_mergeinfo;
-      apr_pool_t *subpool = svn_pool_create(pool);
 
       /* If we need to adjust the paths in PARENT_MERGEINFO do it now. */
       if (path_suffix)
         SVN_ERR(svn_mergeinfo__add_suffix_to_mergeinfo(
                   &path_tweaked_parent_mergeinfo, parent_mergeinfo,
-                  path_suffix, subpool, subpool));
+                  path_suffix, scratch_pool, scratch_pool));
       else
         path_tweaked_parent_mergeinfo = parent_mergeinfo;
 
       SVN_ERR(svn_mergeinfo__equals(elides,
                                     path_tweaked_parent_mergeinfo,
-                                    child_mergeinfo, TRUE, subpool));
-      svn_pool_destroy(subpool);
+                                    child_mergeinfo, TRUE, scratch_pool));
     }
 
   return SVN_NO_ERROR;
@@ -911,7 +966,7 @@ svn_client__elide_mergeinfo(const char *
         return SVN_NO_ERROR;
 
       /* Get TARGET_WCPATH's inherited mergeinfo from the WC. */
-      err = svn_client__get_wc_mergeinfo(&mergeinfo, &inherited,
+      err = svn_client__get_wc_mergeinfo(&mergeinfo, NULL,
                                          svn_mergeinfo_nearest_ancestor,
                                          target_abspath,
                                          limit_abspath,
@@ -936,7 +991,7 @@ svn_client__elide_mergeinfo(const char *
       if (!mergeinfo && !wc_elision_limit_path)
         {
           err = svn_client__get_wc_or_repos_mergeinfo(
-            &mergeinfo, &inherited, NULL, TRUE,
+            &mergeinfo, NULL, NULL, TRUE,
             svn_mergeinfo_nearest_ancestor,
             NULL, target_wcpath, ctx, pool);
           if (err)
@@ -1000,37 +1055,27 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
   const char *url;
   svn_boolean_t use_url = svn_path_is_url(path_or_url);
   svn_revnum_t peg_rev;
-  svn_opt_revision_t opt_rev;
-  opt_rev.kind = svn_opt_revision_unspecified;
 
   SVN_ERR(svn_client__ra_session_from_path(&ra_session, &peg_rev, &url,
                                            path_or_url, NULL, peg_revision,
-                                           &opt_rev, ctx, scratch_pool));
+                                           peg_revision, ctx, scratch_pool));
 
   /* If PATH_OR_URL is as working copy path determine if we will need to
      contact the repository for the requested PEG_REVISION. */
   if (!use_url)
     {
-      const char *repos_root_url;
-      const char *repos_relpath;
-      const char *origin_url = NULL;
+      svn_client__pathrev_t *origin;
       SVN_ERR(svn_dirent_get_absolute(&local_abspath, path_or_url,
                                       scratch_pool));
 
-      SVN_ERR(svn_wc__node_get_origin(NULL, &rev, &repos_relpath,
-                                      &repos_root_url, NULL,
-                                      ctx->wc_ctx, local_abspath, FALSE,
-                                      scratch_pool, scratch_pool));
-
-      if(repos_relpath)
-        origin_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
-                                                 scratch_pool);
-
-      if (!origin_url
-          || strcmp(origin_url, url) != 0
+      SVN_ERR(svn_client__wc_node_get_origin(&origin, local_abspath, ctx,
+                                             scratch_pool, scratch_pool));
+      rev = origin ? origin->rev : SVN_INVALID_REVNUM;
+      if (!origin
+          || strcmp(origin->url, url) != 0
           || peg_rev != rev)
       {
-        use_url = TRUE; /* Don't rely on local merginfo */
+        use_url = TRUE; /* Don't rely on local mergeinfo */
       }
     }
 
@@ -1044,17 +1089,15 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
     {
       rev = peg_rev;
       SVN_ERR(svn_client__get_repos_mergeinfo_catalog(
-        mergeinfo_catalog, ra_session, "", rev, svn_mergeinfo_inherited,
+        mergeinfo_catalog, ra_session, url, rev, svn_mergeinfo_inherited,
         FALSE, include_descendants,
         result_pool, scratch_pool));
     }
   else /* ! svn_path_is_url() */
     {
-      svn_boolean_t inherited;
-
       /* Acquire return values. */
       SVN_ERR(svn_client__get_wc_or_repos_mergeinfo_catalog(
-        mergeinfo_catalog, &inherited, NULL, include_descendants, FALSE,
+        mergeinfo_catalog, NULL, NULL, include_descendants, FALSE,
         ignore_invalid_mergeinfo, svn_mergeinfo_inherited,
         ra_session, path_or_url, ctx,
         result_pool, scratch_pool));
@@ -1064,142 +1107,74 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
 }
 
 /*** In-memory mergeinfo elision ***/
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_dir_baton {
-  const char *inherited_mergeinfo_path;
-  svn_mergeinfo_t mergeinfo_catalog;
-};
-
-/* The root doesn't have mergeinfo (unless it is actually one of the
-   paths passed to svn_delta_path_driver, in which case the callback
-   is called directly instead of this). */
-static svn_error_t *
-elide_mergeinfo_catalog_open_root(void *eb,
-                                  svn_revnum_t base_revision,
-                                  apr_pool_t *dir_pool,
-                                  void **root_baton)
-{
-  struct elide_mergeinfo_catalog_dir_baton *b = apr_pcalloc(dir_pool,
-                                                            sizeof(*b));
-  b->mergeinfo_catalog = eb;
-  *root_baton = b;
-  return SVN_NO_ERROR;
-}
-
-/* Make a directory baton for PATH.  It should have the same
-   inherited_mergeinfo_path as its parent... unless we just called
-   elide_mergeinfo_catalog_cb on its parent with its path. */
-static svn_error_t *
-elide_mergeinfo_catalog_open_directory(const char *path,
-                                       void *parent_baton,
-                                       svn_revnum_t base_revision,
-                                       apr_pool_t *dir_pool,
-                                       void **child_baton)
+svn_error_t *
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+                                    apr_pool_t *scratch_pool)
 {
-  struct elide_mergeinfo_catalog_dir_baton *b, *pb = parent_baton;
-
-  b = apr_pcalloc(dir_pool, sizeof(*b));
-  b->mergeinfo_catalog = pb->mergeinfo_catalog;
-
-  if (apr_hash_get(b->mergeinfo_catalog, path, APR_HASH_KEY_STRING))
-    b->inherited_mergeinfo_path = apr_pstrdup(dir_pool, path);
-  else
-    b->inherited_mergeinfo_path = pb->inherited_mergeinfo_path;
-
-  *child_baton = b;
-  return SVN_NO_ERROR;
-}
-
-/* TODO(reint): Document. */
-struct elide_mergeinfo_catalog_cb_baton {
-  apr_array_header_t *elidable_paths;
-  svn_mergeinfo_t mergeinfo_catalog;
-  apr_pool_t *result_pool;
-};
+  apr_array_header_t *sorted_hash;
+  apr_array_header_t *elidable_paths = apr_array_make(scratch_pool, 1,
+                                                      sizeof(const char *));
+  apr_array_header_t *dir_stack = apr_array_make(scratch_pool, 1,
+                                                 sizeof(const char *));
+  apr_pool_t *iterpool;
+  int i;
 
-/* Implements svn_delta_path_driver_cb_func_t. */
-static svn_error_t *
-elide_mergeinfo_catalog_cb(void **dir_baton,
-                           void *parent_baton,
-                           void *callback_baton,
-                           const char *path,
-                           apr_pool_t *pool)
-{
-  struct elide_mergeinfo_catalog_cb_baton *cb = callback_baton;
-  struct elide_mergeinfo_catalog_dir_baton *pb = parent_baton;
-  const char *path_suffix;
-  svn_boolean_t elides;
+  /* Here's the general algorithm:
+     Walk through the paths sorted in tree order.  For each path, pop
+     the dir_stack until it is either empty or the top item contains a parent
+     of the current path. Check to see if that mergeinfo is then elidable,
+     and build the list of elidable mergeinfo based upon that determination.
+     Finally, push the path of interest onto the stack, and continue. */
+  sorted_hash = svn_sort__hash(mergeinfo_catalog,
+                               svn_sort_compare_items_as_paths,
+                               scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < sorted_hash->nelts; i++)
+    {
+      svn_sort__item_t *item = &APR_ARRAY_IDX(sorted_hash, i,
+                                              svn_sort__item_t);
+      const char *path = item->key;
 
-  /* pb == NULL would imply that there was an *empty* path in the
-     paths given to the driver (which is different from "/"). */
-  SVN_ERR_ASSERT(pb != NULL);
-
-  /* We'll just act like everything is a file. */
-  *dir_baton = NULL;
-
-  /* Is there even any inherited mergeinfo to elide? */
-  /* (Note that svn_delta_path_driver will call open_directory before
-     the callback for the root (only).) */
-  if (!pb->inherited_mergeinfo_path
-      || strcmp(path, "/") == 0)
-    return SVN_NO_ERROR;
+      if (dir_stack->nelts > 0)
+        {
+          const char *top;
+          const char *path_suffix;
+          svn_boolean_t elides = FALSE;
 
-  path_suffix = svn_dirent_is_child(pb->inherited_mergeinfo_path,
-                                    path, NULL);
-  SVN_ERR_ASSERT(path_suffix != NULL);
+          svn_pool_clear(iterpool);
 
-  SVN_ERR(should_elide_mergeinfo(&elides,
-                                 apr_hash_get(cb->mergeinfo_catalog,
-                                              pb->inherited_mergeinfo_path,
-                                              APR_HASH_KEY_STRING),
-                                 apr_hash_get(cb->mergeinfo_catalog,
-                                              path,
-                                              APR_HASH_KEY_STRING),
-                                 path_suffix,
-                                 pool));
+          /* Pop off any paths which are not ancestors of PATH. */
+          do
+            {
+              top = APR_ARRAY_IDX(dir_stack, dir_stack->nelts - 1,
+                                          const char *);
+              path_suffix = svn_dirent_is_child(top, path, NULL);
 
-  if (elides)
-    APR_ARRAY_PUSH(cb->elidable_paths, const char *) =
-      apr_pstrdup(cb->result_pool, path);
+              if (!path_suffix)
+                apr_array_pop(dir_stack);
+            }
+          while (dir_stack->nelts > 0 && !path_suffix);
 
-  return SVN_NO_ERROR;
-}
+          /* If we have a path suffix, it means we haven't popped the stack
+             clean. */
+          if (path_suffix)
+            {
+              SVN_ERR(should_elide_mergeinfo(&elides,
+                                         apr_hash_get(mergeinfo_catalog, top,
+                                                      APR_HASH_KEY_STRING),
+                                         apr_hash_get(mergeinfo_catalog, path,
+                                                      APR_HASH_KEY_STRING),
+                                         path_suffix,
+                                         iterpool));
 
-svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
-                                    apr_pool_t *pool)
-{
-  apr_array_header_t *paths;
-  apr_array_header_t *elidable_paths = apr_array_make(pool, 1,
-                                                      sizeof(const char *));
-  svn_delta_editor_t *editor = svn_delta_default_editor(pool);
-  struct elide_mergeinfo_catalog_cb_baton cb = { 0 };
-  void *eb;
-  int i;
-  svn_delta_shim_callbacks_t *shim_callbacks =
-                                     svn_delta_shim_callbacks_default(pool);
+              if (elides)
+                APR_ARRAY_PUSH(elidable_paths, const char *) = path;
+            }
+        }
 
-  cb.elidable_paths = elidable_paths;
-  cb.mergeinfo_catalog = mergeinfo_catalog;
-  cb.result_pool = pool;
-
-  editor->open_root = elide_mergeinfo_catalog_open_root;
-  editor->open_directory = elide_mergeinfo_catalog_open_directory;
-
-  eb = mergeinfo_catalog;
-  SVN_ERR(svn_editor__insert_shims((const svn_delta_editor_t **)&editor, &eb,
-                                   editor, eb, shim_callbacks, pool, pool));
-
-  /* Walk over the paths, and build up a list of elidable ones. */
-  SVN_ERR(svn_hash_keys(&paths, mergeinfo_catalog, pool));
-  SVN_ERR(svn_delta_path_driver(editor,
-                                eb,
-                                SVN_INVALID_REVNUM,
-                                paths,
-                                elide_mergeinfo_catalog_cb,
-                                &cb,
-                                pool));
+      APR_ARRAY_PUSH(dir_stack, const char *) = path;
+    }
+  svn_pool_destroy(iterpool);
 
   /* Now remove the elidable paths from the catalog. */
   for (i = 0; i < elidable_paths->nelts; i++)
@@ -1357,11 +1332,12 @@ filter_log_entry_with_rangelist(void *ba
 
   /* If the paths changed by LOG_ENTRY->REVISION are provided we can determine
      if LOG_ENTRY->REVISION, while only partially represented in
-     BATON->RANGELIST, is in fact completely applied to all affected paths. */
+     BATON->RANGELIST, is in fact completely applied to all affected paths.
+     ### And ... what if it is, or if it isn't? What do we do with the answer?
+         And how do we cope if the changed paths are not provided? */
   if ((log_entry->non_inheritable || !fleb->filtering_merged)
       && log_entry->changed_paths2)
     {
-      int i;
       apr_hash_index_t *hi;
       svn_boolean_t all_subtrees_have_this_rev = TRUE;
       apr_array_header_t *this_rev_rangelist =
@@ -1373,11 +1349,11 @@ filter_log_entry_with_rangelist(void *ba
            hi;
            hi = apr_hash_next(hi))
         {
+          int i;
           const char *path = svn__apr_hash_index_key(hi);
           svn_log_changed_path2_t *change = svn__apr_hash_index_val(hi);
           const char *target_fspath_affected;
           svn_mergeinfo_t nearest_ancestor_mergeinfo;
-          apr_hash_index_t *hi2;
           svn_boolean_t found_this_revision = FALSE;
           const char *merge_source_rel_target;
           const char *merge_source_fspath;
@@ -1449,6 +1425,8 @@ filter_log_entry_with_rangelist(void *ba
 
           if (nearest_ancestor_mergeinfo)
             {
+              apr_hash_index_t *hi2;
+
               for (hi2 = apr_hash_first(iterpool, nearest_ancestor_mergeinfo);
                    hi2;
                    hi2 = apr_hash_next(hi2))
@@ -1471,15 +1449,30 @@ filter_log_entry_with_rangelist(void *ba
                                                       iterpool));
                       if (intersection->nelts)
                         {
-                          SVN_ERR(svn_rangelist_intersect(&intersection,
-                                                          rangelist,
-                                                          this_rev_rangelist,
-                                                          TRUE, iterpool));
-                          if (intersection->nelts)
+                          if (ancestor_is_self)
                             {
+                              /* TARGET_PATH_AFFECTED has explicit mergeinfo,
+                                 so we don't need to worry if that mergeinfo
+                                 is inheritable or not. */
                               found_this_revision = TRUE;
                               break;
                             }
+                          else
+                            {
+                              /* TARGET_PATH_AFFECTED inherited its mergeinfo,
+                                 so we have to ignore non-inheritable
+                                 ranges. */
+                              SVN_ERR(svn_rangelist_intersect(
+                                &intersection,
+                                rangelist,
+                                this_rev_rangelist,
+                                TRUE, iterpool));
+                              if (intersection->nelts)
+                                {
+                                  found_this_revision = TRUE;
+                                  break;
+                                }
+                            }
                         }
                     }
                 }
@@ -1527,7 +1520,6 @@ logs_for_mergeinfo_rangelist(const char 
   svn_merge_range_t *oldest_range, *youngest_range;
   apr_array_header_t *revision_ranges;
   svn_opt_revision_t oldest_rev, youngest_rev;
-  svn_opt_revision_range_t *range;
   struct filter_log_entry_baton_t fleb;
 
   if (! rangelist->nelts)
@@ -1576,10 +1568,8 @@ logs_for_mergeinfo_rangelist(const char 
   /* Drive the log. */
   revision_ranges = apr_array_make(scratch_pool, 1,
                                    sizeof(svn_opt_revision_range_t *));
-  range = apr_pcalloc(scratch_pool, sizeof(*range));
-  range->end = youngest_rev;
-  range->start = oldest_rev;
-  APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *) = range;
+  APR_ARRAY_PUSH(revision_ranges, svn_opt_revision_range_t *)
+    = svn_opt__revision_range_create(&oldest_rev, &youngest_rev, scratch_pool);
   SVN_ERR(svn_client_log5(target, &youngest_rev, revision_ranges,
                           0, discover_changed_paths, FALSE, FALSE, revprops,
                           filter_log_entry_with_rangelist, &fleb, ctx,
@@ -1648,7 +1638,6 @@ svn_client_mergeinfo_log(svn_boolean_t f
                          apr_pool_t *scratch_pool)
 {
   apr_pool_t *sesspool = svn_pool_create(scratch_pool);
-  svn_ra_session_t *source_session, *target_session;
   const char *log_target = NULL;
   const char *repos_root;
   const char *target_repos_rel;
@@ -1724,38 +1713,32 @@ svn_client_mergeinfo_log(svn_boolean_t f
    * should share a single session, tracking the two URLs separately. */
   if (!finding_merged)
     {
-      svn_revnum_t target_peg_revnum;
+      svn_ra_session_t *target_session;
+      svn_client__pathrev_t *pathrev;
 
-      SVN_ERR(svn_client__ra_session_from_path(&target_session,
-                                               &target_peg_revnum, NULL,
-                                               target_path_or_url, NULL,
-                                               target_peg_revision,
-                                               target_peg_revision,
-                                               ctx, sesspool));
-
-      SVN_ERR(svn_client__get_history_as_mergeinfo(&target_history, NULL,
-                                                   target_peg_revnum,
-                                                   SVN_INVALID_REVNUM,
-                                                   SVN_INVALID_REVNUM,
-                                                   target_session, ctx,
-                                                   scratch_pool));
+      SVN_ERR(svn_client__ra_session_from_path2(
+                &target_session, &pathrev,
+                target_path_or_url, NULL,
+                target_peg_revision, target_peg_revision,
+                ctx, sesspool));
+      SVN_ERR(svn_client__get_history_as_mergeinfo(
+                &target_history, NULL,
+                pathrev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+                target_session, ctx, scratch_pool));
     }
   {
-    svn_revnum_t source_peg_revnum;
+    svn_ra_session_t *source_session;
+    svn_client__pathrev_t *pathrev;
 
-    SVN_ERR(svn_client__ra_session_from_path(&source_session,
-                                             &source_peg_revnum, NULL,
-                                             source_path_or_url, NULL,
-                                             source_peg_revision,
-                                             source_peg_revision,
-                                             ctx, sesspool));
-
-    SVN_ERR(svn_client__get_history_as_mergeinfo(&source_history, NULL,
-                                                 source_peg_revnum,
-                                                 SVN_INVALID_REVNUM,
-                                                 SVN_INVALID_REVNUM,
-                                                 source_session, ctx,
-                                                 scratch_pool));
+    SVN_ERR(svn_client__ra_session_from_path2(
+              &source_session, &pathrev,
+              source_path_or_url, NULL,
+              source_peg_revision, source_peg_revision,
+              ctx, sesspool));
+    SVN_ERR(svn_client__get_history_as_mergeinfo(
+              &source_history, NULL,
+              pathrev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+              source_session, ctx, scratch_pool));
   }
   /* Close the source and target sessions. */
   svn_pool_destroy(sesspool);
@@ -1883,7 +1866,7 @@ svn_client_mergeinfo_log(svn_boolean_t f
       else
         {
           /* Map SUBTREE_PATH to an empty rangelist if there was nothing
-             fully merged. e.g. Only empty or non-inheritable mergienfo
+             fully merged. e.g. Only empty or non-inheritable mergeinfo
              on the subtree or mergeinfo unrelated to the source. */
           apr_hash_set(inheritable_subtree_merges, subtree_path,
                        APR_HASH_KEY_STRING,

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/mergeinfo.h Mon Apr 23 12:32:48 2012
@@ -26,6 +26,7 @@
 
 #include "svn_wc.h"
 #include "svn_client.h"
+#include "private/svn_client_private.h"
 
 
 /*** Data Structures ***/
@@ -40,7 +41,9 @@ typedef struct svn_client__merge_path_t
 {
   const char *abspath;               /* Absolute working copy path. */
   svn_boolean_t missing_child;       /* ABSPATH has an immediate child which
-                                        is missing. */
+                                        is missing, but is not switched. */
+  svn_boolean_t switched_child;      /* ABSPATH has an immediate child which
+                                        is switched. */
   svn_boolean_t switched;            /* ABSPATH is switched. */
   svn_boolean_t has_noninheritable;  /* ABSPATH has svn:mergeinfo set on it
                                         which includes non-inheritable
@@ -79,6 +82,13 @@ typedef struct svn_client__merge_path_t
                                            to the merge, and the operational
                                            depth of the merge is
                                            svn_depth_immediates. */
+  svn_boolean_t record_mergeinfo;       /* Mergeinfo needs to be recorded
+                                           on ABSPATH to describe the
+                                           merge. */
+  svn_boolean_t record_noninheritable;  /* Non-inheritable mergeinfo needs to
+                                           be recorded on ABSPATH to describe
+                                           the merge. Implies RECORD_MERGEINFO
+                                           is true. */
 } svn_client__merge_path_t;
 
 /* Return a deep copy of the merge-path structure OLD, allocated in POOL. */
@@ -86,13 +96,21 @@ svn_client__merge_path_t *
 svn_client__merge_path_dup(const svn_client__merge_path_t *old,
                            apr_pool_t *pool);
 
+/* Create a new merge path structure, allocated in POOL.  Initialize the
+ * 'abspath' member to a deep copy of ABSPATH and all other fields to zero
+ * bytes. */
+svn_client__merge_path_t *
+svn_client__merge_path_create(const char *abspath,
+                              apr_pool_t *pool);
+
 
 
 /*** Functions ***/
 
 /* Find explicit or inherited WC mergeinfo for LOCAL_ABSPATH, and return it
    in *MERGEINFO (NULL if no mergeinfo is set).  Set *INHERITED to
-   whether the mergeinfo was inherited (TRUE or FALSE).
+   whether the mergeinfo was inherited (TRUE or FALSE), if INHERITED is
+   non-null.
 
    This function will search for inherited mergeinfo in the parents of
    LOCAL_ABSPATH only if the base revision of LOCAL_ABSPATH falls within
@@ -153,37 +171,40 @@ svn_client__get_wc_mergeinfo_catalog(svn
                                      apr_pool_t *result_pool,
                                      apr_pool_t *scratch_pool);
 
-/* Obtain any mergeinfo for repository filesystem path REL_PATH
-   (relative to RA_SESSION's session URL) from the repository, and set
+/* Obtain any mergeinfo for URL from the repository, and set
    it in *TARGET_MERGEINFO.
 
    INHERIT indicates whether explicit, explicit or inherited, or only
-   inherited mergeinfo for REL_PATH is obtained.
+   inherited mergeinfo for URL is obtained.
 
-   If REL_PATH does not exist at REV, SVN_ERR_FS_NOT_FOUND or
+   If URL does not exist at REV, SVN_ERR_FS_NOT_FOUND or
    SVN_ERR_RA_DAV_REQUEST_FAILED is returned and *TARGET_MERGEINFO
    is untouched.
 
-   If there is no mergeinfo available for REL_PATH, or if the server
+   If there is no mergeinfo available for URL, or if the server
    doesn't support a mergeinfo capability and SQUELCH_INCAPABLE is
    TRUE, set *TARGET_MERGEINFO to NULL. If the server doesn't support
    a mergeinfo capability and SQUELCH_INCAPABLE is FALSE, return an
-   SVN_ERR_UNSUPPORTED_FEATURE error. */
+   SVN_ERR_UNSUPPORTED_FEATURE error.
+
+   RA_SESSION is an open RA session to the repository in which URL lives;
+   it may be temporarily reparented by this function.
+*/
 svn_error_t *
 svn_client__get_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
                                 svn_ra_session_t *ra_session,
-                                const char *rel_path,
+                                const char *url,
                                 svn_revnum_t rev,
                                 svn_mergeinfo_inheritance_t inherit,
                                 svn_boolean_t squelch_incapable,
                                 apr_pool_t *pool);
 
 /* If INCLUDE_DESCENDANTS is FALSE, behave exactly like
-   svn_client__get_repos_mergeinfo() except the mergeinfo for REL_PATH
+   svn_client__get_repos_mergeinfo() except the mergeinfo for URL
    is put in the mergeinfo catalog MERGEINFO_CAT, with the key being
-   the repository root-relative path of REL_PATH.
+   the repository root-relative path of URL.
 
-   If INCLUDE_DESCENDANTS is true, then any subtrees under REL_PATH
+   If INCLUDE_DESCENDANTS is true, then any subtrees under URL
    with explicit mergeinfo are also included in MERGEINFO_CAT.  The
    keys for the subtree mergeinfo are the repository root-relative
    paths of the subtrees.  If no mergeinfo is found, then
@@ -191,7 +212,7 @@ svn_client__get_repos_mergeinfo(svn_merg
 svn_error_t *
 svn_client__get_repos_mergeinfo_catalog(svn_mergeinfo_catalog_t *mergeinfo_cat,
                                         svn_ra_session_t *ra_session,
-                                        const char *rel_path,
+                                        const char *url,
                                         svn_revnum_t rev,
                                         svn_mergeinfo_inheritance_t inherit,
                                         svn_boolean_t squelch_incapable,
@@ -226,7 +247,7 @@ svn_client__get_repos_mergeinfo_catalog(
 
    If TARGET_WCPATH inherited its mergeinfo from a working copy ancestor
    or if it was obtained from the repository, set *INHERITED to TRUE, set it
-   to FALSE otherwise. */
+   to FALSE otherwise, if INHERITED is non-null. */
 svn_error_t *
 svn_client__get_wc_or_repos_mergeinfo(svn_mergeinfo_t *target_mergeinfo,
                                       svn_boolean_t *inherited,
@@ -269,7 +290,7 @@ svn_client__get_wc_or_repos_mergeinfo_ca
   apr_pool_t *scratch_pool);
 
 /* Set *MERGEINFO_P to a mergeinfo constructed solely from the
-   natural history of RA_SESSION's session URL at PEG_REVNUM.
+   natural history of PATHREV.
 
    If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them to bound the
    revision ranges of returned mergeinfo.  They are governed by the same
@@ -277,11 +298,15 @@ svn_client__get_wc_or_repos_mergeinfo_ca
    svn_ra_get_location_segments().
 
    If HAS_REV_ZERO_HISTORY is not NULL, then set *HAS_REV_ZERO_HISTORY to
-   TRUE if the natural history includes revision 0, else to FALSE. */
+   TRUE if the natural history includes revision 0, else to FALSE.
+
+   RA_SESSION is an open RA session to the repository in which URL lives;
+   it may be temporarily reparented by this function.
+*/
 svn_error_t *
 svn_client__get_history_as_mergeinfo(svn_mergeinfo_t *mergeinfo_p,
                                      svn_boolean_t *has_rev_zero_history,
-                                     svn_revnum_t peg_revnum,
+                                     const svn_client__pathrev_t *pathrev,
                                      svn_revnum_t range_youngest,
                                      svn_revnum_t range_oldest,
                                      svn_ra_session_t *ra_session,
@@ -313,6 +338,13 @@ svn_client__record_wc_mergeinfo(const ch
                                 svn_client_ctx_t *ctx,
                                 apr_pool_t *scratch_pool);
 
+/* Write mergeinfo into the WC.  RESULT_CATALOG maps (const char *) WC paths
+ * to (svn_mergeinfo_t) mergeinfo. */
+svn_error_t *
+svn_client__record_wc_mergeinfo_catalog(apr_hash_t *result_catalog,
+                                        svn_client_ctx_t *ctx,
+                                        apr_pool_t *scratch_pool);
+
 /* Elide any svn:mergeinfo set on TARGET_WCPATH to its nearest working
    copy (or possibly repository) ancestor with equivalent mergeinfo.
 
@@ -352,10 +384,18 @@ svn_client__elide_mergeinfo(const char *
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool);
 
-/* TODO(reint): Document. */
+/* Simplify a mergeinfo catalog, if possible, via elision.
+
+   For each path in MERGEINFO_CATALOG, check if the path's mergeinfo can
+   elide to the path's nearest path-wise parent in MERGEINFO_CATALOG.  If
+   so, remove that path from MERGEINFO_CATALOG.  Elidability is determined
+   as per svn_client__elide_mergeinfo except that elision to the repository
+   is not considered.
+
+   SCRATCH_POOL is used for temporary allocations. */
 svn_error_t *
-svn_client__elide_mergeinfo_catalog(svn_mergeinfo_t mergeinfo_catalog,
-                                    apr_pool_t *pool);
+svn_client__elide_mergeinfo_catalog(svn_mergeinfo_catalog_t mergeinfo_catalog,
+                                    apr_pool_t *scratch_pool);
 
 /* Set *MERGEINFO_CHANGES to TRUE if LOCAL_ABSPATH has locally modified
    mergeinfo, set *MERGEINFO_CHANGES to FALSE otherwise. */

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/patch.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/patch.c Mon Apr 23 12:32:48 2012
@@ -1699,7 +1699,7 @@ apply_hunk(patch_target_t *target, targe
                                                    &eol_str, &eof,
                                                    iterpool, iterpool));
       lines_read++;
-      if (! eof && lines_read > hi->fuzz &&
+      if (lines_read > hi->fuzz &&
           lines_read <= svn_diff_hunk_get_modified_length(hi->hunk) - hi->fuzz)
         {
           apr_size_t len;
@@ -2718,7 +2718,7 @@ delete_empty_dirs(apr_array_header_t *ta
   empty_dirs = apr_hash_make(scratch_pool);
   non_empty_dirs = apr_hash_make(scratch_pool);
   iterpool = svn_pool_create(scratch_pool);
-  for (i = 0; i < targets_info->nelts; i++)
+  for (i = 0; i < deleted_targets->nelts; i++)
     {
       svn_boolean_t parent_empty;
       patch_target_info_t *target_info;
@@ -2729,7 +2729,7 @@ delete_empty_dirs(apr_array_header_t *ta
       if (ctx->cancel_func)
         SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
-      target_info = APR_ARRAY_IDX(targets_info, i, patch_target_info_t *);
+      target_info = APR_ARRAY_IDX(deleted_targets, i, patch_target_info_t *);
 
       parent = svn_dirent_dirname(target_info->local_abspath, iterpool);
 
@@ -2833,54 +2833,36 @@ delete_empty_dirs(apr_array_header_t *ta
   return SVN_NO_ERROR;
 }
 
-/* Baton for apply_patches(). */
-typedef struct apply_patches_baton_t {
-  /* The path to the patch file. */
-  const char *patch_abspath;
-
-  /* The abspath to the working copy the patch should be applied to. */
-  const char *abs_wc_path;
-
-  /* Indicates whether we're doing a dry run. */
-  svn_boolean_t dry_run;
-
-  /* Number of leading components to strip from patch target paths. */
-  int strip_count;
-
-  /* Whether to apply the patch in reverse. */
-  svn_boolean_t reverse;
-
-  /* Indicates whether we should ignore whitespace when matching context
-   * lines */
-  svn_boolean_t ignore_whitespace;
-
-  /* As in svn_client_patch(). */
-  svn_boolean_t remove_tempfiles;
-
-  /* As in svn_client_patch(). */
-  svn_client_patch_func_t patch_func;
-  void *patch_baton;
-
-  /* The client context. */
-  svn_client_ctx_t *ctx;
-} apply_patches_baton_t;
-
-/* Callback for use with svn_wc__call_with_write_lock().
- * This function is the main entry point into the patch code. */
+/* This function is the main entry point into the patch code. */
 static svn_error_t *
-apply_patches(void *baton,
-              apr_pool_t *result_pool,
+apply_patches(/* The path to the patch file. */
+              const char *patch_abspath,
+              /* The abspath to the working copy the patch should be applied to. */
+              const char *abs_wc_path,
+              /* Indicates whether we're doing a dry run. */
+              svn_boolean_t dry_run,
+              /* Number of leading components to strip from patch target paths. */
+              int strip_count,
+              /* Whether to apply the patch in reverse. */
+              svn_boolean_t reverse,
+              /* Whether to ignore whitespace when matching context lines. */
+              svn_boolean_t ignore_whitespace,
+              /* As in svn_client_patch(). */
+              svn_boolean_t remove_tempfiles,
+              /* As in svn_client_patch(). */
+              svn_client_patch_func_t patch_func,
+              void *patch_baton,
+              /* The client context. */
+              svn_client_ctx_t *ctx,
               apr_pool_t *scratch_pool)
 {
   svn_patch_t *patch;
   apr_pool_t *iterpool;
   svn_patch_file_t *patch_file;
   apr_array_header_t *targets_info;
-  apply_patches_baton_t *btn = baton;
 
   /* Try to open the patch file. */
-  SVN_ERR(svn_diff_open_patch_file(&patch_file, btn->patch_abspath,
-                                   scratch_pool));
+  SVN_ERR(svn_diff_open_patch_file(&patch_file, patch_abspath, scratch_pool));
 
   /* Apply patches. */
   targets_info = apr_array_make(scratch_pool, 0,
@@ -2890,23 +2872,21 @@ apply_patches(void *baton,
     {
       svn_pool_clear(iterpool);
 
-      if (btn->ctx->cancel_func)
-        SVN_ERR(btn->ctx->cancel_func(btn->ctx->cancel_baton));
+      if (ctx->cancel_func)
+        SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
 
       SVN_ERR(svn_diff_parse_next_patch(&patch, patch_file,
-                                        btn->reverse, btn->ignore_whitespace,
+                                        reverse, ignore_whitespace,
                                         iterpool, iterpool));
       if (patch)
         {
           patch_target_t *target;
 
-          SVN_ERR(apply_one_patch(&target, patch, btn->abs_wc_path,
-                                  btn->ctx->wc_ctx, btn->strip_count,
-                                  btn->ignore_whitespace,
-                                  btn->remove_tempfiles,
-                                  btn->patch_func, btn->patch_baton,
-                                  btn->ctx->cancel_func,
-                                  btn->ctx->cancel_baton,
+          SVN_ERR(apply_one_patch(&target, patch, abs_wc_path,
+                                  ctx->wc_ctx, strip_count,
+                                  ignore_whitespace, remove_tempfiles,
+                                  patch_func, patch_baton,
+                                  ctx->cancel_func, ctx->cancel_baton,
                                   iterpool, iterpool));
           if (! target->filtered)
             {
@@ -2925,27 +2905,23 @@ apply_patches(void *baton,
                   if (target->has_text_changes
                       || target->added
                       || target->deleted)
-                    SVN_ERR(install_patched_target(target, btn->abs_wc_path,
-                                                   btn->ctx, btn->dry_run,
-                                                   iterpool));
+                    SVN_ERR(install_patched_target(target, abs_wc_path,
+                                                   ctx, dry_run, iterpool));
 
                   if (target->has_prop_changes && (!target->deleted))
-                    SVN_ERR(install_patched_prop_targets(target, btn->ctx,
-                                                         btn->dry_run,
-                                                         iterpool));
+                    SVN_ERR(install_patched_prop_targets(target, ctx,
+                                                         dry_run, iterpool));
 
-                  SVN_ERR(write_out_rejected_hunks(target, btn->dry_run,
-                                                   iterpool));
+                  SVN_ERR(write_out_rejected_hunks(target, dry_run, iterpool));
                 }
-              SVN_ERR(send_patch_notification(target, btn->ctx, iterpool));
+              SVN_ERR(send_patch_notification(target, ctx, iterpool));
             }
         }
     }
   while (patch);
 
   /* Delete directories which are empty after patching, if any. */
-  SVN_ERR(delete_empty_dirs(targets_info, btn->ctx, btn->dry_run,
-                            scratch_pool));
+  SVN_ERR(delete_empty_dirs(targets_info, ctx, dry_run, scratch_pool));
 
   SVN_ERR(svn_diff_close_patch_file(patch_file, iterpool));
   svn_pool_destroy(iterpool);
@@ -2966,7 +2942,6 @@ svn_client_patch(const char *patch_abspa
                  svn_client_ctx_t *ctx,
                  apr_pool_t *scratch_pool)
 {
-  apply_patches_baton_t baton;
   svn_node_kind_t kind;
 
   if (strip_count < 0)
@@ -3003,19 +2978,10 @@ svn_client_patch(const char *patch_abspa
                              svn_dirent_local_style(wc_dir_abspath,
                                                     scratch_pool));
 
-  baton.patch_abspath = patch_abspath;
-  baton.abs_wc_path = wc_dir_abspath;
-  baton.dry_run = dry_run;
-  baton.ctx = ctx;
-  baton.strip_count = strip_count;
-  baton.reverse = reverse;
-  baton.ignore_whitespace = ignore_whitespace;
-  baton.remove_tempfiles = remove_tempfiles;
-  baton.patch_func = patch_func;
-  baton.patch_baton = patch_baton;
-
-  return svn_error_trace(
-           svn_wc__call_with_write_lock(apply_patches, &baton,
-                                        ctx->wc_ctx, wc_dir_abspath, FALSE,
-                                        scratch_pool, scratch_pool));
+  SVN_WC__CALL_WITH_WRITE_LOCK(
+    apply_patches(patch_abspath, wc_dir_abspath, dry_run, strip_count,
+                  reverse, ignore_whitespace, remove_tempfiles,
+                  patch_func, patch_baton, ctx, scratch_pool),
+    ctx->wc_ctx, wc_dir_abspath, FALSE /* lock_anchor */, scratch_pool);
+  return SVN_NO_ERROR;
 }

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/prop_commands.c Mon Apr 23 12:32:48 2012
@@ -41,6 +41,7 @@
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_ra_private.h"
 #include "private/svn_client_private.h"
 
 
@@ -74,7 +75,7 @@ is_revision_prop_name(const char *name)
 static svn_error_t *
 error_if_wcprop_name(const char *name)
 {
-  if (svn_property_kind(NULL, name) == svn_prop_wc_kind)
+  if (svn_property_kind2(name) == svn_prop_wc_kind)
     {
       return svn_error_createf
         (SVN_ERR_CLIENT_PROPERTY_NAME, NULL,
@@ -117,7 +118,8 @@ get_file_for_validation(const svn_string
 
 static
 svn_error_t *
-do_url_propset(const char *propname,
+do_url_propset(const char *url,
+               const char *propname,
                const svn_string_t *propval,
                const svn_node_kind_t kind,
                const svn_revnum_t base_revision_for_url,
@@ -133,8 +135,10 @@ do_url_propset(const char *propname,
   if (kind == svn_node_file)
     {
       void *file_baton;
-      SVN_ERR(editor->open_file("", root_baton, base_revision_for_url,
-                                pool, &file_baton));
+      const char *uri_basename = svn_uri_basename(url, pool);
+
+      SVN_ERR(editor->open_file(uri_basename, root_baton,
+                                base_revision_for_url, pool, &file_baton));
       SVN_ERR(editor->change_file_prop(file_baton, propname, propval, pool));
       SVN_ERR(editor->close_file(file_baton, NULL, pool));
     }
@@ -158,7 +162,7 @@ propset_on_url(const char *propname,
                svn_client_ctx_t *ctx,
                apr_pool_t *pool)
 {
-  enum svn_prop_kind prop_kind = svn_property_kind(NULL, propname);
+  enum svn_prop_kind prop_kind = svn_property_kind2(propname);
   svn_ra_session_t *ra_session;
   svn_node_kind_t node_kind;
   const char *message;
@@ -186,6 +190,18 @@ propset_on_url(const char *propname,
        _("Path '%s' does not exist in revision %ld"),
        target, base_revision_for_url);
 
+  if (node_kind == svn_node_file)
+    {
+      /* We need to reparent our session one directory up, since editor
+         semantics require the root is a directory.
+
+         ### How does this interact with authz? */
+      const char *parent_url;
+      parent_url = svn_uri_dirname(target, pool);
+
+      SVN_ERR(svn_ra_reparent(ra_session, parent_url, pool));
+    }
+
   /* Setting an inappropriate property is not allowed (unless
      overridden by 'skip_checks', in some circumstances).  Deleting an
      inappropriate property is allowed, however, since older clients
@@ -227,6 +243,9 @@ propset_on_url(const char *propname,
                                            message, ctx, pool));
 
   /* Fetch RA commit editor. */
+  SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+                        svn_client__get_shim_callbacks(ctx->wc_ctx,
+                                                       NULL, pool)));
   SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
                                     commit_revprops,
                                     commit_callback,
@@ -234,8 +253,8 @@ propset_on_url(const char *propname,
                                     NULL, TRUE, /* No lock tokens */
                                     pool));
 
-  err = do_url_propset(propname, propval, node_kind, base_revision_for_url,
-                       editor, edit_baton, pool);
+  err = do_url_propset(target, propname, propval, node_kind,
+                       base_revision_for_url, editor, edit_baton, pool);
 
   if (err)
     {
@@ -248,37 +267,6 @@ propset_on_url(const char *propname,
   return editor->close_edit(edit_baton, pool);
 }
 
-/* Baton for set_props_cb */
-struct set_props_baton
-{
-  svn_client_ctx_t *ctx;
-  const char *local_abspath;
-  svn_depth_t depth;
-  svn_node_kind_t kind;
-  const char *propname;
-  const svn_string_t *propval;
-  svn_boolean_t skip_checks;
-  const apr_array_header_t *changelist_filter;
-};
-
-/* Working copy lock callback for svn_client_propset4 */
-static svn_error_t *
-set_props_cb(void *baton,
-             apr_pool_t *result_pool,
-             apr_pool_t *scratch_pool)
-{
-  struct set_props_baton *bt = baton;
-
-  SVN_ERR(svn_wc_prop_set4(bt->ctx->wc_ctx, bt->local_abspath, bt->propname,
-                           bt->propval, bt->depth, bt->skip_checks,
-                           bt->changelist_filter,
-                           bt->ctx->cancel_func, bt->ctx->cancel_baton,
-                           bt->ctx->notify_func2, bt->ctx->notify_baton2,
-                           scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
 /* Check that PROPNAME is a valid name for a versioned property.  Return an
  * error if it is not valid, specifically if it is:
  *   - the name of a standard Subversion rev-prop; or
@@ -342,7 +330,6 @@ svn_client_propset_local(const char *pro
       svn_node_kind_t kind;
       const char *target_abspath;
       svn_error_t *err;
-      struct set_props_baton baton;
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
 
       svn_pool_clear(iterpool);
@@ -357,7 +344,7 @@ svn_client_propset_local(const char *pro
                              iterpool);
 
       if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-          || kind == svn_node_unknown || kind == svn_node_none)
+          || (!err && (kind == svn_node_unknown || kind == svn_node_none)))
         {
           if (ctx->notify_func2)
             {
@@ -374,18 +361,12 @@ svn_client_propset_local(const char *pro
       else
         SVN_ERR(err);
 
-      baton.ctx = ctx;
-      baton.local_abspath = target_abspath;
-      baton.depth = depth;
-      baton.kind = kind;
-      baton.propname = propname;
-      baton.propval = propval;
-      baton.skip_checks = skip_checks;
-      baton.changelist_filter = changelists;
-
-      SVN_ERR(svn_wc__call_with_write_lock(set_props_cb, &baton,
-                                           ctx->wc_ctx, target_abspath,
-                                           FALSE, iterpool, iterpool));
+      SVN_WC__CALL_WITH_WRITE_LOCK(
+        svn_wc_prop_set4(ctx->wc_ctx, target_abspath, propname,
+                         propval, depth, skip_checks, changelists,
+                         ctx->cancel_func, ctx->cancel_baton,
+                         ctx->notify_func2, ctx->notify_baton2, iterpool),
+        ctx->wc_ctx, target_abspath, FALSE /* lock_anchor */, iterpool);
     }
   svn_pool_destroy(iterpool);
 
@@ -999,7 +980,7 @@ remote_proplist(const char *target_prefi
       svn_string_t *value = svn__apr_hash_index_val(hi);
       svn_prop_kind_t prop_kind;
 
-      prop_kind = svn_property_kind(NULL, name);
+      prop_kind = svn_property_kind2(name);
 
       if (prop_kind == svn_prop_regular_kind)
         {

Modified: subversion/branches/javahl-ra/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/libsvn_client/ra.c?rev=1329209&r1=1329208&r2=1329209&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/javahl-ra/subversion/libsvn_client/ra.c Mon Apr 23 12:32:48 2012
@@ -40,6 +40,7 @@
 
 #include "svn_private_config.h"
 #include "private/svn_wc_private.h"
+#include "private/svn_client_private.h"
 
 
 /* This is the baton that we pass svn_ra_open3(), and is associated with
@@ -51,10 +52,6 @@ typedef struct callback_baton_t
      this base directory. */
   const char *base_dir_abspath;
 
-  /* When true, makes sure temporary files are created
-     outside the working copy. */
-  svn_boolean_t read_only_wc;
-
   /* An array of svn_client_commit_item3_t * structures, present only
      during working copy commits. */
   const apr_array_header_t *commit_items;
@@ -62,9 +59,6 @@ typedef struct callback_baton_t
   /* A client context. */
   svn_client_ctx_t *ctx;
 
-  /* The pool to use for session-related items. */
-  apr_pool_t *pool;
-
 } callback_baton_t;
 
 
@@ -292,8 +286,6 @@ svn_client__open_ra_session_internal(svn
   cbtable->get_client_string = get_client_string;
 
   cb->base_dir_abspath = base_dir_abspath;
-  cb->read_only_wc = read_only_wc;
-  cb->pool = pool;
   cb->commit_items = commit_items;
   cb->ctx = ctx;
 
@@ -387,17 +379,6 @@ svn_client_open_ra_session(svn_ra_sessio
 
 
 
-/* Convert a path or URL for display: if it is a local path, convert it to
- * the local path style; if it is a URL, return it unchanged. */
-static const char *
-path_or_url_local_style(const char *path_or_url,
-                        apr_pool_t *pool)
-{
-  if (svn_path_is_url(path_or_url))
-    return path_or_url;
-  return svn_dirent_local_style(path_or_url, pool);
-}
-
 /* Given PATH_OR_URL, which contains either a working copy path or an
    absolute URL, a peg revision PEG_REVISION, and a desired revision
    REVISION, find the path at which that object exists in REVISION,
@@ -406,20 +387,22 @@ path_or_url_local_style(const char *path
    PEG_REVISION and REVISION, and return @c
    SVN_ERR_CLIENT_UNRELATED_RESOURCES if it is not the same node.
 
-   If PEG_REVISION's kind is svn_opt_revision_unspecified, interpret it
-   as "head" for a URL or "working" for a working-copy path.
-
-   Store the actual revision number of the object in *REV_P, and the
-   final resulting URL in *URL_P. REV_P and/or URL_P may be NULL if not
-   wanted.
+   If PEG_REVISION->kind is 'unspecified', the peg revision is 'head'
+   for a URL or 'working' for a WC path.  If REVISION->kind is
+   'unspecified', the operative revision is the peg revision.
+
+   Store the actual location of the object in *RESOLVED_LOC_P.
+
+   RA_SESSION should be an open RA session pointing at the URL of
+   PATH_OR_URL, or NULL, in which case this function will open its own
+   temporary session.
 
    Use authentication baton cached in CTX to authenticate against the
    repository.
 
    Use POOL for all allocations. */
 static svn_error_t *
-resolve_rev_and_url(svn_revnum_t *rev_p,
-                    const char **url_p,
+resolve_rev_and_url(svn_client__pathrev_t **resolved_loc_p,
                     svn_ra_session_t *ra_session,
                     const char *path_or_url,
                     const svn_opt_revision_t *peg_revision,
@@ -432,9 +415,10 @@ resolve_rev_and_url(svn_revnum_t *rev_p,
   const char *url;
   svn_revnum_t rev;
 
+  /* Default revisions: peg -> working or head; operative -> peg. */
   SVN_ERR(svn_opt_resolve_revisions(&peg_rev, &start_rev,
                                     svn_path_is_url(path_or_url),
-                                    TRUE,
+                                    TRUE /* notice_local_mods */,
                                     pool));
 
   /* Run the history function to get the object's (possibly
@@ -443,29 +427,25 @@ resolve_rev_and_url(svn_revnum_t *rev_p,
                                       ra_session, path_or_url, &peg_rev,
                                       &start_rev, NULL, ctx, pool));
 
-  if (rev_p)
-    *rev_p = rev;
-  if (url_p)
-    *url_p = url;
-
+  SVN_ERR(svn_client__pathrev_create_with_session(resolved_loc_p,
+                                                  ra_session, rev, url, pool));
   return SVN_NO_ERROR;
 }
 
 svn_error_t *
-svn_client__ra_session_from_path(svn_ra_session_t **ra_session_p,
-                                 svn_revnum_t *rev_p,
-                                 const char **url_p,
-                                 const char *path_or_url,
-                                 const char *base_dir_abspath,
-                                 const svn_opt_revision_t *peg_revision,
-                                 const svn_opt_revision_t *revision,
-                                 svn_client_ctx_t *ctx,
-                                 apr_pool_t *pool)
+svn_client__ra_session_from_path2(svn_ra_session_t **ra_session_p,
+                                  svn_client__pathrev_t **resolved_loc_p,
+                                  const char *path_or_url,
+                                  const char *base_dir_abspath,
+                                  const svn_opt_revision_t *peg_revision,
+                                  const svn_opt_revision_t *revision,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *pool)
 {
   svn_ra_session_t *ra_session;
   const char *initial_url;
   const char *corrected_url;
-  const char *resolved_url;
+  svn_client__pathrev_t *resolved_loc;
 
   SVN_ERR(svn_client_url_from_path2(&initial_url, path_or_url, ctx, pool,
                                     pool));
@@ -484,16 +464,41 @@ svn_client__ra_session_from_path(svn_ra_
   if (corrected_url && svn_path_is_url(path_or_url))
     path_or_url = corrected_url;
 
-  SVN_ERR(resolve_rev_and_url(rev_p, &resolved_url, ra_session,
+  SVN_ERR(resolve_rev_and_url(&resolved_loc, ra_session,
                               path_or_url, peg_revision, revision,
                               ctx, pool));
 
   /* Make the session point to the real URL. */
-  SVN_ERR(svn_ra_reparent(ra_session, resolved_url, pool));
+  SVN_ERR(svn_ra_reparent(ra_session, resolved_loc->url, pool));
 
   *ra_session_p = ra_session;
+  if (resolved_loc_p)
+    *resolved_loc_p = resolved_loc;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__ra_session_from_path(svn_ra_session_t **ra_session_p,
+                                 svn_revnum_t *rev_p,
+                                 const char **url_p,
+                                 const char *path_or_url,
+                                 const char *base_dir_abspath,
+                                 const svn_opt_revision_t *peg_revision,
+                                 const svn_opt_revision_t *revision,
+                                 svn_client_ctx_t *ctx,
+                                 apr_pool_t *pool)
+{
+  svn_client__pathrev_t *resolved_loc;
+
+  SVN_ERR(svn_client__ra_session_from_path2(ra_session_p, &resolved_loc,
+                                            path_or_url, base_dir_abspath,
+                                            peg_revision, revision,
+                                            ctx, pool));
+  if (rev_p)
+    *rev_p = resolved_loc->rev;
   if (url_p)
-    *url_p = resolved_url;
+    *url_p = resolved_loc->url;
 
   return SVN_NO_ERROR;
 }
@@ -505,7 +510,6 @@ svn_client__ensure_ra_session_url(const 
                                   const char *session_url,
                                   apr_pool_t *pool)
 {
-  *old_session_url = NULL;
   SVN_ERR(svn_ra_get_session_url(ra_session, old_session_url, pool));
   if (! session_url)
     SVN_ERR(svn_ra_get_repos_root2(ra_session, &session_url, pool));
@@ -556,7 +560,7 @@ compare_segments(const void *a, const vo
 svn_error_t *
 svn_client__repos_location_segments(apr_array_header_t **segments,
                                     svn_ra_session_t *ra_session,
-                                    const char *path,
+                                    const char *url,
                                     svn_revnum_t peg_revision,
                                     svn_revnum_t start_revision,
                                     svn_revnum_t end_revision,
@@ -564,19 +568,129 @@ svn_client__repos_location_segments(apr_
                                     apr_pool_t *pool)
 {
   struct gls_receiver_baton_t gls_receiver_baton;
+  const char *old_session_url;
+
   *segments = apr_array_make(pool, 8, sizeof(svn_location_segment_t *));
   gls_receiver_baton.segments = *segments;
   gls_receiver_baton.ctx = ctx;
   gls_receiver_baton.pool = pool;
-  SVN_ERR(svn_ra_get_location_segments(ra_session, path, peg_revision,
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+                                            url, pool));
+  SVN_ERR(svn_ra_get_location_segments(ra_session, "", peg_revision,
                                        start_revision, end_revision,
                                        gls_receiver, &gls_receiver_baton,
                                        pool));
+  SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
   qsort((*segments)->elts, (*segments)->nelts,
         (*segments)->elt_size, compare_segments);
   return SVN_NO_ERROR;
 }
 
+/* Set *START_URL and *END_URL to the URLs that the object URL@PEG_REVNUM
+ * had in revisions START_REVNUM and END_REVNUM.  Return an error if the
+ * node cannot be traced back to one of the requested revisions.
+ *
+ * START_URL and/or END_URL may be NULL if not wanted.  START_REVNUM and
+ * END_REVNUM must be valid revision numbers except that END_REVNUM may
+ * be SVN_INVALID_REVNUM if END_URL is NULL.
+ *
+ * RA_SESSION is an open RA session parented at URL.
+ */
+static svn_error_t *
+repos_locations(const char **start_url,
+                const char **end_url,
+                svn_ra_session_t *ra_session,
+                const char *url,
+                svn_revnum_t peg_revnum,
+                svn_revnum_t start_revnum,
+                svn_revnum_t end_revnum,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  const char *repos_url, *start_path, *end_path;
+  apr_array_header_t *revs;
+  apr_hash_t *rev_locs;
+
+  SVN_ERR_ASSERT(peg_revnum != SVN_INVALID_REVNUM);
+  SVN_ERR_ASSERT(start_revnum != SVN_INVALID_REVNUM);
+  SVN_ERR_ASSERT(end_revnum != SVN_INVALID_REVNUM || end_url == NULL);
+
+  /* Avoid a network request in the common easy case. */
+  if (start_revnum == peg_revnum
+      && (end_revnum == peg_revnum || end_revnum == SVN_INVALID_REVNUM))
+    {
+      if (start_url)
+        *start_url = apr_pstrdup(result_pool, url);
+      if (end_url)
+        *end_url = apr_pstrdup(result_pool, url);
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, scratch_pool));
+
+  revs = apr_array_make(scratch_pool, 2, sizeof(svn_revnum_t));
+  APR_ARRAY_PUSH(revs, svn_revnum_t) = start_revnum;
+  if (end_revnum != start_revnum && end_revnum != SVN_INVALID_REVNUM)
+    APR_ARRAY_PUSH(revs, svn_revnum_t) = end_revnum;
+
+  SVN_ERR(svn_ra_get_locations(ra_session, &rev_locs, "", peg_revnum,
+                               revs, scratch_pool));
+
+  /* We'd better have all the paths we were looking for! */
+  if (start_url)
+    {
+      start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(svn_revnum_t));
+      if (! start_path)
+        return svn_error_createf
+          (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
+           _("Unable to find repository location for '%s' in revision %ld"),
+           url, start_revnum);
+      *start_url = svn_path_url_add_component2(repos_url, start_path + 1,
+                                               result_pool);
+    }
+
+  if (end_url)
+    {
+      end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(svn_revnum_t));
+      if (! end_path)
+        return svn_error_createf
+          (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
+           _("The location for '%s' for revision %ld does not exist in the "
+             "repository or refers to an unrelated object"),
+           url, end_revnum);
+
+      *end_url = svn_path_url_add_component2(repos_url, end_path + 1,
+                                             result_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__repos_location(svn_client__pathrev_t **op_loc_p,
+                           svn_ra_session_t *ra_session,
+                           const svn_client__pathrev_t *peg_loc,
+                           svn_revnum_t op_revnum,
+                           svn_client_ctx_t *ctx,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  const char *old_session_url;
+  const char *op_url;
+
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+                                            peg_loc->url, scratch_pool));
+  SVN_ERR(repos_locations(&op_url, NULL, ra_session,
+                          peg_loc->url, peg_loc->rev,
+                          op_revnum, SVN_INVALID_REVNUM,
+                          result_pool, scratch_pool));
+  SVN_ERR(svn_ra_reparent(ra_session, old_session_url, scratch_pool));
+
+  *op_loc_p = svn_client__pathrev_create(peg_loc->repos_root_url,
+                                         peg_loc->repos_uuid,
+                                         op_revnum, op_url, result_pool);
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_client__repos_locations(const char **start_url,
@@ -591,16 +705,11 @@ svn_client__repos_locations(const char *
                             svn_client_ctx_t *ctx,
                             apr_pool_t *pool)
 {
-  const char *repos_url;
   const char *url;
-  const char *start_path = NULL;
-  const char *end_path = NULL;
   const char *local_abspath_or_url;
   svn_revnum_t peg_revnum = SVN_INVALID_REVNUM;
   svn_revnum_t start_revnum, end_revnum;
   svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
-  apr_array_header_t *revs;
-  apr_hash_t *rev_locs;
   apr_pool_t *subpool = svn_pool_create(pool);
 
   /* Ensure that we are given some real revision data to work with.
@@ -632,7 +741,7 @@ svn_client__repos_locations(const char *
           svn_boolean_t is_copy;
 
           SVN_ERR(svn_wc__node_get_origin(&is_copy, &peg_revnum, &repos_relpath,
-                                          &repos_root_url, NULL,
+                                          &repos_root_url, NULL, NULL,
                                           ctx->wc_ctx, local_abspath_or_url,
                                           FALSE, subpool, subpool));
 
@@ -711,110 +820,62 @@ svn_client__repos_locations(const char *
       *end_revision = end_revnum;
     }
 
-  if (start_revnum == peg_revnum && end_revnum == peg_revnum)
-    {
-      /* Avoid a network request in the common easy case. */
-      *start_url = url;
-      if (end->kind != svn_opt_revision_unspecified)
-        *end_url = url;
-      svn_pool_destroy(subpool);
-      return SVN_NO_ERROR;
-    }
-
-  SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_url, subpool));
-
-  revs = apr_array_make(subpool, 2, sizeof(svn_revnum_t));
-  APR_ARRAY_PUSH(revs, svn_revnum_t) = start_revnum;
-  if (end_revnum != start_revnum)
-    APR_ARRAY_PUSH(revs, svn_revnum_t) = end_revnum;
-
-  SVN_ERR(svn_ra_get_locations(ra_session, &rev_locs, "", peg_revnum,
-                               revs, subpool));
-
-  /* We'd better have all the paths we were looking for! */
-  start_path = apr_hash_get(rev_locs, &start_revnum, sizeof(svn_revnum_t));
-  if (! start_path)
-    return svn_error_createf
-      (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
-       _("Unable to find repository location for '%s' in revision %ld"),
-       path_or_url_local_style(path, pool), start_revnum);
-
-  end_path = apr_hash_get(rev_locs, &end_revnum, sizeof(svn_revnum_t));
-  if (! end_path)
-    return svn_error_createf
-      (SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
-       _("The location for '%s' for revision %ld does not exist in the "
-         "repository or refers to an unrelated object"),
-       path_or_url_local_style(path, pool), end_revnum);
-
-  /* Set our return variables */
-  *start_url = svn_path_url_add_component2(repos_url, start_path + 1, pool);
-  if (end->kind != svn_opt_revision_unspecified)
-    *end_url = svn_path_url_add_component2(repos_url, end_path + 1, pool);
-
+  SVN_ERR(repos_locations(start_url, end_url,
+                          ra_session, url, peg_revnum,
+                          start_revnum, end_revnum,
+                          pool, subpool));
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
 
 svn_error_t *
-svn_client__get_youngest_common_ancestor(const char **ancestor_path,
-                                         svn_revnum_t *ancestor_revision,
-                                         const char *path_or_url1,
-                                         svn_revnum_t rev1,
-                                         const char *path_or_url2,
-                                         svn_revnum_t rev2,
+svn_client__get_youngest_common_ancestor(svn_client__pathrev_t **ancestor_p,
+                                         const svn_client__pathrev_t *loc1,
+                                         const svn_client__pathrev_t *loc2,
                                          svn_client_ctx_t *ctx,
-                                         apr_pool_t *pool)
+                                         apr_pool_t *result_pool,
+                                         apr_pool_t *scratch_pool)
 {
-  apr_pool_t *sesspool = svn_pool_create(pool);
-  svn_ra_session_t *session1, *session2;
+  apr_pool_t *sesspool = svn_pool_create(scratch_pool);
+  svn_ra_session_t *session;
   apr_hash_t *history1, *history2;
   apr_hash_index_t *hi;
   svn_revnum_t yc_revision = SVN_INVALID_REVNUM;
-  const char *yc_path = NULL;
-  svn_opt_revision_t revision1, revision2;
+  const char *yc_relpath = NULL;
   svn_boolean_t has_rev_zero_history1;
   svn_boolean_t has_rev_zero_history2;
 
-  revision1.kind = revision2.kind = svn_opt_revision_number;
-  revision1.value.number = rev1;
-  revision2.value.number = rev2;
-
-  /* Open RA sessions for the two locations.
-   * ### TODO: As they are assumed to be in the same repository, we
-   * should share a single session, tracking the two URLs separately. */
-  {
-    SVN_ERR(svn_client__ra_session_from_path(&session1, NULL, NULL,
-                                             path_or_url1, NULL,
-                                             &revision1, &revision1,
-                                             ctx, sesspool));
-    SVN_ERR(svn_client__ra_session_from_path(&session2, NULL, NULL,
-                                             path_or_url2, NULL,
-                                             &revision2, &revision2,
-                                             ctx, sesspool));
-  }
+  if (strcmp(loc1->repos_root_url, loc2->repos_root_url) != 0)
+    {
+      *ancestor_p = NULL;
+      return SVN_NO_ERROR;
+    }
+
+  /* Open an RA session for the two locations. */
+  SVN_ERR(svn_client_open_ra_session(&session, loc1->url, ctx, sesspool));
+
   /* We're going to cheat and use history-as-mergeinfo because it
      saves us a bunch of annoying custom data comparisons and such. */
   SVN_ERR(svn_client__get_history_as_mergeinfo(&history1,
                                                &has_rev_zero_history1,
-                                               rev1,
+                                               loc1,
                                                SVN_INVALID_REVNUM,
                                                SVN_INVALID_REVNUM,
-                                               session1, ctx, pool));
+                                               session, ctx, scratch_pool));
   SVN_ERR(svn_client__get_history_as_mergeinfo(&history2,
                                                &has_rev_zero_history2,
-                                               rev2,
+                                               loc2,
                                                SVN_INVALID_REVNUM,
                                                SVN_INVALID_REVNUM,
-                                               session2, ctx, pool));
+                                               session, ctx, scratch_pool));
   /* Close the source and target sessions. */
   svn_pool_destroy(sesspool);
 
   /* Loop through the first location's history, check for overlapping
      paths and ranges in the second location's history, and
      remembering the youngest matching location. */
-  for (hi = apr_hash_first(pool, history1); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(scratch_pool, history1); hi; hi = apr_hash_next(hi))
     {
       const char *path = svn__apr_hash_index_key(hi);
       apr_ssize_t path_len = svn__apr_hash_index_klen(hi);
@@ -827,7 +888,7 @@ svn_client__get_youngest_common_ancestor
           /* We have a path match.  Now, did our two histories share
              any revisions at that path? */
           SVN_ERR(svn_rangelist_intersect(&common, ranges1, ranges2,
-                                          TRUE, pool));
+                                          TRUE, scratch_pool));
           if (common->nelts)
             {
               svn_merge_range_t *yc_range =
@@ -836,7 +897,7 @@ svn_client__get_youngest_common_ancestor
                   || (yc_range->end > yc_revision))
                 {
                   yc_revision = yc_range->end;
-                  yc_path = path + 1;
+                  yc_relpath = path + 1;
                 }
             }
         }
@@ -844,13 +905,62 @@ svn_client__get_youngest_common_ancestor
 
   /* It's possible that PATH_OR_URL1 and PATH_OR_URL2's only common
      history is revision 0. */
-  if (!yc_path && has_rev_zero_history1 && has_rev_zero_history2)
+  if (!yc_relpath && has_rev_zero_history1 && has_rev_zero_history2)
     {
-      yc_path = "/";
+      yc_relpath = "";
       yc_revision = 0;
     }
 
-  *ancestor_path = yc_path;
-  *ancestor_revision = yc_revision;
+  if (yc_relpath)
+    {
+      *ancestor_p = svn_client__pathrev_create_with_relpath(
+                      loc1->repos_root_url, loc1->repos_uuid,
+                      yc_revision, yc_relpath, result_pool);
+    }
+  else
+    {
+      *ancestor_p = NULL;
+    }
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_client__youngest_common_ancestor(const char **ancestor_url,
+                                     svn_revnum_t *ancestor_rev,
+                                     const char *path_or_url1,
+                                     const svn_opt_revision_t *revision1,
+                                     const char *path_or_url2,
+                                     const svn_opt_revision_t *revision2,
+                                     svn_client_ctx_t *ctx,
+                                     apr_pool_t *result_pool,
+                                     apr_pool_t *scratch_pool)
+{
+  apr_pool_t *sesspool = svn_pool_create(scratch_pool);
+  svn_ra_session_t *session;
+  svn_client__pathrev_t *loc1, *loc2, *ancestor;
+
+  /* Resolve the two locations */
+  SVN_ERR(svn_client__ra_session_from_path2(&session, &loc1,
+                                            path_or_url1, NULL,
+                                            revision1, revision1,
+                                            ctx, sesspool));
+  SVN_ERR(resolve_rev_and_url(&loc2, session,
+                              path_or_url2, revision2, revision2,
+                              ctx, scratch_pool));
+
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            &ancestor, loc1, loc2, ctx, result_pool, scratch_pool));
+
+  if (ancestor)
+    {
+      *ancestor_url = ancestor->url;
+      *ancestor_rev = ancestor->rev;
+    }
+  else
+    {
+      *ancestor_url = NULL;
+      *ancestor_rev = SVN_INVALID_REVNUM;
+    }
+  svn_pool_destroy(sesspool);
   return SVN_NO_ERROR;
 }



Mime
View raw message