subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pbu...@apache.org
Subject svn commit: r1209176 - in /subversion/trunk/subversion: libsvn_client/merge.c libsvn_client/mergeinfo.h tests/cmdline/merge_authz_tests.py tests/cmdline/merge_tests.py
Date Thu, 01 Dec 2011 18:38:39 GMT
Author: pburba
Date: Thu Dec  1 18:38:38 2011
New Revision: 1209176

URL: http://svn.apache.org/viewvc?rev=1209176&view=rev
Log:
Fix issue #4056 "don't record non-inheritable mergeinfo if missing
subtrees are not touched by the full-depth diff".

* subversion/libsvn_client/mergeinfo.h

  (svn_client__merge_path_t): Add a few new members.

* subversion/libsvn_client/merge.c

  (calculate_merge_inheritance): Stop adjusting a rangelist in place and
   instead simply communicate back to the caller they inheritance type
   required to describe the merge.

  (insert_parent_and_sibs_of_sw_absent_del_subtree): Set one of the new
   svn_client__merge_path_t members.

  (flag_subtrees_needing_mergeinfo): New.  Takes an initial walk over 

  (record_mergeinfo_for_dir_merge): Factor out the bulk of the code which
   determines if a subtree of interest *needs* new mergeinfo to describe a
   merge -- see flag_subtrees_needing_mergeinfo for its new home.  Leave
   behind the code which actually *calculates* what the actual mergeinfo is
   and records it.

  (do_directory_merge): Account for new differentiation between missing and
   switched children.

* subversion/tests/cmdline/merge_authz_tests.py

  (mergeinfo_and_skipped_paths): Expand test for greater coverage of
   issue #4056 and adjust existing expectations to account for the more
   concise mergeinfo produced by this fix.

* subversion/tests/cmdline/merge_tests.py

  (merge_to_path_with_switched_children): Adjust existing expectations to
   account for the more concise mergeinfo produced by this fix.

  (noninheritable_mergeinfo_test_set_up): Adjust test expectations a bit.
   We still expect no spurious subtree mergeinfo, but how this is
   accomplished (set it, then elide it) was not what the test
   originally expected.

  (unnecessary_noninheritable_mergeinfo_missing_subtrees): Remove XFail
   decorator and comment.

