You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ar...@apache.org on 2012/07/30 08:39:38 UTC

svn commit: r1367002 [6/21] - in /subversion/branches/svn-bisect: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/ notes/api-errata/1.7/ notes/http-and-webdav/ ...

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.c Mon Jul 30 06:39:28 2012
@@ -147,6 +147,49 @@ 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. ***/
@@ -250,7 +293,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. */
@@ -421,7 +464,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,
@@ -433,7 +476,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));
 
@@ -453,7 +496,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,
@@ -464,13 +507,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)
@@ -490,11 +538,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;
@@ -581,7 +627,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));
 
@@ -639,16 +685,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(
@@ -658,7 +697,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));
 
@@ -680,11 +719,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));
-                }
             }
         }
     }
@@ -714,6 +748,7 @@ 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,
+                                     const char *url,
                                      svn_revnum_t peg_revnum,
                                      svn_revnum_t range_youngest,
                                      svn_revnum_t range_oldest,
@@ -728,7 +763,8 @@ svn_client__get_history_as_mergeinfo(svn
     range_youngest = peg_revnum;
   if (! SVN_IS_VALID_REVNUM(range_oldest))
     range_oldest = 0;
-  SVN_ERR(svn_client__repos_location_segments(&segments, ra_session, "",
+
+  SVN_ERR(svn_client__repos_location_segments(&segments, ra_session, url,
                                               peg_revnum, range_youngest,
                                               range_oldest, ctx, pool));
 
@@ -776,7 +812,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)
@@ -801,20 +837,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;
@@ -1036,7 +1070,7 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
                                       scratch_pool));
 
       SVN_ERR(svn_wc__node_get_origin(NULL, &rev, &repos_relpath,
-                                      &repos_root_url, NULL,
+                                      &repos_root_url, NULL, NULL,
                                       ctx->wc_ctx, local_abspath, FALSE,
                                       scratch_pool, scratch_pool));
 
@@ -1048,7 +1082,7 @@ get_mergeinfo(svn_mergeinfo_catalog_t *m
           || 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 */
       }
     }
 
@@ -1062,7 +1096,7 @@ 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));
     }
@@ -1080,142 +1114,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;
-};
-
-/* 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;
-
-  /* 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;
+  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;
 
-  path_suffix = svn_dirent_is_child(pb->inherited_mergeinfo_path,
-                                    path, NULL);
-  SVN_ERR_ASSERT(path_suffix != NULL);
+  /* 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;
+
+      if (dir_stack->nelts > 0)
+        {
+          const char *top;
+          const char *path_suffix;
+          svn_boolean_t elides = FALSE;
+          
+          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++)
@@ -1373,11 +1339,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 =
@@ -1389,11 +1356,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;
@@ -1465,6 +1432,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))
@@ -1487,15 +1456,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;
+                                }
+                            }
                         }
                     }
                 }
@@ -1661,7 +1645,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;
@@ -1737,38 +1720,34 @@ 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_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_ra_session_t *target_session;
+      svn_revnum_t rev;
+      const char *url;
+
+      SVN_ERR(svn_client__ra_session_from_path(
+                &target_session, &rev, &url,
+                target_path_or_url, NULL,
+                target_peg_revision, target_peg_revision,
+                ctx, sesspool));
+      SVN_ERR(svn_client__get_history_as_mergeinfo(
+                &target_history, NULL,
+                url, rev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+                target_session, ctx, scratch_pool));
     }
   {
-    svn_revnum_t source_peg_revnum;
-
-    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_ra_session_t *source_session;
+    svn_revnum_t rev;
+    const char *url;
+
+    SVN_ERR(svn_client__ra_session_from_path(
+              &source_session, &rev, &url,
+              source_path_or_url, NULL,
+              source_peg_revision, source_peg_revision,
+              ctx, sesspool));
+    SVN_ERR(svn_client__get_history_as_mergeinfo(
+              &source_history, NULL,
+              url, rev, SVN_INVALID_REVNUM, SVN_INVALID_REVNUM,
+              source_session, ctx, scratch_pool));
   }
   /* Close the source and target sessions. */
   svn_pool_destroy(sesspool);
