subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1777345 - in /subversion/trunk/tools/client-side/svn-mergeinfo-normalizer: log.c logic.c mergeinfo-normalizer.h wc_mergeinfo.c
Date Wed, 04 Jan 2017 17:07:10 GMT
Author: stefan2
Date: Wed Jan  4 17:07:09 2017
New Revision: 1777345

URL: http://svn.apache.org/viewvc?rev=1777345&view=rev
Log:
Teach svn-mergeinfo-normalizer to elide subtree mergeinfo where it got
recorded for all affected subtrees of a given change but not the common
parent.

To do that, we simply need to get the mergeinfo from all nodes (directly)
under a given parent and check for all revisions in question whether their
changes are either outside the parent tree or have been recorded at one
of the subtrees.  The existing code could do this only for the current
subtree.

* tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
  (svn_min__get_mergeinfo_pair): Return the list of sibling mergeinfo, too.
  (svn_min__sibling_ranges): Declare a new utility function API.
  (svn_min__operative_outside_all_subtrees): Declare a new query API.

* tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
  (mergeinfo_t): Add list of children.
  (link_parents): Fill that list.
  (svn_min__get_mergeinfo_pair): Return the list.
  (svn_min__sibling_ranges): Implement the new API.

* tools/client-side/svn-mergeinfo-normalizer/log.c
  (in_subtree, 
   below_path_outside_subtree,
   filter_ranges): Provide the change revision to the callback as well
                   because we will need it for the new query.
  (change_outside_baton_t,
   compare_range_rev,
   change_outside_all_subtree_ranges,
   svn_min__operative_outside_all_subtrees): Implement the log new query.

* tools/client-side/svn-mergeinfo-normalizer/logic.c
  (remove_lines): Add the "search in all siblings" as second step to check
                  whether revisions really can't be moved to the parent.
  (normalize): Update caller.

Modified:
    subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/log.c
    subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/logic.c
    subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
    subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c