Modified:
    subversion/trunk/subversion/libsvn_client/merge.c
    subversion/trunk/subversion/libsvn_client/mergeinfo.h
    subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py
    subversion/trunk/subversion/tests/cmdline/merge_tests.py

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Thu Dec  1 18:38:38 2011
@@ -4528,9 +4528,9 @@ populate_remaining_ranges(apr_array_head
 
 /* Helper for record_mergeinfo_for_dir_merge().
 
-   Adjust, in place, the inheritability of the ranges in RANGELIST to
-   describe a merge of RANGELIST into WC_WCPATH at depth DEPTH.  Set
-   *RANGELIST_INHERITANCE to the inheritability set.
+   Set *NON_INHERITABLE to TRUE if non-inheritable mergeinfo is needed to
+   describe a merge into LOCAL_ABSPATH at DEPTH.  Set *NON_INHERTIABLE to
+   FALSE otherwise.
 
    WC_PATH_IS_MERGE_TARGET is true if WC_PATH is the target of the merge,
    otherwise WC_PATH is a subtree.
@@ -4541,8 +4541,7 @@ populate_remaining_ranges(apr_array_head
 
    Perform any temporary allocations in SCRATCH_POOL. */
 static svn_error_t *
-calculate_merge_inheritance(apr_array_header_t *rangelist,
-                            svn_boolean_t *rangelist_inheritance,
+calculate_merge_inheritance(svn_boolean_t *non_inheritable,
                             const char *local_abspath,
                             svn_boolean_t wc_path_is_merge_target,
                             svn_boolean_t wc_path_has_missing_child,
@@ -4556,14 +4555,10 @@ calculate_merge_inheritance(apr_array_he
                            scratch_pool));
 
   /* Starting assumption. */
-  *rangelist_inheritance = TRUE;
+  *non_inheritable = FALSE;
 
-  if (path_kind == svn_node_file)
-    {
-      /* Files *never* have non-inheritable mergeinfo. */
-      svn_rangelist__set_inheritance(rangelist, TRUE);
-    }
-  else if (path_kind == svn_node_dir)
+  /* Only directories can have non-inheritable mergeinfo. */
+  if (path_kind == svn_node_dir)
     {
       if (wc_path_is_merge_target)
         {
@@ -4571,12 +4566,7 @@ calculate_merge_inheritance(apr_array_he
               || depth == svn_depth_files
               || depth == svn_depth_empty)
             {
-              svn_rangelist__set_inheritance(rangelist, FALSE);
-              *rangelist_inheritance = FALSE;
-            }
-          else /* depth == svn_depth_files || depth == svn_depth_empty */
-            {
-              svn_rangelist__set_inheritance(rangelist, TRUE);
+              *non_inheritable = TRUE;
             }
         }
       else /* WC_PATH is a directory subtree of the target. */
@@ -4584,12 +4574,7 @@ calculate_merge_inheritance(apr_array_he
           if (wc_path_has_missing_child
               || depth == svn_depth_immediates)
             {
-              svn_rangelist__set_inheritance(rangelist, FALSE);
-              *rangelist_inheritance = FALSE;
-            }
-          else /* depth == infinity */
-            {
-              svn_rangelist__set_inheritance(rangelist, TRUE);
+              *non_inheritable = TRUE;
             }
         }
     }
@@ -5481,13 +5466,15 @@ insert_parent_and_sibs_of_sw_absent_del_
   parent = get_child_with_mergeinfo(children_with_mergeinfo, parent_abspath);
   if (parent)
     {
-      parent->missing_child = TRUE;
+      parent->missing_child = child->absent;
+      parent->switched_child = child->switched;
     }
   else
     {
       /* Create a new element to insert into CHILDREN_WITH_MERGEINFO. */
       parent = svn_client__merge_path_create(parent_abspath, pool);
-      parent->missing_child = TRUE;
+      parent->missing_child = child->absent;
+      parent->switched_child = child->switched;
       /* Insert PARENT into CHILDREN_WITH_MERGEINFO. */
       insert_child_to_merge(children_with_mergeinfo, parent, pool);
       /* Increment for loop index so we don't process the inserted element. */
@@ -7426,6 +7413,202 @@ get_inoperative_immediate_children(apr_h
   return SVN_NO_ERROR;
 }
 
+/* Helper for record_mergeinfo_for_dir_merge(): Identify which elements of
+   NOTIFY_B->CHILDREN_WITH_MERGEINFO need new mergeinfo set to accurately
+   describe a merge, what inheritance type such new mergeinfo should have,
+   and what subtrees can be ignored altogether.
+
+   For each svn_client__merge_path_t CHILD in
+   NOTIFY_B->CHILDREN_WITH_MERGEINFO, set CHILD->RECORD_MERGEINFO and
+   CHILD->RECORD_NONINHERITABLE to true if the subtree needs mergeinfo
+   to describe the merge and if that mergeinfo should be non-inheritable
+   respectively.
+
+   If OPERATIVE_MERGE is true, then the merge being described is operative
+   as per subtree_touched_by_merge.  OPERATIVE_MERGE is false otherwise.
+
+   MERGED_RANGE, MERGEINFO_FSPATH, DEPTH, NOTIFY_B, and MERGE_B are all
+   cascaded from record_mergeinfo_for_dir_merge's arguments of the same
+   names.
+
+   SCRATCH_POOL is used for temporary allocations.
+*/
+static svn_error_t *
+flag_subtrees_needing_mergeinfo(svn_boolean_t operative_merge,
+                                const svn_merge_range_t *merged_range,
+                                const char *mergeinfo_fspath,
+                                svn_depth_t depth,
+                                notification_receiver_baton_t *notify_b,
+                                merge_cmd_baton_t *merge_b,
+                                apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  int i;
+  apr_hash_t *inoperative_immediate_children = NULL;
+
+  /* Find all issue #3642 children (i.e immediate child directories of the
+     merge target, with no pre-existing explicit mergeinfo, during a --depth
+     immediates merge).  Stash those that are inoperative at any depth in
+     INOPERATIVE_IMMEDIATE_CHILDREN. */
+  if (!merge_b->record_only
+      && merged_range->start <= merged_range->end
+      && depth == svn_depth_immediates)
+    SVN_ERR(get_inoperative_immediate_children(
+      &inoperative_immediate_children,
+      notify_b->children_with_mergeinfo,
+      mergeinfo_fspath, merged_range->start + 1, merged_range->end,
+      merge_b->target_abspath, merge_b->ra_session1,
+      scratch_pool, iterpool));
+
+  /* Issue #4056: Walk NOTIFY_B->CHILDREN_WITH_MERGEINFO reverse depth-first
+     order.  This way each child knows if it has operative missing/switched
+     children which necessitates non-inheritable mergeinfo. */
+  for (i = notify_b->children_with_mergeinfo->nelts - 1; i >= 0; i--)
+    {
+      svn_client__merge_path_t *child =
+                     APR_ARRAY_IDX(notify_b->children_with_mergeinfo, i,
+                                   svn_client__merge_path_t *);
+
+      /* Can't record mergeinfo on something that isn't here. */
+      if (child->absent)
+        continue;
+
+      /* Don't record mergeinfo on skipped paths. */
+      if (notify_b->skipped_abspaths
+          && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
+                          APR_HASH_KEY_STRING))
+        continue;
+
+      /* ### ptb: Yes, we could combine the follwing into a single
+         ### conditional, but clarity would suffer (even more than
+         ### it does now). */
+      if (i == 0)
+        {
+          /* Always record mergeinfo on the merge target. */
+          child->record_mergeinfo = TRUE;
+        }
+      else if (merge_b->record_only && !merge_b->reintegrate_merge)
+        {
+          /* Always record mergeinfo for --record-only merges. */
+          child->record_mergeinfo = TRUE;
+        }
+      else if (child->immediate_child_dir
+               && !child->pre_merge_mergeinfo
+               && inoperative_immediate_children
+               && !apr_hash_get(inoperative_immediate_children,
+                               child->abspath,
+                               APR_HASH_KEY_STRING))
+        {
+          /* We must record mergeinfo on those issue #3642 children
+             that are operative at a greater depth. */
+          child->record_mergeinfo = TRUE;
+        }
+
+      if (operative_merge)
+        {
+          svn_boolean_t child_is_deleted;
+
+          svn_pool_clear(iterpool);
+
+          /* If CHILD is deleted we don't need to set mergeinfo on it. */
+          SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
+                                                 merge_b->ctx->wc_ctx,
+                                                 child->abspath, iterpool));
+          if (!child_is_deleted
+              && subtree_touched_by_merge(child->abspath, notify_b,
+                                          iterpool))
+            {
+              /* This subtree was affected by the merge. */
+              child->record_mergeinfo = TRUE;
+
+              /* Were any CHILD's missing children skipped by the merge?
+                 If not, then CHILD's missing children don't need to be
+                 considered when recording mergeinfo describing the merge. */
+              if (!merge_b->reintegrate_merge
+                  && child->missing_child
+                  && !path_is_subtree(child->abspath,
+                                      notify_b->skipped_abspaths,
+                                      iterpool))
+                {
+                  child->missing_child = FALSE;
+                }
+
+              /* If CHILD has an immediate switched child or children and
+                 none of these were touched by the merge, then we don't need
+                 need to do any special handling of those switched subtrees
+                 (e.g. record non-inheritable mergeinfo) when recording
+                 mergeinfo desribing the merge. */
+              if (child->switched_child)
+                {
+                  int j;
+                  svn_boolean_t operative_switched_child = FALSE;
+
+                  for (j = i + 1;
+                       j < notify_b->children_with_mergeinfo->nelts;
+                       j++)
+                    {
+                      svn_client__merge_path_t *potential_child =
+                        APR_ARRAY_IDX(notify_b->children_with_mergeinfo, j,
+                                      svn_client__merge_path_t *);
+                      if (!svn_dirent_is_ancestor(child->abspath,
+                                                  potential_child->abspath))
+                        break;
+
+                      /* POTENTIAL_CHILD is a subtree of CHILD, but is it
+                         an immediate child? */
+                      if (strcmp(child->abspath,
+                                 svn_dirent_dirname(potential_child->abspath,
+                                                    iterpool)))
+                        continue;
+
+                      if (potential_child->switched
+                          && potential_child->record_mergeinfo)
+                        {
+                          operative_switched_child = TRUE;
+                          break;
+                        }
+                    }
+
+                  /* Can we treat CHILD as if it has no switched children? */
+                  if (!operative_switched_child)
+                    child->switched_child = FALSE;
+                }
+            }
+        }
+
+      if (child->record_mergeinfo)
+        {
+          SVN_ERR(calculate_merge_inheritance(&(child->record_noninheritable),
+                                              child->abspath,
+                                              i == 0,
+                                              (child->missing_child
+                                               || child->switched_child),
+                                              depth,
+                                              merge_b->ctx->wc_ctx,
+                                              iterpool));
+        }
+      else
+        {
+          /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
+             because it had no explicit mergeinfo of its own at the
+             start of the merge but is the child of of some path with
+             non-inheritable mergeinfo, then the explicit mergeinfo it
+             has *now* was set by get_mergeinfo_paths() -- see criteria
+             3 in that function's doc string.  So since CHILD->ABSPATH
+             was not touched by the merge we can remove the
+             mergeinfo. */
+          if (child->child_of_noninheritable)
+            SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
+                                                    NULL, FALSE,
+                                                    merge_b->ctx,
+                                                    iterpool));
+        }
+    }
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}
+
 /* Helper for do_directory_merge().
 
    If RESULT_CATALOG is NULL then record mergeinfo describing a merge of
@@ -7457,7 +7640,6 @@ record_mergeinfo_for_dir_merge(svn_merge
   int i;
   svn_boolean_t is_rollback = (merged_range->start > merged_range->end);
   svn_boolean_t operative_merge;
-  apr_hash_t *inoperative_immediate_children = NULL;
 
   /* Update the WC mergeinfo here to account for our new
      merges, minus any unresolved conflicts and skips. */
