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 2012/06/28 21:10:26 UTC

svn commit: r1355114 [1/2] - in /subversion/trunk/subversion: libsvn_wc/conflicts.c libsvn_wc/conflicts.h libsvn_wc/externals.c libsvn_wc/merge.c libsvn_wc/props.c libsvn_wc/props.h libsvn_wc/update_editor.c tests/libsvn_wc/conflict-data-test.c

Author: rhuijben
Date: Thu Jun 28 19:10:24 2012
New Revision: 1355114

URL: http://svn.apache.org/viewvc?rev=1355114&view=rev
Log:
Switch the property merge code in libsvn_wc over to handle conflicts via a
conflict skel after installing the property changes in the working copy
database.

This to prove that the conflict skels contain all the necessary data and
to prepare for storing the conflict skel itself in the database for
extended postponed conflict handling.

* subversion/libsvn_wc/conflicts.c
  (includes): Add props.h and private/svn_string_private.h.
  (svn_wc__conflict_skel_set_op_update,
   svn_wc__conflict_skel_set_op_switch): Allow a NULL origin for conflicts on
    files added by update.
  (svn_wc__conflict_skel_add_prop_conflict,
   svn_wc__conflict_read_prop_conflict): Add their_original_props hash
     handling and don't store an () path for no marker file.

  (svn_wc__conflict_create_markers): New function, based on code that was in
     a few places in props.c.
  (generate_propconflict): New function, based on props.c's
    maybe_generate_propconflict.
  (svn_wc__conflict_invoke_resolver): New function.

* subversion/libsvn_wc/conflicts.h
  (svn_wc__conflict_skel_add_prop_conflict,
   svn_wc__conflict_read_prop_conflict): Add additional hash.

  (svn_wc__conflict_create_property_marker_skel): Remove prototype.
  (svn_wc__prop_conflict_skel_new,
   svn_wc__prop_conflict_skel_add): Make private to conflicts.c.

  (svn_wc__conflict_create_markers): New function, to create workingqueue
    operations that install a property conflict marker.
  (svn_wc__conflict_invoke_resolver): Remove invalid '*' from argument.

* subversion/libsvn_wc/externals.c
  (close_file): Collect a conflict skel from the property merging and create
    markers if necessary. Call conflict resolver if requested.

* subversion/libsvn_wc/merge.c
  (includes): Include conflicts.h.
  (svn_wc_merge5): Collect a conflict skel from the property merging and create
    markers if necessary. Call conflict resolver if requested.

* subversion/libsvn_wc/props.c
  (svn_wc__perform_props_merge): Collect a conflict skel from the property
    merging and create markers if necessary. Call conflict resolver if
    requested.

  (maybe_generate_propconflict): Remove function. Implementation moved to
    conflicts.c resolver code.

  (apply_single_prop_add,
   apply_single_prop_delete,
   apply_single_mergeinfo_prop_change,
   apply_single_generic_prop_change,
   apply_single_prop_change): Just tell caller that the property can't be
     merged instead of trying to resolve it directly. Remove unused arguments.

  (svn_wc__merge_props): Return a conflict skel instead of work items.
    Collect data instead of trying to resolve it directly. The resolver
    can then use the stored knowledge to provide the same resolver logic.
    Don't create a marker file directly, but leave that to the time when
    we want to install the db operations. Remove unused arguments.

* subversion/libsvn_wc/props.h
  (svn_wc__merge_props): Return a conflict skel instead of work items.

* subversion/libsvn_wc/update_editor.c
  (includes): Add conflicts.h.
  (dir_baton, file_baton): Add old_repos_relpath.

  (open_root, open_directory): Collect old_repos_relpath.
  (close_directory): Collect conflict skel. Create markers if necessary.
    Invoke conflict resolver if requested.
  (open_file): Collect old_repos_relpath.
  (close_file): Collect conflict skel. Create markers if necessary.
    Invoke conflict resolver if requested.

* subversion/tests/libsvn_wc/conflict-data-test.c
  (test_serialize_prop_conflict): Update caller.

Modified:
    subversion/trunk/subversion/libsvn_wc/conflicts.c
    subversion/trunk/subversion/libsvn_wc/conflicts.h
    subversion/trunk/subversion/libsvn_wc/externals.c
    subversion/trunk/subversion/libsvn_wc/merge.c
    subversion/trunk/subversion/libsvn_wc/props.c
    subversion/trunk/subversion/libsvn_wc/props.h
    subversion/trunk/subversion/libsvn_wc/update_editor.c
    subversion/trunk/subversion/tests/libsvn_wc/conflict-data-test.c

Modified: subversion/trunk/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/conflicts.c?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_wc/conflicts.c Thu Jun 28 19:10:24 2012
@@ -45,9 +45,11 @@
 #include "wc_db.h"
 #include "conflicts.h"
 #include "workqueue.h"
+#include "props.h"
 
 #include "private/svn_wc_private.h"
 #include "private/svn_skel.h"
+#include "private/svn_string_private.h"
 
 #include "svn_private_config.h"
 
