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 2016/01/15 18:50:53 UTC

svn commit: r1724864 - in /subversion/trunk/subversion/svn: cl.h conflict-callbacks.c merge-cmd.c notify.c resolve-cmd.c svn.c switch-cmd.c update-cmd.c

Author: stsp
Date: Fri Jan 15 17:50:52 2016
New Revision: 1724864

URL: http://svn.apache.org/viewvc?rev=1724864&view=rev
Log:
Remove the svn_cl__conflict_func_interactive() callback.

The command line client will now start the conflict resolver by itself if
an update, merge, or switch operation flags conflicts in the working copy.
Before this commit it was relying on the libraries to do so. This finally
gives full control over conflict resolution to the client and paves the
way for future enhancements of the conflict resolver.

Only one use case of the libsvn_wc conflict callback remains. This is
required for supporting 'svn merge --accept' during merges which perform
multiple editor drives. A better solution would be changing the
svn_client_merge API to allow the client to get away without the conflict
callback. I've left this for future work.

* subversion/svn/cl.h
  (svn_cl__conflict_stats_get_paths): Declare this new function which is
   involved in keeping existing conflict resolution behaviour intact.
   The client already records newly conflicted paths as part of conflict
   accounting. We use this list of paths to run the conflict resolver on
   the newly conflicted paths only, rather than running it over the entire
   working copy as 'svn resolve' would do.
  (svn_cl__get_conflict_func_interactive_baton,
   svn_cl__conflict_func_interactive): Remove declaration. Now unused.
  (svn_cl__walk_conflicts): Declare this new function which makes the
   working copy walker logic of 'svn resolve' available to subcommands
   which now need it as well.
   
* subversion/svn/conflict-callbacks.c
  (svn_cl__get_conflict_func_interactive_baton,
   svn_cl__conflict_func_interactive): Remove.

* subversion/svn/merge-cmd.c
  (conflict_func_merge_cmd_baton, conflict_func_merge_cmd): Add this
   temporary implementation of svn_wc_conflict_resolver_func2_t to
   avoid breaking 'svn merge --accept'. Note that we cannot support the
   'edit' and 'launch' accept options anymore, so these now map to 'postpone'.
   This is a small CLI interface change relative to 1.9.
  (svn_cl__merge): Install the above conflict callback if necessary.
   Invoke the interactive conflict resolver if necessary.

* subversion/svn/notify.c
  (svn_cl__conflict_stats_get_paths): Implement.

* subversion/svn/resolve-cmd.c
  (svn_cl__walk_conflicts): Implement. Partly split out of svn_cl__resolve().

* subversion/svn/svn.c
  (sub_main): Do not install a libsvn_wc conflict callback by default.

* subversion/svn/switch-cmd.c
  (svn_cl__switch): Invoke the interactive conflict resolver if necessary.

* subversion/svn/update-cmd.c
  (svn_cl__update): Invoke the interactive conflict resolver if necessary.

Modified:
    subversion/trunk/subversion/svn/cl.h
    subversion/trunk/subversion/svn/conflict-callbacks.c
    subversion/trunk/subversion/svn/merge-cmd.c
    subversion/trunk/subversion/svn/notify.c
    subversion/trunk/subversion/svn/resolve-cmd.c
    subversion/trunk/subversion/svn/svn.c
    subversion/trunk/subversion/svn/switch-cmd.c
    subversion/trunk/subversion/svn/update-cmd.c

Modified: subversion/trunk/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/cl.h?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Fri Jan 15 17:50:52 2016
@@ -362,6 +362,14 @@ svn_cl__conflict_stats_resolved(svn_cl__
                                 const char *path_local,
                                 svn_wc_conflict_kind_t conflict_kind);
 