@@ -1896,7 +1875,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/svn-bisect/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.h?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/mergeinfo.h Mon Jul 30 06:39:28 2012
@@ -40,7 +40,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 +81,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. */
@@ -161,37 +170,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
@@ -199,7 +211,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,
@@ -277,7 +289,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 URL at PEG_REVNUM.
 
    If RANGE_YOUNGEST and RANGE_OLDEST are valid, use them to bound the
    revision ranges of returned mergeinfo.  They are governed by the same
@@ -285,10 +297,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,
+                                     const char *url,
                                      svn_revnum_t peg_revnum,
                                      svn_revnum_t range_youngest,
                                      svn_revnum_t range_oldest,
@@ -321,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.
 
@@ -360,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/svn-bisect/subversion/libsvn_client/patch.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/patch.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/patch.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/patch.c Mon Jul 30 06:39:28 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);
 

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/prop_commands.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/prop_commands.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/prop_commands.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/prop_commands.c Mon Jul 30 06:39:28 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"
 
 
@@ -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));
     }
@@ -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)
     {

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/ra.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/ra.c Mon Jul 30 06:39:28 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
@@ -403,6 +404,10 @@ svn_client_open_ra_session(svn_ra_sessio
    final resulting URL in *URL_P. REV_P and/or URL_P may be NULL if not
    wanted.
 
+   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.
 
@@ -422,9 +427,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
@@ -495,7 +501,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));
@@ -546,7 +551,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,
@@ -554,14 +559,19 @@ 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;
@@ -573,7 +583,9 @@ svn_client__repos_location_segments(apr_
  *
  * 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 required.
+ * 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,
@@ -599,9 +611,9 @@ repos_locations(const char **start_url,
       && (end_revnum == peg_revnum || end_revnum == SVN_INVALID_REVNUM))
     {
       if (start_url)
-        *start_url = url;
+        *start_url = apr_pstrdup(result_pool, url);
       if (end_url)
-        *end_url = url;
+        *end_url = apr_pstrdup(result_pool, url);
       return SVN_NO_ERROR;
     }
 
@@ -655,10 +667,15 @@ svn_client__repos_location(const char **
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool)
 {
+  const char *old_session_url;
+
+  SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url, ra_session,
+                                            peg_url, scratch_pool));
   SVN_ERR(repos_locations(op_url, NULL,
                           ra_session, peg_url, peg_revnum,
                           op_revnum, SVN_INVALID_REVNUM,
                           result_pool, scratch_pool));
+  SVN_ERR(svn_ra_reparent(ra_session, old_session_url, scratch_pool));
   return SVN_NO_ERROR;
 }
 
@@ -711,7 +728,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));
 
@@ -800,56 +817,44 @@ svn_client__repos_locations(const char *
 
 
 svn_error_t *
-svn_client__get_youngest_common_ancestor(const char **ancestor_path,
+svn_client__get_youngest_common_ancestor(const char **ancestor_relpath,
+                                         const char **ancestor_url,
                                          svn_revnum_t *ancestor_revision,
-                                         const char *path_or_url1,
+                                         const char *url1,
                                          svn_revnum_t rev1,
-                                         const char *path_or_url2,
+                                         const char *url2,
                                          svn_revnum_t rev2,
                                          svn_client_ctx_t *ctx,
                                          apr_pool_t *pool)
 {
   apr_pool_t *sesspool = svn_pool_create(pool);
-  svn_ra_session_t *session1, *session2;
+  svn_ra_session_t *session;
+  const char *repos_root_url;
   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));
-  }
+  /* Open an RA session for the two locations. */
+  SVN_ERR(svn_client_open_ra_session(&session, url1, ctx, sesspool));
+  SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, pool));
+
   /* 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,
+                                               url1, rev1,
                                                SVN_INVALID_REVNUM,
                                                SVN_INVALID_REVNUM,
-                                               session1, ctx, pool));
+                                               session, ctx, pool));
   SVN_ERR(svn_client__get_history_as_mergeinfo(&history2,
                                                &has_rev_zero_history2,
-                                               rev2,
+                                               url2, rev2,
                                                SVN_INVALID_REVNUM,
                                                SVN_INVALID_REVNUM,
-                                               session2, ctx, pool));
+                                               session, ctx, pool));
   /* Close the source and target sessions. */
   svn_pool_destroy(sesspool);
 