@@ -149,7 +151,7 @@ svn_wc__conflict_skel_set_op_update(svn_
 
   origins = svn_skel__make_empty_list(result_pool);
 
-  SVN_ERR(conflict__prepend_location(origins, original, FALSE,
+  SVN_ERR(conflict__prepend_location(origins, original, TRUE,
                                      result_pool, scratch_pool));
 
   svn_skel__prepend(origins, why);
@@ -177,7 +179,7 @@ svn_wc__conflict_skel_set_op_switch(svn_
 
   origins = svn_skel__make_empty_list(result_pool);
 
-  SVN_ERR(conflict__prepend_location(origins, original, FALSE,
+  SVN_ERR(conflict__prepend_location(origins, original, TRUE,
                                      result_pool, scratch_pool));
 
   svn_skel__prepend(origins, why);
@@ -260,6 +262,7 @@ svn_wc__conflict_skel_add_prop_conflict(
                                         const char *marker_abspath,
                                         apr_hash_t *original_props,
                                         apr_hash_t *mine_props,
+                                        apr_hash_t *their_original_props,
                                         apr_hash_t *their_props,
                                         apr_hash_t *conflicted_prop_names,
                                         apr_pool_t *result_pool,
@@ -295,6 +298,15 @@ svn_wc__conflict_skel_add_prop_conflict(
   else
     svn_skel__prepend_str("", prop_conflict, result_pool); /* No their_props */
 
+  if (their_original_props)
+    {
+      SVN_ERR(svn_skel__unparse_proplist(&props, their_original_props,
+                                         result_pool));
+      svn_skel__prepend(props, prop_conflict);
+    }
+  else
+    svn_skel__prepend_str("", prop_conflict, result_pool); /* No their_original */
+
   if (mine_props)
     {
       SVN_ERR(svn_skel__unparse_proplist(&props, mine_props, result_pool));
@@ -334,8 +346,8 @@ svn_wc__conflict_skel_add_prop_conflict(
 
       svn_skel__prepend_str(marker_relpath, markers, result_pool);
     }
-  else
-    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
+/*else // ### set via svn_wc__conflict_create_markers
+    svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);*/
 
   svn_skel__prepend(markers, prop_conflict);
 
@@ -351,6 +363,7 @@ svn_error_t *
 svn_wc__conflict_read_prop_conflict(const char **marker_abspath,
                                     apr_hash_t **original_props,
                                     apr_hash_t **mine_props,
+                                    apr_hash_t **their_original_props,
                                     apr_hash_t **their_props,
                                     apr_hash_t **conflicted_prop_names,
                                     svn_wc__db_t *db,
@@ -428,6 +441,17 @@ svn_wc__conflict_read_prop_conflict(cons
   c = c->next;
 
   /* Get their properties */
+  if (their_original_props)
+    {
+      if (c->is_atom)
+        *their_original_props = apr_hash_make(result_pool);
+      else
+        SVN_ERR(svn_skel__parse_proplist(their_original_props, c,
+                                         result_pool));
+    }
+  c = c->next;
+
+  /* Get their properties */
   if (their_props)
     {
       if (c->is_atom)
@@ -502,7 +526,494 @@ svn_wc__prop_conflict_skel_add(
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_wc__conflict_create_markers(svn_skel_t **work_items,
+                                svn_wc__db_t *db,
+                                const char *local_abspath,
+                                svn_skel_t *conflict_skel,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
+{
+  svn_skel_t *prop_conflict;
+  *work_items = NULL;
+
+  SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_PROP));
+
+  if (prop_conflict)
+    {
+      svn_skel_t *work_item;
+
+      /* Ok, currently we have to do a few things for property conflicts:
+         - Create a marker file
+         - Create a WQ item that sets the marker name
+         - Create a WQ item that fills the marker with the expected data
+
+         This can be simplified once we really store conflict_skel in wc.db */
+
+      const char *marker_abspath;
+
+      /* ### as the legacy code, check if we already have a prejfile.
+             Probably never returns anything useful. */
+      SVN_ERR(svn_wc__get_prejfile_abspath(&marker_abspath, db, local_abspath,
+                                           scratch_pool, scratch_pool));
+
+      if (! marker_abspath)
+        {
+          svn_node_kind_t kind;
+          const char *marker_dir;
+          const char *marker_name;
+          const char *marker_relpath;
+
+          SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
+
+          if (kind == svn_node_dir)
+            {
+              marker_dir = local_abspath;
+              marker_name = SVN_WC__THIS_DIR_PREJ;
+            }
+          else
+            svn_dirent_split(&marker_dir, &marker_name, local_abspath,
+                             scratch_pool);
+
+          SVN_ERR(svn_io_open_uniquely_named(NULL, &marker_abspath,
+                                             marker_dir,
+                                             marker_name,
+                                             SVN_WC__PROP_REJ_EXT,
+                                             svn_io_file_del_none,
+                                             scratch_pool, scratch_pool));
+
+
+          SVN_ERR(svn_wc__wq_tmp_build_set_property_conflict_marker(
+                                                        work_items,
+                                                        db, local_abspath,
+                                                        marker_abspath,
+                                                        scratch_pool,
+                                                        scratch_pool));
+
+          SVN_ERR(svn_wc__db_to_relpath(&marker_relpath, db, local_abspath,
+                                        local_abspath,
+                                        result_pool, result_pool));
+
+          /* And store the marker in the skel */
+          svn_skel__prepend_str(marker_relpath, prop_conflict->children->next,
+                                result_pool);
+      }
+
+      /* Store the data in the WQ item in the same format used as 1.7.
+         Once we store the data in DB it is easier to just read it back
+         from the workqueue */
+      {
+        svn_skel_t *prop_data;
+        apr_hash_index_t *hi;
+        apr_hash_t *old_props;
+        apr_hash_t *mine_props;
+        apr_hash_t *their_original_props;
+        apr_hash_t *their_props;
+        apr_hash_t *conflicted_props;
+
+        SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL, &old_props,
+                                                    &mine_props,
+                                                    &their_original_props,
+                                                    &their_props,
+                                                    &conflicted_props,
+                                                    db, local_abspath,
+                                                    conflict_skel,
+                                                    scratch_pool,
+                                                    scratch_pool));
+
+        prop_data = svn_wc__prop_conflict_skel_new(result_pool);
+
+        for (hi = apr_hash_first(scratch_pool, conflicted_props);
+             hi;
+             hi = apr_hash_next(hi))
+          {
+            const char *propname = svn__apr_hash_index_key(hi);
+
+            svn_wc__prop_conflict_skel_add(
+                            prop_data, propname,
+                            old_props
+                                    ? apr_hash_get(old_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                    : NULL,
+                            mine_props
+                                    ? apr_hash_get(mine_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                    : NULL,
+                            their_props
+                                    ? apr_hash_get(their_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                      : NULL,
+                            their_original_props
+                                    ? apr_hash_get(their_original_props, propname,
+                                                   APR_HASH_KEY_STRING)
+                                      : NULL,
+                            result_pool, scratch_pool);
+          }
 
+        SVN_ERR(svn_wc__wq_build_prej_install(&work_item,
+                                              db, local_abspath,
+                                              prop_data,
+                                              scratch_pool, scratch_pool));
+
+        *work_items = svn_wc__wq_merge(*work_items, work_item, scratch_pool);
+      }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Helper function for the three apply_* functions below, used when
+ * merging properties together.
+ *
+ * Given property PROPNAME on LOCAL_ABSPATH, and four possible property
+ * values, generate four tmpfiles and pass them to CONFLICT_FUNC callback.
+ * This gives the client an opportunity to interactively resolve the
+ * property conflict.
+ *
+ * BASE_VAL/WORKING_VAL represent the current state of the working
+ * copy, and INCOMING_OLD_VAL/INCOMING_NEW_VAL represents the incoming
+ * propchange.  Any of these values might be NULL, indicating either
+ * non-existence or intent-to-delete.
+ *
+ * If the callback isn't available, or if it responds with
+ * 'choose_postpone', then set *CONFLICT_REMAINS to TRUE and return.
+ *
+ * If the callback responds with a choice of 'base', 'theirs', 'mine',
+ * or 'merged', then install the proper value into ACTUAL_PROPS and
+ * set *CONFLICT_REMAINS to FALSE.
+ */
+static svn_error_t *
+generate_propconflict(svn_boolean_t *conflict_remains,
+                      svn_wc__db_t *db,
+                      const char *local_abspath,
+                      const svn_wc_conflict_version_t *left_version,
+                      const svn_wc_conflict_version_t *right_version,
+                      const char *propname,
+                      const svn_string_t *base_val,
+                      const svn_string_t *working_val,
+                      const svn_string_t *incoming_old_val,
+                      const svn_string_t *incoming_new_val,
+                      svn_wc_conflict_resolver_func2_t conflict_func,
+                      void *conflict_baton,
+                      apr_pool_t *scratch_pool)
+{
+  svn_wc_conflict_result_t *result = NULL;
+  svn_wc_conflict_description2_t *cdesc;
+  const char *dirpath = svn_dirent_dirname(local_abspath, scratch_pool);
+  svn_kind_t kind;
+  const svn_string_t *new_value = NULL;
+
+  SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath, FALSE, FALSE,
+                               scratch_pool));
+
+  cdesc = svn_wc_conflict_description_create_prop2(
+                local_abspath,
+                (kind == svn_kind_dir) ? svn_node_dir : svn_node_file,
+                propname, scratch_pool);
+
+  cdesc->src_left_version = left_version;
+  cdesc->src_right_version = right_version;
+
+  /* Create a tmpfile for each of the string_t's we've got.  */
+  if (working_val)
+    {
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, working_val->data,
+                                  working_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->my_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  if (incoming_new_val)
+    {
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, incoming_new_val->data,
+                                  incoming_new_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->their_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  if (!base_val && !incoming_old_val)
+    {
+      /* If base and old are both NULL, then that's fine, we just let
+         base_file stay NULL as-is.  Both agents are attempting to add a
+         new property.  */
+    }
+
+  else if ((base_val && !incoming_old_val)
+           || (!base_val && incoming_old_val))
+    {
+      /* If only one of base and old are defined, then we've got a
+         situation where one agent is attempting to add the property
+         for the first time, and the other agent is changing a
+         property it thinks already exists.  In this case, we return
+         whichever older-value happens to be defined, so that the
+         conflict-callback can still attempt a 3-way merge. */
+
+      const svn_string_t *conflict_base_val = base_val ? base_val
+                                                       : incoming_old_val;
+      const char *file_name;
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath,
+                                  conflict_base_val->data,
+                                  conflict_base_val->len,
+                                  svn_io_file_del_on_pool_cleanup,
+                                  scratch_pool));
+      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+    }
+
+  else  /* base and old are both non-NULL */
+    {
+      const svn_string_t *conflict_base_val;
+      const char *file_name;
+
+      if (! svn_string_compare(base_val, incoming_old_val))
+        {
+          /* What happens if 'base' and 'old' don't match up?  In an
+             ideal situation, they would.  But if they don't, this is
+             a classic example of a patch 'hunk' failing to apply due
+             to a lack of context.  For example: imagine that the user
+             is busy changing the property from a value of "cat" to
+             "dog", but the incoming propchange wants to change the
+             same property value from "red" to "green".  Total context
+             mismatch.
+
+             HOWEVER: we can still pass one of the two base values as
+             'base_file' to the callback anyway.  It's still useful to
+             present the working and new values to the user to
+             compare. */
+
+          if (working_val && svn_string_compare(base_val, working_val))
+            conflict_base_val = incoming_old_val;
+          else
+            conflict_base_val = base_val;
+        }
+      else
+        {
+          conflict_base_val = base_val;
+        }
+
+      SVN_ERR(svn_io_write_unique(&file_name, dirpath, conflict_base_val->data,
+                                  conflict_base_val->len,
+                                  svn_io_file_del_on_pool_cleanup, scratch_pool));
+      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+
+      if (working_val && incoming_new_val)
+        {
+          svn_stream_t *mergestream;
+          svn_diff_t *diff;
+          svn_diff_file_options_t *options =
+            svn_diff_file_options_create(scratch_pool);
+
+          SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->merged_file,
+                                         NULL, svn_io_file_del_on_pool_cleanup,
+                                         scratch_pool, scratch_pool));
+          SVN_ERR(svn_diff_mem_string_diff3(&diff, conflict_base_val,
+                                            working_val,
+                                            incoming_new_val, options, scratch_pool));
+          SVN_ERR(svn_diff_mem_string_output_merge2
+                  (mergestream, diff, conflict_base_val, working_val,
+                   incoming_new_val, NULL, NULL, NULL, NULL,
+                   svn_diff_conflict_display_modified_latest, scratch_pool));
+          SVN_ERR(svn_stream_close(mergestream));
+        }
+    }
+
+  if (!incoming_old_val && incoming_new_val)
+    cdesc->action = svn_wc_conflict_action_add;
+  else if (incoming_old_val && !incoming_new_val)
+    cdesc->action = svn_wc_conflict_action_delete;
+  else
+    cdesc->action = svn_wc_conflict_action_edit;
+
+  if (base_val && !working_val)
+    cdesc->reason = svn_wc_conflict_reason_deleted;
+  else if (!base_val && working_val)
+    cdesc->reason = svn_wc_conflict_reason_obstructed;
+  else
+    cdesc->reason = svn_wc_conflict_reason_edited;
+
+  /* Invoke the interactive conflict callback. */
+  {
+    SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
+                          scratch_pool));
+  }
+  if (result == NULL)
+    {
+      *conflict_remains = TRUE;
+      return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                              NULL, _("Conflict callback violated API:"
+                                      " returned no results."));
+    }
+
+
+  switch (result->choice)
+    {
+      default:
+      case svn_wc_conflict_choose_postpone:
+        {
+          *conflict_remains = TRUE;
+          break;
+        }
+      case svn_wc_conflict_choose_mine_full:
+        {
+          /* No need to change actual_props; it already contains working_val */
+          *conflict_remains = FALSE;
+          new_value = working_val;
+          break;
+        }
+      /* I think _mine_full and _theirs_full are appropriate for prop
+         behavior as well as the text behavior.  There should even be
+         analogous behaviors for _mine and _theirs when those are
+         ready, namely: fold in all non-conflicting prop changes, and
+         then choose _mine side or _theirs side for conflicting ones. */
+      case svn_wc_conflict_choose_theirs_full:
+        {
+          *conflict_remains = FALSE;
+          new_value = incoming_new_val;
+          break;
+        }
+      case svn_wc_conflict_choose_base:
+        {
+          *conflict_remains = FALSE;
+          new_value = base_val;
+          break;
+        }
+      case svn_wc_conflict_choose_merged:
+        {
+          if (!cdesc->merged_file && !result->merged_file)
+            return svn_error_create
+                (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+                 NULL, _("Conflict callback violated API:"
+                         " returned no merged file."));
+          else
+            {
+              svn_stringbuf_t *merged_stringbuf;
+              svn_string_t *merged_string;
+
+              SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
+                                               result->merged_file ?
+                                                    result->merged_file :
+                                                    cdesc->merged_file,
+                                               scratch_pool));
+              merged_string = svn_stringbuf__morph_into_string(merged_stringbuf);
+              *conflict_remains = FALSE;
+              new_value = merged_string;
+            }
+          break;
+        }
+    }
+
+  if (!*conflict_remains)
+    {
+      apr_hash_t *props;
+
+      /* For now, just set the property values. This should really do some of the
+         more advanced things from svn_wc_prop_set() */
+
+      SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
+                                    scratch_pool));
+
+      apr_hash_set(props, propname, APR_HASH_KEY_STRING, new_value);
+
+      SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, props,
+                                      FALSE, NULL, NULL,
+                                      scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
+                                 const char *local_abspath,
+                                 svn_skel_t *conflict_skel,
+                                 svn_wc_conflict_resolver_func2_t resolver_func,
+                                 void *resolver_baton,
+                                 apr_pool_t *scratch_pool)
+{
+  svn_skel_t *prop_conflict;
+
+  SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
+                                 SVN_WC__CONFLICT_KIND_PROP));
+
+  /* Quick and dirty compatibility wrapper. My guess would be that most resolvers
+     would want to look at all properties at the same time.
+
+     ### svn currently only invokes this from the merge code to collect the list of
+     ### conflicted paths. Eventually this code will be the base for 'svn resolve'
+     ### and at that time the test coverage will improve
+     */
+  if (prop_conflict)
+    {
+      apr_hash_t *old_props;
+      apr_hash_t *mine_props;
+      apr_hash_t *their_props;
+      apr_hash_t *old_their_props;
+      apr_hash_t *conflicted;
+      apr_pool_t *iterpool;
+      apr_hash_index_t *hi;
+      svn_boolean_t mark_resolved = TRUE;
+
+      SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
+                                                  &old_props,
+                                                  &mine_props,
+                                                  &old_their_props,
+                                                  &their_props,
+                                                  &conflicted,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+      iterpool = svn_pool_create(scratch_pool);
+
+      for (hi = apr_hash_first(scratch_pool, conflicted);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *propname = svn__apr_hash_index_key(hi);
+          svn_boolean_t conflict_remains = TRUE;
+
+          svn_pool_clear(iterpool);
+
+          SVN_ERR(generate_propconflict(&conflict_remains,
+                                        db, local_abspath,
+                                        NULL, NULL, propname,
+                                        old_props
+                                          ? apr_hash_get(old_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        mine_props
+                                          ? apr_hash_get(mine_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        old_their_props
+                                          ? apr_hash_get(old_their_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        their_props
+                                          ? apr_hash_get(their_props, propname,
+                                                         APR_HASH_KEY_STRING)
+                                          : NULL,
+                                        resolver_func, resolver_baton,
+                                        iterpool));
+
+          if (conflict_remains)
+            mark_resolved = FALSE;
+        }
+
+      if (mark_resolved)
+        SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE,
+                                            FALSE, NULL, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 
 /*** Resolving a conflict automatically ***/

Modified: subversion/trunk/subversion/libsvn_wc/conflicts.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/conflicts.h?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/conflicts.h (original)
+++ subversion/trunk/subversion/libsvn_wc/conflicts.h Thu Jun 28 19:10:24 2012
@@ -187,6 +187,7 @@ svn_wc__conflict_skel_add_prop_conflict(
                                         const char *marker_abspath,
                                         apr_hash_t *original_props,
                                         apr_hash_t *mine_props,
+                                        apr_hash_t *their_original_props,
                                         apr_hash_t *their_props,
                                         apr_hash_t *conflicted_prop_names,
                                         apr_pool_t *result_pool,
@@ -233,6 +234,7 @@ svn_error_t *
 svn_wc__conflict_read_prop_conflict(const char **marker_abspath,
                                     apr_hash_t **original_props,
                                     apr_hash_t **mine_props,
+                                    apr_hash_t **their_original_props,
                                     apr_hash_t **their_props,
                                     apr_hash_t **conflicted_prop_names,
                                     svn_wc__db_t *db,
@@ -241,53 +243,24 @@ svn_wc__conflict_read_prop_conflict(cons
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
 
-/* (Temporary) helper to create the (intermediate) data necessary for the
-   property marker workqueue data from the conflict skel */
-svn_error_t *
-svn_wc__conflict_create_property_marker_skel(svn_skel_t **marker_skel,
-                                             svn_skel_t *conflict_skel,
-                                             apr_pool_t *result_pool,
-                                             apr_pool_t *scratch_pool);
 
-/* -----------------------------------------
- * Intermediate property conflict skel store
+/* Create the necessary marker files for the conflicts stored in
+ * CONFLICT_SKEL and return the work items to fill the markers from
+ * the work queue.
+ *
+ * Currently only used for property conflicts as text conflict markers
+ * are just in-wc files.
+ *
+ * Allocate the result in RESULT_POOL. Perform temporary allocations in
+ * SCRATCH_POOL.
  */
-/* Return a new prop_conflict skel, allocated in RESULT_POOL. */
-svn_skel_t *
-svn_wc__prop_conflict_skel_new(apr_pool_t *result_pool);
-
-/* Add a property conflict to SKEL.
-
-   PROP_NAME is the name of the conflicted property.
-
-   ORIGINAL_VALUE is the property's value at the BASE revision. MINE_VALUE
-   is the property's value in WORKING (BASE + local modifications).
-   INCOMING_VALUE is the incoming property value brought in by the
-   operation. When merging, INCOMING_BASE_VALUE is the base value against
-   which INCOMING_VALUE ws being applied. For updates, INCOMING_BASE_VALUE
-   should be the same as ORIGINAL_VALUE.
-
-   *_VALUE may be NULL, indicating no value was present.
-
-   It is an error (### which one?) if no conflicting operation has been
-   set on CONFLICT_SKEL before calling this function.
-   It is an error (### which one?) if CONFLICT_SKEL already cotains
-   a propery conflict for PROP_NAME.
-
-   The conflict recorded in SKEL will be allocated from RESULT_POOL. Do
-   temporary allocations in SCRATCH_POOL.
-*/
 svn_error_t *
-svn_wc__prop_conflict_skel_add(
-  svn_skel_t *skel,
-  const char *prop_name,
-  const svn_string_t *original_value,
-  const svn_string_t *mine_value,
-  const svn_string_t *incoming_value,
-  const svn_string_t *incoming_base_value,
-  apr_pool_t *result_pool,
-  apr_pool_t *scratch_pool);
-
+svn_wc__conflict_create_markers(svn_skel_t **work_item,
+                                svn_wc__db_t *db,
+                                const char *local_abspath,
+                                svn_skel_t *conflict_skel,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool);
 
 /* Call the interactive conflict resolver RESOLVER_FUNC with RESOLVER_BATON to
    allow resolving the conflicts on LOCAL_ABSPATH.
@@ -300,7 +273,7 @@ svn_error_t *
 svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
                                  const char *local_abspath,
                                  svn_skel_t *conflict_skel,
-                                 svn_wc_conflict_resolver_func2_t *resolver_func,
+                                 svn_wc_conflict_resolver_func2_t resolver_func,
                                  void *resolver_baton,
                                  apr_pool_t *scratch_pool);
 

Modified: subversion/trunk/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/externals.c?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/externals.c (original)
+++ subversion/trunk/subversion/libsvn_wc/externals.c Thu Jun 28 19:10:24 2012
@@ -600,10 +600,11 @@ close_file(void *file_baton,
       eb->new_pristine_abspath = NULL;
     }
 
-  /* ### TODO: Merge the changes */
+  /* Merge the changes */
 
   {
     svn_skel_t *all_work_items = NULL;
+    svn_skel_t *conflict_skel = NULL;
     svn_skel_t *work_item;
     apr_hash_t *base_props = NULL;
     apr_hash_t *actual_props = NULL;
@@ -675,26 +676,20 @@ close_file(void *file_baton,
 
       if (regular_prop_changes->nelts > 0)
         {
-          SVN_ERR(svn_wc__merge_props(&work_item, &prop_state,
+          SVN_ERR(svn_wc__merge_props(&conflict_skel,
+                                      &prop_state,
                                       &new_pristine_props,
                                       &new_actual_props,
                                       eb->db, eb->local_abspath,
                                       svn_kind_file,
-                                      NULL, NULL,
                                       NULL /* server_baseprops*/,
                                       base_props,
                                       actual_props,
                                       regular_prop_changes,
                                       TRUE /* base_merge */,
                                       FALSE /* dry_run */,
-                                      eb->conflict_func,
-                                      eb->conflict_baton,
                                       eb->cancel_func, eb->cancel_baton,
                                       pool, pool));
-
-          if (work_item)
-            all_work_items = svn_wc__wq_merge(all_work_items, work_item,
-                                              pool);
         }
       else
         {
@@ -784,6 +779,29 @@ close_file(void *file_baton,
         /* ### Retranslate on magic property changes, etc. */
       }
 
+    if (conflict_skel)
+      {
+        SVN_ERR(svn_wc__conflict_skel_set_op_switch(
+                            conflict_skel,
+                            svn_wc_conflict_version_create2(
+                                    eb->repos_root_url,
+                                    eb->repos_uuid,
+                                    repos_relpath,
+                                    eb->original_revision,
+                                    svn_node_file,
+                                    pool),
+                            pool, pool));
+
+
+        SVN_ERR(svn_wc__conflict_create_markers(&work_item,
+                                                eb->db, eb->local_abspath,
+                                                conflict_skel,
+                                                pool, pool));
+
+        all_work_items = svn_wc__wq_merge(all_work_items, work_item,
+                                          pool);
+      }
+
     SVN_ERR(svn_wc__db_external_add_file(
                         eb->db,
                         eb->local_abspath,

Modified: subversion/trunk/subversion/libsvn_wc/merge.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/merge.c?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/merge.c (original)
+++ subversion/trunk/subversion/libsvn_wc/merge.c Thu Jun 28 19:10:24 2012
@@ -29,6 +29,7 @@
 
 #include "wc.h"
 #include "adm_files.h"
+#include "conflicts.h"
 #include "translate.h"
 #include "workqueue.h"
 
@@ -1521,8 +1522,8 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
               apr_pool_t *scratch_pool)
 {
   const char *dir_abspath = svn_dirent_dirname(target_abspath, scratch_pool);
-  svn_skel_t *prop_items = NULL;
   svn_skel_t *work_items;
+  svn_skel_t *conflict_skel = NULL;
   apr_hash_t *pristine_props = NULL;
   apr_hash_t *actual_props = NULL;
   apr_hash_t *new_actual_props = NULL;
@@ -1600,14 +1601,13 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
                                                             scratch_pool));
         }
 
-      SVN_ERR(svn_wc__merge_props(&prop_items, merge_props_outcome,
+      SVN_ERR(svn_wc__merge_props(&conflict_skel,
+                                  merge_props_outcome,
                                   &new_pristine_props, &new_actual_props,
                                   wc_ctx->db, target_abspath, svn_kind_file,
-                                  left_version, right_version,
                                   original_props, pristine_props, actual_props,
                                   prop_diff, FALSE /* base_merge */,
                                   dry_run,
-                                  conflict_func, conflict_baton,
                                   cancel_func, cancel_baton,
                                   scratch_pool, scratch_pool));
     }
@@ -1630,11 +1630,27 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
                                  cancel_func, cancel_baton,
                                  scratch_pool, scratch_pool));
 
-  work_items = svn_wc__wq_merge(prop_items, work_items, scratch_pool);
-
   /* If this isn't a dry run, then run the work!  */
   if (!dry_run)
     {
+      if (conflict_skel)
+        {
+          svn_skel_t *work_item;
+
+          SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_skel,
+                                                     left_version,
+                                                     right_version,
+                                                     scratch_pool,
+                                                     scratch_pool));
+
+          SVN_ERR(svn_wc__conflict_create_markers(&work_item,
+                                                  wc_ctx->db, target_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+          work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+        }
+
       if (new_actual_props)
         SVN_ERR(svn_wc__db_op_set_props(wc_ctx->db, target_abspath,
                                         new_actual_props,
@@ -1646,6 +1662,12 @@ svn_wc_merge5(enum svn_wc_merge_outcome_
       SVN_ERR(svn_wc__wq_run(wc_ctx->db, target_abspath,
                              cancel_func, cancel_baton,
                              scratch_pool));
+
+      if (conflict_skel && conflict_func)
+        SVN_ERR(svn_wc__conflict_invoke_resolver(wc_ctx->db, target_abspath,
+                                                 conflict_skel,
+                                                 conflict_func, conflict_baton,
+                                                 scratch_pool));
     }
   
   return SVN_NO_ERROR;

Modified: subversion/trunk/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.c?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/props.c (original)
+++ subversion/trunk/subversion/libsvn_wc/props.c Thu Jun 28 19:10:24 2012
@@ -237,7 +237,8 @@ svn_wc__perform_props_merge(svn_wc_notif
   apr_hash_t *new_actual_props;
   svn_boolean_t had_props, props_mod;
   svn_boolean_t have_base;
-  svn_skel_t *work_items;
+  svn_skel_t *work_items = NULL;
+  svn_skel_t *conflict_skel = NULL;
 
   /* IMPORTANT: svn_wc_merge_prop_diffs relies on the fact that baseprops
      may be NULL. */
@@ -299,24 +300,38 @@ svn_wc__perform_props_merge(svn_wc_notif
 
   /* Note that while this routine does the "real" work, it's only
      prepping tempfiles and writing log commands.  */
-  SVN_ERR(svn_wc__merge_props(&work_items, state,
+  SVN_ERR(svn_wc__merge_props(&conflict_skel, state,
                               &new_pristine_props, &new_actual_props,
                               db, local_abspath, kind,
-                              left_version, right_version,
                               baseprops /* server_baseprops */,
                               pristine_props,
                               actual_props,
                               propchanges, base_merge, dry_run,
-                              conflict_func, conflict_baton,
                               cancel_func, cancel_baton,
                               scratch_pool, scratch_pool));
 
   if (dry_run)
     {
-      SVN_ERR_ASSERT(! work_items);
       return SVN_NO_ERROR;
     }
 
+  if (conflict_skel)
+    {
+      svn_skel_t *work_item;
+      SVN_ERR(svn_wc__conflict_skel_set_op_merge(conflict_skel,
+                                                 left_version,
+                                                 right_version,
+                                                 scratch_pool,
+                                                 scratch_pool));
+
+      SVN_ERR(svn_wc__conflict_create_markers(&work_item,
+                                              db, local_abspath,
+                                              conflict_skel,
+                                              scratch_pool, scratch_pool));
+
+      work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+    }
+
   {
     const char *dir_abspath;
 
@@ -344,6 +359,7 @@ svn_wc__perform_props_merge(svn_wc_notif
       return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
                               U_("base_merge=TRUE is no longer supported"));
 #endif
+
     SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, new_actual_props,
                                     svn_wc__has_magic_property(propchanges),
                                     NULL /* conflict */,
@@ -355,6 +371,11 @@ svn_wc__perform_props_merge(svn_wc_notif
                              scratch_pool));
   }
 
+  if (conflict_skel && conflict_func)
+    SVN_ERR(svn_wc__conflict_invoke_resolver(db, local_abspath, conflict_skel,
+                                             conflict_func, conflict_baton,
+                                             scratch_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -769,268 +790,6 @@ set_prop_merge_state(svn_wc_notify_state
   *state = new_value;
 }
 
-/* Helper function for the three apply_* functions below, used when
- * merging properties together.
- *
- * Given property PROPNAME on LOCAL_ABSPATH, and four possible property
- * values, generate four tmpfiles and pass them to CONFLICT_FUNC callback.
- * This gives the client an opportunity to interactively resolve the
- * property conflict.
- *
- * BASE_VAL/WORKING_VAL represent the current state of the working
- * copy, and INCOMING_OLD_VAL/INCOMING_NEW_VAL represents the incoming
- * propchange.  Any of these values might be NULL, indicating either
- * non-existence or intent-to-delete.
- *
- * If the callback isn't available, or if it responds with
- * 'choose_postpone', then set *CONFLICT_REMAINS to TRUE and return.
- *
- * If the callback responds with a choice of 'base', 'theirs', 'mine',
- * or 'merged', then install the proper value into ACTUAL_PROPS and
- * set *CONFLICT_REMAINS to FALSE.
- */
-static svn_error_t *
-maybe_generate_propconflict(svn_boolean_t *conflict_remains,
-                            svn_wc__db_t *db,
-                            const char *local_abspath,
-                            const svn_wc_conflict_version_t *left_version,
-                            const svn_wc_conflict_version_t *right_version,
-                            svn_boolean_t is_dir,
-                            const char *propname,
-                            apr_hash_t *actual_props,
-                            const svn_string_t *incoming_old_val,
-                            const svn_string_t *incoming_new_val,
-                            const svn_string_t *base_val,
-                            const svn_string_t *working_val,
-                            svn_wc_conflict_resolver_func2_t conflict_func,
-                            void *conflict_baton,
-                            svn_boolean_t dry_run,
-                            apr_pool_t *scratch_pool)
-{
-  svn_wc_conflict_result_t *result = NULL;
-  apr_pool_t *filepool = svn_pool_create(scratch_pool);
-  svn_wc_conflict_description2_t *cdesc;
-  const char *dirpath = svn_dirent_dirname(local_abspath, filepool);
-
-  if (! conflict_func || dry_run)
-    {
-      /* Just postpone the conflict. */
-      *conflict_remains = TRUE;
-      return SVN_NO_ERROR;
-    }
-
-  cdesc = svn_wc_conflict_description_create_prop2(
-    local_abspath,
-    is_dir ? svn_node_dir : svn_node_file, propname, scratch_pool);
-
-  cdesc->src_left_version = left_version;
-  cdesc->src_right_version = right_version;
-
-  /* Create a tmpfile for each of the string_t's we've got.  */
-  if (working_val)
-    {
-      const char *file_name;
-
-      SVN_ERR(svn_io_write_unique(&file_name, dirpath, working_val->data,
-                                  working_val->len,
-                                  svn_io_file_del_on_pool_cleanup, filepool));
-      cdesc->my_abspath = svn_dirent_join(dirpath, file_name, filepool);
-    }
-
-  if (incoming_new_val)
-    {
-      const char *file_name;
-
-      SVN_ERR(svn_io_write_unique(&file_name, dirpath, incoming_new_val->data,
-                                  incoming_new_val->len,
-                                  svn_io_file_del_on_pool_cleanup, filepool));
-      cdesc->their_abspath = svn_dirent_join(dirpath, file_name, filepool);
-    }
-
-  if (!base_val && !incoming_old_val)
-    {
-      /* If base and old are both NULL, then that's fine, we just let
-         base_file stay NULL as-is.  Both agents are attempting to add a
-         new property.  */
-    }
-
-  else if ((base_val && !incoming_old_val)
-           || (!base_val && incoming_old_val))
-    {
-      /* If only one of base and old are defined, then we've got a
-         situation where one agent is attempting to add the property
-         for the first time, and the other agent is changing a
-         property it thinks already exists.  In this case, we return
-         whichever older-value happens to be defined, so that the
-         conflict-callback can still attempt a 3-way merge. */
-
-      const svn_string_t *conflict_base_val = base_val ? base_val
-                                                       : incoming_old_val;
-      const char *file_name;
-
-      SVN_ERR(svn_io_write_unique(&file_name, dirpath,
-                                  conflict_base_val->data,
-                                  conflict_base_val->len,
-                                  svn_io_file_del_on_pool_cleanup,
-                                  filepool));
-      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, filepool);
-    }
-
-  else  /* base and old are both non-NULL */
-    {
-      const svn_string_t *conflict_base_val;
-      const char *file_name;
-
-      if (! svn_string_compare(base_val, incoming_old_val))
-        {
-          /* What happens if 'base' and 'old' don't match up?  In an
-             ideal situation, they would.  But if they don't, this is
-             a classic example of a patch 'hunk' failing to apply due
-             to a lack of context.  For example: imagine that the user
-             is busy changing the property from a value of "cat" to
-             "dog", but the incoming propchange wants to change the
-             same property value from "red" to "green".  Total context
-             mismatch.
-
-             HOWEVER: we can still pass one of the two base values as
-             'base_file' to the callback anyway.  It's still useful to
-             present the working and new values to the user to
-             compare. */
-
-          if (working_val && svn_string_compare(base_val, working_val))
-            conflict_base_val = incoming_old_val;
-          else
-            conflict_base_val = base_val;
-        }
-      else
-        {
-          conflict_base_val = base_val;
-        }
-
-      SVN_ERR(svn_io_write_unique(&file_name, dirpath, conflict_base_val->data,
-                                  conflict_base_val->len,
-                                  svn_io_file_del_on_pool_cleanup, filepool));
-      cdesc->base_abspath = svn_dirent_join(dirpath, file_name, filepool);
-
-      if (working_val && incoming_new_val)
-        {
-          svn_stream_t *mergestream;
-          svn_diff_t *diff;
-          svn_diff_file_options_t *options =
-            svn_diff_file_options_create(filepool);
-
-          SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->merged_file,
-                                         NULL, svn_io_file_del_on_pool_cleanup,
-                                         filepool, scratch_pool));
-          SVN_ERR(svn_diff_mem_string_diff3(&diff, conflict_base_val,
-                                            working_val,
-                                            incoming_new_val, options, filepool));
-          SVN_ERR(svn_diff_mem_string_output_merge2
-                  (mergestream, diff, conflict_base_val, working_val,
-                   incoming_new_val, NULL, NULL, NULL, NULL,
-                   svn_diff_conflict_display_modified_latest, filepool));
-          SVN_ERR(svn_stream_close(mergestream));
-        }
-    }
-
-  /* Build the rest of the description object: */
-  cdesc->mime_type = (is_dir ? NULL : svn_prop_get_value(actual_props,
-                                                         SVN_PROP_MIME_TYPE));
-  cdesc->is_binary = (cdesc->mime_type
-                      && svn_mime_type_is_binary(cdesc->mime_type));
-
-  if (!incoming_old_val && incoming_new_val)
-    cdesc->action = svn_wc_conflict_action_add;
-  else if (incoming_old_val && !incoming_new_val)
-    cdesc->action = svn_wc_conflict_action_delete;
-  else
-    cdesc->action = svn_wc_conflict_action_edit;
-
-  if (base_val && !working_val)
-    cdesc->reason = svn_wc_conflict_reason_deleted;
-  else if (!base_val && working_val)
-    cdesc->reason = svn_wc_conflict_reason_obstructed;
-  else
-    cdesc->reason = svn_wc_conflict_reason_edited;
-
-  /* Invoke the interactive conflict callback. */
-  {
-    SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
-                          scratch_pool));
-  }
-  if (result == NULL)
-    {
-      *conflict_remains = TRUE;
-      return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
-                              NULL, _("Conflict callback violated API:"
-                                      " returned no results."));
-    }
-
-  switch (result->choice)
-    {
-      default:
-      case svn_wc_conflict_choose_postpone:
-        {
-          *conflict_remains = TRUE;
-          break;
-        }
-      case svn_wc_conflict_choose_mine_full:
-        {
-          /* No need to change actual_props; it already contains working_val */
-          *conflict_remains = FALSE;
-          break;
-        }
-      /* I think _mine_full and _theirs_full are appropriate for prop
-         behavior as well as the text behavior.  There should even be
-         analogous behaviors for _mine and _theirs when those are
-         ready, namely: fold in all non-conflicting prop changes, and
-         then choose _mine side or _theirs side for conflicting ones. */
-      case svn_wc_conflict_choose_theirs_full:
-        {
-          apr_hash_set(actual_props, propname, APR_HASH_KEY_STRING,
-                       incoming_new_val);
-          *conflict_remains = FALSE;
-          break;
-        }
-      case svn_wc_conflict_choose_base:
-        {
-          apr_hash_set(actual_props, propname, APR_HASH_KEY_STRING, base_val);
-          *conflict_remains = FALSE;
-          break;
-        }
-      case svn_wc_conflict_choose_merged:
-        {
-          if (!cdesc->merged_file && !result->merged_file)
-            return svn_error_create
-                (SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
-                 NULL, _("Conflict callback violated API:"
-                         " returned no merged file."));
-          else
-            {
-              svn_stringbuf_t *merged_stringbuf;
-              svn_string_t *merged_string;
-
-              SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
-                                               result->merged_file ?
-                                                    result->merged_file :
-                                                    cdesc->merged_file,
-                                               scratch_pool));
-              merged_string = svn_stringbuf__morph_into_string(merged_stringbuf);
-              apr_hash_set(actual_props, propname,
-                           APR_HASH_KEY_STRING, merged_string);
-              *conflict_remains = FALSE;
-            }
-          break;
-        }
-    }
-
-  /* Delete any tmpfiles we made. */
-  svn_pool_destroy(filepool);
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Add the property with name PROPNAME to the set of ACTUAL_PROPS on
  * PATH, setting *STATE or *CONFLICT_REMAINS according to merge outcomes.
  *
@@ -1040,26 +799,16 @@ maybe_generate_propconflict(svn_boolean_
  * BASE_VAL contains the working copy base property value
  *
  * NEW_VAL contains the value to be set.
- *
- * CONFLICT_FUNC/BATON is a callback to be called before declaring a
- * property conflict;  it gives the client a chance to resolve the
- * conflict interactively.
  */
 static svn_error_t *
 apply_single_prop_add(svn_wc_notify_state_t *state,
                       svn_boolean_t *conflict_remains,
                       svn_wc__db_t *db,
                       const char *local_abspath,
-                      const svn_wc_conflict_version_t *left_version,
-                      const svn_wc_conflict_version_t *right_version,
-                      svn_boolean_t is_dir,
                       apr_hash_t *actual_props,
                       const char *propname,
                       const svn_string_t *base_val,
                       const svn_string_t *new_val,
-                      svn_wc_conflict_resolver_func2_t conflict_func,
-                      void *conflict_baton,
-                      svn_boolean_t dry_run,
                       apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 
@@ -1112,31 +861,11 @@ apply_single_prop_add(svn_wc_notify_stat
             }
 
           if (!merged_prop)
-            {
-              SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                                  db, local_abspath,
-                                                  left_version, right_version,
-                                                  is_dir,
-                                                  propname, actual_props,
-                                                  NULL, new_val,
-                                                  base_val, working_val,
-                                                  conflict_func,
-                                                  conflict_baton,
-                                                  dry_run, scratch_pool));
-            }
+            *conflict_remains = TRUE;
         }
     }
   else if (base_val)
-    {
-      SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                          db, local_abspath,
-                                          left_version, right_version,
-                                          is_dir, propname,
-                                          actual_props, NULL, new_val,
-                                          base_val, NULL,
-                                          conflict_func, conflict_baton,
-                                          dry_run, scratch_pool));
-    }
+    *conflict_remains = TRUE;
   else  /* property doesn't yet exist in actual_props...  */
     /* so just set it */
     apr_hash_set(actual_props, propname, APR_HASH_KEY_STRING, new_val);
@@ -1156,26 +885,16 @@ apply_single_prop_add(svn_wc_notify_stat
  *
  * OLD_VAL contains the value the of the property the server
  * thinks it's deleting.
- *
- * CONFLICT_FUNC/BATON is a callback to be called before declaring a
- * property conflict;  it gives the client a chance to resolve the
- * conflict interactively.
  */
 static svn_error_t *
 apply_single_prop_delete(svn_wc_notify_state_t *state,
                          svn_boolean_t *conflict_remains,
                          svn_wc__db_t *db,
                          const char *local_abspath,
-                         const svn_wc_conflict_version_t *left_version,
-                         const svn_wc_conflict_version_t *right_version,
-                         svn_boolean_t is_dir,
                          apr_hash_t *actual_props,
                          const char *propname,
                          const svn_string_t *base_val,
                          const svn_string_t *old_val,
-                         svn_wc_conflict_resolver_func2_t conflict_func,
-                         void *conflict_baton,
-                         svn_boolean_t dry_run,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
@@ -1190,14 +909,7 @@ apply_single_prop_delete(svn_wc_notify_s
           && !svn_string_compare(working_val, old_val))
         {
           /* We are trying to delete a locally-added prop. */
-          SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                              db, local_abspath,
-                                              left_version, right_version,
-                                              is_dir, propname,
-                                              actual_props, old_val, NULL,
-                                              base_val, working_val,
-                                              conflict_func, conflict_baton,
-                                              dry_run, scratch_pool));
+          *conflict_remains = TRUE;
         }
       else
         {
@@ -1217,18 +929,7 @@ apply_single_prop_delete(svn_wc_notify_s
              /* they have the same values, so it's an update */
              apr_hash_set(actual_props, propname, APR_HASH_KEY_STRING, NULL);
            else
-             {
-               SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                                   db, local_abspath,
-                                                   left_version, right_version,
-                                                   is_dir,
-                                                   propname, actual_props,
-                                                   old_val, NULL,
-                                                   base_val, working_val,
-                                                   conflict_func,
-                                                   conflict_baton,
-                                                   dry_run, scratch_pool));
-             }
+             *conflict_remains = TRUE;
          }
        else
          /* The property is locally deleted from the same value, so it's
@@ -1237,16 +938,7 @@ apply_single_prop_delete(svn_wc_notify_s
     }
 
   else
-    {
-      SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                          db, local_abspath,
-                                          left_version, right_version,
-                                          is_dir, propname,
-                                          actual_props, old_val, NULL,
-                                          base_val, working_val,
-                                          conflict_func, conflict_baton,
-                                          dry_run, scratch_pool));
-    }
+    *conflict_remains = TRUE;
 
   return SVN_NO_ERROR;
 }
@@ -1264,17 +956,11 @@ apply_single_mergeinfo_prop_change(svn_w
                                    svn_boolean_t *conflict_remains,
                                    svn_wc__db_t *db,
                                    const char *local_abspath,
-                                   const svn_wc_conflict_version_t *left_version,
-                                   const svn_wc_conflict_version_t *right_version,
-                                   svn_boolean_t is_dir,
                                    apr_hash_t *actual_props,
                                    const char *propname,
                                    const svn_string_t *base_val,
                                    const svn_string_t *old_val,
                                    const svn_string_t *new_val,
-                                   svn_wc_conflict_resolver_func2_t conflict_func,
-                                   void *conflict_baton,
-                                   svn_boolean_t dry_run,
                                    apr_pool_t *result_pool,
                                    apr_pool_t *scratch_pool)
 {
@@ -1312,14 +998,7 @@ apply_single_mergeinfo_prop_change(svn_w
       else
         {
           /* There is a base_val but no working_val */
-          SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                              db, local_abspath,
-                                              left_version, right_version,
-                                              is_dir, propname, actual_props,
-                                              old_val, new_val,
-                                              base_val, working_val,
-                                              conflict_func, conflict_baton,
-                                              dry_run, scratch_pool));
+          *conflict_remains = TRUE;
         }
     }
 
@@ -1376,17 +1055,11 @@ apply_single_generic_prop_change(svn_wc_
                                  svn_boolean_t *conflict_remains,
                                  svn_wc__db_t *db,
                                  const char *local_abspath,
-                                 const svn_wc_conflict_version_t *left_version,
-                                 const svn_wc_conflict_version_t *right_version,
-                                 svn_boolean_t is_dir,
                                  apr_hash_t *actual_props,
                                  const char *propname,
                                  const svn_string_t *base_val,
                                  const svn_string_t *old_val,
                                  const svn_string_t *new_val,
-                                 svn_wc_conflict_resolver_func2_t conflict_func,
-                                 void *conflict_baton,
-                                 svn_boolean_t dry_run,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool)
 {
@@ -1414,14 +1087,7 @@ apply_single_generic_prop_change(svn_wc_
   else
     {
       /* Merge the change. */
-      SVN_ERR(maybe_generate_propconflict(conflict_remains,
-                                          db, local_abspath,
-                                          left_version, right_version,
-                                          is_dir, propname, actual_props,
-                                          old_val, new_val,
-                                          base_val, working_val,
-                                          conflict_func, conflict_baton,
-                                          dry_run, scratch_pool));
+      *conflict_remains = TRUE;
     }
 
   return SVN_NO_ERROR;
@@ -1439,27 +1105,17 @@ apply_single_generic_prop_change(svn_wc_
  * thinks it's overwriting. (Not null.)
  *
  * NEW_VAL contains the value to be set. (Not null.)
- *
- * CONFLICT_FUNC/BATON is a callback to be called before declaring a
- * property conflict;  it gives the client a chance to resolve the
- * conflict interactively.
  */
 static svn_error_t *
 apply_single_prop_change(svn_wc_notify_state_t *state,
                          svn_boolean_t *conflict_remains,
                          svn_wc__db_t *db,
                          const char *local_abspath,
-                         const svn_wc_conflict_version_t *left_version,
-                         const svn_wc_conflict_version_t *right_version,
-                         svn_boolean_t is_dir,
                          apr_hash_t *actual_props,
                          const char *propname,
                          const svn_string_t *base_val,
                          const svn_string_t *old_val,
                          const svn_string_t *new_val,
-                         svn_wc_conflict_resolver_func2_t conflict_func,
-                         void *conflict_baton,
-                         svn_boolean_t dry_run,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
@@ -1485,17 +1141,11 @@ apply_single_prop_change(svn_wc_notify_s
       svn_error_t *err = apply_single_mergeinfo_prop_change(state,
                                                             conflict_remains,
                                                             db, local_abspath,
-                                                            left_version,
-                                                            right_version,
-                                                            is_dir,
                                                             actual_props,
                                                             propname,
                                                             base_val,
                                                             old_val,
                                                             new_val,
-                                                            conflict_func,
-                                                            conflict_baton,
-                                                            dry_run,
                                                             result_pool,
                                                             scratch_pool);
        if (err)
@@ -1518,13 +1168,9 @@ apply_single_prop_change(svn_wc_notify_s
 
       SVN_ERR(apply_single_generic_prop_change(state, conflict_remains,
                                                db, local_abspath,
-                                               left_version, right_version,
-                                               is_dir,
                                                actual_props,
                                                propname, base_val, old_val,
                                                new_val,
-                                               conflict_func, conflict_baton,
-                                               dry_run,
                                                result_pool, scratch_pool));
     }
 
@@ -1533,23 +1179,19 @@ apply_single_prop_change(svn_wc_notify_s
 
 
 svn_error_t *
-svn_wc__merge_props(svn_skel_t **work_items,
+svn_wc__merge_props(svn_skel_t **conflict_skel,
                     svn_wc_notify_state_t *state,
                     apr_hash_t **new_pristine_props,
                     apr_hash_t **new_actual_props,
                     svn_wc__db_t *db,
                     const char *local_abspath,
                     svn_kind_t kind,
-                    const svn_wc_conflict_version_t *left_version,
-                    const svn_wc_conflict_version_t *right_version,
                     apr_hash_t *server_baseprops,
                     apr_hash_t *pristine_props,
                     apr_hash_t *actual_props,
                     const apr_array_header_t *propchanges,
                     svn_boolean_t base_merge,
                     svn_boolean_t dry_run,
-                    svn_wc_conflict_resolver_func2_t conflict_func,
-                    void *conflict_baton,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *result_pool,
@@ -1558,12 +1200,18 @@ svn_wc__merge_props(svn_skel_t **work_it
   apr_pool_t *iterpool;
   int i;
   svn_boolean_t is_dir;
-  svn_skel_t *conflict_skel = NULL;
+  apr_hash_t *conflict_props = NULL;
+  apr_hash_t *old_pristine_props;
+  apr_hash_t *old_actual_props;
+  apr_hash_t *their_props;
 
   SVN_ERR_ASSERT(pristine_props != NULL);
   SVN_ERR_ASSERT(actual_props != NULL);
 
-  *work_items = NULL;
+  /* Just copy the pointers as we copy the data in the skel if
+     necessary */
+  old_pristine_props = apr_hash_copy(scratch_pool, pristine_props);
+  old_actual_props = apr_hash_copy(scratch_pool, actual_props);
 
   *new_pristine_props = NULL;
   *new_actual_props = NULL;
@@ -1573,6 +1221,8 @@ svn_wc__merge_props(svn_skel_t **work_it
   if (!server_baseprops)
     server_baseprops = pristine_props;
 
+  their_props = apr_hash_copy(scratch_pool, server_baseprops);
+
   if (state)
     {
       /* Start out assuming no changes or conflicts.  Don't bother to
@@ -1613,6 +1263,8 @@ svn_wc__merge_props(svn_skel_t **work_it
       /* Save MINE for later message generation.  */
       mine_val = apr_hash_get(actual_props, propname, APR_HASH_KEY_STRING);
 
+      apr_hash_set(their_props, propname, APR_HASH_KEY_STRING, to_val);
+
       /* We already know that state is at least `changed', so mark
          that, but remember that we may later upgrade to `merged' or
          even `conflicted'. */
@@ -1621,31 +1273,23 @@ svn_wc__merge_props(svn_skel_t **work_it
       if (! from_val)  /* adding a new property */
         SVN_ERR(apply_single_prop_add(state, &conflict_remains,
                                       db, local_abspath,
-                                      left_version, right_version,
-                                      is_dir, actual_props,
+                                      actual_props,
                                       propname, base_val, to_val,
-                                      conflict_func, conflict_baton,
-                                      dry_run, result_pool, iterpool));
+                                      result_pool, iterpool));
 
       else if (! to_val) /* delete an existing property */
         SVN_ERR(apply_single_prop_delete(state, &conflict_remains,
                                          db, local_abspath,
-                                         left_version, right_version,
-                                         is_dir,
                                          actual_props,
                                          propname, base_val, from_val,
-                                         conflict_func, conflict_baton,
-                                         dry_run, result_pool, iterpool));
+                                         result_pool, iterpool));
 
       else  /* changing an existing property */
         SVN_ERR(apply_single_prop_change(state, &conflict_remains,
                                          db, local_abspath,
-                                         left_version, right_version,
-                                         is_dir,
                                          actual_props,
                                          propname, base_val, from_val, to_val,
-                                         conflict_func, conflict_baton,
-                                         dry_run, result_pool, iterpool));
+                                         result_pool, iterpool));
 
 
       /* merging logic complete, now we need to possibly log conflict
@@ -1658,17 +1302,11 @@ svn_wc__merge_props(svn_skel_t **work_it
           if (dry_run)
             continue;   /* skip to next incoming change */
 
-          if (conflict_skel == NULL)
-            conflict_skel = svn_wc__prop_conflict_skel_new(result_pool);
+          if (!conflict_props)
+            conflict_props = apr_hash_make(result_pool);
 
-          SVN_ERR(svn_wc__prop_conflict_skel_add(conflict_skel,
-                                                 propname,
-                                                 base_val,
-                                                 mine_val,
-                                                 to_val,
-                                                 from_val,
-                                                 result_pool,
-                                                 iterpool));
+          apr_hash_set(conflict_props, apr_pstrdup(result_pool, propname),
+                       APR_HASH_KEY_STRING, "");
         }
 
     }  /* foreach propchange ... */
@@ -1682,63 +1320,24 @@ svn_wc__merge_props(svn_skel_t **work_it
   *new_pristine_props = pristine_props;
   *new_actual_props = actual_props;
 
-  if (conflict_skel != NULL)
+  if (conflict_props != NULL)
     {
-      const char *reject_path;
-
-      /* Now try to get the name of a pre-existing .prej file from the
-         entries file */
-      SVN_ERR(svn_wc__get_prejfile_abspath(&reject_path, db, local_abspath,
-                                           scratch_pool, scratch_pool));
+      /* Ok, we got some conflict. Lets store all the property knowledge we
+         have for resolving later */
 
-      if (! reject_path)
-        {
-          /* Reserve a new .prej file *above* the .svn/ directory by
-             opening and closing it. */
-          const char *reject_dirpath;
-          const char *reject_filename;
-          svn_skel_t *work_item;
+      if (!*conflict_skel)
+        *conflict_skel = svn_wc__conflict_skel_create(result_pool);
 
-          if (is_dir)
-            {
-              reject_dirpath = local_abspath;
-              reject_filename = SVN_WC__THIS_DIR_PREJ;
-            }
-          else
-            svn_dirent_split(&reject_dirpath, &reject_filename, local_abspath,
-                             scratch_pool);
-
-          SVN_ERR(svn_io_open_uniquely_named(NULL, &reject_path,
-                                             reject_dirpath,
-                                             reject_filename,
-                                             SVN_WC__PROP_REJ_EXT,
-                                             svn_io_file_del_none,
-                                             scratch_pool, scratch_pool));
-
-          /* This file will be overwritten when the wq is run; that's
-             ok, because at least now we have a reservation on
-             disk. */
-
-          /* Mark entry as "conflicted" with a particular .prej file. */
-          SVN_ERR(svn_wc__wq_tmp_build_set_property_conflict_marker(
-                                          &work_item,
-                                          db, local_abspath, reject_path,
-                                          result_pool, scratch_pool));
-
-          *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
-        }
-
-      /* Once the prejfile is recorded, then install the file.  */
-      {
-        svn_skel_t *work_item;
-
-        SVN_ERR(svn_wc__wq_build_prej_install(&work_item,
-                                              db, local_abspath,
-                                              conflict_skel,
-                                              result_pool, scratch_pool));
-
-        *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
-      }
+      SVN_ERR(svn_wc__conflict_skel_add_prop_conflict(*conflict_skel,
+                                                      db, local_abspath,
+                                                      NULL /* reject_path */,
+                                                      old_pristine_props,
+                                                      old_actual_props,
+                                                      server_baseprops,
+                                                      their_props,
+                                                      conflict_props,
+                                                      result_pool,
+                                                      scratch_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/trunk/subversion/libsvn_wc/props.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/props.h?rev=1355114&r1=1355113&r2=1355114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/props.h (original)
+++ subversion/trunk/subversion/libsvn_wc/props.h Thu Jun 28 19:10:24 2012
@@ -91,32 +91,24 @@ svn_wc__internal_propget(const svn_strin
    into the .prej file later. Modify base properties unconditionally,
    if BASE_MERGE is TRUE, they do not generate conficts.
 
-   TODO ### LEFT_VERSION and RIGHT_VERSION ...
-
    TODO ### DRY_RUN ...
 
-   TODO ### CONFLICT_FUNC/CONFLICT_BATON ...
-
    If STATE is non-null, set *STATE to the state of the local properties
    after the merge.  */
 svn_error_t *
-svn_wc__merge_props(svn_skel_t **work_items,
+svn_wc__merge_props(svn_skel_t **conflict_skel,
                     svn_wc_notify_state_t *state,
                     apr_hash_t **new_pristine_props,
                     apr_hash_t **new_actual_props,
                     svn_wc__db_t *db,
                     const char *local_abspath,
                     svn_kind_t kind,
-                    const svn_wc_conflict_version_t *left_version,
-                    const svn_wc_conflict_version_t *right_version,
                     apr_hash_t *server_baseprops,
                     apr_hash_t *pristine_props,
                     apr_hash_t *actual_props,
                     const apr_array_header_t *propchanges,
                     svn_boolean_t base_merge,
                     svn_boolean_t dry_run,
-                    svn_wc_conflict_resolver_func2_t conflict_func,
-                    void *conflict_baton,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *result_pool,