+/* Set *CONFLICTED_PATHS to the conflicted paths contained in CONFLICT_STATS.
+ * If no conflicted path exists, set *CONFLICTED_PATHS to NULL. */
+svn_error_t *
+svn_cl__conflict_stats_get_paths(apr_array_header_t **conflicted_paths,
+                                 svn_cl__conflict_stats_t *conflict_stats,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
+
 /* Print the conflict stats accumulated in CONFLICT_STATS.
  *
  * Return any error encountered during printing.
@@ -371,39 +379,11 @@ svn_error_t *
 svn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
                              apr_pool_t *scratch_pool);
 
-/* Create and return an baton for use with svn_cl__conflict_func_interactive
- * in *B, allocated from RESULT_POOL, and initialised with the values
- * ACCEPT_WHICH, CONFIG, EDITOR_CMD, CANCEL_FUNC and CANCEL_BATON. */
-svn_error_t *
-svn_cl__get_conflict_func_interactive_baton(
-  svn_cl__interactive_conflict_baton_t **b,
-  svn_cl__accept_t accept_which,
-  apr_hash_t *config,
-  const char *editor_cmd,
-  svn_cl__conflict_stats_t *conflict_stats,
-  svn_cancel_func_t cancel_func,
-  void *cancel_baton,
-  apr_pool_t *result_pool);
-
-/* A callback capable of doing interactive conflict resolution.
-
-   The BATON must come from svn_cl__get_conflict_func_interactive_baton().
-   Resolves based on the --accept option if one was given to that function,
-   otherwise prompts the user to choose one of the three fulltexts, edit
-   the merged file on the spot, or just skip the conflict (to be resolved
-   later), among other options.
-
-   Implements svn_wc_conflict_resolver_func2_t.
+/* 
+ * Interactively resolve the conflict a @a CONFLICT.
+ * TODO: more docs
  */
 svn_error_t *
-svn_cl__conflict_func_interactive(svn_wc_conflict_result_t **result,
-                                  const svn_wc_conflict_description2_t *desc,
-                                  void *baton,
-                                  apr_pool_t *result_pool,
-                                  apr_pool_t *scratch_pool);
-
-
-svn_error_t *
 svn_cl__resolve_conflict(svn_boolean_t *resolved,
                          svn_cl__accept_t *accept_which,
                          svn_boolean_t *quit,
@@ -419,6 +399,18 @@ svn_cl__resolve_conflict(svn_boolean_t *
                          svn_client_ctx_t *ctx,
                          apr_pool_t *scratch_pool);
 
+/* 
+ * Interactively resolve conflicts for all TARGETS.
+ * TODO: more docs
+ */
+svn_error_t *
+svn_cl__walk_conflicts(apr_array_header_t *targets,
+                       svn_cl__conflict_stats_t *conflict_stats,
+                       svn_boolean_t is_resolve_cmd,
+                       svn_cl__opt_state_t *opt_state,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *scratch_pool);
+
 
 /*** Command-line output functions -- printing to the user. ***/
 

Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Fri Jan 15 17:50:52 2016
@@ -63,35 +63,6 @@ struct svn_cl__interactive_conflict_bato
   svn_boolean_t printed_summary;
 };
 
-svn_error_t *
-svn_cl__get_conflict_func_interactive_baton(
-  svn_cl__interactive_conflict_baton_t **b,
-  svn_cl__accept_t accept_which,
-  apr_hash_t *config,
-  const char *editor_cmd,
-  svn_cl__conflict_stats_t *conflict_stats,
-  svn_cancel_func_t cancel_func,
-  void *cancel_baton,
-  apr_pool_t *result_pool)
-{
-  svn_cmdline_prompt_baton_t *pb = apr_palloc(result_pool, sizeof(*pb));
-  pb->cancel_func = cancel_func;
-  pb->cancel_baton = cancel_baton;
-
-  *b = apr_palloc(result_pool, sizeof(**b));
-  (*b)->accept_which = accept_which;
-  (*b)->config = config;
-  (*b)->editor_cmd = editor_cmd;
-  (*b)->external_failed = FALSE;
-  (*b)->pb = pb;
-  SVN_ERR(svn_dirent_get_absolute(&(*b)->path_prefix, "", result_pool));
-  (*b)->quit = FALSE;
-  (*b)->conflict_stats = conflict_stats;
-  (*b)->printed_summary = FALSE;
-
-  return SVN_NO_ERROR;
-}
-
 svn_cl__accept_t
 svn_cl__accept_from_word(const char *word)
 {
@@ -1272,7 +1243,6 @@ handle_tree_conflict(svn_client_conflict
   return SVN_NO_ERROR;
 }
 
-/* The body of svn_cl__conflict_func_interactive(). */
 static svn_error_t *
 conflict_func_interactive(svn_client_conflict_option_id_t *option_id,
                           svn_boolean_t *save_merged,
@@ -1499,48 +1469,6 @@ conflict_option_id_to_wc_conflict_choice
 }
 
 svn_error_t *
-svn_cl__conflict_func_interactive(svn_wc_conflict_result_t **result,
-                                  const svn_wc_conflict_description2_t *desc,
-                                  void *baton,
-                                  apr_pool_t *result_pool,
-                                  apr_pool_t *scratch_pool)
-{
-  svn_cl__interactive_conflict_baton_t *b = baton;
-  svn_client_conflict_t *conflict;
-  svn_client_conflict_option_id_t option_id;
-  svn_boolean_t save_merged = FALSE;
-  const svn_string_t *merged_propval = NULL;
-
-  SVN_ERR(svn_client_conflict_from_wc_description2_t(&conflict, desc,
-                                                     scratch_pool,
-                                                     scratch_pool));
-  *result = svn_wc_create_conflict_result(svn_client_conflict_option_postpone,
-                                          NULL, result_pool);
-  SVN_ERR(conflict_func_interactive(&option_id, &save_merged, &merged_propval,
-                                    &b->accept_which, &b->quit,
-                                    &b->external_failed, &b->printed_summary,
-                                    conflict, b->editor_cmd, b->config,
-                                    b->path_prefix, b->pb, b->conflict_stats,
-                                    result_pool, scratch_pool));
-  (*result)->choice = conflict_option_id_to_wc_conflict_choice(option_id);
-  (*result)->save_merged = save_merged;
-  (*result)->merged_value = merged_propval;
-
-  /* If we are resolving a conflict, adjust the summary of conflicts. */
-  if (option_id != svn_client_conflict_option_postpone)
-    {
-      const char *local_path
-        = svn_cl__local_style_skip_ancestor(
-            b->path_prefix, svn_client_conflict_get_local_abspath(conflict),
-            scratch_pool);
-
-      svn_cl__conflict_stats_resolved(b->conflict_stats, local_path,
-                                      svn_client_conflict_get_kind(conflict));
-    }
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_cl__resolve_conflict(svn_boolean_t *resolved,
                          svn_cl__accept_t *accept_which,
                          svn_boolean_t *quit,

Modified: subversion/trunk/subversion/svn/merge-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/merge-cmd.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/merge-cmd.c (original)
+++ subversion/trunk/subversion/svn/merge-cmd.c Fri Jan 15 17:50:52 2016
@@ -145,6 +145,84 @@ run_merge(svn_boolean_t two_sources_spec
   return merge_err;
 }
 
+/* Baton type for conflict_func_merge_cmd(). */
+struct conflict_func_merge_cmd_baton {
+  svn_cl__accept_t accept_which;
+  const char *path_prefix;
+  svn_cl__conflict_stats_t *conflict_stats;
+};
+
+/* This implements the `svn_wc_conflict_resolver_func2_t ' interface.
+ *
+ * The merge subcommand needs to install this legacy conflict callback
+ * in case the user passed an --accept option to 'svn merge'.
+ * Otherwise, merges involving multiple editor drives might encounter a
+ * conflict during one of the editor drives and abort with an error,
+ * rather than resolving conflicts as per the --accept option and
+ * continuing with the next editor drive.
+ * ### TODO add an svn_client_merge API that makes this callback unnecessary
+ */
+static svn_error_t *
+conflict_func_merge_cmd(svn_wc_conflict_result_t **result,
+                        const svn_wc_conflict_description2_t *desc,
+                        void *baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool)
+{
+  struct conflict_func_merge_cmd_baton *b = baton;
+  svn_wc_conflict_choice_t choice;
+
+  switch (b->accept_which)
+    {
+    case svn_cl__accept_postpone:
+    case svn_cl__accept_invalid:
+    case svn_cl__accept_unspecified:
+      /* Postpone or no valid --accept option, postpone the conflict. */
+      choice = svn_wc_conflict_choose_postpone;
+      break;
+    case svn_cl__accept_base:
+      choice = svn_wc_conflict_choose_base;
+      break;
+    case svn_cl__accept_working:
+      choice = svn_wc_conflict_choose_merged;
+      break;
+    case svn_cl__accept_mine_conflict:
+      choice = svn_wc_conflict_choose_mine_conflict;
+      break;
+    case svn_cl__accept_theirs_conflict:
+      choice = svn_wc_conflict_choose_theirs_conflict;
+      break;
+    case svn_cl__accept_mine_full:
+      choice = svn_wc_conflict_choose_mine_full;
+      break;
+    case svn_cl__accept_theirs_full:
+      choice = svn_wc_conflict_choose_theirs_full;
+      break;
+    case svn_cl__accept_edit:
+    case svn_cl__accept_launch:
+      /* The 'edit' and 'launch' options used to be valid in Subversion 1.9 but
+       * we can't support these options for the purposes of this callback. */
+      choice = svn_wc_conflict_choose_postpone;
+      break;
+    }
+
+  *result = svn_wc_create_conflict_result(choice, NULL, result_pool);
+
+  /* If we are resolving a conflict, adjust the summary of conflicts. */
+  if (choice != svn_wc_conflict_choose_postpone)
+    {
+      const char *local_path;
+
+      local_path = svn_cl__local_style_skip_ancestor(b->path_prefix,
+                                                     desc->local_abspath,
+                                                     scratch_pool);
+      svn_cl__conflict_stats_resolved(b->conflict_stats, local_path,
+                                      desc->kind);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
 svn_cl__merge(apr_getopt_t *os,
@@ -152,6 +230,8 @@ svn_cl__merge(apr_getopt_t *os,
               apr_pool_t *pool)
 {
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+  svn_cl__conflict_stats_t *conflict_stats =
+    ((svn_cl__cmd_baton_t *) baton)->conflict_stats;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   const char *sourcepath1 = NULL, *sourcepath2 = NULL, *targetpath = "";
@@ -160,6 +240,7 @@ svn_cl__merge(apr_getopt_t *os,
   svn_opt_revision_t first_range_start, first_range_end, peg_revision1,
     peg_revision2;
   apr_array_header_t *options, *ranges_to_merge = opt_state->revision_ranges;
+  apr_array_header_t *conflicted_paths;
   svn_boolean_t has_explicit_target = FALSE;
 
   /* Merge doesn't support specifying a revision or revision range
@@ -427,6 +508,21 @@ svn_cl__merge(apr_getopt_t *os,
                                   "with --reintegrate"));
     }
 
+  /* Install a legacy conflict handler if the --accept option was given.
+   * Else, svn_client_merge5() may abort the merge in an undesirable way.
+   * See the docstring at conflict_func_merge_cmd() for details */
+  if (opt_state->accept_which != svn_cl__accept_unspecified)
+    {
+      struct conflict_func_merge_cmd_baton b;
+
+      b.accept_which = opt_state->accept_which;
+      SVN_ERR(svn_dirent_get_absolute(&b.path_prefix, "", pool));
+      b.conflict_stats = conflict_stats;
+
+      ctx->conflict_func2 = conflict_func_merge_cmd;
+      ctx->conflict_baton2 = &b;
+    }
+
   merge_err = run_merge(two_sources_specified,
                         sourcepath1, peg_revision1,
                         sourcepath2,
@@ -442,6 +538,13 @@ svn_cl__merge(apr_getopt_t *os,
                  "fix invalid mergeinfo in target with 'svn propset'"));
     }
 
+  /* Run the interactive resolver if conflicts were raised. */
+  SVN_ERR(svn_cl__conflict_stats_get_paths(&conflicted_paths, conflict_stats,
+                                           pool, pool));
+  if (conflicted_paths)
+    SVN_ERR(svn_cl__walk_conflicts(conflicted_paths, conflict_stats, FALSE,
+                                   opt_state, ctx, pool));
+
   if (!opt_state->quiet)
     {
       svn_error_t *err = svn_cl__notifier_print_conflict_stats(

Modified: subversion/trunk/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/notify.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/notify.c (original)
+++ subversion/trunk/subversion/svn/notify.c Fri Jan 15 17:50:52 2016
@@ -39,6 +39,7 @@
 #include "svn_hash.h"
 #include "cl.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_sorts_private.h"
 #include "private/svn_dep_compat.h"
 
 #include "svn_private_config.h"
@@ -145,6 +146,76 @@ resolved_str(apr_pool_t *pool, int n_res
 }
 
 svn_error_t *
+svn_cl__conflict_stats_get_paths(apr_array_header_t **conflicted_paths,
+                                 svn_cl__conflict_stats_t *conflict_stats,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+
+  int n_text = apr_hash_count(conflict_stats->text_conflicts);
+  int n_prop = apr_hash_count(conflict_stats->prop_conflicts);
+  int n_tree = apr_hash_count(conflict_stats->tree_conflicts);
+  apr_hash_t *all_conflicts;
+
+  *conflicted_paths = NULL;
+  if (n_text == 0 && n_prop == 0 && n_tree == 0)
+      return SVN_NO_ERROR;
+
+  /* Use a hash table to ensure paths with multiple conflicts are
+   * returned just once. */
+  all_conflicts = apr_hash_make(result_pool);
+  if (n_text > 0)
+    {
+      apr_array_header_t *k_text;
+      int i;
+
+      SVN_ERR(svn_hash_keys(&k_text, conflict_stats->text_conflicts,
+                            scratch_pool));
+      for (i = 0; i < k_text->nelts; i++)
+        {
+          const char *path = APR_ARRAY_IDX(k_text, i, const char *);
+
+          svn_hash_sets(all_conflicts, path, "");
+        }
+    }
+
+  if (n_prop > 0)
+    {
+      apr_array_header_t *k_prop;
+      int i;
+
+      SVN_ERR(svn_hash_keys(&k_prop, conflict_stats->prop_conflicts,
+                            scratch_pool));
+      for (i = 0; i < k_prop->nelts; i++)
+        {
+          const char *path = APR_ARRAY_IDX(k_prop, i, const char *);
+
+          svn_hash_sets(all_conflicts, path, "");
+        }
+    }
+
+  if (n_tree > 0)
+    {
+      apr_array_header_t *k_tree;
+      int i;
+
+      SVN_ERR(svn_hash_keys(&k_tree, conflict_stats->tree_conflicts,
+                            scratch_pool));
+      for (i = 0; i < k_tree->nelts; i++)
+        {
+          const char *path = APR_ARRAY_IDX(k_tree, i, const char *);
+
+          svn_hash_sets(all_conflicts, path, "");
+        }
+    }
+
+  svn_hash_keys(conflicted_paths, all_conflicts, result_pool);
+  svn_sort__array(*conflicted_paths, svn_sort_compare_paths);
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_cl__print_conflict_stats(svn_cl__conflict_stats_t *conflict_stats,
                              apr_pool_t *scratch_pool)
 {

Modified: subversion/trunk/subversion/svn/resolve-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/resolve-cmd.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/resolve-cmd.c (original)
+++ subversion/trunk/subversion/svn/resolve-cmd.c Fri Jan 15 17:50:52 2016
@@ -292,84 +292,74 @@ walk_conflicts(svn_client_ctx_t *ctx,
   return SVN_NO_ERROR;
 }
 
-/* This implements the `svn_opt_subcommand_t' interface. */
 svn_error_t *
-svn_cl__resolve(apr_getopt_t *os,
-                void *baton,
-                apr_pool_t *scratch_pool)
+svn_cl__walk_conflicts(apr_array_header_t *targets,
+                       svn_cl__conflict_stats_t *conflict_stats,
+                       svn_boolean_t is_resolve_cmd,
+                       svn_cl__opt_state_t *opt_state,
+                       svn_client_ctx_t *ctx,
+                       apr_pool_t *scratch_pool)
 {
-  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
-  svn_cl__conflict_stats_t *conflict_stats =
-    ((svn_cl__cmd_baton_t *) baton)->conflict_stats;
-  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
-  svn_client_conflict_option_id_t option_id;
-  svn_error_t *err;
-  apr_array_header_t *targets;
-  const char *path_prefix;
-  int i;
-  apr_pool_t *iterpool;
   svn_boolean_t had_error = FALSE;
   svn_boolean_t quit = FALSE;
   svn_boolean_t external_failed = FALSE;
   svn_boolean_t printed_summary = FALSE;
+  svn_client_conflict_option_id_t option_id;
   svn_cmdline_prompt_baton_t *pb = apr_palloc(scratch_pool, sizeof(*pb));
+  const char *path_prefix;
+  svn_error_t *err;
+  int i;
+  apr_pool_t *iterpool;
+
+  SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", scratch_pool));
 
   pb->cancel_func = ctx->cancel_func;
   pb->cancel_baton = ctx->cancel_baton;
 
-  option_id = svn_client_conflict_option_unspecified;
-
-  SVN_ERR(svn_dirent_get_absolute(&path_prefix, "", scratch_pool));
-
   switch (opt_state->accept_which)
     {
     case svn_cl__accept_working:
-      option_id = svn_wc_conflict_choose_merged;
+      option_id = svn_client_conflict_option_merged_text;
       break;
     case svn_cl__accept_base:
-      option_id = svn_wc_conflict_choose_base;
+      option_id = svn_client_conflict_option_base_text;
       break;
     case svn_cl__accept_theirs_conflict:
-      option_id = svn_wc_conflict_choose_theirs_conflict;
+      option_id = svn_client_conflict_option_incoming_text_where_conflicted;
       break;
     case svn_cl__accept_mine_conflict:
-      option_id = svn_wc_conflict_choose_mine_conflict;
+      option_id = svn_client_conflict_option_working_text_where_conflicted;
       break;
     case svn_cl__accept_theirs_full:
-      option_id = svn_wc_conflict_choose_theirs_full;
+      option_id = svn_client_conflict_option_incoming_text;
       break;
     case svn_cl__accept_mine_full:
-      option_id = svn_wc_conflict_choose_mine_full;
+      option_id = svn_client_conflict_option_working_text;
       break;
     case svn_cl__accept_unspecified:
-      if (opt_state->non_interactive)
+      if (is_resolve_cmd && opt_state->non_interactive)
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                 _("missing --accept option"));
-      option_id = svn_wc_conflict_choose_unspecified;
+      option_id = svn_client_conflict_option_unspecified;
+      break;
+    case svn_cl__accept_postpone:
+      if (is_resolve_cmd)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("invalid 'accept' ARG"));
+      option_id = svn_client_conflict_option_postpone;
+      break;
+    case svn_cl__accept_edit:
+    case svn_cl__accept_launch:
+      if (is_resolve_cmd)
+        return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                _("invalid 'accept' ARG"));
+      option_id = svn_client_conflict_option_unspecified;
       break;
     default:
       return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                               _("invalid 'accept' ARG"));
     }
 
-  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
-                                                      opt_state->targets,
-                                                      ctx, FALSE,
-                                                      scratch_pool));
-  if (! targets->nelts)
-    svn_opt_push_implicit_dot_target(targets, scratch_pool);
-
-  if (opt_state->depth == svn_depth_unknown)
-    {
-      if (opt_state->accept_which == svn_cl__accept_unspecified)
-        opt_state->depth = svn_depth_infinity;
-      else
-        opt_state->depth = svn_depth_empty;
-    }
-
-  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
-
-  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
 
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < targets->nelts; i++)
@@ -422,6 +412,42 @@ svn_cl__resolve(apr_getopt_t *os,
     return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
                             _("Failure occurred resolving one or more "
                               "conflicts"));
+  return SVN_NO_ERROR;
+}
+
+/* This implements the `svn_opt_subcommand_t' interface. */
+svn_error_t *
+svn_cl__resolve(apr_getopt_t *os,
+                void *baton,
+                apr_pool_t *scratch_pool)
+{
+  svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+  svn_cl__conflict_stats_t *conflict_stats =
+    ((svn_cl__cmd_baton_t *) baton)->conflict_stats;
+  svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+  apr_array_header_t *targets;
+
+  SVN_ERR(svn_cl__args_to_target_array_print_reserved(&targets, os,
+                                                      opt_state->targets,
+                                                      ctx, FALSE,
+                                                      scratch_pool));
+  if (! targets->nelts)
+    svn_opt_push_implicit_dot_target(targets, scratch_pool);
+
+  if (opt_state->depth == svn_depth_unknown)
+    {
+      if (opt_state->accept_which == svn_cl__accept_unspecified)
+        opt_state->depth = svn_depth_infinity;
+      else
+        opt_state->depth = svn_depth_empty;
+    }
+
+  SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, scratch_pool));
+
+  SVN_ERR(svn_cl__check_targets_are_local_paths(targets));
+
+  SVN_ERR(svn_cl__walk_conflicts(targets, conflict_stats, TRUE,
+                                 opt_state, ctx, scratch_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/trunk/subversion/svn/svn.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/svn.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/svn.c (original)
+++ subversion/trunk/subversion/svn/svn.c Fri Jan 15 17:50:52 2016
@@ -3035,20 +3035,12 @@ sub_main(int *exit_code, int argc, const
         opt_state.accept_which = svn_cl__accept_postpone;
     }
 
-  /* Install the default conflict handler. */
+  /* We don't use legacy libsvn_wc conflict handlers by default. */
   {
-    svn_cl__interactive_conflict_baton_t *b;
-
     ctx->conflict_func = NULL;
     ctx->conflict_baton = NULL;
-
-    ctx->conflict_func2 = svn_cl__conflict_func_interactive;
-    SVN_ERR(svn_cl__get_conflict_func_interactive_baton(
-                &b,
-                opt_state.accept_which,
-                ctx->config, opt_state.editor_cmd, conflict_stats,
-                ctx->cancel_func, ctx->cancel_baton, pool));
-    ctx->conflict_baton2 = b;
+    ctx->conflict_func2 = NULL;
+    ctx->conflict_baton2 = NULL;
   }
 
   /* And now we finally run the subcommand. */

Modified: subversion/trunk/subversion/svn/switch-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/switch-cmd.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/switch-cmd.c (original)
+++ subversion/trunk/subversion/svn/switch-cmd.c Fri Jan 15 17:50:52 2016
@@ -96,8 +96,11 @@ svn_cl__switch(apr_getopt_t *os,
   svn_error_t *err = SVN_NO_ERROR;
   svn_error_t *externals_err = SVN_NO_ERROR;
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+  svn_cl__conflict_stats_t *conflict_stats =
+    ((svn_cl__cmd_baton_t *) baton)->conflict_stats;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
+  apr_array_header_t *conflicted_paths;
   const char *target, *switch_url;
   svn_opt_revision_t peg_revision;
   svn_depth_t depth;
@@ -188,6 +191,13 @@ svn_cl__switch(apr_getopt_t *os,
                                      _("Failure occurred processing one or "
                                        "more externals definitions"));
 
+  /* Run the interactive resolver if conflicts were raised. */
+  SVN_ERR(svn_cl__conflict_stats_get_paths(&conflicted_paths, conflict_stats,
+                                           scratch_pool, scratch_pool));
+  if (conflicted_paths)
+    SVN_ERR(svn_cl__walk_conflicts(conflicted_paths, conflict_stats, FALSE,
+                                   opt_state, ctx, scratch_pool));
+
   if (! opt_state->quiet)
     {
       err = svn_cl__notifier_print_conflict_stats(nwb.wrapped_baton, scratch_pool);

Modified: subversion/trunk/subversion/svn/update-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/update-cmd.c?rev=1724864&r1=1724863&r2=1724864&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/update-cmd.c (original)
+++ subversion/trunk/subversion/svn/update-cmd.c Fri Jan 15 17:50:52 2016
@@ -111,12 +111,15 @@ svn_cl__update(apr_getopt_t *os,
                apr_pool_t *scratch_pool)
 {
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
+  svn_cl__conflict_stats_t *conflict_stats =
+    ((svn_cl__cmd_baton_t *) baton)->conflict_stats;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
   apr_array_header_t *targets;
   svn_depth_t depth;
   svn_boolean_t depth_is_sticky;
   struct svn_cl__check_externals_failed_notify_baton nwb;
   apr_array_header_t *result_revs;
+  apr_array_header_t *conflicted_paths;
   svn_error_t *err = SVN_NO_ERROR;
   svn_error_t *externals_err = SVN_NO_ERROR;
 
@@ -177,6 +180,13 @@ svn_cl__update(apr_getopt_t *os,
                                      _("Failure occurred processing one or "
                                        "more externals definitions"));
 
+  /* Run the interactive resolver if conflicts were raised. */
+  SVN_ERR(svn_cl__conflict_stats_get_paths(&conflicted_paths, conflict_stats,
+                                           scratch_pool, scratch_pool));
+  if (conflicted_paths)
+    SVN_ERR(svn_cl__walk_conflicts(conflicted_paths, conflict_stats, FALSE,
+                                   opt_state, ctx, scratch_pool));
+
   if (! opt_state->quiet)
     {
       err = print_update_summary(targets, result_revs, scratch_pool);