@@ -878,7 +883,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;
                 }
             }
         }
@@ -886,13 +891,52 @@ 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 (ancestor_relpath)
+    *ancestor_relpath = yc_relpath;
+  if (ancestor_url)
+    *ancestor_url
+      = yc_relpath ? svn_path_url_add_component2(repos_root_url, yc_relpath,
+                                                 pool) : NULL;
+  if (ancestor_revision)
+    *ancestor_revision = yc_revision;
+  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;
+  const char *url1, *url2;
+  svn_revnum_t rev1, rev2;
+
+  /* Resolve the two locations */
+  SVN_ERR(svn_client__ra_session_from_path(&session, &rev1, &url1,
+                                           path_or_url1, NULL,
+                                           revision1, revision1,
+                                           ctx, sesspool));
+  SVN_ERR(resolve_rev_and_url(&rev2, &url2, session,
+                              path_or_url2, revision2, revision2,
+                              ctx, scratch_pool));
+
+  SVN_ERR(svn_client__get_youngest_common_ancestor(
+            NULL, ancestor_url, ancestor_rev,
+            url1, rev1, url2, rev2, ctx, result_pool));
+
+  svn_pool_destroy(sesspool);
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/repos_diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/repos_diff.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/repos_diff.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/repos_diff.c Mon Jul 30 06:39:28 2012
@@ -478,38 +478,84 @@ open_root(void *edit_baton,
   return SVN_NO_ERROR;
 }
 
