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/30 19:19:37 UTC

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

Author: rhuijben
Date: Wed Jan 30 18:19:36 2013
New Revision: 1440575

URL: http://svn.apache.org/viewvc?rev=1440575&view=rev
Log:
Refactor merge_dir_props_changed() and merge_dir_added() to become propert
diff tree processor functions. This temporarily duplicates some code that
was used for quite different purposes.

* subversion/libsvn_client/merge.c
  (merge_dir_props_changed): Rename this function to ...
  (merge_dir_changed): ... this. Extract the new directory code into ...
  (merge_dir_added): ... this function.

  (ignore_dir_props_changed,
   ignore_dir_added): New stubs.
  (merge_callbacks): Install stubs.

  (do_merge): Hook property change functions.

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=1440575&r1=1440574&r2=1440575&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Wed Jan 30 18:19:36 2013
@@ -2594,21 +2594,29 @@ merge_dir_opened(void **new_dir_baton,
   return SVN_NO_ERROR;
 }
 
-/* An svn_wc_diff_callbacks4_t function. */
+/* An svn_diff_tree_processor_t function.
+ *
+ * Called after merge_dir_opened() when a node exists in both the left and
+ * right source, but has its properties changed inbetween.
+ *
+ * After the merge_dir_opened() but before the call to this merge_dir_changed()
+ * function all descendants will have been updated.
+ */
 static svn_error_t *
-merge_dir_props_changed(svn_wc_notify_state_t *state,
-                        svn_boolean_t *tree_conflicted,
-                        const char *local_relpath,
-                        svn_boolean_t dir_was_added,
-                        const apr_array_header_t *propchanges,
-                        apr_hash_t *original_props,
-                        void *diff_baton,
-                        apr_pool_t *scratch_pool)
+merge_dir_changed(const char *relpath,
+                  const svn_diff_source_t *left_source,
+                  const svn_diff_source_t *right_source,
+                  /*const*/ apr_hash_t *left_props,
+                  /*const*/ apr_hash_t *right_props,
+                  const apr_array_header_t *prop_changes,
+                  void *dir_baton,
+                  const struct svn_diff_tree_processor_t *processor,
+                  apr_pool_t *scratch_pool)
 {
-  merge_cmd_baton_t *merge_b = diff_baton;
+  merge_cmd_baton_t *merge_b = processor->baton;
   const apr_array_header_t *props;
   const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
-                                              local_relpath, scratch_pool);
+                                              relpath, scratch_pool);
   svn_wc_notify_state_t obstr_state;
   svn_boolean_t is_deleted;
   svn_node_kind_t kind;
@@ -2653,14 +2661,121 @@ merge_dir_props_changed(svn_wc_notify_st
       return SVN_NO_ERROR;
     }
 
