svn commit: r1922065 - in /subversion/branches/apply-processor/subversion/libsvn_client: merge.c merge_processor.c

[email protected]
Newsgroups gmane.comp.version-control.subversion.svn
Message-ID <[email protected]>
Author: rinrab
Date: Sun Nov 24 23:32:26 2024
New Revision: 1922065

URL: http://svn.apache.org/viewvc?rev=1922065&view=rev
Log:
On the 'apply-processor' branch: (going to follow up r1922048)

Move filter_self_referential_mergeinfo() function back to the merge.c
file from merge_processor.c. Also move the split_mergeinfo_on_revision()
function there as a dependency.

I just noticed that we'll need it there.

Note: these functions are not being referenced from anywhere, since all the
usages are currently disabled using #if TODO_FILTER_MERGEINFO, so there are
no functional changes, only the move of unreferenced function.

* subversion/libsvn_client/merge_processor.c
  (split_mergeinfo_on_revision,
   filter_self_referential_mergeinfo): moved from...

* subversion/libsvn_client/merge.c
  (split_mergeinfo_on_revision,
   filter_self_referential_mergeinfo): ...moved to

Modified:
    subversion/branches/apply-processor/subversion/libsvn_client/merge.c
    subversion/branches/apply-processor/subversion/libsvn_client/merge_processor.c

Modified: subversion/branches/apply-processor/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/apply-processor/subversion/libsvn_client/merge.c?rev=1922065&r1=1922064&r2=1922065&view=diff
==============================================================================
--- subversion/branches/apply-processor/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/apply-processor/subversion/libsvn_client/merge.c Sun Nov 24 23:32:26 2024
@@ -604,6 +604,380 @@ find_nearest_ancestor(const apr_array_he
   return NULL;
 }
 