-/* Recursively walk tree rooted at DIR (at REVISION) in the repository,
+/* Compare a file being deleted against an empty file.
+ */
+static svn_error_t *
+diff_deleted_file(svn_wc_notify_state_t *state_p,
+                  svn_boolean_t *tree_conflicted_p,
+                  const char *path,
+                  struct edit_baton *eb,
+                  apr_pool_t *scratch_pool)
+{
+  struct file_baton *b = make_file_baton(path, FALSE, eb, scratch_pool);
+/*  struct edit_baton *eb = b->edit_baton;*/
+  const char *mimetype1, *mimetype2;
+
+  if (eb->cancel_func)
+    SVN_ERR(eb->cancel_func(eb->cancel_baton));
+
+  if (eb->text_deltas)
+    SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool));
+  else
+    SVN_ERR(get_empty_file(eb, &b->path_start_revision));
+  SVN_ERR(get_empty_file(eb, &b->path_end_revision));
+  get_file_mime_types(&mimetype1, &mimetype2, b);
+
+  SVN_ERR(eb->diff_callbacks->file_deleted(state_p, tree_conflicted_p,
+                                           b->path,
+                                           b->path_start_revision,
+                                           b->path_end_revision,
+                                           mimetype1, mimetype2,
+                                           b->pristine_props,
+                                           eb->diff_cmd_baton,
+                                           scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Recursively walk tree rooted at DIR (at EB->revision) in the repository,
  * reporting all children as deleted.  Part of a workaround for issue 2333.
  *
- * DIR is a repository path relative to the URL in RA_SESSION.  REVISION
- * must be a valid revision number, not SVN_INVALID_REVNUM.  EB is the
- * overall crawler editor baton.  If CANCEL_FUNC is not NULL, then it
- * should refer to a cancellation function (along with CANCEL_BATON).
+ * DIR is a repository path relative to the URL in EB->ra_session.  EB is
+ * the overall crawler editor baton.  EB->revision must be a valid revision
+ * number, not SVN_INVALID_REVNUM.  Use EB->cancel_func (if not null) with
+ * EB->cancel_baton for cancellation.
  */
 /* ### TODO: Handle depth. */
 static svn_error_t *
-diff_deleted_dir(const char *dir,
-                 svn_revnum_t revision,
-                 svn_ra_session_t *ra_session,
+diff_deleted_dir(svn_wc_notify_state_t *state_p,
+                 svn_boolean_t *tree_conflicted_p,
+                 const char *dir,
                  struct edit_baton *eb,
-                 svn_cancel_func_t cancel_func,
-                 void *cancel_baton,
                  apr_pool_t *pool)
 {
   apr_hash_t *dirents;
   apr_pool_t *iterpool = svn_pool_create(pool);
   apr_hash_index_t *hi;
 
-  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
+  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(eb->revision));
 
-  if (cancel_func)
-    SVN_ERR(cancel_func(cancel_baton));
+  if (eb->cancel_func)
+    SVN_ERR(eb->cancel_func(eb->cancel_baton));
 
-  SVN_ERR(svn_ra_get_dir2(ra_session,
+  SVN_ERR(eb->diff_callbacks->dir_deleted(
+                        state_p, tree_conflicted_p, dir,
+                        eb->diff_cmd_baton, pool));
+
+  /* The "old" dir will be skipped by the repository report.  If required,
+   * crawl it recursively, diffing each file against the empty file.  This
+   * is a workaround for issue 2333 "'svn diff URL1 URL2' not reverse of
+   * 'svn diff URL2 URL1'". */
+  if (! eb->walk_deleted_repos_dirs)
+    {
+      svn_pool_destroy(iterpool);
+      return SVN_NO_ERROR;
+    }
+
+  SVN_ERR(svn_ra_get_dir2(eb->ra_session,
                           &dirents,
                           NULL, NULL,
                           dir,
-                          revision,
+                          eb->revision,
                           SVN_DIRENT_KIND,
                           pool));
 
@@ -526,42 +572,12 @@ diff_deleted_dir(const char *dir,
 
       if (dirent->kind == svn_node_file)
         {
-          struct file_baton *b;
-          const char *mimetype1, *mimetype2;
-
-          /* Compare a file being deleted against an empty file */
-          b = make_file_baton(path, FALSE, eb, iterpool);
-          if (eb->text_deltas)
-            SVN_ERR(get_file_from_ra(b, FALSE, iterpool));
-          else
-            SVN_ERR(get_empty_file(eb, &b->path_start_revision));
-
-          SVN_ERR(get_empty_file(b->edit_baton, &(b->path_end_revision)));
-
-          get_file_mime_types(&mimetype1, &mimetype2, b);
-
-          SVN_ERR(eb->diff_callbacks->file_deleted(
-                                NULL, NULL, b->path,
-                                b->path_start_revision,
-                                b->path_end_revision,
-                                mimetype1, mimetype2,
-                                b->pristine_props,
-                                b->edit_baton->diff_cmd_baton,
-                                iterpool));
+          SVN_ERR(diff_deleted_file(NULL, NULL, path, eb, iterpool));
         }
 
       if (dirent->kind == svn_node_dir)
         {
-          SVN_ERR(eb->diff_callbacks->dir_deleted(
-                                NULL, NULL, path,
-                                eb->diff_cmd_baton, iterpool));
-          SVN_ERR(diff_deleted_dir(path,
-                                   revision,
-                                   ra_session,
-                                   eb,
-                                   cancel_func,
-                                   cancel_baton,
-                                   iterpool));
+          SVN_ERR(diff_deleted_dir(NULL, NULL, path, eb, iterpool));
         }
     }
 
@@ -599,51 +615,14 @@ delete_entry(const char *path,
     {
     case svn_node_file:
       {
-        const char *mimetype1, *mimetype2;
-        struct file_baton *b;
-
-        /* Compare a file being deleted against an empty file */
-        b = make_file_baton(path, FALSE, eb, scratch_pool);
-        if (eb->text_deltas)
-          SVN_ERR(get_file_from_ra(b, FALSE, scratch_pool));
-        else
-          SVN_ERR(get_empty_file(eb, &b->path_start_revision));
-
-        SVN_ERR(get_empty_file(b->edit_baton, &(b->path_end_revision)));
-
-        get_file_mime_types(&mimetype1, &mimetype2, b);
-
-        SVN_ERR(eb->diff_callbacks->file_deleted(
-                     &state, &tree_conflicted, b->path,
-                     b->path_start_revision,
-                     b->path_end_revision,
-                     mimetype1, mimetype2,
-                     b->pristine_props,
-                     b->edit_baton->diff_cmd_baton,
-                     scratch_pool));
-
+        SVN_ERR(diff_deleted_file(&state, &tree_conflicted, path, eb,
+                                  scratch_pool));
         break;
       }
     case svn_node_dir:
       {
-        SVN_ERR(eb->diff_callbacks->dir_deleted(
-                     &state, &tree_conflicted,
-                     path,
-                     eb->diff_cmd_baton, scratch_pool));
-
-        if (eb->walk_deleted_repos_dirs)
-          {
-            /* A workaround for issue 2333.  The "old" dir will be
-            skipped by the repository report.  Crawl it recursively,
-            diffing each file against the empty file. */
-            SVN_ERR(diff_deleted_dir(path,
-                                     eb->revision,
-                                     eb->ra_session,
-                                     eb,
-                                     eb->cancel_func,
-                                     eb->cancel_baton,
-                                     scratch_pool));
-          }
+        SVN_ERR(diff_deleted_dir(&state, &tree_conflicted, path, eb,
+                                 scratch_pool));
         break;
       }
     default:
@@ -1328,6 +1307,96 @@ absent_file(const char *path,
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+fetch_kind_func(svn_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  svn_node_kind_t node_kind;
+
+  SVN_ERR(svn_ra_check_path(eb->ra_session, path, eb->revision, &node_kind,
+                            scratch_pool));
+
+  *kind = svn__kind_from_node_kind(node_kind, FALSE);
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+                 void *baton,
+                 const char *path,
+                 svn_revnum_t base_revision,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  svn_node_kind_t node_kind;
+
+  SVN_ERR(svn_ra_check_path(eb->ra_session, path, eb->revision, &node_kind,
+                            scratch_pool));
+
+  if (node_kind == svn_node_file)
+    {
+      SVN_ERR(svn_ra_get_file(eb->ra_session, path, eb->revision,
+                              NULL, NULL, props, result_pool));
+    }
+  else if (node_kind == svn_node_dir)
+    {
+      apr_array_header_t *tmp_props;
+
+      SVN_ERR(svn_ra_get_dir2(eb->ra_session, NULL, NULL, props, path,
+                              eb->revision, 0 /* Dirent fields */,
+                              result_pool));
+      tmp_props = svn_prop_hash_to_array(*props, result_pool);
+      SVN_ERR(svn_categorize_props(tmp_props, NULL, NULL, &tmp_props,
+                                   result_pool));
+      *props = svn_prop_array_to_hash(tmp_props, result_pool);
+    }
+  else
+    {
+      *props = apr_hash_make(result_pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_base_func(const char **filename,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  struct edit_baton *eb = baton;
+  svn_stream_t *fstream;
+  svn_error_t *err;
+
+  SVN_ERR(svn_stream_open_unique(&fstream, filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 result_pool, scratch_pool));
+
+  err = svn_ra_get_file(eb->ra_session, path, eb->revision,
+                        fstream, NULL, NULL, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_FS_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      SVN_ERR(svn_stream_close(fstream));
+
+      *filename = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (err)
+    return svn_error_trace(err);
+  
+  SVN_ERR(svn_stream_close(fstream));
+
+  return SVN_NO_ERROR;
+}
+
 /* Create a repository diff editor and baton.  */
 svn_error_t *
 svn_client__get_diff_editor(const svn_delta_editor_t **editor,
@@ -1389,6 +1458,11 @@ svn_client__get_diff_editor(const svn_de
                                             editor, edit_baton,
                                             eb->pool));
 
+  shim_callbacks->fetch_kind_func = fetch_kind_func;
+  shim_callbacks->fetch_props_func = fetch_props_func;
+  shim_callbacks->fetch_base_func = fetch_base_func;
+  shim_callbacks->fetch_baton = eb;
+
   SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
                                    shim_callbacks,
                                    result_pool, result_pool));

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/status.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/status.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/status.c Mon Jul 30 06:39:28 2012
@@ -374,7 +374,7 @@ svn_client_status5(svn_revnum_t *result_
       SVN_ERR(svn_ra_has_capability(ra_session, &server_supports_depth,
                                     SVN_RA_CAPABILITY_DEPTH, pool));
 
-      SVN_ERR(svn_wc_get_status_editor5(&editor, &edit_baton, &set_locks_baton,
+      SVN_ERR(svn_wc__get_status_editor(&editor, &edit_baton, &set_locks_baton,
                                     &edit_revision, ctx->wc_ctx,
                                     dir_abspath, target_basename,
                                     depth, get_all,

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/switch.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/switch.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/switch.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/switch.c Mon Jul 30 06:39:28 2012
@@ -197,7 +197,7 @@ switch_internal(svn_revnum_t *result_rev
      ### okay? */
   if (! ignore_ancestry)
     {
-      const char *target_url, *yc_path;
+      const char *target_url, *yc_url;
       svn_revnum_t target_rev, yc_rev;
 
       SVN_ERR(svn_wc__node_get_url(&target_url, ctx->wc_ctx, local_abspath,
@@ -206,11 +206,11 @@ switch_internal(svn_revnum_t *result_rev
                                         local_abspath, pool));
       /* ### It would be nice if this function could reuse the existing
              ra session instead of opening two for its own use. */
-      SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_path, &yc_rev,
+      SVN_ERR(svn_client__get_youngest_common_ancestor(NULL, &yc_url, &yc_rev,
                                                        switch_rev_url, revnum,
                                                        target_url, target_rev,
                                                        ctx, pool));
-      if (! (yc_path && SVN_IS_VALID_REVNUM(yc_rev)))
+      if (! (yc_url && SVN_IS_VALID_REVNUM(yc_rev)))
         return svn_error_createf(SVN_ERR_CLIENT_UNRELATED_RESOURCES, NULL,
                                  _("'%s' shares no common ancestry with '%s'"),
                                  switch_url, local_abspath);
@@ -228,7 +228,7 @@ switch_internal(svn_revnum_t *result_rev
   SVN_ERR(svn_ra_get_session_url(ra_session, &dfb.anchor_url, pool));
   dfb.target_revision = revnum;
 
-  SVN_ERR(svn_wc_get_switch_editor4(&switch_editor, &switch_edit_baton,
+  SVN_ERR(svn_wc__get_switch_editor(&switch_editor, &switch_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
                                     target, switch_rev_url, use_commit_times,
                                     depth,

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/update.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/update.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/update.c Mon Jul 30 06:39:28 2012
@@ -370,7 +370,7 @@ update_internal(svn_revnum_t *result_rev
 
   /* Fetch the update editor.  If REVISION is invalid, that's okay;
      the RA driver will call editor->set_target_revision later on. */
-  SVN_ERR(svn_wc_get_update_editor4(&update_editor, &update_edit_baton,
+  SVN_ERR(svn_wc__get_update_editor(&update_editor, &update_edit_baton,
                                     &revnum, ctx->wc_ctx, anchor_abspath,
                                     target, use_commit_times, depth,
                                     depth_is_sticky, allow_unver_obstructions,

Modified: subversion/branches/svn-bisect/subversion/libsvn_client/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-bisect/subversion/libsvn_client/util.c?rev=1367002&r1=1367001&r2=1367002&view=diff
==============================================================================
--- subversion/branches/svn-bisect/subversion/libsvn_client/util.c (original)
+++ subversion/branches/svn-bisect/subversion/libsvn_client/util.c Mon Jul 30 06:39:28 2012
@@ -240,3 +240,102 @@ svn_client__assert_homogeneous_target_ty
 
   return SVN_NO_ERROR;
 }
+
+struct shim_callbacks_baton
+{
+  svn_wc_context_t *wc_ctx;
+  const char *anchor_abspath;
+};
+
+static svn_error_t *
+fetch_props_func(apr_hash_t **props,
+                 void *baton,
+                 const char *path,
+                 svn_revnum_t base_revision,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  struct shim_callbacks_baton *scb = baton;
+  const char *local_abspath = svn_dirent_join(scb->anchor_abspath, path,
+                                              scratch_pool);
+
+  SVN_ERR(svn_wc_get_pristine_props(props, scb->wc_ctx, local_abspath,
+                                    result_pool, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_kind_func(svn_kind_t *kind,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *scratch_pool)
+{
+  struct shim_callbacks_baton *scb = baton;
+  svn_node_kind_t node_kind;
+  const char *local_abspath = svn_dirent_join(scb->anchor_abspath, path,
+                                              scratch_pool);
+
+  SVN_ERR(svn_wc_read_kind(&node_kind, scb->wc_ctx, local_abspath, FALSE,
+                           scratch_pool));
+  *kind = svn__kind_from_node_kind(node_kind, FALSE);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fetch_base_func(const char **filename,
+                void *baton,
+                const char *path,
+                svn_revnum_t base_revision,
+                apr_pool_t *result_pool,
+                apr_pool_t *scratch_pool)
+{
+  struct shim_callbacks_baton *scb = baton;
+  const char *local_abspath = svn_dirent_join(scb->anchor_abspath, path,
+                                              scratch_pool);
+  svn_stream_t *pristine_stream;
+  svn_stream_t *temp_stream;
+  svn_error_t *err;
+
+  err = svn_wc_get_pristine_contents2(&pristine_stream, scb->wc_ctx,
+                                      local_abspath, scratch_pool,
+                                      scratch_pool);
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+      *filename = NULL;
+      return SVN_NO_ERROR;
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  SVN_ERR(svn_stream_open_unique(&temp_stream, filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 result_pool, scratch_pool));
+  SVN_ERR(svn_stream_copy3(pristine_stream, temp_stream, NULL, NULL,
+                           scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_delta_shim_callbacks_t *
+svn_client__get_shim_callbacks(svn_wc_context_t *wc_ctx,
+                               const char *anchor_abspath,
+                               apr_pool_t *result_pool)
+{
+  svn_delta_shim_callbacks_t *callbacks = 
+                            svn_delta_shim_callbacks_default(result_pool);
+  struct shim_callbacks_baton *scb = apr_pcalloc(result_pool, sizeof(*scb));
+
+  scb->wc_ctx = wc_ctx;
+  scb->anchor_abspath = apr_pstrdup(result_pool, anchor_abspath);
+
+  callbacks->fetch_props_func = fetch_props_func;
+  callbacks->fetch_kind_func = fetch_kind_func;
+  callbacks->fetch_base_func = fetch_base_func;
+  callbacks->fetch_baton = scb;
+
+  return callbacks;
+}