You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2013/01/26 21:51:23 UTC

svn commit: r1438961 - /subversion/trunk/subversion/libsvn_client/merge.c

Author: rhuijben
Date: Sat Jan 26 20:51:23 2013
New Revision: 1438961

URL: http://svn.apache.org/viewvc?rev=1438961&view=rev
Log:
Record skips and tree conflicts from the merge code itself instead of via
hooking the repository diff notification handler.

* subversion/libsvn_client/merge.c
  (contains_path): New helper function.
  (record_skip,
   record_tree_conflict): New functions.

  (merge_dir_props_changed,
   merge_file_changed,
   merge_file_deleted,
   merge_file_added,
   merge_dir_added,
   merge_dir_deleted,
   merge_dir_opened): Call record_skip and record_tree_conflict where
     we already set the output arguments.

  (notification_receiver): Stop recording skips and tree conflicts.

  (record_skips): Rename to ...
  (record_skips_in_mergeinfo): ... this to avoid confusion.

  (single_file_merge_notify): Remove APR_INLINE, which doesn't seem very
    relevant for such a large function. Return svn_error_t *.
  (do_file_merge): Update caller.
  (record_mergeinfo_for_dir_merge): Update caller.

Modified:
    subversion/trunk/subversion/libsvn_client/merge.c

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1438961&r1=1438960&r2=1438961&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Sat Jan 26 20:51:23 2013
@@ -499,6 +499,13 @@ alloc_and_store_path(apr_hash_t **path_h
   store_path(*path_hash_p, local_abspath);
 }
 
+/* Helper function to easy in checking if a path is in a path hash */
+static APR_INLINE svn_boolean_t
+contains_path(apr_hash_t *path_hash, const char *local_abspath)
+{
+  return apr_hash_get(path_hash, local_abspath, APR_HASH_KEY_STRING) != NULL;
+}
+
 /* Return true iff we're in dry-run mode and LOCAL_ABSPATH would have been
    deleted by now if we weren't in dry-run mode.
    Used to avoid spurious notifications (e.g. conflicts) from a merge
@@ -1397,6 +1404,75 @@ check_moved_here(svn_boolean_t *moved_he
   return SVN_NO_ERROR;
 }
 
+/* #defined HANDLE_NOTIFY_FROM_MERGE */
+
+/* Record the skip for future processing and (later) produce the
+   skip notification */
+static svn_error_t *
+record_skip(const merge_cmd_baton_t *merge_b,
+            const char *local_abspath,
+            svn_node_kind_t kind,
+            svn_wc_notify_state_t state,
+            apr_pool_t *scratch_pool)
+{
+  if (merge_b->merge_source.ancestral
+      || merge_b->reintegrate_merge)
+    {
+      store_path(merge_b->skipped_abspaths, local_abspath);
+    }
+
+#ifdef HANDLE_NOTIFY_FROM_MERGE
+  if (merge_b->ctx->notify_func2)
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(local_abspath, svn_wc_notify_skip,
+                                    scratch_pool);
+      notify->kind = kind;
+      notify->content_state = notify->prop_state = state;
+
+      (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
+                                    scratch_pool);
+    }
+#endif
+  return SVN_NO_ERROR;
+}
+
+/* Record the skip for future processing and (later) produce the
+   tree conflict notification */
+static svn_error_t *
+record_tree_conflict(const merge_cmd_baton_t *merge_b,
+                     const char *local_abspath,
+                     svn_node_kind_t kind,
+                     apr_pool_t *scratch_pool)
+{
+#ifdef HANDLE_NOTIFY_FROM_MERGE
+  /* On a replacement we currently get two tree conflicts */
+  if (merge_b->ctx->notify_func2
+      && !contains_path(merge_b->tree_conflicted_abspaths,
+                        local_abspath))
+    {
+      svn_wc_notify_t *notify;
+
+      notify = svn_wc_create_notify(local_abspath, svn_wc_notify_tree_conflict,
+                                    scratch_pool);
+      notify->kind = kind;
+
+      (*merge_b->ctx->notify_func2)(merge_b->ctx->notify_baton2, notify,
+                                    scratch_pool);
+    }
+#endif
+
+  if (merge_b->merge_source.ancestral
+      || merge_b->reintegrate_merge)
+    {
+      store_path(merge_b->tree_conflicted_abspaths, local_abspath);
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
 /* An svn_wc_diff_callbacks4_t function. */
 static svn_error_t *
 merge_dir_props_changed(svn_wc_notify_state_t *state,
@@ -1423,6 +1499,8 @@ merge_dir_props_changed(svn_wc_notify_st
   if (obstr_state != svn_wc_notify_state_inapplicable)
     {
       *state = obstr_state;
+      SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
+                          obstr_state, scratch_pool));
       return SVN_NO_ERROR;
     }
 
@@ -1450,6 +1528,8 @@ merge_dir_props_changed(svn_wc_notify_st
 
       *tree_conflicted = TRUE;
       *state = svn_wc_notify_state_missing;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                   scratch_pool));
 
       return SVN_NO_ERROR;
     }