@@ -7484,23 +7666,12 @@ record_mergeinfo_for_dir_merge(svn_merge
   remove_absent_children(merge_b->target_abspath,
                          notify_b->children_with_mergeinfo);
 
+  /* Determine which subtrees of interest need mergeinfo recorded... */
+  SVN_ERR(flag_subtrees_needing_mergeinfo(operative_merge, &range,
+                                          mergeinfo_fspath, depth, notify_b,
+                                          merge_b, iterpool));
 
-  /* Find all issue #3642 children (i.e immediate child directories of the
-     merge target, with no pre-existing explicit mergeinfo, during a --depth
-     immediates merge).  Stash those that are inoperative at any depth in
-     INOPERATIVE_IMMEDIATE_CHILDREN. */
-  if (!merge_b->record_only && range.start <= range.end
-      && depth == svn_depth_immediates)
-    SVN_ERR(get_inoperative_immediate_children(
-      &inoperative_immediate_children,
-      notify_b->children_with_mergeinfo,
-      mergeinfo_fspath, range.start + 1, range.end,
-      merge_b->target_abspath, merge_b->ra_session1,
-      pool, iterpool));
-
-  /* Record mergeinfo on any subtree affected by the merge or for
-     every subtree if this is a --record-only merge.  Always record
-     mergeinfo on the merge target CHILDREN_WITH_MERGEINFO[0]. */
+  /* ...and then record it. */
   for (i = 0; i < notify_b->children_with_mergeinfo->nelts; i++)
     {
       const char *child_repos_path;
@@ -7512,60 +7683,10 @@ record_mergeinfo_for_dir_merge(svn_merge
                                    svn_client__merge_path_t *);
       SVN_ERR_ASSERT(child);
 
-      /* Can't record mereginfo on something that isn't here. */
-      if (child->absent)
-        continue;
-
       svn_pool_clear(iterpool);
 
-      /* If CHILD is a subtree, this is not a record only merge, and
-         CHILD was not affected by the merge then we don't need to
-         record mergeinfo.  If this is a record only merge being done
-         as part of a reintegrate merge then we need to check if CHILD
-         was affected by the merge. */
-      if (i > 0 /* Always record mergeinfo on the merge target. */
-          && (!merge_b->record_only || merge_b->reintegrate_merge)
-          && (!child->immediate_child_dir || child->pre_merge_mergeinfo)
-          && (!operative_merge
-              || !subtree_touched_by_merge(child->abspath, notify_b,
-                                           iterpool)))
+      if (child->record_mergeinfo)
         {
-          /* If CHILD is in NOTIFY_B->CHILDREN_WITH_MERGEINFO simply
-             because it had no explicit mergeinfo of its own at the
-             start of the merge but is the child of of some path with
-             non-inheritable mergeinfo, then the explicit mergeinfo it
-             has *now* was set by get_mergeinfo_paths() -- see criteria
-             3 in that function's doc string.  So since CHILD->ABSPATH
-             was not touched by the merge we can remove the
-             mergeinfo. */
-          if (child->child_of_noninheritable)
-            {
-              SVN_ERR(svn_client__record_wc_mergeinfo(child->abspath,
-                                                      NULL, FALSE,
-                                                      merge_b->ctx,
-                                                      iterpool));
-            }
-        }
-      else /* Record mergeinfo on CHILD. */
-        {
-          svn_boolean_t child_is_deleted;
-          svn_boolean_t rangelist_inheritance;
-
-          /* If CHILD is deleted we don't need to set mergeinfo on it. */
-          SVN_ERR(svn_wc__node_is_status_deleted(&child_is_deleted,
-                                                 merge_b->ctx->wc_ctx,
-                                                 child->abspath, iterpool));
-          if (child_is_deleted)
-            continue;
-
-          /* We don't need to record mergeinfo on those issue #3642 children
-             that are inoperative at any depth. */
-          if (inoperative_immediate_children
-              && apr_hash_get(inoperative_immediate_children,
-                              child->abspath,
-                             APR_HASH_KEY_STRING))
-            continue;
-
           child_repos_path = svn_dirent_skip_ancestor(merge_b->target_abspath,
                                                       child->abspath);
           SVN_ERR_ASSERT(child_repos_path != NULL);
@@ -7582,35 +7703,21 @@ record_mergeinfo_for_dir_merge(svn_merge
             continue;
 
           if (!squelch_mergeinfo_notifications)
-            {
-              notify_mergeinfo_recording(child->abspath, merged_range,
-                                         merge_b->ctx, iterpool);
-            }
+            notify_mergeinfo_recording(child->abspath, merged_range,
+                                      merge_b->ctx, iterpool);
 
           /* If we are here we know we will be recording some mergeinfo, but
-             before we do set override mergeinfo on skipped paths so they
-             don't incorrectly inherit the mergeinfo we are about to set.
-             We only need to do this once.  If we are dealing with a subtree
-             (i.e. i != 0) that was skipped then don't record mergeinfo on
-             it.  The earlier call to record_skips will already have taken
-             care of this. */
+             before we do, set override mergeinfo on skipped paths so they
+             don't incorrectly inherit the mergeinfo we are about to set. */
           if (i == 0)
             SVN_ERR(record_skips(mergeinfo_fspath, child_merge_rangelist,
                                  is_rollback, notify_b->skipped_abspaths,
                                  merge_b, iterpool));
-          else if (notify_b->skipped_abspaths
-                   && apr_hash_get(notify_b->skipped_abspaths, child->abspath,
-                                   APR_HASH_KEY_STRING))
-            continue;
 
-          SVN_ERR(calculate_merge_inheritance(child_merge_rangelist,
-                                              &rangelist_inheritance,
-                                              child->abspath,
-                                              i == 0,
-                                              child->missing_child,
-                                              depth,
-                                              merge_b->ctx->wc_ctx,
-                                              iterpool));
+          /* We may need to record non-inheritable mergeinfo that applies
+             only to CHILD->ABSPATH. */
+          if (child->record_noninheritable)
+            svn_rangelist__set_inheritance(child_merge_rangelist, FALSE);
 
           /* If CHILD has inherited mergeinfo set it before
              recording the first merge range. */
@@ -7718,7 +7825,7 @@ record_mergeinfo_for_dir_merge(svn_merge
                                                   child_merge_rangelist,
                                                   child_merge_src_rangelist,
                                                   FALSE, iterpool));
-                  if (!rangelist_inheritance)
+                  if (child->record_noninheritable)
                     svn_rangelist__set_inheritance(child_merge_rangelist,
                                                    FALSE);
                 }
@@ -8400,7 +8507,8 @@ do_directory_merge(svn_mergeinfo_catalog
      the target thanks to depth-first ordering. */
   target_merge_path = APR_ARRAY_IDX(notify_b->children_with_mergeinfo, 0,
                                     svn_client__merge_path_t *);
-  merge_b->target_missing_child = target_merge_path->missing_child;
+  merge_b->target_missing_child = (target_merge_path->missing_child
+                                   || target_merge_path->switched_child);
 
   /* If we are honoring mergeinfo, then for each item in
      NOTIFY_B->CHILDREN_WITH_MERGEINFO, we need to calculate what needs to be

Modified: subversion/trunk/subversion/libsvn_client/mergeinfo.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/mergeinfo.h?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/mergeinfo.h (original)
+++ subversion/trunk/subversion/libsvn_client/mergeinfo.h Thu Dec  1 18:38:38 2011
@@ -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. */

Modified: subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_authz_tests.py Thu Dec  1 18:38:38 2011
@@ -73,7 +73,10 @@ from svntest.actions import inject_confl
 #         This is *not* a full test of issue #2829, see also merge_tests.py,
 #         search for "2829".  This tests the problem where a merge adds a path
 #         with a missing sibling and so needs its own explicit mergeinfo.
-@Issues(2893,2997,2829)
+#
+# #4056 - Don't record non-inheritable mergeinfo if missing subtrees are not
+#         touched by the full-depth diff
+@Issues(2893,2997,2829,4056)
 @SkipUnless(svntest.main.server_has_mergeinfo)
 @Skip(svntest.main.is_ra_type_file)
 def mergeinfo_and_skipped_paths(sbox):
@@ -393,10 +396,54 @@ def mergeinfo_and_skipped_paths(sbox):
 
   # Merge -r7:9 to the restricted WC's A_COPY_2/D/H.
   #
+  # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a missing sibling 'psi',
+  # but since 'psi' is untouched by the merge it isn't skipped, and since it
+  # isn't skipped, its parent 'A_COPY_2/D/H' won't get non-inheritable
+  # mergeinfo set on it to describe the merge, so none of the parent's
+  # children will get explicit mergeinfo -- see issue #4056.
+  expected_output = wc.State(A_COPY_2_H_path, {
+    'omega' : Item(status='U '),
+    'zeta'  : Item(status='A '),
+    })
+  expected_mergeinfo_output = wc.State(A_COPY_2_H_path, {
+    ''      : Item(status=' U'),
+    'omega' : Item(status=' U'),
+    })
+  expected_elision_output = wc.State(A_COPY_2_H_path, {
+    'omega' : Item(status=' U'),
+    })
+  expected_status = wc.State(A_COPY_2_H_path, {
+    ''      : Item(status=' M', wc_rev=8),
+    'chi'   : Item(status='  ', wc_rev=8),
+    'omega' : Item(status='M ', wc_rev=8),
+    'zeta'  : Item(status='A ', copied='+', wc_rev='-'),
+    })
+  expected_disk = wc.State('', {
+    ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9'}),
+    'omega' : Item("New content"),
+    'chi'   : Item("This is the file 'chi'.\n"),
+    'zeta'  : Item("This is the file 'zeta'.\n"),
+    })
+  expected_skip = wc.State(A_COPY_2_H_path, {})
+  svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+                                       sbox.repo_url + '/A/D/H', None,
+                                       expected_output,
+                                       expected_mergeinfo_output,
+                                       expected_elision_output,
+                                       expected_disk,
+                                       expected_status,
+                                       expected_skip,
+                                       None, None, None, None,
+                                       None, 1, 0)
+
+  # Merge -r4:9 to the restricted WC's A_COPY_2/D/H.
+  #
   # r9 adds a path, 'A_COPY_2/D/H/zeta', which has a parent with
-  # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing).
-  # 'A_COPY_2/D/H/zeta' must therefore get its own explicit mergeinfo from
-  # this merge.
+  # non-inheritable mergeinfo (due to the fact 'A_COPY_2/D/H/psi' is missing
+  # and skipped). 'A_COPY_2/D/H/zeta' must therefore get its own explicit
+  # mergeinfo from this merge.
+  svntest.actions.run_and_verify_svn(None, None, [], 'revert', '--recursive',
+                                     wc_restricted)  
   expected_output = wc.State(A_COPY_2_H_path, {
     'omega' : Item(status='U '),
     'zeta'  : Item(status='A '),
@@ -415,15 +462,17 @@ def mergeinfo_and_skipped_paths(sbox):
     'zeta'  : Item(status='A ', copied='+', wc_rev='-'),
     })
   expected_disk = wc.State('', {
-    ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8-9*'}),
+    ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-9*'}),
     'omega' : Item("New content",
-                   props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8-9'}),
+                   props={SVN_PROP_MERGEINFO : '/A/D/H/omega:5-9'}),
     'chi'   : Item("This is the file 'chi'.\n"),
     'zeta'  : Item("This is the file 'zeta'.\n",
                    props={SVN_PROP_MERGEINFO : '/A/D/H/zeta:9'}),
     })
-  expected_skip = wc.State(A_COPY_2_H_path, {})
-  svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '7', '9',
+  expected_skip = wc.State(A_COPY_2_H_path, {
+    'psi' : Item(),
+    })
+  svntest.actions.run_and_verify_merge(A_COPY_2_H_path, '4', '9',
                                        sbox.repo_url + '/A/D/H', None,
                                        expected_output,
                                        expected_mergeinfo_output,

Modified: subversion/trunk/subversion/tests/cmdline/merge_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/merge_tests.py?rev=1209176&r1=1209175&r2=1209176&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/merge_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/merge_tests.py Thu Dec  1 18:38:38 2011
@@ -5599,7 +5599,7 @@ def merge_to_switched_path(sbox):
 #   3188: Mergeinfo on switched targets/subtrees should
 #         elide to repos
 @SkipUnless(server_has_mergeinfo)
-@Issue(2823,2839,3187,3188)
+@Issue(2823,2839,3187,3188,4056)
 def merge_to_path_with_switched_children(sbox):
   "merge to path with switched children"
 
@@ -5694,18 +5694,18 @@ def merge_to_path_with_switched_children
     'omega' : Item(status=' U')
     })
   expected_elision_output = wc.State(A_COPY_H_path, {
+    'omega' : Item(status=' U')
     })
   expected_status = wc.State(A_COPY_H_path, {
     ''      : Item(status=' M', wc_rev=8),
     'psi'   : Item(status='  ', wc_rev=8, switched='S'),
-    'omega' : Item(status='MM', wc_rev=8),
+    'omega' : Item(status='M ', wc_rev=8),
     'chi'   : Item(status='  ', wc_rev=8),
     })
   expected_disk = wc.State('', {
-    ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+    ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
     'psi'   : Item("This is the file 'psi'.\n"),
-    'omega' : Item("New content",
-                   props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+    'omega' : Item("New content"),
     'chi'   : Item("This is the file 'chi'.\n"),
     })
   expected_skip = wc.State(A_COPY_H_path, { })
@@ -5739,7 +5739,7 @@ def merge_to_path_with_switched_children
     ''        : Item(status=' M', wc_rev=8),
     'H'       : Item(status=' M', wc_rev=8),
     'H/chi'   : Item(status='  ', wc_rev=8),
-    'H/omega' : Item(status='MM', wc_rev=8),
+    'H/omega' : Item(status='M ', wc_rev=8),
     'H/psi'   : Item(status='  ', wc_rev=8, switched='S'),
     'G'       : Item(status=' M', wc_rev=8, switched='S'),
     'G/pi'    : Item(status='  ', wc_rev=8),
@@ -5749,10 +5749,9 @@ def merge_to_path_with_switched_children
     })
   expected_disk_D = wc.State('', {
     ''        : Item(props={SVN_PROP_MERGEINFO : '/A/D:6*'}),
-    'H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8*'}),
+    'H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:8'}),
     'H/chi'   : Item("This is the file 'chi'.\n"),
