You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC

svn commit: r1442344 [16/39] - in /subversion/branches/fsfs-format7: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.c Mon Feb  4 20:48:05 2013
@@ -209,6 +209,7 @@ conflict__get_operation(svn_skel_t **why
 svn_error_t *
 svn_wc__conflict_skel_set_op_update(svn_skel_t *conflict_skel,
                                     const svn_wc_conflict_version_t *original,
+                                    const svn_wc_conflict_version_t *target,
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool)
 {
@@ -228,6 +229,8 @@ svn_wc__conflict_skel_set_op_update(svn_
 
   origins = svn_skel__make_empty_list(result_pool);
 
+  SVN_ERR(conflict__prepend_location(origins, target, TRUE,
+                                     result_pool, scratch_pool));
   SVN_ERR(conflict__prepend_location(origins, original, TRUE,
                                      result_pool, scratch_pool));
 
@@ -240,6 +243,7 @@ svn_wc__conflict_skel_set_op_update(svn_
 svn_error_t *
 svn_wc__conflict_skel_set_op_switch(svn_skel_t *conflict_skel,
                                     const svn_wc_conflict_version_t *original,
+                                    const svn_wc_conflict_version_t *target,
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool)
 {
@@ -259,6 +263,8 @@ svn_wc__conflict_skel_set_op_switch(svn_
 
   origins = svn_skel__make_empty_list(result_pool);
 
+  SVN_ERR(conflict__prepend_location(origins, target, TRUE,
+                                     result_pool, scratch_pool));
   SVN_ERR(conflict__prepend_location(origins, original, TRUE,
                                      result_pool, scratch_pool));
 
@@ -409,10 +415,10 @@ svn_wc__conflict_skel_add_prop_conflict(
                                         svn_wc__db_t *db,
                                         const char *wri_abspath,
                                         const char *marker_abspath,
-                                        apr_hash_t *mine_props,
-                                        apr_hash_t *their_old_props,
-                                        apr_hash_t *their_props,
-                                        apr_hash_t *conflicted_prop_names,
+                                        const apr_hash_t *mine_props,
+                                        const apr_hash_t *their_old_props,
+                                        const apr_hash_t *their_props,
+                                        const apr_hash_t *conflicted_prop_names,
                                         apr_pool_t *result_pool,
                                         apr_pool_t *scratch_pool)
 {
@@ -435,6 +441,8 @@ svn_wc__conflict_skel_add_prop_conflict(
       mine-props
       their-props)
      NULL lists are recorded as "" */
+  /* ### Seems that this may not match what we read out.  Read-out of
+   * 'theirs-old' comes as NULL. */
 
   prop_conflict = svn_skel__make_empty_list(result_pool);
 
@@ -464,7 +472,7 @@ svn_wc__conflict_skel_add_prop_conflict(
     svn_skel__prepend_str("", prop_conflict, result_pool); /* No old_props */
 
   conflict_names = svn_skel__make_empty_list(result_pool);
-  for (hi = apr_hash_first(scratch_pool, conflicted_prop_names);
+  for (hi = apr_hash_first(scratch_pool, (apr_hash_t *)conflicted_prop_names);
        hi;
        hi = apr_hash_next(hi))
     {
@@ -529,6 +537,7 @@ svn_wc__conflict_skel_add_tree_conflict(
                                         const char *wri_abspath,
                                         svn_wc_conflict_reason_t local_change,
                                         svn_wc_conflict_action_t incoming_change,
+                                        const char *moved_away_op_root_abspath,
                                         apr_pool_t *result_pool,
                                         apr_pool_t *scratch_pool)
 {
@@ -540,8 +549,25 @@ svn_wc__conflict_skel_add_tree_conflict(
 
   SVN_ERR_ASSERT(!tree_conflict); /* ### Use proper error? */
 
+  SVN_ERR_ASSERT((local_change != svn_wc_conflict_reason_moved_away
+                  && !moved_away_op_root_abspath)
+                 || moved_away_op_root_abspath); /* ### Use proper error? */
+
   tree_conflict = svn_skel__make_empty_list(result_pool);
 
+  if (local_change == svn_wc_conflict_reason_moved_away)
+    {
+      const char *moved_away_op_root_relpath;
+
+      SVN_ERR(svn_wc__db_to_relpath(&moved_away_op_root_relpath,
+                                    db, wri_abspath,
+                                    moved_away_op_root_abspath,
+                                    result_pool, scratch_pool));
+
+      svn_skel__prepend_str(moved_away_op_root_relpath, tree_conflict,
+                            result_pool);
+    }
+
   svn_skel__prepend_str(
                 svn_token__to_word(incoming_change_map, incoming_change),
                 tree_conflict, result_pool);
@@ -907,6 +933,7 @@ svn_wc__conflict_read_prop_conflict(cons
 svn_error_t *
 svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change,
                                     svn_wc_conflict_action_t *incoming_change,
+                                    const char **moved_away_op_root_abspath,
                                     svn_wc__db_t *db,
                                     const char *wri_abspath,
                                     const svn_skel_t *conflict_skel,
@@ -915,6 +942,7 @@ svn_wc__conflict_read_tree_conflict(svn_
 {
   svn_skel_t *tree_conflict;
   const svn_skel_t *c;
+  svn_boolean_t is_moved_away = FALSE;
 
   SVN_ERR(conflict__get_conflict(&tree_conflict, conflict_skel,
                                  SVN_WC__CONFLICT_KIND_TREE));
@@ -936,6 +964,8 @@ svn_wc__conflict_read_tree_conflict(svn_
         *local_change = value;
       else
         *local_change = svn_wc_conflict_reason_edited;
+
+      is_moved_away = *local_change == svn_wc_conflict_reason_moved_away;
     }
   c = c->next;
 
@@ -949,6 +979,19 @@ svn_wc__conflict_read_tree_conflict(svn_
         *incoming_change = svn_wc_conflict_action_edit;
     }
 
+  c = c->next;
+
+  if (is_moved_away && moved_away_op_root_abspath)
+    {
+      const char *moved_away_op_root_relpath = apr_pstrmemdup(scratch_pool,
+                                                              c->data, c->len);
+
+      SVN_ERR(svn_wc__db_from_relpath(moved_away_op_root_abspath,
+                                      db, wri_abspath,
+                                      moved_away_op_root_relpath,
+                                      result_pool, scratch_pool));
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -1217,6 +1260,7 @@ static svn_error_t *
 generate_propconflict(svn_boolean_t *conflict_remains,
                       svn_wc__db_t *db,
                       const char *local_abspath,
+                      svn_wc_operation_t operation,
                       const svn_wc_conflict_version_t *left_version,
                       const svn_wc_conflict_version_t *right_version,
                       const char *propname,
@@ -1242,6 +1286,7 @@ generate_propconflict(svn_boolean_t *con
                 (kind == svn_kind_dir) ? svn_node_dir : svn_node_file,
                 propname, scratch_pool);
 
+  cdesc->operation = operation;
   cdesc->src_left_version = left_version;
   cdesc->src_right_version = right_version;
 
@@ -1378,7 +1423,7 @@ generate_propconflict(svn_boolean_t *con
       *conflict_remains = TRUE;
       return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
                               NULL, _("Conflict callback violated API:"
-                                      " returned no results."));
+                                      " returned no results"));
     }
 
 
@@ -1416,25 +1461,21 @@ generate_propconflict(svn_boolean_t *con
         }
       case svn_wc_conflict_choose_merged:
         {
+          svn_stringbuf_t *merged_stringbuf;
+
           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;
+                         " returned no merged file"));
 
-              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;
-            }
+          SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
+                                           result->merged_file ?
+                                                result->merged_file :
+                                                cdesc->merged_file,
+                                           scratch_pool));
+          new_value = svn_stringbuf__morph_into_string(merged_stringbuf);
+          *conflict_remains = FALSE;
           break;
         }
     }
@@ -1459,34 +1500,39 @@ generate_propconflict(svn_boolean_t *con
   return SVN_NO_ERROR;
 }
 
-/* Deal with the result of the conflict resolution callback, as indicated by
- * CHOICE.
+/* Resolve the text conflict on DB/LOCAL_ABSPATH in the manner specified
+ * by CHOICE.
  *
- * Set *WORK_ITEMS to new work items that will ...
- * Set *MERGE_OUTCOME to the result of the 3-way merge.
+ * Set *WORK_ITEMS to new work items that will make the on-disk changes
+ * needed to complete the resolution (but not to mark it as resolved).
+ * Set *IS_RESOLVED to true if the conflicts are resolved; otherwise
+ * (which is only if CHOICE is 'postpone') to false.
  *
- * LEFT_ABSPATH, RIGHT_ABSPATH, and TARGET_ABSPATH are the input files to
- * the 3-way merge, and MERGED_FILE is the merged result as generated by the
- * internal or external merge or by the conflict resolution callback.
+ * LEFT_ABSPATH, RIGHT_ABSPATH, and DETRANSLATED_TARGET are the
+ * input files to the 3-way merge that will be performed if CHOICE is
+ * 'theirs-conflict' or 'mine-conflict'.  LEFT_ABSPATH is also the file
+ * that will be used if CHOICE is 'base', and RIGHT_ABSPATH if CHOICE is
+ * 'theirs-full'.  MERGED_ABSPATH will be used if CHOICE is 'merged'.
  *
- * DETRANSLATED_TARGET is the detranslated version of TARGET_ABSPATH
- * (see detranslate_wc_file() above).  DIFF3_OPTIONS are passed to the
- * diff3 implementation in case a 3-way merge has to be carried out. */
-static svn_error_t*
+ * DETRANSLATED_TARGET is the detranslated version of 'mine' (see
+ * detranslate_wc_file() above).  MERGE_OPTIONS are passed to the
+ * diff3 implementation in case a 3-way merge has to be carried out.
+ */
+static svn_error_t *
 eval_text_conflict_func_result(svn_skel_t **work_items,
-                               enum svn_wc_merge_outcome_t *merge_outcome,
-                               svn_wc_conflict_choice_t choice,
-                               const apr_array_header_t *merge_options,
+                               svn_boolean_t *is_resolved,
                                svn_wc__db_t *db,
                                const char *local_abspath,
+                               svn_wc_conflict_choice_t choice,
+                               const apr_array_header_t *merge_options,
                                const char *left_abspath,
                                const char *right_abspath,
-                               const char *merged_file,
+                               const char *merged_abspath,
                                const char *detranslated_target,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
-  const char *install_from = NULL;
+  const char *install_from_abspath = NULL;
   svn_boolean_t remove_source = FALSE;
 
   *work_items = NULL;
@@ -1497,26 +1543,26 @@ eval_text_conflict_func_result(svn_skel_
          to resolve the conflict, so be it.*/
       case svn_wc_conflict_choose_base:
         {
-          install_from = left_abspath;
-          *merge_outcome = svn_wc_merge_merged;
+          install_from_abspath = left_abspath;
+          *is_resolved = TRUE;
           break;
         }
       case svn_wc_conflict_choose_theirs_full:
         {
-          install_from = right_abspath;
-          *merge_outcome = svn_wc_merge_merged;
+          install_from_abspath = right_abspath;
+          *is_resolved = TRUE;
           break;
         }
       case svn_wc_conflict_choose_mine_full:
         {
-          /* Do nothing to merge_target, let it live untouched! */
-          *merge_outcome = svn_wc_merge_merged;
-          return SVN_NO_ERROR;
+          install_from_abspath = detranslated_target;
+          *is_resolved = TRUE;
+          break;
         }
       case svn_wc_conflict_choose_theirs_conflict:
       case svn_wc_conflict_choose_mine_conflict:
         {
-          const char *chosen_path;
+          const char *chosen_abspath;
           const char *temp_dir;
           svn_stream_t *chosen_stream;
           svn_diff_t *diff;
@@ -1537,7 +1583,7 @@ eval_text_conflict_func_result(svn_skel_
           SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
                                                  local_abspath,
                                                  scratch_pool, scratch_pool));
-          SVN_ERR(svn_stream_open_unique(&chosen_stream, &chosen_path,
+          SVN_ERR(svn_stream_open_unique(&chosen_stream, &chosen_abspath,
                                          temp_dir, svn_io_file_del_none,
                                          scratch_pool, scratch_pool));
 
@@ -1556,9 +1602,9 @@ eval_text_conflict_func_result(svn_skel_
                                               scratch_pool));
           SVN_ERR(svn_stream_close(chosen_stream));
 
-          install_from = chosen_path;
+          install_from_abspath = chosen_abspath;
           remove_source = TRUE;
-          *merge_outcome = svn_wc_merge_merged;
+          *is_resolved = TRUE;
           break;
         }
 
@@ -1570,32 +1616,27 @@ eval_text_conflict_func_result(svn_skel_
            good to use". */
       case svn_wc_conflict_choose_merged:
         {
-          install_from = merged_file;
-          *merge_outcome = svn_wc_merge_merged;
+          install_from_abspath = merged_abspath;
+          *is_resolved = TRUE;
           break;
         }
       case svn_wc_conflict_choose_postpone:
       default:
         {
-#if 0
-          /* ### what should this value be? no caller appears to initialize
-             ### it, so we really SHOULD be setting a value here.  */
-          *merge_outcome = svn_wc_merge_merged;
-#endif
-
           /* Assume conflict remains. */
+          *is_resolved = FALSE;
           return SVN_NO_ERROR;
         }
     }
 
-  SVN_ERR_ASSERT(install_from != NULL);
+  SVN_ERR_ASSERT(install_from_abspath != NULL);
 
   {
     svn_skel_t *work_item;
 
     SVN_ERR(svn_wc__wq_build_file_install(&work_item,
                                           db, local_abspath,
-                                          install_from,
+                                          install_from_abspath,
                                           FALSE /* use_commit_times */,
                                           FALSE /* record_fileinfo */,
                                           result_pool, scratch_pool));
@@ -1608,7 +1649,8 @@ eval_text_conflict_func_result(svn_skel_
     if (remove_source)
       {
         SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
-                                             db, local_abspath, install_from,
+                                             db, local_abspath,
+                                             install_from_abspath,
                                              result_pool, scratch_pool));
         *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
       }
@@ -1618,21 +1660,21 @@ eval_text_conflict_func_result(svn_skel_
 }
 
 
-/* Create a new file in the same directory as VERSIONED_ABSPATH, with the
-   same basename as VERSIONED_ABSPATH, with a ".edited" extension, and set
+/* Create a new file in the same directory as LOCAL_ABSPATH, with the
+   same basename as LOCAL_ABSPATH, with a ".edited" extension, and set
    *WORK_ITEM to a new work item that will copy and translate from the file
-   SOURCE to that new file.  It will be translated from repository-normal
-   form to working-copy form according to the versioned properties of
-   VERSIONED_ABSPATH that are current when the work item is executed.
+   SOURCE_ABSPATH to that new file.  It will be translated from repository-
+   normal form to working-copy form according to the versioned properties
+   of LOCAL_ABSPATH that are current when the work item is executed.
 
    DB should have a write lock for the directory containing SOURCE.
 
    Allocate *WORK_ITEM in RESULT_POOL. */
-static svn_error_t*
+static svn_error_t *
 save_merge_result(svn_skel_t **work_item,
                   svn_wc__db_t *db,
                   const char *local_abspath,
-                  const char *source,
+                  const char *source_abspath,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
@@ -1653,33 +1695,54 @@ save_merge_result(svn_skel_t **work_item
                                      scratch_pool, scratch_pool));
   SVN_ERR(svn_wc__wq_build_file_copy_translated(work_item,
                                                 db, local_abspath,
-                                                source, edited_copy_abspath,
+                                                source_abspath,
+                                                edited_copy_abspath,
                                                 result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
 
 
-/* XXX Insane amount of parameters... */
-/* RESULT_TARGET is the path to the merged file produced by the internal or
-   external 3-way merge. */
-static svn_error_t*
-resolve_text_conflicts(svn_skel_t **work_items,
-                       svn_wc__db_t *db,
-                       const char *local_abspath,
-                       const apr_array_header_t *merge_options,
-                       const char *left_abspath,
-                       const char *right_abspath,
-                       enum svn_wc_merge_outcome_t *merge_outcome,
-                       const svn_wc_conflict_version_t *left_version,
-                       const svn_wc_conflict_version_t *right_version,
-                       const char *result_target,
-                       const char *detranslated_target,
-                       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,
-                       apr_pool_t *scratch_pool)
+/* Call the conflict resolver callback for a text conflict, and resolve
+ * the conflict if it tells us to do so.
+ *
+ * Assume that there is a text conflict on the path DB/LOCAL_ABSPATH.
+ *
+ * Call CONFLICT_FUNC with CONFLICT_BATON to find out whether and how
+ * it wants to resolve the conflict.  Pass it a conflict description
+ * containing OPERATION, LEFT/RIGHT_ABSPATH, LEFT/RIGHT_VERSION,
+ * RESULT_TARGET and DETRANSLATED_TARGET.
+ *
+ * If the callback returns a resolution other than 'postpone', then
+ * perform that requested resolution and prepare to mark the conflict
+ * as resolved.
+ *
+ * Return *WORK_ITEMS that will do the on-disk work required to complete
+ * the resolution (but not to mark the conflict as resolved), and set
+ * *WAS_RESOLVED to true, if it was resolved.  Set *WORK_ITEMS to NULL
+ * and *WAS_RESOLVED to FALSE otherwise.
+ *
+ * RESULT_TARGET is the path to the merged file produced by the internal
+ * or external 3-way merge, which may contain conflict markers, in
+ * repository normal form.  DETRANSLATED_TARGET is the 'mine' version of
+ * the file, also in RNF.
+ */
+static svn_error_t *
+resolve_text_conflict(svn_skel_t **work_items,
+                      svn_boolean_t *was_resolved,
+                      svn_wc__db_t *db,
+                      const char *local_abspath,
+                      const apr_array_header_t *merge_options,
+                      svn_wc_operation_t operation,
+                      const char *left_abspath,
+                      const char *right_abspath,
+                      const svn_wc_conflict_version_t *left_version,
+                      const svn_wc_conflict_version_t *right_version,
+                      const char *result_target,
+                      const char *detranslated_target,
+                      svn_wc_conflict_resolver_func2_t conflict_func,
+                      void *conflict_baton,
+                      apr_pool_t *result_pool,
+                      apr_pool_t *scratch_pool)
 {
   svn_wc_conflict_result_t *result;
   svn_skel_t *work_item;
@@ -1687,6 +1750,7 @@ resolve_text_conflicts(svn_skel_t **work
   apr_hash_t *props;
 
   *work_items = NULL;
+  *was_resolved = FALSE;
 
   /* Give the conflict resolution callback a chance to clean
      up the conflicts before we mark the file 'conflicted' */
@@ -1702,6 +1766,7 @@ resolve_text_conflicts(svn_skel_t **work
   cdesc->their_abspath = right_abspath;
   cdesc->my_abspath = detranslated_target;
   cdesc->merged_file = result_target;
+  cdesc->operation = operation;
   cdesc->src_left_version = left_version;
   cdesc->src_right_version = right_version;
 
@@ -1709,8 +1774,8 @@ resolve_text_conflicts(svn_skel_t **work
                         scratch_pool));
   if (result == NULL)
     return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
-                            _("Conflict callback violated API: "
-                              "returned no results"));
+                            _("Conflict callback violated API:"
+                              " returned no results"));
 
   if (result->save_merged)
     {
@@ -1724,27 +1789,25 @@ resolve_text_conflicts(svn_skel_t **work
                                 result_pool, scratch_pool));
     }
 
-  SVN_ERR(eval_text_conflict_func_result(&work_item,
-                                         merge_outcome,
-                                         result->choice,
-                                         merge_options,
-                                         db, local_abspath,
-                                         left_abspath,
-                                         right_abspath,
-                                         result->merged_file
-                                           ? result->merged_file
-                                           : result_target,
-                                         detranslated_target,
-                                         result_pool, scratch_pool));
-  *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
-
   if (result->choice != svn_wc_conflict_choose_postpone)
-    /* The conflicts have been dealt with, nothing else
-     * to do for us here. */
-    return SVN_NO_ERROR;
-
-  /* The conflicts have not been dealt with. */
-  *merge_outcome = svn_wc_merge_conflict;
+    {
+      SVN_ERR(eval_text_conflict_func_result(&work_item,
+                                             was_resolved,
+                                             db, local_abspath,
+                                             result->choice,
+                                             merge_options,
+                                             left_abspath,
+                                             right_abspath,
+                                             /* ### Sure this is an abspath? */
+                                             result->merged_file
+                                               ? result->merged_file
+                                               : result_target,
+                                             detranslated_target,
+                                             result_pool, scratch_pool));
+      *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+    }
+  else
+    *was_resolved = FALSE;
 
   return SVN_NO_ERROR;
 }
@@ -1752,97 +1815,28 @@ resolve_text_conflicts(svn_skel_t **work
 
 static svn_error_t *
 setup_tree_conflict_desc(svn_wc_conflict_description2_t **desc,
-                         svn_wc_operation_t operation,
-                         const apr_array_header_t *locations,
-                         const svn_skel_t *conflict_skel,
-                         const char *local_abspath,
                          svn_wc__db_t *db,
+                         const char *local_abspath,
+                         svn_wc_operation_t operation,
+                         const svn_wc_conflict_version_t *left_version,
+                         const svn_wc_conflict_version_t *right_version,
+                         svn_wc_conflict_reason_t local_change,
+                         svn_wc_conflict_action_t incoming_change,
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
-  svn_wc_conflict_version_t *v1;
-  svn_wc_conflict_version_t *v2;
   svn_node_kind_t tc_kind;
-  svn_wc_conflict_reason_t local_change;
-  svn_wc_conflict_action_t incoming_change;
-
-  SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
-                                              &incoming_change,
-                                              db, local_abspath,
-                                              conflict_skel,
-                                              result_pool, scratch_pool));
-
-  v1 = (locations && locations->nelts > 0)
-                ? APR_ARRAY_IDX(locations, 0, svn_wc_conflict_version_t *)
-                : NULL;
-
-  v2 = (locations && locations->nelts > 1)
-                ? APR_ARRAY_IDX(locations, 1, svn_wc_conflict_version_t *)
-                : NULL;
-
-  if (incoming_change != svn_wc_conflict_action_delete
-      && (operation == svn_wc_operation_update
-          || operation == svn_wc_operation_switch))
-    {
-      svn_wc__db_status_t status;
-      svn_revnum_t revision;
-      const char *repos_relpath;
-      const char *repos_root_url;
-      const char *repos_uuid;
-      svn_kind_t kind;
-      svn_error_t *err;
-
-      /* ### Theoretically we should just fetch the BASE information
-             here. This code might need tweaks until all tree conflicts
-             are installed in the proper state */
-
-      SVN_ERR_ASSERT(v2 == NULL); /* Not set for update and switch */
-
-      /* With an update or switch we have to fetch the second location
-         for a tree conflict from WORKING. (For text or prop from BASE)
-       */
-      err = svn_wc__db_base_get_info(&status, &kind, &revision,
-                                     &repos_relpath, &repos_root_url,
-                                     &repos_uuid, NULL, NULL, NULL,
-                                     NULL, NULL, NULL, NULL, NULL, NULL,
-                                     db, local_abspath,
-                                     scratch_pool, scratch_pool);
-
-      if (err)
-        {
-          if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-            return svn_error_trace(err);
-
-          svn_error_clear(err);
-          /* Ignore BASE */
 
-          tc_kind = svn_node_file; /* Avoid assertion */
-        }
-      else if (repos_relpath)
-        {
-          v2 = svn_wc_conflict_version_create2(repos_root_url,
-                                               repos_uuid,
-                                               repos_relpath,
-                                               revision,
-                                               svn__node_kind_from_kind(kind),
-                                               result_pool);
-          tc_kind = svn__node_kind_from_kind(kind);
-        }
-      else
-        tc_kind = svn_node_file; /* Avoid assertion */
-    }
+  if (left_version)
+    tc_kind = left_version->node_kind;
+  else if (right_version)
+    tc_kind = right_version->node_kind;
   else
-    {
-      if (v1)
-        tc_kind = v1->node_kind;
-      else if (v2)
-        tc_kind = v2->node_kind;
-      else
-        tc_kind = svn_node_file; /* Avoid assertion */
-    }
+    tc_kind = svn_node_file; /* Avoid assertion */
 
   *desc = svn_wc_conflict_description_create_tree2(local_abspath, tc_kind,
-                                                   operation, v1, v2,
+                                                   operation,
+                                                   left_version, right_version,
                                                    result_pool);
   (*desc)->reason = local_change;
   (*desc)->action = incoming_change;
@@ -1858,6 +1852,8 @@ svn_wc__conflict_invoke_resolver(svn_wc_
                                  const apr_array_header_t *merge_options,
                                  svn_wc_conflict_resolver_func2_t resolver_func,
                                  void *resolver_baton,
+                                 svn_cancel_func_t cancel_func,
+                                 void *cancel_baton,
                                  apr_pool_t *scratch_pool)
 {
   svn_boolean_t text_conflicted;
@@ -1865,6 +1861,8 @@ svn_wc__conflict_invoke_resolver(svn_wc_
   svn_boolean_t tree_conflicted;
   svn_wc_operation_t operation;
   const apr_array_header_t *locations;
+  const svn_wc_conflict_version_t *left_version = NULL;
+  const svn_wc_conflict_version_t *right_version = NULL;
 
   SVN_ERR(svn_wc__conflict_read_info(&operation, &locations,
                                      &text_conflicted, &prop_conflicted,
@@ -1872,6 +1870,12 @@ svn_wc__conflict_invoke_resolver(svn_wc_
                                      db, local_abspath, conflict_skel,
                                      scratch_pool, scratch_pool));
 
+  if (locations && locations->nelts > 0)
+    left_version = APR_ARRAY_IDX(locations, 0, const svn_wc_conflict_version_t *);
+
+  if (locations && locations->nelts > 1)
+    right_version = APR_ARRAY_IDX(locations, 1, const svn_wc_conflict_version_t *);
+
   /* Quick and dirty compatibility wrapper. My guess would be that most resolvers
      would want to look at all properties at the same time.
 
@@ -1916,9 +1920,15 @@ svn_wc__conflict_invoke_resolver(svn_wc_
 
           svn_pool_clear(iterpool);
 
+          if (cancel_func)
+            SVN_ERR(cancel_func(cancel_baton));
+
           SVN_ERR(generate_propconflict(&conflict_remains,
                                         db, local_abspath,
-                                        NULL, NULL, propname,
+                                        operation,
+                                        left_version,
+                                        right_version,
+                                        propname,
                                         old_props
                                           ? apr_hash_get(old_props, propname,
                                                          APR_HASH_KEY_STRING)
@@ -1943,8 +1953,10 @@ svn_wc__conflict_invoke_resolver(svn_wc_
         }
 
       if (mark_resolved)
-        SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE,
-                                            FALSE, NULL, scratch_pool));
+        {
+          SVN_ERR(svn_wc__mark_resolved_prop_conflicts(db, local_abspath,
+                                                       scratch_pool));
+        }
     }
 
   if (text_conflicted)
@@ -1952,33 +1964,38 @@ svn_wc__conflict_invoke_resolver(svn_wc_
       const char *mine_abspath;
       const char *their_original_abspath;
       const char *their_abspath;
-      svn_skel_t *work_item = NULL;
-      svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_conflict;
+      svn_skel_t *work_items;
+      svn_boolean_t was_resolved;
 
-      SVN_ERR(svn_wc__conflict_read_text_conflict(&their_original_abspath,
-                                                  &mine_abspath,
+      SVN_ERR(svn_wc__conflict_read_text_conflict(&mine_abspath,
+                                                  &their_original_abspath,
                                                   &their_abspath,
                                                   db, local_abspath,
                                                   conflict_skel,
                                                   scratch_pool, scratch_pool));
 
-      SVN_ERR(resolve_text_conflicts(&work_item, db, local_abspath,
-                                     merge_options,
-                                     their_original_abspath, their_abspath,
-                                     &merge_outcome,
-                                     NULL /* left_version */,
-                                     NULL /* right_version */,
-                                     local_abspath,
-                                     mine_abspath,
-                                     resolver_func, resolver_baton,
-                                     NULL, NULL,
-                                     scratch_pool, scratch_pool));
+      SVN_ERR(resolve_text_conflict(&work_items, &was_resolved,
+                                    db, local_abspath,
+                                    merge_options,
+                                    operation,
+                                    their_original_abspath, their_abspath,
+                                    left_version, right_version,
+                                    local_abspath, mine_abspath,
+                                    resolver_func, resolver_baton,
+                                    scratch_pool, scratch_pool));
 
-      if (merge_outcome == svn_wc_merge_merged)
+      if (was_resolved)
         {
-          SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, TRUE, FALSE,
-                                              FALSE, work_item, scratch_pool));
-          SVN_ERR(svn_wc__wq_run(db, local_abspath, NULL, NULL, scratch_pool));
+          if (work_items)
+            {
+              SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_items,
+                                        scratch_pool));
+              SVN_ERR(svn_wc__wq_run(db, local_abspath,
+                                     cancel_func, cancel_baton,
+                                     scratch_pool));
+            }
+          SVN_ERR(svn_wc__mark_resolved_text_conflict(db, local_abspath,
+                                                      scratch_pool));
         }
     }
 
@@ -1991,12 +2008,17 @@ svn_wc__conflict_invoke_resolver(svn_wc_
 
       SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
                                                   &incoming_change,
+                                                  NULL,
                                                   db, local_abspath,
                                                   conflict_skel,
                                                   scratch_pool, scratch_pool));
-      SVN_ERR(setup_tree_conflict_desc(&desc, operation, locations,
-                                       conflict_skel, local_abspath, db,
+
+      SVN_ERR(setup_tree_conflict_desc(&desc,
+                                       db, local_abspath,
+                                       operation, left_version, right_version,
+                                       local_change, incoming_change,
                                        scratch_pool, scratch_pool));
+
       /* Tell the resolver func about this conflict. */
       SVN_ERR(resolver_func(&result, desc, resolver_baton, scratch_pool,
                             scratch_pool));
@@ -2024,6 +2046,9 @@ read_prop_conflicts(apr_array_header_t *
                     const char *local_abspath,
                     svn_skel_t *conflict_skel,
                     svn_boolean_t create_tempfiles,
+                    svn_wc_operation_t operation,
+                    const svn_wc_conflict_version_t *left_version,
+                    const svn_wc_conflict_version_t *right_version,
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
@@ -2058,6 +2083,10 @@ read_prop_conflicts(apr_array_header_t *
        * ### conflict description struct for this. */
       desc->their_abspath = apr_pstrdup(result_pool, prop_reject_file);
 
+      desc->operation = operation;
+      desc->src_left_version = left_version;
+      desc->src_right_version = right_version;
+
       APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t*) = desc;
 
       return SVN_NO_ERROR;
@@ -2081,6 +2110,10 @@ read_prop_conflicts(apr_array_header_t *
                                                        propname,
                                                        result_pool);
 
+      desc->operation = operation;
+      desc->src_left_version = left_version;
+      desc->src_right_version = right_version;
+
       desc->property_name = apr_pstrdup(result_pool, propname);
 
       my_value = apr_hash_get(my_props, propname, APR_HASH_KEY_STRING);
@@ -2177,6 +2210,8 @@ svn_wc__read_conflicts(const apr_array_h
   svn_boolean_t tree_conflicted;
   svn_wc_operation_t operation;
   const apr_array_header_t *locations;
+  const svn_wc_conflict_version_t *left_version = NULL;
+  const svn_wc_conflict_version_t *right_version = NULL;
 
   SVN_ERR(svn_wc__db_read_conflict(&conflict_skel, db, local_abspath,
                                    scratch_pool, scratch_pool));
@@ -2197,9 +2232,15 @@ svn_wc__read_conflicts(const apr_array_h
   cflcts = apr_array_make(result_pool, 4,
                           sizeof(svn_wc_conflict_description2_t*));
 
+  if (locations && locations->nelts > 0)
+    left_version = APR_ARRAY_IDX(locations, 0, const svn_wc_conflict_version_t *);
+  if (locations && locations->nelts > 1)
+    right_version = APR_ARRAY_IDX(locations, 1, const svn_wc_conflict_version_t *);
+
   if (prop_conflicted)
     SVN_ERR(read_prop_conflicts(cflcts, db, local_abspath, conflict_skel,
                                 create_tempfiles,
+                                operation, left_version, right_version,
                                 result_pool, scratch_pool));
 
   if (text_conflicted)
@@ -2208,6 +2249,10 @@ svn_wc__read_conflicts(const apr_array_h
       desc  = svn_wc_conflict_description_create_text2(local_abspath,
                                                        result_pool);
 
+      desc->operation = operation;
+      desc->src_left_version = left_version;
+      desc->src_right_version = right_version;
+
       SVN_ERR(svn_wc__conflict_read_text_conflict(&desc->my_abspath,
                                                   &desc->base_abspath,
                                                   &desc->their_abspath,
@@ -2222,11 +2267,23 @@ svn_wc__read_conflicts(const apr_array_h
 
   if (tree_conflicted)
     {
+      svn_wc_conflict_reason_t local_change;
+      svn_wc_conflict_action_t incoming_change;
       svn_wc_conflict_description2_t *desc;
 
-      SVN_ERR(setup_tree_conflict_desc(&desc, operation, locations,
-                                       conflict_skel, local_abspath, db,
+      SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
+                                                  &incoming_change,
+                                                  NULL,
+                                                  db, local_abspath,
+                                                  conflict_skel,
+                                                  scratch_pool, scratch_pool));
+
+      SVN_ERR(setup_tree_conflict_desc(&desc,
+                                       db, local_abspath,
+                                       operation, left_version, right_version,
+                                       local_change, incoming_change,
                                        result_pool, scratch_pool));
+
       APR_ARRAY_PUSH(cflcts, const svn_wc_conflict_description2_t *) = desc;
     }
 
@@ -2241,12 +2298,26 @@ svn_wc__read_conflicts(const apr_array_h
    and clearing the conflict filenames from the entry.  The latter needs to
    be done whether or not the conflict files exist.
 
+   ### This func combines *resolving* and *marking as resolved* -- seems poor.
+
+   ### Resolving is shared between this func and its caller
+       'conflict_status_walker()' -- seems poor.
+
    LOCAL_ABSPATH in DB is the path to the item to be resolved.
    RESOLVE_TEXT, RESOLVE_PROPS and RESOLVE_TREE are TRUE iff text, property
    and tree conflicts respectively are to be resolved.
 
    If this call marks any conflict as resolved, set *DID_RESOLVE to true,
-   else do not change *DID_RESOLVE.
+   else to false.
+   If asked to resolve a text or prop conflict, only set *DID_RESOLVE
+   to true if a conflict marker file was present, because if no marker
+   file was present then the conflict is considered to be marked as
+   resolved already.
+   ### If asked to resolve a tree conflict, always set *DID_RESOLVE to true.
+       This would make sense if 'resolve_tree' is only requested when
+       there is in fact a tree conflict to be resolved, but, for
+       consistency with text & prop conflicts, the code should probably
+       say "if (resolve_tree && tree_conflicted) *did_resolve = TRUE".
 
    See svn_wc_resolved_conflict5() for how CONFLICT_CHOICE behaves.
 */
@@ -2524,8 +2595,29 @@ resolve_conflict_on_node(svn_boolean_t *
             }
         }
     }
+
   if (resolve_tree)
-    *did_resolve = TRUE;
+    {
+      svn_wc_conflict_reason_t reason;
+
+      SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL, 
+                                                  db, local_abspath,
+                                                  conflicts,
+                                                  scratch_pool, scratch_pool));
+
+      if (reason == svn_wc_conflict_reason_deleted)
+        {
+          /* ### FIXME.  At the moment this is a separate transaction
+             ### but it should somehow be combined with the transaction
+             ### in svn_wc__db_op_mark_resolved.  Perhaps move this
+             ### functionality into that function?  Perhaps have this
+             ### function generate "raise conflict" workqueue items? */
+          SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(db, local_abspath,
+                                                             scratch_pool));
+        }
+                                                  
+      *did_resolve = TRUE;
+    }
 
   if (resolve_text || resolve_props || resolve_tree)
     {
@@ -2544,9 +2636,9 @@ resolve_conflict_on_node(svn_boolean_t *
 
 
 svn_error_t *
-svn_wc__resolve_text_conflict(svn_wc__db_t *db,
-                              const char *local_abspath,
-                              apr_pool_t *scratch_pool)
+svn_wc__mark_resolved_text_conflict(svn_wc__db_t *db,
+                                    const char *local_abspath,
+                                    apr_pool_t *scratch_pool)
 {
   svn_boolean_t ignored_result;
 
@@ -2562,6 +2654,25 @@ svn_wc__resolve_text_conflict(svn_wc__db
                            scratch_pool));
 }
 
+svn_error_t *
+svn_wc__mark_resolved_prop_conflicts(svn_wc__db_t *db,
+                                     const char *local_abspath,
+                                     apr_pool_t *scratch_pool)
+{
+  svn_boolean_t ignored_result;
+
+  return svn_error_trace(resolve_conflict_on_node(
+                           &ignored_result,
+                           db, local_abspath,
+                           FALSE /* resolve_text */,
+                           TRUE /* resolve_props */,
+                           FALSE /* resolve_tree */,
+                           svn_wc_conflict_choose_merged,
+                           NULL /* work_items */,
+                           NULL, NULL, /* cancel_func */
+                           scratch_pool));
+}
+
 
 /* Baton for conflict_status_walker */
 struct conflict_status_walker_baton
@@ -2648,13 +2759,32 @@ conflict_status_walker(void *baton,
               {
                 if (my_choice == svn_wc_conflict_choose_mine_conflict)
                   SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(
-                            &work_items, local_abspath, cswb->db,
+                            &work_items,
+                            cswb->db, local_abspath,
                             cswb->notify_func, cswb->notify_baton,
                             cswb->cancel_func, cswb->cancel_baton,
                             scratch_pool, scratch_pool));
                  else if (my_choice == svn_wc_conflict_choose_theirs_conflict)
                   {
-                    /* ### TODO break move */
+                    switch (status->node_status)
+                      {
+                        case svn_wc_status_deleted:
+                          /* Break the move by reverting the deleted half of
+                           * the move, keeping the copied-half as a copy.
+                           * Reverting a node requires write lock on parent. */
+                          SVN_ERR(svn_wc__revert_internal(cswb->db, local_abspath,
+                                                          svn_depth_infinity,
+                                                          FALSE, 
+                                                          cswb->cancel_func,
+                                                          cswb->cancel_baton,
+                                                          cswb->notify_func,
+                                                          cswb->notify_baton,
+                                                          scratch_pool));
+                          break;
+                        default:
+                          /* ### TODO other node_status cases */
+                          break;
+                      }
                   }
               }
             else if (my_choice != svn_wc_conflict_choose_merged)
@@ -2864,3 +2994,19 @@ svn_wc_resolved_conflict5(svn_wc_context
                                                    notify_func, notify_baton,
                                                    scratch_pool));
 }
+
+/* Constructor for the result-structure returned by conflict callbacks. */
+svn_wc_conflict_result_t *
+svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice,
+                              const char *merged_file,
+                              apr_pool_t *pool)
+{
+  svn_wc_conflict_result_t *result = apr_pcalloc(pool, sizeof(*result));
+  result->choice = choice;
+  result->merged_file = merged_file;
+  result->save_merged = FALSE;
+
+  /* If we add more fields to svn_wc_conflict_result_t, add them here. */
+
+  return result;
+}

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.h?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.h (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/conflicts.h Mon Feb  4 20:48:05 2013
@@ -77,7 +77,7 @@ svn_wc__conflict_skel_is_complete(svn_bo
 /* Set 'update' as the conflicting operation in CONFLICT_SKEL.
    Allocate data stored in the skel in RESULT_POOL.
 
-   ORIGINAL specifies the BASE node before updating.
+   ORIGINAL and TARGET specify the BASE node before and after updating.
 
    It is an error to set another operation to a conflict skel that
    already has an operation.
@@ -87,6 +87,7 @@ svn_wc__conflict_skel_is_complete(svn_bo
 svn_error_t *
 svn_wc__conflict_skel_set_op_update(svn_skel_t *conflict_skel,
                                     const svn_wc_conflict_version_t *original,
+                                    const svn_wc_conflict_version_t *target,
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
 
@@ -94,7 +95,7 @@ svn_wc__conflict_skel_set_op_update(svn_
 /* Set 'switch' as the conflicting operation in CONFLICT_SKEL.
    Allocate data stored in the skel in RESULT_POOL.
 
-   ORIGINAL specifies the BASE node before switching.
+   ORIGINAL and TARGET specify the BASE node before and after switching.
 
    It is an error to set another operation to a conflict skel that
    already has an operation.
@@ -103,6 +104,7 @@ svn_wc__conflict_skel_set_op_update(svn_
 svn_error_t *
 svn_wc__conflict_skel_set_op_switch(svn_skel_t *conflict_skel,
                                     const svn_wc_conflict_version_t *original,
+                                    const svn_wc_conflict_version_t *target,
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
 
@@ -182,10 +184,10 @@ svn_wc__conflict_skel_add_prop_conflict(
                                         svn_wc__db_t *db,
                                         const char *wri_abspath,
                                         const char *marker_abspath,
-                                        apr_hash_t *mine_props,
-                                        apr_hash_t *their_old_props,
-                                        apr_hash_t *their_props,
-                                        apr_hash_t *conflicted_prop_names,
+                                        const apr_hash_t *mine_props,
+                                        const apr_hash_t *their_old_props,
+                                        const apr_hash_t *their_props,
+                                        const apr_hash_t *conflicted_prop_names,
                                         apr_pool_t *result_pool,
                                         apr_pool_t *scratch_pool);
 
@@ -199,6 +201,19 @@ svn_wc__conflict_skel_add_prop_conflict(
    It is an error to add another tree conflict to a conflict skel that
    already contains a tree conflict.
 
+   MOVED_AWAY_OP_ROOT_ABSPATH must be set when LOCAL_CHANGE is
+   svn_wc_conflict_reason_moved_away and NULL otherwise.  It should be
+   set to the op-root of the move-away unless the move is inside a
+   delete in which case it should be set to the op-root of the delete
+   (the delete can be a replace). So given:
+       A/B/C moved away (1)
+       A deleted and replaced
+       A/B/C moved away (2)
+       A/B deleted
+   MOVED_AWAY_OP_ROOT_ABSPATH should be A for a conflict associated
+   with (1), MOVED_AWAY_OP_ROOT_ABSPATH should be A/B for a conflict
+   associated with (2).
+
    ### Is it an error to add a tree conflict to any existing conflict?
 
    Do temporary allocations in SCRATCH_POOL.
@@ -209,6 +224,7 @@ svn_wc__conflict_skel_add_tree_conflict(
                                         const char *wri_abspath,
                                         svn_wc_conflict_reason_t local_change,
                                         svn_wc_conflict_action_t incoming_change,
+                                        const char *moved_away_op_root_abspath,
                                         apr_pool_t *result_pool,
                                         apr_pool_t *scratch_pool);
 
@@ -260,7 +276,12 @@ svn_wc__conflict_skel_resolve(svn_boolea
  *
  * Output arguments can be NULL if the value is not necessary.
  *
- * ### stsp asks: what is LOCATIONS?
+ * Set *LOCATIONS to an array of (svn_wc_conflict_version_t *).  For
+ * conflicts written by current code, there are 2 elements: index [0] is
+ * the 'old' or 'left' side and [1] is the 'new' or 'right' side.
+ *
+ * For conflicts written by 1.6 or 1.7 there are 2 locations for a tree
+ * conflict, but none for a text or property conflict.
  *
  * TEXT_, PROP_ and TREE_CONFLICTED (when not NULL) will be set to TRUE
  * when the conflict contains the specified kind of conflict, otherwise
@@ -281,10 +302,10 @@ svn_wc__conflict_read_info(svn_wc_operat
                            apr_pool_t *result_pool,
                            apr_pool_t *scratch_pool);
 
-/* Reads back the original data stored by svn_wc__conflict_add_text_conflict()
+/* Reads back the original data stored by svn_wc__conflict_skel_add_text_conflict()
  * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH.
  *
- * Values as documented for svn_wc__conflict_add_text_conflict().
+ * Values as documented for svn_wc__conflict_skel_add_text_conflict().
  *
  * Output arguments can be NULL if the value is not necessary.
  *
@@ -301,10 +322,10 @@ svn_wc__conflict_read_text_conflict(cons
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
 
-/* Reads back the original data stored by svn_wc__conflict_add_prop_conflict()
+/* Reads back the original data stored by svn_wc__conflict_skel_add_prop_conflict()
  * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH.
  *
- * Values as documented for svn_wc__conflict_add_prop_conflict().
+ * Values as documented for svn_wc__conflict_skel_add_prop_conflict().
  *
  * Output arguments can be NULL if the value is not necessary
  * Allocate the result in RESULT_POOL. Perform temporary allocations in
@@ -322,10 +343,10 @@ svn_wc__conflict_read_prop_conflict(cons
                                     apr_pool_t *result_pool,
                                     apr_pool_t *scratch_pool);
 
-/* Reads back the original data stored by svn_wc__conflict_add_tree_conflict()
+/* Reads back the original data stored by svn_wc__conflict_skel_add_tree_conflict()
  * in CONFLICT_SKEL for a node in DB, WRI_ABSPATH.
  *
- * Values as documented for svn_wc__conflict_add_tree_conflict().
+ * Values as documented for svn_wc__conflict_skel_add_tree_conflict().
  *
  * Output arguments can be NULL if the value is not necessary
  * Allocate the result in RESULT_POOL. Perform temporary allocations in
@@ -334,6 +355,7 @@ svn_wc__conflict_read_prop_conflict(cons
 svn_error_t *
 svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change,
                                     svn_wc_conflict_action_t *incoming_change,
+                                    const char **moved_away_op_root_abspath,
                                     svn_wc__db_t *db,
                                     const char *wri_abspath,
                                     const svn_skel_t *conflict_skel,
@@ -374,7 +396,11 @@ svn_wc__conflict_create_markers(svn_skel
 /* Call the interactive conflict resolver RESOLVER_FUNC with RESOLVER_BATON to
    allow resolving the conflicts on LOCAL_ABSPATH.
 
+   Call RESOLVER_FUNC once for each property conflict, and again for any
+   text conflict, and again for any tree conflict on the node.
+
    CONFLICT_SKEL contains the details of the conflicts on LOCAL_ABSPATH.
+
    Resolver actions are directly applied to the in-db state of LOCAL_ABSPATH,
    so the conflict and the state in CONFLICT_SKEL must already be installed in
    wc.db. */
@@ -385,14 +411,22 @@ svn_wc__conflict_invoke_resolver(svn_wc_
                                  const apr_array_header_t *merge_options,
                                  svn_wc_conflict_resolver_func2_t resolver_func,
                                  void *resolver_baton,
+                                 svn_cancel_func_t cancel_func,
+                                 void *cancel_baton,
                                  apr_pool_t *scratch_pool);
 
 
-/* Resolve text conflicts on the given node.  */
+/* Mark as resolved any text conflict on the node at DB/LOCAL_ABSPATH.  */
 svn_error_t *
-svn_wc__resolve_text_conflict(svn_wc__db_t *db,
-                              const char *local_abspath,
-                              apr_pool_t *scratch_pool);
+svn_wc__mark_resolved_text_conflict(svn_wc__db_t *db,
+                                    const char *local_abspath,
+                                    apr_pool_t *scratch_pool);
+
+/* Mark as resolved any prop conflicts on the node at DB/LOCAL_ABSPATH.  */
+svn_error_t *
+svn_wc__mark_resolved_prop_conflicts(svn_wc__db_t *db,
+                                     const char *local_abspath,
+                                     apr_pool_t *scratch_pool);
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/copy.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/copy.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/copy.c Mon Feb  4 20:48:05 2013
@@ -166,9 +166,6 @@ copy_to_tmpdir(svn_skel_t **work_item,
    If IS_MOVE is true, record move information in working copy meta
    data in addition to copying the file.
 
-   If COPY_PRISTINE_FILE is true, make sure the necessary pristine files are
-   available in the destination working copy.
-
    If the versioned file has a text conflict, and the .mine file exists in
    the filesystem, copy the .mine file to DST_ABSPATH.  Otherwise, copy the
    versioned file itself.
@@ -181,7 +178,6 @@ copy_versioned_file(svn_wc__db_t *db,
                     const char *dst_abspath,
                     const char *dst_op_root_abspath,
                     const char *tmpdir_abspath,
-                    svn_boolean_t copy_pristine_file,
                     svn_boolean_t metadata_only,
                     svn_boolean_t conflicted,
                     svn_boolean_t is_move,
@@ -196,12 +192,6 @@ copy_versioned_file(svn_wc__db_t *db,
   /* In case we are copying from one WC to another (e.g. an external dir),
      ensure the destination WC has a copy of the pristine text. */
 
-  if (copy_pristine_file)
-    SVN_ERR(svn_wc__db_pristine_transfer(db, src_abspath, NULL,
-                                         dst_op_root_abspath,
-                                         cancel_func, cancel_baton,
-                                         scratch_pool));
-
   /* Prepare a temp copy of the filesystem node.  It is usually a file, but
      copy recursively if it's a dir. */
   if (!metadata_only)
@@ -288,9 +278,7 @@ copy_versioned_file(svn_wc__db_t *db,
    otherwise copy both the versioned metadata and the filesystem nodes (even
    if they are the wrong kind, and including unversioned children).
    If IS_MOVE is true, record move information in working copy meta
-   data in addition to copying the directory. If IS_MOVE is TRUE and
-   ALLOW_MIXED_REVISIONS is FALSE, raise an error if a move of a
-   mixed-revision subtree is attempted.
+   data in addition to copying the directory.
 
    WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root)
  */
@@ -302,8 +290,6 @@ copy_versioned_dir(svn_wc__db_t *db,
                    const char *tmpdir_abspath,
                    svn_boolean_t metadata_only,
                    svn_boolean_t is_move,
-                   svn_boolean_t allow_mixed_revisions,
-                   svn_boolean_t within_one_wc,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    svn_wc_notify_func2_t notify_func,
@@ -319,24 +305,6 @@ copy_versioned_dir(svn_wc__db_t *db,
   svn_node_kind_t disk_kind;
   apr_pool_t *iterpool;
 
-  if (is_move && !allow_mixed_revisions)
-    {
-      svn_revnum_t min_rev;
-      svn_revnum_t max_rev;
-
-      /* Verify that the move source is a single-revision subtree. */
-      SVN_ERR(svn_wc__db_min_max_revisions(&min_rev, &max_rev, db,
-                                           src_abspath, FALSE, scratch_pool));
-      if (SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev) &&
-          min_rev != max_rev)
-        return svn_error_createf(SVN_ERR_WC_MIXED_REVISIONS, NULL,
-                                 _("Cannot move mixed-revision subtree '%s' "
-                                   "[%lu:%lu]; try updating it first"),
-                                   svn_dirent_local_style(src_abspath,
-                                                          scratch_pool),
-                                   min_rev, max_rev);
-    }
-
   /* Prepare a temp copy of the single filesystem node (usually a dir). */
   if (!metadata_only)
     {
@@ -423,7 +391,6 @@ copy_versioned_dir(svn_wc__db_t *db,
                                             child_dst_abspath,
                                             dst_op_root_abspath,
                                             tmpdir_abspath,
-                                            !within_one_wc && info->has_checksum,
                                             metadata_only, info->conflicted,
                                             is_move,
                                             cancel_func, cancel_baton,
@@ -435,7 +402,6 @@ copy_versioned_dir(svn_wc__db_t *db,
                                        child_src_abspath, child_dst_abspath,
                                        dst_op_root_abspath, tmpdir_abspath,
                                        metadata_only, is_move,
-                                       allow_mixed_revisions, within_one_wc,
                                        cancel_func, cancel_baton, NULL, NULL,
                                        iterpool));
           else
@@ -539,9 +505,13 @@ copy_versioned_dir(svn_wc__db_t *db,
 
 /* The guts of svn_wc_copy3() and svn_wc_move().
  * The additional parameter IS_MOVE indicates whether this is a copy or
- * a move operation. */
+ * a move operation.
+ *
+ * If MOVE_DEGRADED_TO_COPY is not NULL and a move had to be degraded
+ * to a copy, then set *MOVE_DEGRADED_TO_COPY. */
 static svn_error_t *
-copy_or_move(svn_wc_context_t *wc_ctx,
+copy_or_move(svn_boolean_t *move_degraded_to_copy,
+             svn_wc_context_t *wc_ctx,
              const char *src_abspath,
              const char *dst_abspath,
              svn_boolean_t metadata_only,
@@ -557,7 +527,6 @@ copy_or_move(svn_wc_context_t *wc_ctx,
   svn_kind_t src_db_kind;
   const char *dstdir_abspath;
   svn_boolean_t conflicted;
-  const svn_checksum_t *checksum;
   const char *tmpdir_abspath;
   const char *src_wcroot_abspath;
   const char *dst_wcroot_abspath;
@@ -578,7 +547,7 @@ copy_or_move(svn_wc_context_t *wc_ctx,
 
     err = svn_wc__db_read_info(&src_status, &src_db_kind, NULL, NULL,
                                &src_repos_root_url, &src_repos_uuid, NULL,
-                               NULL, NULL, NULL, &checksum, NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL, NULL, NULL, NULL,
                                NULL, NULL, NULL, NULL, NULL, NULL, &conflicted,
                                NULL, NULL, NULL, NULL, NULL, NULL,
                                db, src_abspath, scratch_pool, scratch_pool);
@@ -759,12 +728,25 @@ copy_or_move(svn_wc_context_t *wc_ctx,
 
   within_one_wc = (strcmp(src_wcroot_abspath, dst_wcroot_abspath) == 0);
 
+  if (move_degraded_to_copy != NULL)
+    {
+      /* Cross-WC moves cannot be tracked.
+       * Degrade such moves to a copy+delete. */
+      *move_degraded_to_copy = (is_move && !within_one_wc);
+      if (*move_degraded_to_copy)
+        is_move = FALSE;
+    }
+
+  if (!within_one_wc)
+    SVN_ERR(svn_wc__db_pristine_transfer(db, src_abspath, dst_wcroot_abspath,
+                                         cancel_func, cancel_baton,
+                                         scratch_pool));
+
   if (src_db_kind == svn_kind_file
       || src_db_kind == svn_kind_symlink)
     {
       err = copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath,
                                 tmpdir_abspath,
-                                !within_one_wc && (checksum != NULL),
                                 metadata_only, conflicted, is_move,
                                 cancel_func, cancel_baton,
                                 notify_func, notify_baton,
@@ -772,9 +754,26 @@ copy_or_move(svn_wc_context_t *wc_ctx,
     }
   else
     {
+      if (is_move && !allow_mixed_revisions)
+        {
+          svn_revnum_t min_rev;
+          svn_revnum_t max_rev;
+        
+          /* Verify that the move source is a single-revision subtree. */
+          SVN_ERR(svn_wc__db_min_max_revisions(&min_rev, &max_rev, db,
+                                               src_abspath, FALSE, scratch_pool));
+          if (SVN_IS_VALID_REVNUM(min_rev) && SVN_IS_VALID_REVNUM(max_rev) &&
+              min_rev != max_rev)
+            return svn_error_createf(SVN_ERR_WC_MIXED_REVISIONS, NULL,
+                                     _("Cannot move mixed-revision subtree '%s' "
+                                       "[%ld:%ld]; try updating it first"),
+                                       svn_dirent_local_style(src_abspath,
+                                                              scratch_pool),
+                                       min_rev, max_rev);
+        }
+
       err = copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath,
                                tmpdir_abspath, metadata_only, is_move,
-                               allow_mixed_revisions, within_one_wc,
                                cancel_func, cancel_baton,
                                notify_func, notify_baton,
                                scratch_pool);
@@ -812,7 +811,7 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
                               svn_dirent_dirname(dst_abspath, scratch_pool),
                               scratch_pool));
 
-  return svn_error_trace(copy_or_move(wc_ctx, src_abspath, dst_abspath,
+  return svn_error_trace(copy_or_move(NULL, wc_ctx, src_abspath, dst_abspath,
                                       metadata_only, FALSE /* is_move */,
                                       TRUE /* allow_mixed_revisions */,
                                       cancel_func, cancel_baton,
@@ -947,6 +946,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
               apr_pool_t *scratch_pool)
 {
   svn_wc__db_t *db = wc_ctx->db;
+  svn_boolean_t move_degraded_to_copy = FALSE;
 
   /* Verify that we have the required write locks. */
   SVN_ERR(svn_wc__write_check(wc_ctx->db,
@@ -956,7 +956,8 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
                               svn_dirent_dirname(dst_abspath, scratch_pool),
                               scratch_pool));
 
-  SVN_ERR(copy_or_move(wc_ctx, src_abspath, dst_abspath,
+  SVN_ERR(copy_or_move(&move_degraded_to_copy,
+                       wc_ctx, src_abspath, dst_abspath,
                        TRUE /* metadata_only */,
                        TRUE /* is_move */,
                        allow_mixed_revisions,
@@ -971,7 +972,13 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
   /* Should we be using a workqueue for this move?  It's not clear.
      What should happen if the copy above is interrupted?  The user
      may want to abort the move and a workqueue might interfere with
-     that. */
+     that.
+
+     BH: On Windows it is not unlikely to encounter an access denied on
+     this line. Installing the move in the workqueue via the copy_or_move
+     might make it hard to recover from that situation, while the DB
+     is still in a valid state. So be careful when switching this over
+     to the workqueue. */
   if (!metadata_only)
     SVN_ERR(svn_io_file_rename(src_abspath, dst_abspath, scratch_pool));
 
@@ -997,7 +1004,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
   }
 
   SVN_ERR(svn_wc__delete_internal(wc_ctx, src_abspath, TRUE, FALSE,
-                                  dst_abspath,
+                                  move_degraded_to_copy ? NULL : dst_abspath,
                                   cancel_func, cancel_baton,
                                   notify_func, notify_baton,
                                   scratch_pool));

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/crop.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/crop.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/crop.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/crop.c Mon Feb  4 20:48:05 2013
@@ -107,7 +107,9 @@ crop_children(svn_wc__db_t *db,
                                             ? svn_depth_immediates
                                             : svn_depth_files;
           if (new_depth < remove_below)
-            SVN_ERR(svn_wc__db_base_remove(db, local_abspath, FALSE,
+            SVN_ERR(svn_wc__db_base_remove(db, child_abspath,
+                                           FALSE /* keep_as_working */,
+                                           FALSE /* queue_deletes */,
                                            SVN_INVALID_REVNUM,
                                            NULL, NULL, iterpool));
 
@@ -196,8 +198,8 @@ svn_wc_exclude(svn_wc_context_t *wc_ctx,
   svn_revnum_t revision;
   const char *repos_relpath, *repos_root, *repos_uuid;
 
-  SVN_ERR(svn_wc__check_wc_root(&is_root, NULL, &is_switched,
-                                wc_ctx->db, local_abspath, scratch_pool));
+  SVN_ERR(svn_wc__db_is_switched(&is_root, &is_switched, NULL,
+                                 wc_ctx->db, local_abspath, scratch_pool));
 
   if (is_root)
     {

Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/deprecated.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/deprecated.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/deprecated.c Mon Feb  4 20:48:05 2013
@@ -607,6 +607,34 @@ svn_wc_create_tmp_file(apr_file_t **fp,
                                  pool);
 }
 
+svn_error_t *
+svn_wc_create_tmp_file2(apr_file_t **fp,
+                        const char **new_name,
+                        const char *path,
+                        svn_io_file_del_t delete_when,
+                        apr_pool_t *pool)
+{
+  svn_wc_context_t *wc_ctx;
+  const char *local_abspath;
+  const char *temp_dir;
+  svn_error_t *err;
+
+  SVN_ERR_ASSERT(fp || new_name);
+
+  SVN_ERR(svn_wc_context_create(&wc_ctx, NULL /* config */, pool, pool));
+
+  SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
+  err = svn_wc__get_tmpdir(&temp_dir, wc_ctx, local_abspath, pool, pool);
+  err = svn_error_compose_create(err, svn_wc_context_destroy(wc_ctx));
+  if (err)
+    return svn_error_trace(err);
+
+  SVN_ERR(svn_io_open_unique_file3(fp, new_name, temp_dir,
+                                   delete_when, pool, pool));
+
+  return SVN_NO_ERROR;
+}
+
 
 /*** From adm_ops.c ***/
 svn_error_t *
@@ -903,6 +931,18 @@ svn_wc_delete(const char *path,
 }
 
 svn_error_t *
+svn_wc_add_from_disk(svn_wc_context_t *wc_ctx,
+                     const char *local_abspath,
+                     svn_wc_notify_func2_t notify_func,
+                     void *notify_baton,
+                     apr_pool_t *scratch_pool)
+{
+  SVN_ERR(svn_wc_add_from_disk2(wc_ctx, local_abspath, NULL,
+                                 notify_func, notify_baton, scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_wc_add3(const char *path,
             svn_wc_adm_access_t *parent_access,
             svn_depth_t depth,
@@ -2471,27 +2511,36 @@ svn_wc_merge_props2(svn_wc_notify_state_
 {
   const char *local_abspath;
   svn_error_t *err;
+  svn_wc_context_t *wc_ctx;
   struct conflict_func_1to2_baton conflict_wrapper;
 
+  if (base_merge && !dry_run)
+    return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+                            U_("base_merge=TRUE is no longer supported; "
+                               "see notes/api-errata/1.7/wc006.txt"));
+
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
 
   conflict_wrapper.inner_func = conflict_func;
   conflict_wrapper.inner_baton = conflict_baton;
 
-  err = svn_wc__perform_props_merge(state,
-                                    svn_wc__adm_get_db(adm_access),
-                                    local_abspath,
-                                    NULL /* left_version */,
-                                    NULL /* right_version */,
-                                    baseprops,
-                                    propchanges,
-                                    base_merge,
-                                    dry_run,
-                                    conflict_func ? conflict_func_1to2_wrapper
-                                                  : NULL,
-                                    &conflict_wrapper,
-                                    NULL, NULL,
-                                    scratch_pool);
+  SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL,
+                                         svn_wc__adm_get_db(adm_access),
+                                         scratch_pool));
+
+  err = svn_wc_merge_props3(state,
+                            wc_ctx,
+                            local_abspath,
+                            NULL /* left_version */,
+                            NULL /* right_version */,
+                            baseprops,
+                            propchanges,
+                            dry_run,
+                            conflict_func ? conflict_func_1to2_wrapper
+                                          : NULL,
+                            &conflict_wrapper,
+                            NULL, NULL,
+                            scratch_pool);
 
   if (err)
     switch(err->apr_err)
@@ -2501,7 +2550,9 @@ svn_wc_merge_props2(svn_wc_notify_state_
           err->apr_err = SVN_ERR_UNVERSIONED_RESOURCE;
           break;
       }
-  return svn_error_trace(err);
+  return svn_error_trace(
+            svn_error_compose_create(err,
+                                     svn_wc_context_destroy(wc_ctx)));
 }
 
 svn_error_t *
@@ -3211,8 +3262,8 @@ svn_wc_is_wc_root2(svn_boolean_t *wc_roo
   svn_error_t *err;
   SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
 
-  err = svn_wc__check_wc_root(&is_root, &kind, &is_switched,
-                              wc_ctx->db, local_abspath, scratch_pool);
+  err = svn_wc__db_is_switched(&is_root, &is_switched, &kind,
+                               wc_ctx->db, local_abspath, scratch_pool);
 
   if (err)
     {