@@ -1673,6 +1753,8 @@ merge_file_changed(svn_wc_notify_state_t
         *content_state = obstr_state;
         if (obstr_state == svn_wc_notify_state_missing)
           *prop_state = svn_wc_notify_state_missing;
+        SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
+                            obstr_state, scratch_pool));
         return SVN_NO_ERROR;
       }
   }
@@ -1704,6 +1786,8 @@ merge_file_changed(svn_wc_notify_state_t
             {
               *content_state = svn_wc_notify_state_missing;
               *prop_state = svn_wc_notify_state_missing;
+              SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
+                                  svn_wc_notify_state_missing, scratch_pool));
               return SVN_NO_ERROR;
             }
         }
@@ -1727,6 +1811,8 @@ merge_file_changed(svn_wc_notify_state_t
       *tree_conflicted = TRUE;
       *content_state = svn_wc_notify_state_missing;
       *prop_state = svn_wc_notify_state_missing;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                   scratch_pool));
       return SVN_NO_ERROR;
     }
 
@@ -1915,6 +2001,9 @@ merge_file_added(svn_wc_notify_state_t *
       {
         *content_state = obstr_state;
 
+        SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
+                            obstr_state, scratch_pool));
+
         return SVN_NO_ERROR;
       }
 
@@ -1940,6 +2029,10 @@ merge_file_added(svn_wc_notify_state_t *
       else
         /* this will make the repos_editor send a 'skipped' message */
         *content_state = svn_wc_notify_state_obstructed;
+
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                   scratch_pool));
+
       return SVN_NO_ERROR;
     }
 
@@ -1964,6 +2057,8 @@ merge_file_added(svn_wc_notify_state_t *
       if (parent_kind != svn_node_dir)
         {
           *content_state = svn_wc_notify_state_obstructed;
+          SVN_ERR(record_skip(merge_b, local_abspath, svn_node_file,
+                              svn_wc_notify_state_obstructed, scratch_pool));
           return SVN_NO_ERROR;
         }
 
@@ -2032,6 +2127,8 @@ merge_file_added(svn_wc_notify_state_t *
                                        svn_wc_conflict_action_add,
                                        reason));
           *tree_conflicted = TRUE;
+          SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                       scratch_pool));
         }
       else
         {
@@ -2180,6 +2277,9 @@ merge_file_deleted(svn_wc_notify_state_t
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         *state = obstr_state;
+        SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
+                            obstr_state, scratch_pool));
+
         return SVN_NO_ERROR;
       }
   }
@@ -2215,6 +2315,8 @@ merge_file_deleted(svn_wc_notify_state_t
 
       *tree_conflicted = TRUE;
       *state = svn_wc_notify_state_missing;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                   scratch_pool));
 
       return SVN_NO_ERROR;
     }