-    'H/omega' : Item("New content",
-                     props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+    'H/omega' : Item("New content"),
     'H/psi'   : Item("This is the file 'psi'.\n",),
     'G'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
     'G/pi'    : Item("This is the file 'pi'.\n"),
@@ -5786,10 +5785,10 @@ def merge_to_path_with_switched_children
     })
   expected_elision_output = wc.State(A_COPY_D_path, {
     })
-  expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
-  expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+  expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
+  expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
   expected_disk_D.tweak('H/psi', contents="New content",
-                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5'})
+                        props={SVN_PROP_MERGEINFO :'/A/D/H/psi:5,8'})
   expected_status_D.tweak('H/psi', status='MM')
   svntest.actions.run_and_verify_merge(A_COPY_D_path, '4', '5',
                                        sbox.repo_url + '/A/D', None,
@@ -5830,7 +5829,7 @@ def merge_to_path_with_switched_children
     'D/H'       : Item(status=' M', wc_rev=8),
     'D/H/chi'   : Item(status='  ', wc_rev=8),
     'D/H/psi'   : Item(status='MM', wc_rev=8, switched='S'),
-    'D/H/omega' : Item(status='MM', wc_rev=8),
+    'D/H/omega' : Item(status='M ', wc_rev=8),
     })
   expected_disk = wc.State('', {
     ''          : Item(props={SVN_PROP_MERGEINFO : '/A:5-8'}),
@@ -5842,19 +5841,18 @@ def merge_to_path_with_switched_children
     'B/lambda'  : Item("This is the file 'lambda'.\n"),
     'B/F'       : Item(),
     'C'         : Item(),
-    'D'         : Item(props={SVN_PROP_MERGEINFO : '/A/D:5-6*'}),
+    'D'         : Item(props={SVN_PROP_MERGEINFO : '/A/D:5,6*'}),
     'D/G'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/G:6*'}),
     'D/G/pi'    : Item("This is the file 'pi'.\n"),
     'D/G/rho'   : Item("New content",
                        props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'}),
     'D/G/tau'   : Item("This is the file 'tau'.\n"),
     'D/gamma'   : Item("This is the file 'gamma'.\n"),
-    'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'}),
+    'D/H'       : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'}),
     'D/H/chi'   : Item("This is the file 'chi'.\n"),
     'D/H/psi'   : Item("New content",
-                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5'}),
-    'D/H/omega' : Item("New content",
-                       props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+                       props={SVN_PROP_MERGEINFO : '/A/D/H/psi:5,8'}),
+    'D/H/omega' : Item("New content"),
     })
   expected_skip = wc.State(A_COPY_path, { })
   svntest.actions.run_and_verify_merge(A_COPY_path, '4', '8',
@@ -5865,7 +5863,6 @@ def merge_to_path_with_switched_children
                                        expected_disk,
                                        expected_status, expected_skip,
                                        None, None, None, None, None, 1)