Modified: subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/log.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/log.c?rev=1777345&r1=1777344&r2=1777345&view=diff
==============================================================================
--- subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/log.c (original)
+++ subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/log.c Wed Jan  4 17:07:09
2017
@@ -465,11 +465,12 @@ is_relevant(const char *changed_path,
 }
 
 /* Return TRUE if PATH is either equal to, a parent of or sub-path of
- * SUB_TREE.  Ignore BATON but keep it for a unified signature to be
- * used with filter_ranges. */
+ * SUB_TREE.  Ignore REVISION and BATON but keep it for a unified signature
+ * to be used with filter_ranges. */
 static svn_boolean_t
 in_subtree(const char *changed_path,
            const char *sub_tree,
+           svn_revnum_t revision,
            const void *baton)
 {
   return svn_dirent_is_ancestor(sub_tree, changed_path);
@@ -477,10 +478,12 @@ in_subtree(const char *changed_path,
 
 /* Return TRUE if
  * - CHANGED_PATH is is either equal to or a sub-node of PATH, and
- * - CHNAGED_PATH is outside the sub-tree given as BATON. */
+ * - CHNAGED_PATH is outside the sub-tree given as BATON.
+ * Ignore REVISION. */
 static svn_boolean_t
 below_path_outside_subtree(const char *changed_path,
                            const char *path,
+                           svn_revnum_t revision,
                            const void *baton)
 {
   const char *subtree = baton;
@@ -491,16 +494,88 @@ below_path_outside_subtree(const char *c
         && strcmp(path, changed_path);
 }
 
+/* Baton struct to be used with change_outside_all_subtree_ranges. */
+typedef struct change_outside_baton_t
+{
+  /* Maps FS path to revision range lists. */
+  apr_hash_t *sibling_ranges;
+
+  /* Pool for temporary allocations.
+   * Baton users may clear this at will. */
+  apr_pool_t *iterpool;
+} change_outside_baton_t;
+
+/* Comparison function comparing range *LHS to revision *RHS. */
+static int
+compare_range_rev(const void *lhs,
+                  const void *rhs)
+{
+  const svn_merge_range_t *range = *(const svn_merge_range_t * const *)lhs;
+  svn_revnum_t revision = *(const svn_revnum_t *)rhs;
+
+  if (range->start >= revision)
+    return 1;
+
+  return range->end < revision ? 1 : 0;
+}
+
+/* Return TRUE if CHANGED_PATH is either equal to or a sub-node of PATH,
+ * CHNAGED_PATH@REVISION is not covered by BATON->SIBLING_RANGES. */
+static svn_boolean_t
+change_outside_all_subtree_ranges(const char *changed_path,
+                                  const char *path,
+                                  svn_revnum_t revision,
+                                  const void *baton)
+{
+  const change_outside_baton_t *b = baton;
+  svn_boolean_t missing = TRUE;
+  apr_size_t len;
+  svn_rangelist_t *ranges;
+
+  /* Don't collect changes outside the subtree starting at PARENT_PATH. */
+  if (!svn_dirent_is_ancestor(path, changed_path))
+    return FALSE;
+
+  svn_pool_clear(b->iterpool);
+
+  /* All branches that contain CHANGED_PATH, i.e. match either it or one
+   * of its parents, must mention REVISION in their mergeinfo. */
+  for (len = strlen(changed_path);
+       !svn_fspath__is_root(changed_path, len);
+       len = strlen(changed_path))
+    {
+      ranges = apr_hash_get(b->sibling_ranges, changed_path, len);
+      if (ranges)
+        {
+          /* If any of the matching branches does not list REVISION
+           * as already merged, we found an "outside" change. */
+          if (!svn_sort__array_lookup(ranges, &revision, NULL,
+                                      compare_range_rev))
+            return TRUE;
+
+          /* Mergeinfo for this path has been found. */
+          missing = FALSE;
+        }
+
+      changed_path = svn_fspath__dirname(changed_path, b->iterpool);
+    }
+
+  /* Record, if no mergeinfo has been found for this CHANGED_PATH. */
+  return missing;
+}
+
 /* In LOG, scan the revisions given in RANGES and return the revision /
- * ranges that are relevant to PATH with respect to the PATH_RELEVANT
+ * ranges that are relevant to PATH with respect to the CHANGE_RELEVANT
  * criterion using BATON.  Keep revisions that lie outside what is covered
  * by LOG. Allocate the result in RESULT_POOL. */
 static svn_rangelist_t *
 filter_ranges(svn_min__log_t *log,
               const char *path,
               svn_rangelist_t *ranges,
-              svn_boolean_t (*path_relavent)(const char*, const char *,
-                                             const void *),
+              svn_boolean_t (*change_relavent)(const char *,
+                                               const char *,
+                                               svn_revnum_t,
+                                               const void *),
               const void *baton,
               apr_pool_t *result_pool)
 {
@@ -541,7 +616,7 @@ filter_ranges(svn_min__log_t *log,
               const char *changed_path
                 = APR_ARRAY_IDX(entry->paths, l, const char *);
 
-              if (path_relavent(changed_path, path, baton))
+              if (change_relavent(changed_path, path, entry->revision, baton))
                 {
                   append_rev_to_ranges(result, entry->revision,
                                        range.inheritable);
@@ -574,6 +649,26 @@ svn_min__operative_outside_subtree(svn_m
                        subtree, result_pool);
 }
 
+svn_rangelist_t *
+svn_min__operative_outside_all_subtrees(svn_min__log_t *log,
+                                        const char *path,
+                                        svn_rangelist_t *ranges,
+                                        apr_hash_t *sibling_ranges,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool)
+{
+  svn_rangelist_t *result;
+  change_outside_baton_t baton;
+  baton.sibling_ranges = sibling_ranges;
+  baton.iterpool = svn_pool_create(scratch_pool);
+
+  result = filter_ranges(log, path, ranges, change_outside_all_subtree_ranges,
+                         &baton, result_pool);
+  svn_pool_destroy(baton.iterpool);
+
+  return result;
+}
+
 svn_revnum_t
 svn_min__find_deletion(svn_min__log_t *log,
                        const char *path,

Modified: subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/logic.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/logic.c?rev=1777345&r1=1777344&r2=1777345&view=diff
==============================================================================
--- subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/logic.c (original)
+++ subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/logic.c Wed Jan  4 17:07:09
2017
@@ -947,6 +947,11 @@ remove_redundant_misaligned_branches(svn
  * possible using LOG and LOOKUP.  OPT_STATE determines if we may remove
  * deleted branches.  Elision happens by comparing the node's mergeinfo
  * with the PARENT_MERGEINFO using REL_PATH to match up the branch paths.
+ *
+ * SIBLING_MERGEINFO contains the mergeinfo of all nodes with mergeinfo
+ * immediately below the parent.  It can be used to "summarize" m/i over
+ * all sub-nodes and elide that to the parent.
+ *
  * Use SCRATCH_POOL for temporaries.
  */
 static svn_error_t *
@@ -956,6 +961,7 @@ remove_lines(svn_min__log_t *log,
              const char *relpath,
              svn_mergeinfo_t parent_mergeinfo,
              svn_mergeinfo_t subtree_mergeinfo,
+             apr_array_header_t *sibling_mergeinfo,
              svn_min__opt_state_t *opt_state,
              apr_pool_t *scratch_pool)
 {
@@ -1169,6 +1175,26 @@ remove_lines(svn_min__log_t *log,
             continue;
         }
 
+      /* Try harder:
+       * There are cases where a merge affected multiple sibling nodes, got
+       * recorded there but was not recorded at the parent.  Remove these
+       * from the list of revisions that couldn't be propagated to the
+       * parent node. */
+      if (operative_outside_subtree->nelts && sibling_mergeinfo->nelts >
1)
+        {
+          apr_hash_t *sibling_ranges;
+          SVN_ERR(svn_min__sibling_ranges(&sibling_ranges, sibling_mergeinfo,
+                                          parent_path,
+                                          operative_outside_subtree,
+                                          iterpool, iterpool));
+
+          operative_outside_subtree
+            = svn_min__operative_outside_all_subtrees(log, parent_path,
+                                                  operative_outside_subtree,
+                                                      sibling_ranges,
+                                                      iterpool, iterpool);
+        }
+
       /* Log whether an elision was possible. */
       SVN_ERR(show_branch_elision(subtree_path, subtree_only,
                                   parent_only, operative_outside_subtree,
@@ -1465,6 +1491,7 @@ normalize(apr_array_header_t *wc_mergein
       svn_mergeinfo_t subtree_mergeinfo;
       svn_mergeinfo_t subtree_mergeinfo_copy;
       svn_mergeinfo_t mergeinfo_to_report;
+      apr_array_header_t *sibling_mergeinfo;
 
       svn_pool_clear(iterpool);
       progress.nodes_todo = i;
@@ -1472,7 +1499,7 @@ normalize(apr_array_header_t *wc_mergein
       /* Get the relevant mergeinfo. */
       svn_min__get_mergeinfo_pair(&fs_path, &parent_path, &relpath,
                                   &parent_mergeinfo, &subtree_mergeinfo,
-                                  wc_mergeinfo, i);
+                                  &sibling_mergeinfo, wc_mergeinfo, i);
       SVN_ERR(show_elision_header(parent_path, relpath, opt_state,
                                   scratch_pool));
 
@@ -1500,7 +1527,7 @@ normalize(apr_array_header_t *wc_mergein
 
           SVN_ERR(remove_lines(log, lookup, fs_path, relpath,
                                parent_mergeinfo_copy, subtree_mergeinfo_copy,
-                               opt_state, iterpool));
+                               sibling_mergeinfo, opt_state, iterpool));
 
           /* If all sub-tree mergeinfo could be elided, clear it.  Update
              the parent mergeinfo in case we moved some up the tree. */

Modified: subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h?rev=1777345&r1=1777344&r2=1777345&view=diff
==============================================================================
--- subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h (original)
+++ subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/mergeinfo-normalizer.h Wed
Jan  4 17:07:09 2017
@@ -163,7 +163,8 @@ svn_min__get_mergeinfo(apr_array_header_
  * the working copy node that carries the closest parent mergeinfo.
  * return the working.  Set *SUBTREE_MERGEINFO to the parsed mergeinfo at
  * *SUBTREE_RELPATH and *PARENT_MERGEINFO to the parsed mergeinfo at
- * *PARENT_PATH.
+ * *PARENT_PATH.  In *SIBLING_MERGEINFO return the list of immediate sub-node
+ * mergeinfo below *PARENT_PATH, including the *SUBTREE_MERGEINFO.
  *
  * If there is no parent mergeinfo, *PARENT_PATH will be "" and
  * *PARENT_MERGEINFO will be NULL.  If IDX is not a valid array index,
@@ -178,9 +179,23 @@ svn_min__get_mergeinfo_pair(const char *
                             const char **subtree_relpath,
                             svn_mergeinfo_t *parent_mergeinfo,
                             svn_mergeinfo_t *subtree_mergeinfo,
+                            apr_array_header_t **siblings_mergeinfo,
                             apr_array_header_t *mergeinfo,
                             int idx);
 
+/* Search SIBLING_MERGEINFO for mergeinfo that intersects PARENT_PATH
+ * and RELEVANT_RANGES.  Return the FS path to range list hash in
+ * *SIBLING_RANGES, allocated in RESULT_POOL.  Use SCRATCH_POOL for
+ * temporary allocations
+ */
+svn_error_t *
+svn_min__sibling_ranges(apr_hash_t **sibling_ranges,
+                        apr_array_header_t *sibling_mergeinfo,
+                        const char *parent_path,
+                        svn_rangelist_t *relevant_ranges,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
+
 /* Store the MERGEINFO in the working copy specified by BATON.  Delete
  * the mergeinfo on those nodes where it is empty but keep the empty data
  * in MERGEINFO.  Use SCRATCH_POOL for temporary allocations. */
@@ -247,6 +262,20 @@ svn_min__operative_outside_subtree(svn_m
                                    svn_rangelist_t *ranges,
                                    apr_pool_t *result_pool);
 
+/* Scan LOG and return those revisions from RANGES that have changes
+ * operative on the PATH subtree and where at least one of these changes
+ * are not covered by any entry in SIBLING_RANGES.
+ *
+ * Allocate the result in RESULT_POOL and use SCRATCH_POOL for tempoaries.
+ */
+svn_rangelist_t *
+svn_min__operative_outside_all_subtrees(svn_min__log_t *log,
+                                        const char *path,
+                                        svn_rangelist_t *ranges,
+                                        apr_hash_t *sibling_ranges,
+                                        apr_pool_t *result_pool,
+                                        apr_pool_t *scratch_pool);
+
 /* Scan LOG from START_REV down to END_REV and find the latest deletion of
  * PATH or a parent thereof and return the revision that contains the
  * deletion.  Return SVN_INVALID_REVNUM if no such deletion could be found.

Modified: subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c?rev=1777345&r1=1777344&r2=1777345&view=diff
==============================================================================
--- subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c (original)
+++ subversion/trunk/tools/client-side/svn-mergeinfo-normalizer/wc_mergeinfo.c Wed Jan  4
17:07:09 2017
@@ -34,12 +34,14 @@
 #include "svn_sorts.h"
 #include "svn_dirent_uri.h"
 #include "svn_props.h"
+#include "svn_hash.h"
 
 #include "mergeinfo-normalizer.h"
 
 #include "private/svn_fspath.h"
 #include "private/svn_opt_private.h"
 #include "private/svn_sorts_private.h"
+#include "private/svn_subr_private.h"
 #include "svn_private_config.h"
 
 
@@ -61,6 +63,9 @@ typedef struct mergeinfo_t
    * copy.  May be NULL. */
   struct mergeinfo_t *parent;
 
+  /* All mergeinfo_t* who's PARENT points to this.  May be NULL. */
+  apr_array_header_t *children;
+
   /* The parsed mergeinfo. */
   svn_mergeinfo_t mergeinfo;
 } mergeinfo_t;
@@ -140,6 +145,7 @@ link_parents(apr_array_header_t *mergein
              svn_min__cmd_baton_t *baton,
              apr_pool_t *scratch_pool)
 {
+  apr_pool_t *result_pool = mergeinfo->pool;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
 
@@ -173,6 +179,17 @@ link_parents(apr_array_header_t *mergein
              && !svn_dirent_is_ancestor(entry->parent->local_path,
                                         entry->local_path))
         entry->parent = entry->parent->parent;
+
+      /* Reverse pointer. */
+      if (entry->parent)
+        {
+          if (!entry->parent->children)
+            entry->parent->children
+              = apr_array_make(result_pool, 4, sizeof(svn_mergeinfo_t));
+
+          APR_ARRAY_PUSH(entry->parent->children, svn_mergeinfo_t)
+            = entry->mergeinfo;
+        }
     }
 
   /* break links for switched paths */
@@ -276,6 +293,7 @@ svn_min__get_mergeinfo_pair(const char *
                             const char **subtree_relpath,
                             svn_mergeinfo_t *parent_mergeinfo,
                             svn_mergeinfo_t *subtree_mergeinfo,
+                            apr_array_header_t **siblings_mergeinfo,
                             apr_array_header_t *mergeinfo,
                             int idx)
 {
@@ -287,6 +305,7 @@ svn_min__get_mergeinfo_pair(const char *
       *subtree_relpath = "";
       *parent_mergeinfo = NULL;
       *subtree_mergeinfo = NULL;
+      *siblings_mergeinfo = NULL;
 
       return;
     }
@@ -300,6 +319,7 @@ svn_min__get_mergeinfo_pair(const char *
       *parent_path = entry->local_path;
       *subtree_relpath = "";
       *parent_mergeinfo = NULL;
+      *siblings_mergeinfo = NULL;
 
       return;
     }
@@ -308,6 +328,7 @@ svn_min__get_mergeinfo_pair(const char *
   *subtree_relpath = svn_dirent_skip_ancestor(entry->parent->local_path,
                                               entry->local_path);
   *parent_mergeinfo = entry->parent->mergeinfo;
+  *siblings_mergeinfo = entry->parent->children;
 }
 
 svn_mergeinfo_t
@@ -319,6 +340,53 @@ svn_min__get_mergeinfo(apr_array_header_
 }
 
 svn_error_t *
+svn_min__sibling_ranges(apr_hash_t **sibling_ranges,
+                        apr_array_header_t *sibling_mergeinfo,
+                        const char *parent_path,
+                        svn_rangelist_t *relevant_ranges,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  int i;
+  apr_hash_t *result = svn_hash__make(result_pool);
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  for (i = 0; i < sibling_mergeinfo->nelts; ++i)
+    {
+      svn_mergeinfo_t mergeinfo;
+      apr_hash_index_t *hi;
+
+      svn_pool_clear(iterpool);
+      mergeinfo = APR_ARRAY_IDX(sibling_mergeinfo, i, svn_mergeinfo_t);
+
+      for (hi = apr_hash_first(iterpool, mergeinfo);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *path = apr_hash_this_key(hi);
+          if (svn_dirent_is_ancestor(parent_path, path))
+            {
+              svn_rangelist_t *common, *ranges = apr_hash_this_val(hi);
+              SVN_ERR(svn_rangelist_intersect(&common, ranges,
+                                              relevant_ranges, TRUE,
+                                              result_pool));
+
+              if (common->nelts)
+                {
+                  svn_hash__sets(result, apr_pstrdup(result_pool, path),
+                                 common);
+                }
+            }
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+  *sibling_ranges = result;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_min__write_mergeinfo(svn_min__cmd_baton_t *baton,
                          apr_array_header_t *mergeinfo,
                          apr_pool_t *scratch_pool)



Mime
View raw message