@@ -2251,6 +2353,8 @@ merge_file_deleted(svn_wc_notify_state_t
       *tree_conflicted = TRUE;
 
       *state = svn_wc_notify_state_obstructed;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                   scratch_pool));
     }
   
   return SVN_NO_ERROR;
@@ -2337,6 +2441,8 @@ merge_dir_added(svn_wc_notify_state_t *s
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         *state = obstr_state;
+        SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
+                            obstr_state, scratch_pool));
         return SVN_NO_ERROR;
       }
 
@@ -2365,6 +2471,9 @@ merge_dir_added(svn_wc_notify_state_t *s
         /* this will make the repos_editor send a 'skipped' message */
         *state = svn_wc_notify_state_obstructed;
 
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                   scratch_pool));
+
       return SVN_NO_ERROR;
     }
 
@@ -2427,6 +2536,8 @@ merge_dir_deleted(svn_wc_notify_state_t 
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         *state = obstr_state;
+        SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
+                             obstr_state, scratch_pool));
         return SVN_NO_ERROR;
       }
 
@@ -2461,6 +2572,8 @@ merge_dir_deleted(svn_wc_notify_state_t 
 
       *tree_conflicted = TRUE;
       *state = svn_wc_notify_state_missing;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                   scratch_pool));
 
       return SVN_NO_ERROR;
     }
@@ -2490,6 +2603,8 @@ merge_dir_deleted(svn_wc_notify_state_t 
                             svn_wc_conflict_reason_edited));
       *tree_conflicted = TRUE;
       *state = svn_wc_notify_state_conflicted;
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_file,
+                                   scratch_pool));
     }
   else
     {
@@ -2600,6 +2715,8 @@ merge_dir_opened(svn_boolean_t *tree_con
                                 svn_wc_conflict_reason_replaced));
           *tree_conflicted = TRUE;
           *skip_children = TRUE;
+          SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                       scratch_pool));
         }
 
       /* If we're trying to open a directory that's locally deleted,
@@ -2632,6 +2749,8 @@ merge_dir_opened(svn_boolean_t *tree_con
           *tree_conflicted = TRUE;
           *skip = TRUE;
           *skip_children = TRUE;
+          SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                       scratch_pool));
         }
     }
 
@@ -2968,16 +3087,6 @@ notification_receiver(void *baton, const
           store_path(merge_b->merged_abspaths, notify_abspath);
         }
 
-      if (notify->action == svn_wc_notify_skip)
-        {
-          store_path(merge_b->skipped_abspaths, notify_abspath);
-        }
-
-      if (notify->action == svn_wc_notify_tree_conflict)
-        {
-          store_path(merge_b->tree_conflicted_abspaths, notify_abspath);
-        }
-
       if (notify->action == svn_wc_notify_update_add)
         {
           update_the_list_of_added_subtrees(merge_b->target->abspath,
@@ -4716,11 +4825,11 @@ update_wc_mergeinfo(svn_mergeinfo_catalo
    otherwise.  RANGELIST is the set of revisions being merged from
    MERGEINFO_PATH to MERGE_B->target. */
 static svn_error_t *