+
+/* Helper for filter_self_referential_mergeinfo()
+
+   *MERGEINFO is a non-empty, non-null collection of mergeinfo.
+
+   Remove all mergeinfo from *MERGEINFO that describes revision ranges
+   greater than REVISION.  Put a copy of any removed mergeinfo, allocated
+   in POOL, into *YOUNGER_MERGEINFO.
+
+   If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set
+   to NULL.  If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is
+   set to NULL.
+   */
+static svn_error_t*
+split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo,
+                            svn_mergeinfo_t *mergeinfo,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool)
+{
+  apr_hash_index_t *hi;
+  apr_pool_t *iterpool = svn_pool_create(pool);
+
+  *younger_mergeinfo = NULL;
+  for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi))
+    {
+      int i;
+      const char *merge_source_path = apr_hash_this_key(hi);
+      svn_rangelist_t *rangelist = apr_hash_this_val(hi);
+
+      svn_pool_clear(iterpool);
+
+      for (i = 0; i < rangelist->nelts; i++)
+        {
+          svn_merge_range_t *range =
+            APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
+          if (range->end <= revision)
+            {
+              /* This entirely of this range is as old or older than
+                 REVISION, so leave it in *MERGEINFO. */
+              continue;
+            }
+          else
+            {
+              /* Since the rangelists in svn_mergeinfo_t's are sorted in
+                 increasing order we know that part or all of *this* range
+                 and *all* of the remaining ranges in *RANGELIST are younger
+                 than REVISION.  Remove the younger rangelists from
+                 *MERGEINFO and put them in *YOUNGER_MERGEINFO. */
+              int j;
+              svn_rangelist_t *younger_rangelist =
+                apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
+
+              for (j = i; j < rangelist->nelts; j++)
+                {
+                  svn_merge_range_t *younger_range = svn_merge_range_dup(
+                    APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool);
+
+                  /* REVISION might intersect with the first range where
+                     range->end > REVISION.  If that is the case then split
+                     the current range into two, putting the younger half
+                     into *YOUNGER_MERGEINFO and leaving the older half in
+                     *MERGEINFO. */
+                  if (j == i && range->start + 1 <= revision)
+                    younger_range->start = range->end = revision;
+
+                  APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) =
+                    younger_range;
+                }
+
+              /* So far we've only been manipulating rangelists, now we
+                 actually create *YOUNGER_MERGEINFO and then remove the older
+                 ranges from *MERGEINFO */
+              if (!(*younger_mergeinfo))
+                *younger_mergeinfo = apr_hash_make(pool);
+              svn_hash_sets(*younger_mergeinfo, merge_source_path,
+                            younger_rangelist);
+              SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo,
+                                            *mergeinfo, TRUE, pool, iterpool));
+              break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */
+            }
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+
+/* Helper for merge_props_changed().
+
+   *PROPS is an array of svn_prop_t structures representing regular properties
+   to be added to the working copy TARGET_ABSPATH.
+
+   The merge source and target are assumed to be in the same repository.
+
+   Filter out mergeinfo property additions to TARGET_ABSPATH when
+   those additions refer to the same line of history as TARGET_ABSPATH as
+   described below.
+
+   Examine the added mergeinfo, looking at each range (or single rev)
+   of each source path.  If a source_path/range refers to the same line of
+   history as TARGET_ABSPATH (pegged at its base revision), then filter out
+   that range.  If the entire rangelist for a given path is filtered then
+   filter out the path as well.
+
+   RA_SESSION is an open RA session to the repository
+   in which both the source and target live, else RA_SESSION is not used. It
+   may be temporarily reparented as needed by this function.
+
+   Use CTX for any further client operations.
+
+   If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated
+   in POOL) of incoming *PROPS minus the filtered mergeinfo. */
+static svn_error_t *
+filter_self_referential_mergeinfo(apr_array_header_t **props,
+                                  const char *target_abspath,
+                                  svn_ra_session_t *ra_session,
+                                  svn_client_ctx_t *ctx,
+                                  apr_pool_t *pool)
+{
+  apr_array_header_t *adjusted_props;
+  int i;
+  apr_pool_t *iterpool;
+  svn_boolean_t is_copy;
+  const char *repos_relpath;
+  svn_client__pathrev_t target_base;
+
+  /* If PATH itself has been added there is no need to filter. */
+  SVN_ERR(svn_wc__node_get_origin(&is_copy,  &target_base.rev, &repos_relpath,
+                                  &target_base.repos_root_url,
+                                  &target_base.repos_uuid, NULL, NULL,
+                                  ctx->wc_ctx, target_abspath, FALSE,
+                                  pool, pool));
+
+  if (is_copy || !repos_relpath)
+    return SVN_NO_ERROR; /* A copy or a local addition */
+
+  target_base.url = svn_path_url_add_component2(target_base.repos_root_url,
+                                                repos_relpath, pool);
+
+  adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < (*props)->nelts; ++i)
+    {
+      svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t);
+
+      svn_mergeinfo_t mergeinfo, younger_mergeinfo;
+      svn_mergeinfo_t filtered_mergeinfo = NULL;
+      svn_mergeinfo_t filtered_younger_mergeinfo = NULL;
+      svn_error_t *err;
+
+      /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal)
+         or empty mergeinfo it does not require any special handling.  There
+         is nothing to filter out of empty mergeinfo and the concept of
+         filtering doesn't apply if we are trying to remove mergeinfo
+         entirely.  */
+      if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0)
+          || (! prop->value)       /* Removal of mergeinfo */
+          || (! prop->value->len)) /* Empty mergeinfo */
+        {
+          APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
+          continue;
+        }
+
+      svn_pool_clear(iterpool);
+
+      /* Non-empty mergeinfo; filter self-referential mergeinfo out. */
+
+      /* Parse the incoming mergeinfo to allow easier manipulation. */
+      err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool);
+
+      if (err)
+        {
+          /* Issue #3896: If we can't parse it, we certainly can't
+             filter it. */
+          if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
+            {
+              svn_error_clear(err);
+              APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
+              continue;
+            }
+          else
+            {
+              return svn_error_trace(err);
+            }
+        }
+
+      /* The working copy target PATH is at BASE_REVISION.  Divide the
+         incoming mergeinfo into two groups.  One where all revision ranges
+         are as old or older than BASE_REVISION and one where all revision
+         ranges are younger.
+
+         Note: You may be wondering why we do this.
+
+         For the incoming mergeinfo "older" than target's base revision we
+         can filter out self-referential mergeinfo efficiently using
+         svn_client__get_history_as_mergeinfo().  We simply look at PATH's
+         natural history as mergeinfo and remove that from any incoming
+         mergeinfo.
+
+         For mergeinfo "younger" than the base revision we can't use
+         svn_ra_get_location_segments() to look into PATH's future
+         history.  Instead we must use svn_client__repos_locations() and
+         look at each incoming source/range individually and see if PATH
+         at its base revision and PATH at the start of the incoming range
+         exist on the same line of history.  If they do then we can filter
+         out the incoming range.  But since we have to do this for each
+         range there is a substantial performance penalty to pay if the
+         incoming ranges are not contiguous, i.e. we call
+         svn_client__repos_locations for each discrete range and incur
+         the cost of a roundtrip communication with the repository. */
+      SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo,
+                                          &mergeinfo,
+                                          target_base.rev,
+                                          iterpool));
+
+      /* Filter self-referential mergeinfo from younger_mergeinfo. */
+      if (younger_mergeinfo)
+        {
+          apr_hash_index_t *hi;
+          const char *merge_source_root_url;
+
+          SVN_ERR(svn_ra_get_repos_root2(ra_session,
+                                         &merge_source_root_url, iterpool));
+
+          for (hi = apr_hash_first(iterpool, younger_mergeinfo);
+               hi; hi = apr_hash_next(hi))
+            {
+              int j;
+              const char *source_path = apr_hash_this_key(hi);
+              svn_rangelist_t *rangelist = apr_hash_this_val(hi);
+              const char *merge_source_url;
+              svn_rangelist_t *adjusted_rangelist =
+                apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
+
+              merge_source_url =
+                    svn_path_url_add_component2(merge_source_root_url,
+                                                source_path + 1, iterpool);
+
+              for (j = 0; j < rangelist->nelts; j++)
+                {
+                  svn_error_t *err2;
+                  svn_client__pathrev_t *start_loc;
+                  svn_merge_range_t *range =
+                    APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *);
+
+                  /* Because the merge source normalization code
+                     ensures mergeinfo refers to real locations on
+                     the same line of history, there's no need to
+                     look at the whole range, just the start. */
+
+                  /* Check if PATH@BASE_REVISION exists at
+                     RANGE->START on the same line of history.
+                     (start+1 because RANGE->start is not inclusive.) */
+                  err2 = svn_client__repos_location(&start_loc, ra_session,
+                                                    &target_base,
+                                                    range->start + 1,
+                                                    ctx, iterpool, iterpool);
+                  if (err2)
+                    {
+                      if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES
+                          || err2->apr_err == SVN_ERR_FS_NOT_FOUND
+                          || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
+                        {
+                          /* PATH@BASE_REVISION didn't exist at
+                             RANGE->START + 1 or is unrelated to the
+                             resource PATH@RANGE->START.  Some of the
+                             requested revisions may not even exist in
+                             the repository; a real possibility since
+                             mergeinfo is hand editable.  In all of these
+                             cases clear and ignore the error and don't
+                             do any filtering.
+
+                             Note: In this last case it is possible that
+                             we will allow self-referential mergeinfo to
+                             be applied, but fixing it here is potentially
+                             very costly in terms of finding what part of
+                             a range is actually valid.  Simply allowing
+                             the merge to proceed without filtering the
+                             offending range seems the least worst
+                             option. */
+                          svn_error_clear(err2);
+                          err2 = NULL;
+                          APR_ARRAY_PUSH(adjusted_rangelist,
+                                         svn_merge_range_t *) = range;
+                        }
+                      else
+                        {
+                          return svn_error_trace(err2);
+                        }
+                     }
+                  else
+                    {
+                      /* PATH@BASE_REVISION exists on the same
+                         line of history at RANGE->START and RANGE->END.
+                         Now check that PATH@BASE_REVISION's path
+                         names at RANGE->START and RANGE->END are the same.
+                         If the names are not the same then the mergeinfo
+                         describing PATH@RANGE->START through
+                         PATH@RANGE->END actually belong to some other
+                         line of history and we want to record this
+                         mergeinfo, not filter it. */
+                      if (strcmp(start_loc->url, merge_source_url) != 0)
+                        {
+                          APR_ARRAY_PUSH(adjusted_rangelist,
+                                         svn_merge_range_t *) = range;
+                        }
+                    }
+                    /* else no need to add, this mergeinfo is
+                       all on the same line of history. */
+                } /* for (j = 0; j < rangelist->nelts; j++) */
+
+              /* Add any rangelists for source_path that are not
+                 self-referential. */
+              if (adjusted_rangelist->nelts)
+                {
+                  if (!filtered_younger_mergeinfo)
+                    filtered_younger_mergeinfo = apr_hash_make(iterpool);
+                  svn_hash_sets(filtered_younger_mergeinfo, source_path,
+                                adjusted_rangelist);
+                }
+
+            } /* Iteration over each merge source in younger_mergeinfo. */
+        } /* if (younger_mergeinfo) */
+
+      /* Filter self-referential mergeinfo from "older" mergeinfo. */
+      if (mergeinfo)
+        {
+          svn_mergeinfo_t implicit_mergeinfo;
+
+          SVN_ERR(svn_client__get_history_as_mergeinfo(
+            &implicit_mergeinfo, NULL,
+            &target_base, target_base.rev, SVN_INVALID_REVNUM,
+            ra_session, ctx, iterpool));
+
+          /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
+          SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
+                                        implicit_mergeinfo,
+                                        mergeinfo, TRUE, iterpool, iterpool));
+        }
+
+      /* Combine whatever older and younger filtered mergeinfo exists
+         into filtered_mergeinfo. */
+      if (filtered_mergeinfo && filtered_younger_mergeinfo)
+        SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo,
+                                     filtered_younger_mergeinfo, iterpool,
+                                     iterpool));
+      else if (filtered_younger_mergeinfo)
+        filtered_mergeinfo = filtered_younger_mergeinfo;
+
+      /* If there is any incoming mergeinfo remaining after filtering
+         then put it in adjusted_props. */
+      if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo))
+        {
+          /* Convert filtered_mergeinfo to a svn_prop_t and put it
+             back in the array. */
+          svn_string_t *filtered_mergeinfo_str;
+          svn_prop_t *adjusted_prop = apr_pcalloc(pool,
+                                                  sizeof(*adjusted_prop));
+          SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str,
+                                          filtered_mergeinfo,
+                                          pool));
+          adjusted_prop->name = SVN_PROP_MERGEINFO;
+          adjusted_prop->value = filtered_mergeinfo_str;
+          APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop;
+        }
+    }
+  svn_pool_destroy(iterpool);
+
+  *props = adjusted_props;
+  return SVN_NO_ERROR;
+}
+
 /* Find the highest level path in a merge target (possibly the merge target
    itself) to use in a merge notification header.
 

Modified: subversion/branches/apply-processor/subversion/libsvn_client/merge_processor.c
URL: http://svn.apache.org/viewvc/subversion/branches/apply-processor/subversion/libsvn_client/merge_processor.c?rev=1922065&r1=1922064&r2=1922065&view=diff
==============================================================================
--- subversion/branches/apply-processor/subversion/libsvn_client/merge_processor.c (original)
+++ subversion/branches/apply-processor/subversion/libsvn_client/merge_processor.c Sun Nov 24 23:32:26 2024
@@ -233,405 +233,6 @@ make_conflict_versions(const svn_wc_conf
   return SVN_NO_ERROR;
 }
 
-/* Helper for filter_self_referential_mergeinfo()
-
-   *MERGEINFO is a non-empty, non-null collection of mergeinfo.
-
-   Remove all mergeinfo from *MERGEINFO that describes revision ranges
-   greater than REVISION.  Put a copy of any removed mergeinfo, allocated
-   in POOL, into *YOUNGER_MERGEINFO.
-
-   If no mergeinfo is removed from *MERGEINFO then *YOUNGER_MERGEINFO is set
-   to NULL.  If all mergeinfo is removed from *MERGEINFO then *MERGEINFO is
-   set to NULL.
-   */
-static svn_error_t*
-split_mergeinfo_on_revision(svn_mergeinfo_t *younger_mergeinfo,
-                            svn_mergeinfo_t *mergeinfo,
-                            svn_revnum_t revision,
-                            apr_pool_t *pool)
-{
-  apr_hash_index_t *hi;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-
-  *younger_mergeinfo = NULL;
-  for (hi = apr_hash_first(pool, *mergeinfo); hi; hi = apr_hash_next(hi))
-    {
-      int i;
-      const char *merge_source_path = apr_hash_this_key(hi);
-      svn_rangelist_t *rangelist = apr_hash_this_val(hi);
-
-      svn_pool_clear(iterpool);
-
-      for (i = 0; i < rangelist->nelts; i++)
-        {
-          svn_merge_range_t *range =
-            APR_ARRAY_IDX(rangelist, i, svn_merge_range_t *);
-          if (range->end <= revision)
-            {
-              /* This entirely of this range is as old or older than
-                 REVISION, so leave it in *MERGEINFO. */
-              continue;
-            }
-          else
-            {
-              /* Since the rangelists in svn_mergeinfo_t's are sorted in
-                 increasing order we know that part or all of *this* range
-                 and *all* of the remaining ranges in *RANGELIST are younger
-                 than REVISION.  Remove the younger rangelists from
-                 *MERGEINFO and put them in *YOUNGER_MERGEINFO. */
-              int j;
-              svn_rangelist_t *younger_rangelist =
-                apr_array_make(pool, 1, sizeof(svn_merge_range_t *));
-
-              for (j = i; j < rangelist->nelts; j++)
-                {
-                  svn_merge_range_t *younger_range = svn_merge_range_dup(
-                    APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *), pool);
-
-                  /* REVISION might intersect with the first range where
-                     range->end > REVISION.  If that is the case then split
-                     the current range into two, putting the younger half
-                     into *YOUNGER_MERGEINFO and leaving the older half in
-                     *MERGEINFO. */
-                  if (j == i && range->start + 1 <= revision)
-                    younger_range->start = range->end = revision;
-
-                  APR_ARRAY_PUSH(younger_rangelist, svn_merge_range_t *) =
-                    younger_range;
-                }
-
-              /* So far we've only been manipulating rangelists, now we
-                 actually create *YOUNGER_MERGEINFO and then remove the older
-                 ranges from *MERGEINFO */
-              if (!(*younger_mergeinfo))
-                *younger_mergeinfo = apr_hash_make(pool);
-              svn_hash_sets(*younger_mergeinfo, merge_source_path,
-                            younger_rangelist);
-              SVN_ERR(svn_mergeinfo_remove2(mergeinfo, *younger_mergeinfo,
-                                            *mergeinfo, TRUE, pool, iterpool));
-              break; /* ...out of for (i = 0; i < rangelist->nelts; i++) */
-            }
-        }
-    }
-
-  svn_pool_destroy(iterpool);
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Make a copy of PROPCHANGES (array of svn_prop_t) into *TRIMMED_PROPCHANGES,
-   omitting any svn:mergeinfo changes.  */
-static svn_error_t *
-omit_mergeinfo_changes(apr_array_header_t **trimmed_propchanges,
-                       const apr_array_header_t *propchanges,
-                       apr_pool_t *result_pool)
-{
-  int i;
-
-  *trimmed_propchanges = apr_array_make(result_pool,
-                                        propchanges->nelts,
-                                        sizeof(svn_prop_t));
-
-  for (i = 0; i < propchanges->nelts; ++i)
-    {
-      const svn_prop_t *change = &APR_ARRAY_IDX(propchanges, i, svn_prop_t);
-
-      /* If this property is not svn:mergeinfo, then copy it.  */
-      if (strcmp(change->name, SVN_PROP_MERGEINFO) != 0)
-        APR_ARRAY_PUSH(*trimmed_propchanges, svn_prop_t) = *change;
-    }
-
-  return SVN_NO_ERROR;
-}
-
-
-/* Helper for merge_props_changed().
-
-   *PROPS is an array of svn_prop_t structures representing regular properties
-   to be added to the working copy TARGET_ABSPATH.
-
-   The merge source and target are assumed to be in the same repository.
-
-   Filter out mergeinfo property additions to TARGET_ABSPATH when
-   those additions refer to the same line of history as TARGET_ABSPATH as
-   described below.
-
-   Examine the added mergeinfo, looking at each range (or single rev)
-   of each source path.  If a source_path/range refers to the same line of
-   history as TARGET_ABSPATH (pegged at its base revision), then filter out
-   that range.  If the entire rangelist for a given path is filtered then
-   filter out the path as well.
-
-   RA_SESSION is an open RA session to the repository
-   in which both the source and target live, else RA_SESSION is not used. It
-   may be temporarily reparented as needed by this function.
-
-   Use CTX for any further client operations.
-
-   If any filtering occurs, set outgoing *PROPS to a shallow copy (allocated
-   in POOL) of incoming *PROPS minus the filtered mergeinfo. */
-static svn_error_t *
-filter_self_referential_mergeinfo(apr_array_header_t **props,
-                                  const char *target_abspath,
-                                  svn_ra_session_t *ra_session,
-                                  svn_client_ctx_t *ctx,
-                                  apr_pool_t *pool)
-{
-  apr_array_header_t *adjusted_props;
-  int i;
-  apr_pool_t *iterpool;
-  svn_boolean_t is_copy;
-  const char *repos_relpath;
-  svn_client__pathrev_t target_base;
-
-  /* If PATH itself has been added there is no need to filter. */
-  SVN_ERR(svn_wc__node_get_origin(&is_copy,  &target_base.rev, &repos_relpath,
-                                  &target_base.repos_root_url,
-                                  &target_base.repos_uuid, NULL, NULL,
-                                  ctx->wc_ctx, target_abspath, FALSE,
-                                  pool, pool));
-
-  if (is_copy || !repos_relpath)
-    return SVN_NO_ERROR; /* A copy or a local addition */
-
-  target_base.url = svn_path_url_add_component2(target_base.repos_root_url,
-                                                repos_relpath, pool);
-
-  adjusted_props = apr_array_make(pool, (*props)->nelts, sizeof(svn_prop_t));
-  iterpool = svn_pool_create(pool);
-  for (i = 0; i < (*props)->nelts; ++i)
-    {
-      svn_prop_t *prop = &APR_ARRAY_IDX((*props), i, svn_prop_t);
-
-      svn_mergeinfo_t mergeinfo, younger_mergeinfo;
-      svn_mergeinfo_t filtered_mergeinfo = NULL;
-      svn_mergeinfo_t filtered_younger_mergeinfo = NULL;
-      svn_error_t *err;
-
-      /* If this property isn't mergeinfo or is NULL valued (i.e. prop removal)
-         or empty mergeinfo it does not require any special handling.  There
-         is nothing to filter out of empty mergeinfo and the concept of
-         filtering doesn't apply if we are trying to remove mergeinfo
-         entirely.  */
-      if ((strcmp(prop->name, SVN_PROP_MERGEINFO) != 0)
-          || (! prop->value)       /* Removal of mergeinfo */
-          || (! prop->value->len)) /* Empty mergeinfo */
-        {
-          APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
-          continue;
-        }
-
-      svn_pool_clear(iterpool);
-
-      /* Non-empty mergeinfo; filter self-referential mergeinfo out. */
-
-      /* Parse the incoming mergeinfo to allow easier manipulation. */
-      err = svn_mergeinfo_parse(&mergeinfo, prop->value->data, iterpool);
-
-      if (err)
-        {
-          /* Issue #3896: If we can't parse it, we certainly can't
-             filter it. */
-          if (err->apr_err == SVN_ERR_MERGEINFO_PARSE_ERROR)
-            {
-              svn_error_clear(err);
-              APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *prop;
-              continue;
-            }
-          else
-            {
-              return svn_error_trace(err);
-            }
-        }
-
-      /* The working copy target PATH is at BASE_REVISION.  Divide the
-         incoming mergeinfo into two groups.  One where all revision ranges
-         are as old or older than BASE_REVISION and one where all revision
-         ranges are younger.
-
-         Note: You may be wondering why we do this.
-
-         For the incoming mergeinfo "older" than target's base revision we
-         can filter out self-referential mergeinfo efficiently using
-         svn_client__get_history_as_mergeinfo().  We simply look at PATH's
-         natural history as mergeinfo and remove that from any incoming
-         mergeinfo.
-
-         For mergeinfo "younger" than the base revision we can't use
-         svn_ra_get_location_segments() to look into PATH's future
-         history.  Instead we must use svn_client__repos_locations() and
-         look at each incoming source/range individually and see if PATH
-         at its base revision and PATH at the start of the incoming range
-         exist on the same line of history.  If they do then we can filter
-         out the incoming range.  But since we have to do this for each
-         range there is a substantial performance penalty to pay if the
-         incoming ranges are not contiguous, i.e. we call
-         svn_client__repos_locations for each discrete range and incur
-         the cost of a roundtrip communication with the repository. */
-      SVN_ERR(split_mergeinfo_on_revision(&younger_mergeinfo,
-                                          &mergeinfo,
-                                          target_base.rev,
-                                          iterpool));
-
-      /* Filter self-referential mergeinfo from younger_mergeinfo. */
-      if (younger_mergeinfo)
-        {
-          apr_hash_index_t *hi;
-          const char *merge_source_root_url;
-
-          SVN_ERR(svn_ra_get_repos_root2(ra_session,
-                                         &merge_source_root_url, iterpool));
-
-          for (hi = apr_hash_first(iterpool, younger_mergeinfo);
-               hi; hi = apr_hash_next(hi))
-            {
-              int j;
-              const char *source_path = apr_hash_this_key(hi);
-              svn_rangelist_t *rangelist = apr_hash_this_val(hi);
-              const char *merge_source_url;
-              svn_rangelist_t *adjusted_rangelist =
-                apr_array_make(iterpool, 0, sizeof(svn_merge_range_t *));
-
-              merge_source_url =
-                    svn_path_url_add_component2(merge_source_root_url,
-                                                source_path + 1, iterpool);
-
-              for (j = 0; j < rangelist->nelts; j++)
-                {
-                  svn_error_t *err2;
-                  svn_client__pathrev_t *start_loc;
-                  svn_merge_range_t *range =
-                    APR_ARRAY_IDX(rangelist, j, svn_merge_range_t *);
-
-                  /* Because the merge source normalization code
-                     ensures mergeinfo refers to real locations on
-                     the same line of history, there's no need to
-                     look at the whole range, just the start. */
-
-                  /* Check if PATH@BASE_REVISION exists at
-                     RANGE->START on the same line of history.
-                     (start+1 because RANGE->start is not inclusive.) */
-                  err2 = svn_client__repos_location(&start_loc, ra_session,
-                                                    &target_base,
-                                                    range->start + 1,
-                                                    ctx, iterpool, iterpool);
-                  if (err2)
-                    {
-                      if (err2->apr_err == SVN_ERR_CLIENT_UNRELATED_RESOURCES
-                          || err2->apr_err == SVN_ERR_FS_NOT_FOUND
-                          || err2->apr_err == SVN_ERR_FS_NO_SUCH_REVISION)
-                        {
-                          /* PATH@BASE_REVISION didn't exist at
-                             RANGE->START + 1 or is unrelated to the
-                             resource PATH@RANGE->START.  Some of the
-                             requested revisions may not even exist in
-                             the repository; a real possibility since
-                             mergeinfo is hand editable.  In all of these
-                             cases clear and ignore the error and don't
-                             do any filtering.
-
-                             Note: In this last case it is possible that
-                             we will allow self-referential mergeinfo to
-                             be applied, but fixing it here is potentially
-                             very costly in terms of finding what part of
-                             a range is actually valid.  Simply allowing
-                             the merge to proceed without filtering the
-                             offending range seems the least worst
-                             option. */
-                          svn_error_clear(err2);
-                          err2 = NULL;
-                          APR_ARRAY_PUSH(adjusted_rangelist,
-                                         svn_merge_range_t *) = range;
-                        }
-                      else
-                        {
-                          return svn_error_trace(err2);
-                        }
-                     }
-                  else
-                    {
-                      /* PATH@BASE_REVISION exists on the same
-                         line of history at RANGE->START and RANGE->END.
-                         Now check that PATH@BASE_REVISION's path
-                         names at RANGE->START and RANGE->END are the same.
-                         If the names are not the same then the mergeinfo
-                         describing PATH@RANGE->START through
-                         PATH@RANGE->END actually belong to some other
-                         line of history and we want to record this
-                         mergeinfo, not filter it. */
-                      if (strcmp(start_loc->url, merge_source_url) != 0)
-                        {
-                          APR_ARRAY_PUSH(adjusted_rangelist,
-                                         svn_merge_range_t *) = range;
-                        }
-                    }
-                    /* else no need to add, this mergeinfo is
-                       all on the same line of history. */
-                } /* for (j = 0; j < rangelist->nelts; j++) */
-
-              /* Add any rangelists for source_path that are not
-                 self-referential. */
-              if (adjusted_rangelist->nelts)
-                {
-                  if (!filtered_younger_mergeinfo)
-                    filtered_younger_mergeinfo = apr_hash_make(iterpool);
-                  svn_hash_sets(filtered_younger_mergeinfo, source_path,
-                                adjusted_rangelist);
-                }
-
-            } /* Iteration over each merge source in younger_mergeinfo. */
-        } /* if (younger_mergeinfo) */
-
-      /* Filter self-referential mergeinfo from "older" mergeinfo. */
-      if (mergeinfo)
-        {
-          svn_mergeinfo_t implicit_mergeinfo;
-
-          SVN_ERR(svn_client__get_history_as_mergeinfo(
-            &implicit_mergeinfo, NULL,
-            &target_base, target_base.rev, SVN_INVALID_REVNUM,
-            ra_session, ctx, iterpool));
-
-          /* Remove PATH's implicit mergeinfo from the incoming mergeinfo. */
-          SVN_ERR(svn_mergeinfo_remove2(&filtered_mergeinfo,
-                                        implicit_mergeinfo,
-                                        mergeinfo, TRUE, iterpool, iterpool));
-        }
-
-      /* Combine whatever older and younger filtered mergeinfo exists
-         into filtered_mergeinfo. */
-      if (filtered_mergeinfo && filtered_younger_mergeinfo)
-        SVN_ERR(svn_mergeinfo_merge2(filtered_mergeinfo,
-                                     filtered_younger_mergeinfo, iterpool,
-                                     iterpool));
-      else if (filtered_younger_mergeinfo)
-        filtered_mergeinfo = filtered_younger_mergeinfo;
-
-      /* If there is any incoming mergeinfo remaining after filtering
-         then put it in adjusted_props. */
-      if (filtered_mergeinfo && apr_hash_count(filtered_mergeinfo))
-        {
-          /* Convert filtered_mergeinfo to a svn_prop_t and put it
-             back in the array. */
-          svn_string_t *filtered_mergeinfo_str;
-          svn_prop_t *adjusted_prop = apr_pcalloc(pool,
-                                                  sizeof(*adjusted_prop));
-          SVN_ERR(svn_mergeinfo_to_string(&filtered_mergeinfo_str,
-                                          filtered_mergeinfo,
-                                          pool));
-          adjusted_prop->name = SVN_PROP_MERGEINFO;
-          adjusted_prop->value = filtered_mergeinfo_str;
-          APR_ARRAY_PUSH(adjusted_props, svn_prop_t) = *adjusted_prop;
-        }
-    }
-  svn_pool_destroy(iterpool);
-
-  *props = adjusted_props;
-  return SVN_NO_ERROR;
-}
-
 /* Prepare a set of property changes PROPCHANGES to be used for a merge
    operation on LOCAL_ABSPATH.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.