-  if (dir_was_added
-      && merge_b->dry_run
+  SVN_ERR(prepare_merge_props_changed(&props, local_abspath, prop_changes,
+                                      merge_b, scratch_pool, scratch_pool));
+
+  if (props->nelts)
+    {
+      const svn_wc_conflict_version_t *left;
+      const svn_wc_conflict_version_t *right;
+      svn_client_ctx_t *ctx = merge_b->ctx;
+      svn_wc_notify_state_t prop_state;
+
+      SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
+                                     svn_node_dir, &merge_b->merge_source,
+                                     merge_b->target, merge_b->pool));
+
+      SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath,
+                                  left, right,
+                                  left_props, props,
+                                  merge_b->dry_run,
+                                  ctx->conflict_func2, ctx->conflict_baton2,
+                                  ctx->cancel_func, ctx->cancel_baton,
+                                  scratch_pool));
+
+      if (prop_state == svn_wc_notify_state_conflicted)
+        {
+          alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
+                               merge_b->pool);
+        }
+
+      if (prop_state == svn_wc_notify_state_conflicted
+          || prop_state == svn_wc_notify_state_merged
+          || prop_state == svn_wc_notify_state_changed)
+        {
+          SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
+                                       svn_wc_notify_state_inapplicable,
+                                       prop_state, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+
+/* An svn_diff_tree_processor_t function.
+ *
+ * Called after merge_dir_opened() when a node doesn't exist in LEFT_SOURCE,
+ * but does in RIGHT_SOURCE. After the merge_dir_opened() but before the call
+ * to this merge_dir_added() function all descendants will have been added.
+ *
+ * When a node is replaced instead of just added a separate opened+deleted will
+ * be invoked before the current open+added.
+ */
+static svn_error_t *
+merge_dir_added(const char *relpath,
+                const svn_diff_source_t *copyfrom_source,
+                const svn_diff_source_t *right_source,
+                /*const*/ apr_hash_t *copyfrom_props,
+                /*const*/ apr_hash_t *right_props,
+                void *dir_baton,
+                const struct svn_diff_tree_processor_t *processor,
+                apr_pool_t *scratch_pool)
+{
+  merge_cmd_baton_t *merge_b = processor->baton;
+  const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
+                                              relpath, scratch_pool);
+  svn_wc_notify_state_t obstr_state;
+  svn_boolean_t is_deleted;
+  svn_node_kind_t kind;
+
+  SVN_ERR(perform_obstruction_check(&obstr_state, &is_deleted, &kind,
+                                    merge_b, local_abspath, svn_node_dir,
+                                    scratch_pool));
+
+  if (obstr_state != svn_wc_notify_state_inapplicable)
+    {
+      SVN_ERR(record_skip(merge_b, local_abspath, svn_node_dir,
+                          obstr_state, scratch_pool));
+      return SVN_NO_ERROR;
+    }
+
+  if (kind != svn_node_dir || is_deleted)
+    {
+      svn_wc_conflict_reason_t reason;
+      const char *moved_away_op_root_abspath = NULL;
+
+      if (is_deleted)
+        {
+          SVN_ERR(check_moved_away(&moved_away_op_root_abspath,
+                                   merge_b->ctx->wc_ctx,
+                                   local_abspath, scratch_pool));
+
+          if (moved_away_op_root_abspath)
+            reason = svn_wc_conflict_reason_moved_away;
+          else
+            reason = svn_wc_conflict_reason_deleted;
+        }
+      else
+        reason = svn_wc_conflict_reason_missing;
+
+      SVN_ERR(tree_conflict(merge_b, local_abspath, svn_node_file,
+                            svn_wc_conflict_action_edit, reason,
+                            moved_away_op_root_abspath));
+
+      SVN_ERR(record_tree_conflict(merge_b, local_abspath, svn_node_dir,
+                                   scratch_pool));
+
+      return SVN_NO_ERROR;
+    }
+
+  if (merge_b->dry_run
       && dry_run_added_p(merge_b, local_abspath))
     {
       return SVN_NO_ERROR; /* We can't do a real prop merge for added dirs */
     }
 
-  if (dir_was_added && merge_b->same_repos)
+  if (merge_b->same_repos)
     {
       /* When the directory was added in merge_dir_added() we didn't update its
          pristine properties. Instead we receive the property changes later and
@@ -2681,8 +2796,7 @@ merge_dir_props_changed(svn_wc_notify_st
       const char *child;
 
       /* Creating a hash containing regular and entry props */
-      apr_hash_t *new_pristine_props = svn_prop__patch(original_props, propchanges,
-                                                       scratch_pool);
+      apr_hash_t *new_pristine_props = right_props;
 
       parent_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
       child = svn_dirent_is_child(merge_b->target->abspath, local_abspath, NULL);
@@ -2726,66 +2840,38 @@ merge_dir_props_changed(svn_wc_notify_st
 
       return SVN_NO_ERROR;
     }
-
-  SVN_ERR(prepare_merge_props_changed(&props, local_abspath, propchanges,
-                                      merge_b, scratch_pool, scratch_pool));
-
-  if (props->nelts)
+  else
     {
-      const svn_wc_conflict_version_t *left;
-      const svn_wc_conflict_version_t *right;
-      svn_client_ctx_t *ctx = merge_b->ctx;
+      apr_array_header_t *regular_props;
+      apr_hash_t *new_props;
       svn_wc_notify_state_t prop_state;
 
-      SVN_ERR(make_conflict_versions(&left, &right, local_abspath,
-                                     svn_node_dir, &merge_b->merge_source,
-                                     merge_b->target, merge_b->pool));
+      SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(right_props,
+                                                          scratch_pool),
+                                   NULL, NULL, &regular_props, scratch_pool));
 
-      SVN_ERR(svn_wc_merge_props3(&prop_state, ctx->wc_ctx, local_abspath,
-                                  left, right,
-                                  original_props, props,
-                                  merge_b->dry_run,
-                                  ctx->conflict_func2, ctx->conflict_baton2,
-                                  ctx->cancel_func, ctx->cancel_baton,
-                                  scratch_pool));
+      new_props = svn_prop_array_to_hash(regular_props, scratch_pool);
 
-      if (prop_state == svn_wc_notify_state_conflicted)
-        {
-          alloc_and_store_path(&merge_b->conflicted_paths, local_abspath,
-                               merge_b->pool);
-        }
+      apr_hash_set(new_props, SVN_PROP_MERGEINFO, APR_HASH_KEY_STRING, NULL);
 
-      if (prop_state == svn_wc_notify_state_conflicted
-          || prop_state == svn_wc_notify_state_merged
-          || prop_state == svn_wc_notify_state_changed)
-        {
-          SVN_ERR(record_update_update(merge_b, local_abspath, svn_node_file,
-                                       svn_wc_notify_state_inapplicable,
-                                       prop_state, scratch_pool));
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
+      /* ### What is the easiest way to set new_props on LOCAL_ABSPATH?
 
+         ### This doesn't need a merge as we just added the node
+         ### (or installed a tree conflict and skipped this node)*/
 
-/* An svn_wc_diff_callbacks4_t function. */
-static svn_error_t *
-merge_dir_added(svn_wc_notify_state_t *state,
-                svn_boolean_t *tree_conflicted,
-                svn_boolean_t *skip,
-                svn_boolean_t *skip_children,
-                const char *local_relpath,
-                svn_revnum_t rev,
-                const char *copyfrom_path,
-                svn_revnum_t copyfrom_revision,
-                void *baton,
-                apr_pool_t *scratch_pool)
-{
-  merge_cmd_baton_t *merge_b = baton;
-  /*const char *local_abspath = svn_dirent_join(merge_b->target->abspath,
-                                              local_relpath, scratch_pool);*/
-
+      SVN_ERR(svn_wc_merge_props3(&prop_state, merge_b->ctx->wc_ctx,
+                                  local_abspath,
+                                  NULL, NULL,
+                                  apr_hash_make(scratch_pool),
+                                  svn_prop_hash_to_array(new_props,
+                                                         scratch_pool),
+                                  merge_b->dry_run,
+                                  merge_b->ctx->conflict_func2,
+                                  merge_b->ctx->conflict_baton2,
+                                  merge_b->ctx->cancel_func,
+                                  merge_b->ctx->cancel_baton,
+                                  scratch_pool));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -3061,6 +3147,35 @@ ignore_dir_opened(svn_boolean_t *tree_co
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+ignore_dir_props_changed(svn_wc_notify_state_t *state,
+                         svn_boolean_t *tree_conflicted,
+                         const char *local_relpath,
+                         svn_boolean_t dir_was_added,
+                         const apr_array_header_t *propchanges,
+                         apr_hash_t *original_props,
+                         void *diff_baton,
+                         apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+ignore_dir_added(svn_wc_notify_state_t *state,
+                svn_boolean_t *tree_conflicted,
+                svn_boolean_t *skip,
+                svn_boolean_t *skip_children,
+                const char *local_relpath,
+                svn_revnum_t rev,
+                const char *copyfrom_path,
+                svn_revnum_t copyfrom_revision,
+                void *baton,
+                apr_pool_t *scratch_pool)
+{
+  return SVN_NO_ERROR;
+}
+
+
 /* The main callback table for 'svn merge'.  */
 static const svn_wc_diff_callbacks4_t
 merge_callbacks =
@@ -3071,8 +3186,8 @@ merge_callbacks =
     ignore_file_deleted,
     merge_dir_deleted,
     ignore_dir_opened,
-    merge_dir_added,
-    merge_dir_props_changed,
+    ignore_dir_added,
+    ignore_dir_props_changed,
     merge_dir_closed
   };
 
@@ -9262,6 +9377,8 @@ do_merge(apr_hash_t **modified_subtrees,
                                                       scratch_pool);
 
     merge_processor->dir_opened   = merge_dir_opened;
+    merge_processor->dir_changed  = merge_dir_changed;
+    merge_processor->dir_added    = merge_dir_added;
 
     merge_processor->file_opened  = merge_file_opened;
     merge_processor->file_changed = merge_file_changed;