-
   # Commit changes thus far.
   expected_output = svntest.wc.State(wc_dir, {
     'A_COPY'           : Item(verb='Sending'),
@@ -5892,17 +5889,16 @@ def merge_to_path_with_switched_children
   wc_disk.tweak("A_COPY/B/E/beta",
                 contents="New content")
   wc_disk.tweak("A_COPY/D",
-                props={SVN_PROP_MERGEINFO : '/A/D:5-6*'})
+                props={SVN_PROP_MERGEINFO : '/A/D:5,6*'})
   wc_disk.tweak("A_COPY/D/G",
                 props={SVN_PROP_MERGEINFO : '/A/D/G:6*'})
   wc_disk.tweak("A_COPY/D/G/rho",
                 contents="New content",
                 props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
   wc_disk.tweak("A_COPY/D/H",
-                props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8*'})
+                props={SVN_PROP_MERGEINFO : '/A/D/H:5*,8'})
   wc_disk.tweak("A_COPY/D/H/omega",
-                contents="New content",
-                props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
+                contents="New content")
   wc_disk.tweak("A_COPY_2", props={})
   svntest.actions.run_and_verify_switch(sbox.wc_dir, A_COPY_psi_path,
                                         sbox.repo_url + "/A_COPY/D/H/psi",
@@ -5941,8 +5937,7 @@ def merge_to_path_with_switched_children
   expected_disk = wc.State('', {
     ''      : Item(props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'}),
     'psi'   : Item("New content"),
-    'omega' : Item("New content",
-                   props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'}),
+    'omega' : Item("New content"),
     'chi'   : Item("This is the file 'chi'.\n"),
     })
   expected_skip = wc.State(A_COPY_H_path, { })
@@ -5992,14 +5987,11 @@ def merge_to_path_with_switched_children
   expected_status_D.tweak('H/psi', wc_rev=10, switched=None)
   expected_status_D.tweak('H/omega', wc_rev=9)
   expected_status_D.tweak('G', 'G/rho', switched='S', wc_rev=9)
-  expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5-6*,10*',
+  expected_disk_D.tweak('', props={SVN_PROP_MERGEINFO : '/A/D:5,6*,10',
                                    "prop:name" : "propval"})
   expected_disk_D.tweak('G/rho',
                         props={SVN_PROP_MERGEINFO : '/A/D/G/rho:6'})
   expected_disk_D.tweak('H', props={SVN_PROP_MERGEINFO : '/A/D/H:5-8'})
-
-  expected_disk_D.tweak('H/omega',
-                        props={SVN_PROP_MERGEINFO : '/A/D/H/omega:8'})
   expected_disk_D.tweak('H/psi', contents="New content", props={})
   svntest.actions.run_and_verify_merge(A_COPY_D_path, '9', '10',
                                        sbox.repo_url + '/A/D', None,
@@ -6060,7 +6052,6 @@ def merge_to_path_with_switched_children
     'D/G'       : Item(status=' U'),
     'D/G/rho'   : Item(status=' U'),
     'D/H'       : Item(status=' U'),
-    'D/H/omega' : Item(status=' U'),
     })
   expected_elision_output = wc.State(A_COPY_path, {
     ''          : Item(status=' U'),
@@ -6068,7 +6059,6 @@ def merge_to_path_with_switched_children
     'D/G'       : Item(status=' U'),
     'D/G/rho'   : Item(status=' U'),
     'D/H'       : Item(status=' U'),
-    'D/H/omega' : Item(status=' U'),
     })
   expected_status = wc.State(A_COPY_path, {
     ''          : Item(status=' M', wc_rev=10),
@@ -6089,7 +6079,7 @@ def merge_to_path_with_switched_children
     'D/H'       : Item(status=' M', wc_rev=10),
     'D/H/chi'   : Item(status='  ', wc_rev=10),
     'D/H/psi'   : Item(status='M ', wc_rev=10),
-    'D/H/omega' : Item(status='MM', wc_rev=10),
+    'D/H/omega' : Item(status='M ', wc_rev=10),
     })
   expected_disk = wc.State('', {
     'B'         : Item(),
@@ -17173,8 +17163,10 @@ def noninheritable_mergeinfo_test_set_up
     })
   expected_mergeinfo_output = wc.State(B_branch_path, {
     ''       : Item(status=' U'),
+    'lambda' : Item(status=' U'),
     })
   expected_elision_output = wc.State(B_branch_path, {
+    'lambda' : Item(status=' U'),
     })
   expected_status = wc.State(B_branch_path, {
     ''        : Item(status=' M'),
@@ -17203,7 +17195,6 @@ def noninheritable_mergeinfo_test_set_up
 # Test for issue #4056 "don't record non-inheritable mergeinfo if missing
 # subtrees are not touched by the full-depth diff".
 @Issue(4056)
-@XFail()
 @SkipUnless(server_has_mergeinfo)
 def unnecessary_noninheritable_mergeinfo_missing_subtrees(sbox):
   "missing subtrees untouched by infinite depth merge"
@@ -17222,19 +17213,16 @@ def unnecessary_noninheritable_mergeinfo
 
   # Merge r3 from ^/A/B to branch/B
   #
-  # Currently this fails because merge isn't smart enough to
-  # realize that despite the shallow merge target, the diff can
-  # only affect branch/B/lambda, which is still present, so there
+  # Merge is smart enough to realize that despite the shallow merge target,
+  # the diff can only affect branch/B/lambda, which is still present, so there
   # is no need to record non-inheritable mergeinfo on the target
   # or any subtree mergeinfo whatsoever:
   #
   #   >svn pg svn:mergeinfo -vR
   #   Properties on 'branch\B':
   #     svn:mergeinfo
-  #       /A/B:3* <-- Should be inheritable
-  #   Properties on 'branch\B\lambda':
-  #     svn:mergeinfo
-  #       /A/B/lambda:3 <-- Not neccessary
+  #       /A/B:3 <-- Nothing was skipped, so doesn't need
+  #                  to be non-inheritable.
   svntest.actions.run_and_verify_merge(B_branch_path,
                                        '2', '3',
                                        sbox.repo_url + '/A/B', None,



Mime
View raw message