-record_skips(const char *mergeinfo_path,
-             const svn_rangelist_t *rangelist,
-             svn_boolean_t is_rollback,
-             merge_cmd_baton_t *merge_b,
-             apr_pool_t *scratch_pool)
+record_skips_in_mergeinfo(const char *mergeinfo_path,
+                          const svn_rangelist_t *rangelist,
+                          svn_boolean_t is_rollback,
+                          merge_cmd_baton_t *merge_b,
+                          apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
   apr_hash_t *merges;
@@ -5311,7 +5420,7 @@ single_file_merge_get_file(const char **
 
    If *HEADER_SENT is not set, then send a header notification for range R
    before sending the state notification, and set *HEADER_SENT to TRUE. */
-static APR_INLINE void
+static svn_error_t *
 single_file_merge_notify(notification_receiver_baton_t *notify_baton,
                          const char *target_relpath,
                          svn_wc_notify_action_t action,
@@ -5326,7 +5435,15 @@ single_file_merge_notify(notification_re
   notify->content_state = text_state;
   notify->prop_state = prop_state;
   if (notify->content_state == svn_wc_notify_state_missing)
-    notify->action = svn_wc_notify_skip;
+    {
+      notify->action = svn_wc_notify_skip;
+      SVN_ERR(record_skip(notify_baton->merge_b, 
+                          svn_dirent_join(
+                                notify_baton->merge_b->target->abspath,
+                                target_relpath, pool),
+                          svn_node_file, text_state,
+                          pool));
+    }
 
   if (IS_OPERATIVE_NOTIFICATION(notify) && (! *header_sent))
     {
@@ -5337,6 +5454,8 @@ single_file_merge_notify(notification_re
       *header_sent = TRUE;
     }
   notification_receiver(notify_baton, notify, pool);
+
+  return SVN_NO_ERROR;
 }
 
 /* Compare two svn_client__merge_path_t elements **A and **B, given the
@@ -6921,12 +7040,13 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                          mimetype1, mimetype2,
                                          props1,
                                          merge_b, iterpool));
-              single_file_merge_notify(notify_b, target_relpath,
-                                       tree_conflicted
-                                         ? svn_wc_notify_tree_conflict
-                                         : svn_wc_notify_update_delete,
-                                       text_state, svn_wc_notify_state_unknown,
-                                       r, &header_sent, iterpool);
+              SVN_ERR(single_file_merge_notify(notify_b, target_relpath,
+                                               tree_conflicted
+                                                 ? svn_wc_notify_tree_conflict
+                                                 : svn_wc_notify_update_delete,
+                                               text_state,
+                                               svn_wc_notify_state_unknown,
+                                               r, &header_sent, iterpool));
 
               /* ...plus add... */
               SVN_ERR(merge_file_added(&text_state, &prop_state,
@@ -6938,12 +7058,12 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                        NULL, SVN_INVALID_REVNUM,
                                        propchanges, props1,
                                        merge_b, iterpool));
-              single_file_merge_notify(notify_b, target_relpath,
-                                       tree_conflicted
-                                         ? svn_wc_notify_tree_conflict
-                                         : svn_wc_notify_update_add,
-                                       text_state, prop_state,
-                                       r, &header_sent, iterpool);
+              SVN_ERR(single_file_merge_notify(notify_b, target_relpath,
+                                               tree_conflicted
+                                                 ? svn_wc_notify_tree_conflict
+                                                 : svn_wc_notify_update_add,
+                                               text_state, prop_state,
+                                               r, &header_sent, iterpool));
               /* ... equals replace. */
             }
           else
@@ -6956,12 +7076,12 @@ do_file_merge(svn_mergeinfo_catalog_t re
                                          mimetype1, mimetype2,
                                          propchanges, props1,
                                          merge_b, iterpool));
-              single_file_merge_notify(notify_b, target_relpath,
-                                       tree_conflicted
-                                         ? svn_wc_notify_tree_conflict
-                                         : svn_wc_notify_update_update,
-                                       text_state, prop_state,
-                                       r, &header_sent, iterpool);
+              SVN_ERR(single_file_merge_notify(notify_b, target_relpath,
+                                               tree_conflicted
+                                                 ? svn_wc_notify_tree_conflict
+                                                 : svn_wc_notify_update_update,
+                                               text_state, prop_state,
+                                               r, &header_sent, iterpool));
             }
 
           /* Remove the temporary files. Ignore if not found: they may
@@ -7776,8 +7896,9 @@ record_mergeinfo_for_dir_merge(svn_merge
              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, merge_b, iterpool));
+            SVN_ERR(record_skips_in_mergeinfo(mergeinfo_fspath,
+                                              child_merge_rangelist,
+                                              is_rollback, merge_b, iterpool));
 
           /* We may need to record non-inheritable mergeinfo that applies
              only to CHILD->ABSPATH. */