You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2015/07/24 15:57:28 UTC

svn commit: r1692519 - /subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c

Author: stefan2
Date: Fri Jul 24 13:57:28 2015
New Revision: 1692519

URL: http://svn.apache.org/r1692519
Log:
On the svn-mergeinfo-normalizer branch:
Enable the m/i normalization code to detect revisions that are
implied through the branche's natural history.  Don't flag those
as "missing" etc.

* tools/client-side/svn-mergeinfo-normalizer/logic.c
  (show_branch_elision): Show implied revisions separately.
  (remove_overlapping_history): New function removing revisions that
                                refer to common history between merge
                                source and target.
  (remove_lines): Call the above for revisions that could not otherwise
                  be elided.

Modified:
    subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c

Modified: subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c?rev=1692519&r1=1692518&r2=1692519&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/tools/client-side/svn-mergeinfo-normalizer/logic.c Fri Jul 24 13:57:28 2015
@@ -122,6 +122,8 @@ show_branch_elision(const char *branch,
                     svn_rangelist_t *parent_only,
                     svn_rangelist_t *operative_outside_subtree,
                     svn_rangelist_t *operative_in_subtree,
+                    svn_rangelist_t *implied_in_parent,
+                    svn_rangelist_t *implied_in_subtree,
                     svn_min__opt_state_t *opt_state,
                     apr_pool_t *scratch_pool)
 {
@@ -152,13 +154,26 @@ show_branch_elision(const char *branch,
     }
   else if (opt_state->verbose)
     {
+      SVN_ERR(svn_rangelist_remove(&subtree_only, implied_in_parent,
+                                   subtree_only, TRUE, scratch_pool));
+      SVN_ERR(svn_rangelist_remove(&parent_only, implied_in_subtree,
+                                   parent_only, TRUE, scratch_pool));
+
       SVN_ERR(svn_cmdline_printf(scratch_pool,
                                   _("    elide branch %s\n"),
                                   branch));
+      if (implied_in_parent->nelts)
+        SVN_ERR(print_ranges(implied_in_parent,
+                              _("revisions implied in parent: "),
+                              scratch_pool));
       if (subtree_only->nelts)
         SVN_ERR(print_ranges(subtree_only,
                               _("revisions moved to parent: "),
                               scratch_pool));
+      if (implied_in_subtree->nelts)
+        SVN_ERR(print_ranges(implied_in_subtree,
+                              _("revisions implied in sub-node: "),
+                              scratch_pool));
       if (parent_only->nelts)
         SVN_ERR(print_ranges(parent_only,
                               _("revisions inoperative in sub-node: "),
@@ -276,6 +291,95 @@ get_parent_path(const char *child,
   return "";
 }
 
+/* Remove all ranges from RANGES where the history of SOURCE_PATH@RANGE and
+   TARGET_PATH@HEAD overlap.  Return the list of removed ranges.
+
+   Note that SOURCE_PATH@RANGE may actually refer to different branches
+   created or re-created and then deleted at different points in time.
+ */
+static svn_error_t *
+remove_overlapping_history(svn_rangelist_t **removed,
+                           svn_rangelist_t **ranges,
+                           svn_min__log_t *log,
+                           const char *source_path,
+                           const char *target_path,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *target_history;
+  apr_array_header_t *source_history;
+  apr_array_header_t *deletions;
+  svn_revnum_t source_rev, next_deletion;
+  apr_pool_t *iterpool;
+  int i;
+
+  svn_rangelist_t *result = apr_array_make(result_pool, 0,
+                                           sizeof(svn_merge_range_t *));
+
+  /* In most cases, there is nothing to do. */
+  if (!(*ranges)->nelts)
+    {
+      *removed = result;
+      return SVN_NO_ERROR;
+    }
+
+  /* The history of the working copy branch ("target") is always the same. */
+  iterpool = svn_pool_create(scratch_pool);
+  target_history = svn_min__get_history(log, target_path, SVN_INVALID_REVNUM,
+                                        0, scratch_pool, scratch_pool);
+
+  /* Collect the deletion revisions, i.e. the revisons separating different
+     branches with the same name. */
+  deletions = svn_min__find_deletions(log, source_path, scratch_pool);
+  next_deletion = SVN_INVALID_REVNUM;
+
+  /* Get the history of each of these branches up to the point where the
+     respective previous branch was deleted (or r0). Intersect with the
+     target history and RANGES. */
+  for (i = 0; i <= deletions->nelts; ++i)
+    {
+      apr_array_header_t *common_history;
+      apr_array_header_t *common_ranges;
+      apr_array_header_t *removable_ranges;
+      svn_pool_clear(iterpool);
+
+      /* First iteration: HEAD to whatever latest deletion or r0.
+
+         NEXT_DELETION points to the last revision that may contain
+         changes of the previous branch at SOURCE_PATH.  The deletion
+         rev itself is not relevant but may instead contains the modyfing
+         creation of the next incarnation of that branch. */
+      source_rev = next_deletion;
+      next_deletion = i <  deletions->nelts
+                    ? APR_ARRAY_IDX(deletions, i, svn_revnum_t) - 1
+                    : 0;
+
+      /* Determine the overlapping history of merge source & target. */
+      source_history = svn_min__get_history(log, source_path,
+                                            source_rev, next_deletion,
+                                            iterpool, iterpool);
+      common_history = svn_min__intersect_history(source_history,
+                                                  target_history, iterpool);
+
+      /* Remove that overlap from RANGES. */
+      common_ranges = svn_min__history_ranges(common_history, iterpool);
+      if (!common_ranges->nelts)
+        continue;
+
+      SVN_ERR(svn_rangelist_intersect(&removable_ranges, common_ranges,
+                                      *ranges, TRUE, iterpool));
+      SVN_ERR(svn_rangelist_remove(ranges, removable_ranges, *ranges, TRUE,
+                                   (*ranges)->pool));
+      SVN_ERR(svn_rangelist_merge2(result, removable_ranges, result_pool,
+                                   result_pool));
+    }
+
+  svn_pool_destroy(iterpool);
+  *removed = result;
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 remove_lines(svn_min__log_t *log,
              svn_min__branch_lookup_t *lookup,
@@ -299,6 +403,7 @@ remove_lines(svn_min__log_t *log,
       svn_rangelist_t *parent_ranges, *subtree_ranges, *reverse_ranges;
       svn_rangelist_t *subtree_only, *parent_only;
       svn_rangelist_t *operative_outside_subtree, *operative_in_subtree;
+      svn_rangelist_t *implied_in_subtree, *implied_in_parent;
       const svn_sort__item_t *item;
       svn_boolean_t deleted;
 
@@ -379,6 +484,17 @@ remove_lines(svn_min__log_t *log,
       operative_in_subtree
         = svn_min__operative(log, subtree_path, parent_only, iterpool);
 
+      /* Remove revision ranges that are implied by the "natural" history
+         of the merged branch vs. the current branch. */
+      SVN_ERR(remove_overlapping_history(&implied_in_subtree,
+                                         &operative_in_subtree, log,
+                                         subtree_path, fs_path,
+                                         iterpool, iterpool));
+      SVN_ERR(remove_overlapping_history(&implied_in_parent,
+                                         &operative_outside_subtree, log,
+                                         parent_path, parent_fs_path,
+                                         iterpool, iterpool));
+
       /* Before we show a branch as "CANNOT elide", make sure it is even
          still relevant. */
       if (   operative_outside_subtree->nelts
@@ -395,8 +511,8 @@ remove_lines(svn_min__log_t *log,
       /* Log whether an elision was possible. */
       SVN_ERR(show_branch_elision(subtree_path, subtree_only,
                                   parent_only, operative_outside_subtree,
-                                  operative_in_subtree, opt_state,
-                                  iterpool));
+                                  operative_in_subtree, implied_in_parent,
+                                  implied_in_subtree, opt_state, iterpool));
 
       /* This will also work when subtree_only is empty. */
       if (   !operative_outside_subtree->nelts
@@ -656,6 +772,7 @@ normalize(apr_array_header_t *wc_mergein
     {
       const char *parent_path;
       const char *relpath;
+      const char *fs_path;
       svn_mergeinfo_t parent_mergeinfo;
       svn_mergeinfo_t subtree_mergeinfo;