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 2012/09/26 17:42:40 UTC

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

Author: stsp
Date: Wed Sep 26 15:42:40 2012
New Revision: 1390572

URL: http://svn.apache.org/viewvc?rev=1390572&view=rev
Log:
Change the way the command line client handles conflicted paths.

As of r1357313 the list of conflicted paths was stored in the notifier's
baton. Storing the list there would cause crashes when running with
the --quiet option because that option disables use of the notifier.
For details, see http://svn.haxx.se/dev/archive-2012-09/0058.shtml

Instead, use two separate conflict resolver callback functions, one
for postponing all conflicts and one for performing actual conflict
resolution, either interactive or based on the --accept option.
This approach was suggested by rhuijben.

While at it, hide implementation details of these functions, such as
the baton structure, completely within the conflict resolution code
in conflict-callbacks.c by introducing new svn_cl__ API functions.

* subversion/svn/cl.h
  (svn_cl__opt_state_t): Remove conflict_func and conflict_baton. Now unused.
  (svn_cl__conflict_baton_t): Renamed to ...
  (svn_cl__interactive_conflict_baton_t): ... this. Now declared as an opaque
   structure.
  (svn_cl__conflict_baton_make): Rename to ...
  (svn_cl__get_conflict_func_interactive_baton): ... this. Adjust parameter
   list to simplify this interface from the caller's point of view.
  (svn_cl__conflict_handler): Rename to ...
  (svn_cl__conflict_func_interactive): ... this.
  (svn_cl__get_conflict_func_postpone_baton,
   svn_cl__conflict_func_postpone): New.
  (svn_cl__notifier_check_conflicts,
   svn_cl__notifier_get_conflicted_paths): Remove these declarations.
  (svn_cl__resolve_conflicts): Rename to ...
  (svn_cl__resolve_postponed_conflicts): ... this. Move declaration up in the
   file to group it with related functions. This function now expects a baton
   from svn_cl__conflict_func_postpone() as an argument, rather than a list
   of conflicted paths, to hide the details of conflicted paths from the caller.

* subversion/svn/conflict-callbacks.c
  (svn_cl__interactive_conflict_baton_t,
   svn_cl__get_conflict_func_interactive_baton): New baton and constructor.
  (open_editor, launch_resolver, handle_text_conflict,
   handle_prop_conflict): Track rename of interactive conflict baton.
  (svn_cl__conflict_handler): Rename to ...
  (svn_cl__conflict_func_interactive): ... this, and track baton renaming.
  (svn_cl__conflict_func_postpone,
   svn_cl__get_conflict_func_interactive_baton,
   get_postponed_conflicted_paths): New helpers, partly based on notify.c.
  (svn_cl__resolve_conflicts): Rename to ...
  (svn_cl__resolve_postponed_conflicts): ... this, and expect a baton
   argument which corresponds to a baton from svn_cl__conflict_func_postpone().
   The list of conflicted paths is obtained from it, and the interactive
   conflict resolution function is run on these paths via svn_client_resolve().


  ):

* subversion/svn/main.c
  (sub_main): Adjust setup of interactive conflict resolution callback. Always
   install svn_cl__conflict_func_postpone in the client context by default.
   Subcommands may override this (currently only 'svn resolve' will do so).
   Re-shuffle handling of options related to conflict resolution a little for
   clarity (no behaviour change).

* subversion/svn/merge-cmd.c
  (svn_cl__merge): Use svn_cl__resolve_postponed_conflicts() to resolve
   any conflicts after the merge.

* subversion/svn/notify.c
  (notify_baton): Remove conflicted_paths list.
  (add_conflicted_path): Remove.
  (notify): Don't call add_conflicted_path() anymore.
  (svn_cl__get_notifier): Don't set up conflicted_paths anymore.
  (svn_cl__notifier_check_conflicts,
   svn_cl__notifier_get_conflicted_paths): Remove, superseded by the
   postponing conflict function.

* subversion/svn/resolve-cmd.c
  (svn_cl__resolve): Cope with the fact that conflict_func was removed
   from opt_state. Force use of the interactive resolver with this
   subcommand so it can serve its purpose.

* subversion/svn/switch-cmd.c
  (svn_cl__switch): Use svn_cl__resolve_postponed_conflicts() to resolve
   any conflicts after the switch.

* subversion/svn/update-cmd.c
  (svn_cl__update): Use svn_cl__resolve_postponed_conflicts() to resolve
   any conflicts after the update.

Modified:
    subversion/trunk/subversion/svn/cl.h
    subversion/trunk/subversion/svn/conflict-callbacks.c
    subversion/trunk/subversion/svn/main.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/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=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/cl.h (original)
+++ subversion/trunk/subversion/svn/cl.h Wed Sep 26 15:42:40 2012
@@ -237,9 +237,6 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */
   svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */
   apr_array_header_t* search_patterns; /* pattern arguments for --search */
-
-  svn_wc_conflict_resolver_func2_t conflict_func;
-  void *conflict_baton;
 } svn_cl__opt_state_t;
 
 
@@ -332,37 +329,58 @@ svn_cl__check_cancel(void *baton);
 
 /* Various conflict-resolution callbacks. */
 
-typedef struct svn_cl__conflict_baton_t {
-  svn_cl__accept_t accept_which;
-  apr_hash_t *config;
-  const char *editor_cmd;
-  svn_boolean_t external_failed;
-  svn_cmdline_prompt_baton_t *pb;
-  const char *path_prefix;
-} svn_cl__conflict_baton_t;
-
-/* Create and return a conflict baton in *B, allocated from POOL, with the
- * values ACCEPT_WHICH, CONFIG, EDITOR_CMD and PB placed in the same-named
- * fields of the baton, and its 'external_failed' field initialised to FALSE. */
-svn_error_t *
-svn_cl__conflict_baton_make(svn_cl__conflict_baton_t **b,
-                            svn_cl__accept_t accept_which,
-                            apr_hash_t *config,
-                            const char *editor_cmd,
-                            svn_cmdline_prompt_baton_t *pb,
-                            apr_pool_t *pool);
+/* Opaque baton type for svn_cl__conflict_func_interactive(). */
+typedef struct svn_cl__interactive_conflict_baton_t
+  svn_cl__interactive_conflict_baton_t;
+
+/* 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_cancel_func_t cancel_func,
+  void *cancel_baton,
+  apr_pool_t *result_pool);
 
 /* A conflict-resolution callback which prompts the user to choose
    one of the 3 fulltexts, edit the merged file on the spot, or just
    skip the conflict (to be resolved later).
    Implements @c svn_wc_conflict_resolver_func_t. */
 svn_error_t *
-svn_cl__conflict_handler(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__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);
+
+/* Create an return a baton for use with svn_cl__conflict_func_postpone(),
+ * allocated in RESULT_POOL. */
+void *
+svn_cl__get_conflict_func_postpone_baton(apr_pool_t *result_pool);
+
+/* A conflict-resolution callback which postpones all conflicts and
+ * remembers conflicted paths in BATON. */
+svn_error_t *
+svn_cl__conflict_func_postpone(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);
+
+/* Run the interactive conflict resolver, obtained internally from
+ * svn_cl__get_conflict_func_interactive(), on any conflicted paths
+ * stored in the BATON obtained from svn_cl__get_conflict_func_postpone(). */
+svn_error_t *
+svn_cl__resolve_postponed_conflicts(void *baton,
+                                    svn_depth_t depth,
+                                    svn_cl__accept_t accept_which,
+                                    const char *editor_cmd,
+                                    svn_client_ctx_t *ctx,
+                                    apr_pool_t *scratch_pool);
 
 
 /*** Command-line output functions -- printing to the user. ***/
@@ -617,14 +635,6 @@ svn_cl__notifier_mark_export(void *baton
 svn_error_t *
 svn_cl__notifier_mark_wc_to_repos_copy(void *baton);
 
-/* Return TRUE if any conflicts were detected during notification. */
-svn_boolean_t
-svn_cl__notifier_check_conflicts(void *baton);
-
-/* Return a sorted array of conflicted paths detected during notification. */
-apr_array_header_t *
-svn_cl__notifier_get_conflicted_paths(void *baton, apr_pool_t *result_pool);
-
 /* Baton for use with svn_cl__check_externals_failed_notify_wrapper(). */
 struct svn_cl__check_externals_failed_notify_baton
 {
@@ -872,15 +882,6 @@ svn_cl__check_related_source_and_target(
                                         svn_client_ctx_t *ctx,
                                         apr_pool_t *pool);
 
-/* Run the conflict resolver for all targets in the TARGETS list with
- * the specified DEPTH. */
-svn_error_t *
-svn_cl__resolve_conflicts(apr_array_header_t *targets,
-                          svn_depth_t depth,
-                          const svn_cl__opt_state_t *opt_state,
-                          svn_client_ctx_t *ctx,
-                          apr_pool_t *scratch_pool);
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/conflict-callbacks.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/conflict-callbacks.c (original)
+++ subversion/trunk/subversion/svn/conflict-callbacks.c Wed Sep 26 15:42:40 2012
@@ -33,6 +33,7 @@
 #include "svn_dirent_uri.h"
 #include "svn_types.h"
 #include "svn_pools.h"
+#include "svn_sorts.h"
 
 #include "cl.h"
 #include "tree-conflicts.h"
@@ -41,22 +42,37 @@
 
 
 
+struct svn_cl__interactive_conflict_baton_t {
+  svn_cl__accept_t accept_which;
+  apr_hash_t *config;
+  const char *editor_cmd;
+  svn_boolean_t external_failed;
+  svn_cmdline_prompt_baton_t *pb;
+  const char *path_prefix;
+};
 
 svn_error_t *
-svn_cl__conflict_baton_make(svn_cl__conflict_baton_t **b,
-                            svn_cl__accept_t accept_which,
-                            apr_hash_t *config,
-                            const char *editor_cmd,
-                            svn_cmdline_prompt_baton_t *pb,
-                            apr_pool_t *pool)
+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_cancel_func_t cancel_func,
+  void *cancel_baton,
+  apr_pool_t *result_pool)
 {
-  *b = apr_palloc(pool, sizeof(**b));
+  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, "", pool));
+  SVN_ERR(svn_dirent_get_absolute(&(*b)->path_prefix, "", result_pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -180,7 +196,7 @@ show_conflicts(const svn_wc_conflict_des
 static svn_error_t *
 open_editor(svn_boolean_t *performed_edit,
             const svn_wc_conflict_description2_t *desc,
-            svn_cl__conflict_baton_t *b,
+            svn_cl__interactive_conflict_baton_t *b,
             apr_pool_t *pool)
 {
   svn_error_t *err;
@@ -232,7 +248,7 @@ open_editor(svn_boolean_t *performed_edi
 static svn_error_t *
 launch_resolver(svn_boolean_t *performed_edit,
                 const svn_wc_conflict_description2_t *desc,
-                svn_cl__conflict_baton_t *b,
+                svn_cl__interactive_conflict_baton_t *b,
                 apr_pool_t *pool)
 {
   svn_error_t *err;
@@ -272,7 +288,7 @@ launch_resolver(svn_boolean_t *performed
 static svn_error_t *
 handle_text_conflict(svn_wc_conflict_result_t *result,
                      const svn_wc_conflict_description2_t *desc,
-                     svn_cl__conflict_baton_t *b,
+                     svn_cl__interactive_conflict_baton_t *b,
                      apr_pool_t *scratch_pool)
 {
   const char *answer;
@@ -533,7 +549,7 @@ handle_text_conflict(svn_wc_conflict_res
 static svn_error_t *
 handle_prop_conflict(svn_wc_conflict_result_t *result,
                      const svn_wc_conflict_description2_t *desc,
-                     svn_cl__conflict_baton_t *b,
+                     svn_cl__interactive_conflict_baton_t *b,
                      apr_pool_t *scratch_pool)
 {
   const char *answer;
@@ -610,13 +626,13 @@ handle_prop_conflict(svn_wc_conflict_res
 /* Implement svn_wc_conflict_resolver_func2_t; resolves based on
    --accept option if given, else by prompting. */
 svn_error_t *
-svn_cl__conflict_handler(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__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__conflict_baton_t *b = baton;
+  svn_cl__interactive_conflict_baton_t *b = baton;
   svn_error_t *err;
   apr_pool_t *subpool;
 
@@ -875,16 +891,77 @@ svn_cl__conflict_handler(svn_wc_conflict
   return SVN_NO_ERROR;
 }
 
+/* Implement svn_wc_conflict_resolver_func2_t; postpones all conflicts
+ * and remembers conflicted paths in BATON. */
 svn_error_t *
-svn_cl__resolve_conflicts(apr_array_header_t *targets,
-                          svn_depth_t depth,
-                          const svn_cl__opt_state_t *opt_state,
-                          svn_client_ctx_t *ctx,
-                          apr_pool_t *scratch_pool)
+svn_cl__conflict_func_postpone(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)
+{
+  apr_hash_t *conflicted_paths = baton;
+  
+  apr_hash_set(conflicted_paths,
+               apr_pstrdup(apr_hash_pool_get(conflicted_paths),
+                           desc->local_abspath),
+               APR_HASH_KEY_STRING, "");
+
+  *result = svn_wc_create_conflict_result(svn_wc_conflict_choose_postpone,
+                                          NULL, result_pool);
+  return SVN_NO_ERROR;
+}
+
+void *
+svn_cl__get_conflict_func_postpone_baton(apr_pool_t *result_pool)
+{
+  return apr_hash_make(result_pool);
+}
+
+static apr_array_header_t *
+get_postponed_conflicted_paths(void *baton, apr_pool_t *result_pool)
 {
+  apr_hash_t *conflicted_paths = baton;
+  apr_array_header_t *sorted_array;
+  apr_array_header_t *result_array;
+  int i;
+
+  if (apr_hash_count(conflicted_paths) == 0)
+    return NULL;
+
+  sorted_array = svn_sort__hash(conflicted_paths,
+                                svn_sort_compare_items_as_paths,
+                                apr_hash_pool_get(conflicted_paths));
+  result_array = apr_array_make(result_pool, sorted_array->nelts,
+                                sizeof(const char *));
+  for (i = 0; i < sorted_array->nelts; i++)
+    {
+      svn_sort__item_t item;
+      
+      item = APR_ARRAY_IDX(sorted_array, i, svn_sort__item_t);
+      APR_ARRAY_PUSH(result_array, const char *) = apr_pstrdup(result_pool,
+                                                               item.key);
+    }
+
+  return result_array;
+}
+
+svn_error_t *
+svn_cl__resolve_postponed_conflicts(void *baton,
+                                    svn_depth_t depth,
+                                    svn_cl__accept_t accept_which,
+                                    const char *editor_cmd,
+                                    svn_client_ctx_t *ctx,
+                                    apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *targets;
   int i;
   apr_pool_t *iterpool;
 
+  targets = get_postponed_conflicted_paths(baton, scratch_pool);
+  if (targets == NULL)
+    return SVN_NO_ERROR;
+
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < targets->nelts; i++)
     {
@@ -893,19 +970,25 @@ svn_cl__resolve_conflicts(apr_array_head
       const char *local_abspath;
       svn_wc_conflict_resolver_func2_t conflict_func2;
       void *conflict_baton2;
+      svn_cl__interactive_conflict_baton_t *b;
 
       svn_pool_clear(iterpool);
 
       SVN_ERR(svn_dirent_get_absolute(&local_abspath, target, iterpool));
 
-
       /* Store old state */
       conflict_func2 = ctx->conflict_func2;
       conflict_baton2 = ctx->conflict_baton2;
 
-      /* Store interactive resolver */
-      ctx->conflict_func2 = opt_state->conflict_func;
-      ctx->conflict_baton2 = opt_state->conflict_baton;
+      /* Set up the interactive resolver. */
+      ctx->conflict_func2 = svn_cl__conflict_func_interactive;
+      SVN_ERR(svn_cl__get_conflict_func_interactive_baton(&b, accept_which,
+                                                          ctx->config,
+                                                          editor_cmd,
+                                                          ctx->cancel_func,
+                                                          ctx->cancel_baton,
+                                                          scratch_pool));
+      ctx->conflict_baton2 = b;
 
       err = svn_client_resolve(local_abspath, depth,
                                svn_wc_conflict_choose_unspecified,

Modified: subversion/trunk/subversion/svn/main.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/main.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/main.c (original)
+++ subversion/trunk/subversion/svn/main.c Wed Sep 26 15:42:40 2012
@@ -2650,60 +2650,53 @@ sub_main(int argc, const char *argv[], a
 
   ctx->auth_baton = ab;
 
-  /* Set up conflict resolution callback. */
-  SVN_INT_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
-                                  SVN_CONFIG_SECTION_MISCELLANY,
-                                  SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
-                                  TRUE));  /* ### interactivity on by default.
-                                                  we can change this. */
-
-  /* The new svn behavior is to postpone everything until after the operation
-     completed */
+  /* Install the default conflict handler which postpones all conflicts
+   * and remembers the list of conflicted paths to be resolved later.
+   * This is overridden only within the 'resolve' subcommand. */
   ctx->conflict_func = NULL;
   ctx->conflict_baton = NULL;
-  ctx->conflict_func2 = NULL;
-  ctx->conflict_baton2 = NULL;
+  ctx->conflict_func2 = svn_cl__conflict_func_postpone;
+  ctx->conflict_baton2 = svn_cl__get_conflict_func_postpone_baton(pool);
 
-  if ((opt_state.accept_which == svn_cl__accept_unspecified
-       && (!interactive_conflicts || opt_state.non_interactive))
-      || opt_state.accept_which == svn_cl__accept_postpone)
+  if (opt_state.non_interactive)
     {
-      /* If no --accept option at all and we're non-interactive, we're
-         leaving the conflicts behind, so don't need the callback.  Same if
-         the user said to postpone. */
-      opt_state.conflict_func = NULL;
-      opt_state.conflict_baton = NULL;
+      if (opt_state.accept_which == svn_cl__accept_edit)
+        return EXIT_ERROR(
+                 svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                   _("--accept=%s incompatible with"
+                                     " --non-interactive"),
+                                   SVN_CL__ACCEPT_EDIT));
+
+      if (opt_state.accept_which == svn_cl__accept_launch)
+        return EXIT_ERROR(
+                 svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                   _("--accept=%s incompatible with"
+                                     " --non-interactive"),
+                                   SVN_CL__ACCEPT_LAUNCH));
+
+      /* The default action when we're non-interactive is to postpone
+       * conflict resolution. */
+      if (opt_state.accept_which == svn_cl__accept_unspecified)
+        opt_state.accept_which = svn_cl__accept_postpone;
     }
-  else
-    {
-      svn_cl__conflict_baton_t * conflict_baton2;
-      svn_cmdline_prompt_baton_t *pb = apr_palloc(pool, sizeof(*pb));
-      pb->cancel_func = ctx->cancel_func;
-      pb->cancel_baton = ctx->cancel_baton;
 
-      if (opt_state.non_interactive)
-        {
-          if (opt_state.accept_which == svn_cl__accept_edit)
-            return EXIT_ERROR
-              (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                 _("--accept=%s incompatible with"
-                                   " --non-interactive"), SVN_CL__ACCEPT_EDIT));
-          if (opt_state.accept_which == svn_cl__accept_launch)
-            return EXIT_ERROR
-              (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
-                                 _("--accept=%s incompatible with"
-                                   " --non-interactive"),
-                                 SVN_CL__ACCEPT_LAUNCH));
-        }
-
-      opt_state.conflict_func = svn_cl__conflict_handler;
-      SVN_INT_ERR(svn_cl__conflict_baton_make(&conflict_baton2,
-                                              opt_state.accept_which,
-                                              ctx->config,
-                                              opt_state.editor_cmd,
-                                              pb,
-                                              pool));
-      opt_state.conflict_baton = conflict_baton2;
+  /* Check whether interactive conflict resolution is disabled by
+   * the configuration file. If no --accept option was specified
+   * we postpone all conflicts in this case. */
+  SVN_INT_ERR(svn_config_get_bool(cfg_config, &interactive_conflicts,
+                                  SVN_CONFIG_SECTION_MISCELLANY,
+                                  SVN_CONFIG_OPTION_INTERACTIVE_CONFLICTS,
+                                  TRUE));
+  if (!interactive_conflicts)
+    {
+      /* Make 'svn resolve' non-interactive. */
+      if (subcommand->cmd_func == svn_cl__resolve)
+        opt_state.non_interactive = TRUE;
+
+      /* We're not resolving conflicts interactively. If no --accept option
+       * was provided the default behaviour is to postpone all conflicts. */
+      if (opt_state.accept_which == svn_cl__accept_unspecified)
+        opt_state.accept_which = svn_cl__accept_postpone;
     }
 
   /* And now we finally run the subcommand. */

Modified: subversion/trunk/subversion/svn/merge-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/merge-cmd.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/merge-cmd.c (original)
+++ subversion/trunk/subversion/svn/merge-cmd.c Wed Sep 26 15:42:40 2012
@@ -521,15 +521,12 @@ svn_cl__merge(apr_getopt_t *os,
   if (! opt_state->quiet)
     err = svn_cl__print_conflict_stats(ctx->notify_baton2, pool);
 
-  if (!err
-      && opt_state->conflict_func
-      && svn_cl__notifier_check_conflicts(ctx->notify_baton2))
-    {
-      err = svn_cl__resolve_conflicts(
-              svn_cl__notifier_get_conflicted_paths(ctx->notify_baton2, pool),
-              opt_state->depth, opt_state, ctx, pool);
-    }
-
+  if (!err)
+    err = svn_cl__resolve_postponed_conflicts(ctx->conflict_baton2,
+                                              opt_state->depth,
+                                              opt_state->accept_which,
+                                              opt_state->editor_cmd,
+                                              ctx, pool);
   if (merge_err)
     {
       if (merge_err->apr_err ==

Modified: subversion/trunk/subversion/svn/notify.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/notify.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/notify.c (original)
+++ subversion/trunk/subversion/svn/notify.c Wed Sep 26 15:42:40 2012
@@ -58,7 +58,6 @@ struct notify_baton
   unsigned int prop_conflicts;
   unsigned int tree_conflicts;
   unsigned int skipped_paths;
-  apr_hash_t *conflicted_paths;
 
   /* The cwd, for use in decomposing absolute paths. */
   const char *path_prefix;
@@ -102,16 +101,6 @@ svn_cl__print_conflict_stats(void *notif
   return SVN_NO_ERROR;
 }
 
-/* Add a conflicted path to the list of conflicted paths stored
- * in the notify baton. */
-static void
-add_conflicted_path(struct notify_baton *nb, const char *path)
-{
-  apr_hash_set(nb->conflicted_paths,
-               apr_pstrdup(apr_hash_pool_get(nb->conflicted_paths), path),
-               APR_HASH_KEY_STRING, "");
-}
-
 /* This implements `svn_wc_notify_func2_t'.
  * NOTE: This function can't fail, so we just ignore any print errors. */
 static void
@@ -231,7 +220,6 @@ notify(void *baton, const svn_wc_notify_
       if (n->content_state == svn_wc_notify_state_conflicted)
         {
           nb->text_conflicts++;
-          add_conflicted_path(nb, n->path);
           if ((err = svn_cmdline_printf(pool, "C    %s\n", path_local)))
             goto print_error;
         }
@@ -247,7 +235,6 @@ notify(void *baton, const svn_wc_notify_
       if (n->content_state == svn_wc_notify_state_conflicted)
         {
           nb->text_conflicts++;
-          add_conflicted_path(nb, n->path);
           statchar_buf[0] = 'C';
         }
       else
@@ -256,7 +243,6 @@ notify(void *baton, const svn_wc_notify_
       if (n->prop_state == svn_wc_notify_state_conflicted)
         {
           nb->prop_conflicts++;
-          add_conflicted_path(nb, n->path);
           statchar_buf[1] = 'C';
         }
       else if (n->prop_state == svn_wc_notify_state_merged)
@@ -323,7 +309,6 @@ notify(void *baton, const svn_wc_notify_
         if (n->content_state == svn_wc_notify_state_conflicted)
           {
             nb->text_conflicts++;
-            add_conflicted_path(nb, n->path);
             statchar_buf[0] = 'C';
           }
         else if (n->kind == svn_node_file)
@@ -337,7 +322,6 @@ notify(void *baton, const svn_wc_notify_
         if (n->prop_state == svn_wc_notify_state_conflicted)
           {
             nb->prop_conflicts++;
-            add_conflicted_path(nb, n->path);
             statchar_buf[1] = 'C';
           }
         else if (n->prop_state == svn_wc_notify_state_changed)
@@ -531,7 +515,6 @@ notify(void *baton, const svn_wc_notify_
         if (n->content_state == svn_wc_notify_state_conflicted)
           {
             nb->text_conflicts++;
-            add_conflicted_path(nb, n->path);
             statchar_buf[0] = 'C';
           }
         else if (n->kind == svn_node_file)
@@ -545,7 +528,6 @@ notify(void *baton, const svn_wc_notify_
         if (n->prop_state == svn_wc_notify_state_conflicted)
           {
             nb->prop_conflicts++;
-            add_conflicted_path(nb, n->path);
             statchar_buf[1] = 'C';
           }
         else if (n->prop_state == svn_wc_notify_state_merged)
@@ -923,7 +905,6 @@ notify(void *baton, const svn_wc_notify_
 
     case svn_wc_notify_tree_conflict:
       nb->tree_conflicts++;
-      add_conflicted_path(nb, n->path);
       if ((err = svn_cmdline_printf(pool, "   C %s\n", path_local)))
         goto print_error;
       break;
@@ -1064,7 +1045,6 @@ svn_cl__get_notifier(svn_wc_notify_func2
   nb->prop_conflicts = 0;
   nb->tree_conflicts = 0;
   nb->skipped_paths = 0;
-  nb->conflicted_paths = apr_hash_make(pool);
   SVN_ERR(svn_dirent_get_absolute(&nb->path_prefix, "", pool));
 
   *notify_func_p = notify;
@@ -1112,36 +1092,3 @@ svn_cl__check_externals_failed_notify_wr
   if (nwb->wrapped_func)
     nwb->wrapped_func(nwb->wrapped_baton, n, pool);
 }
-
-svn_boolean_t
-svn_cl__notifier_check_conflicts(void *baton)
-{
-  struct notify_baton *nb = baton;
-
-  return (nb->text_conflicts || nb->prop_conflicts || nb->tree_conflicts);
-}
-
-apr_array_header_t *
-svn_cl__notifier_get_conflicted_paths(void *baton, apr_pool_t *result_pool)
-{
-  struct notify_baton *nb = baton;
-  apr_array_header_t *sorted_array;
-  apr_array_header_t *result_array;
-  int i;
-
-  sorted_array = svn_sort__hash(nb->conflicted_paths,
-                                svn_sort_compare_items_as_paths,
-                                apr_hash_pool_get(nb->conflicted_paths));
-  result_array = apr_array_make(result_pool, sorted_array->nelts,
-                                sizeof(const char *));
-  for (i = 0; i < sorted_array->nelts; i++)
-    {
-      svn_sort__item_t item;
-      
-      item = APR_ARRAY_IDX(sorted_array, i, svn_sort__item_t);
-      APR_ARRAY_PUSH(result_array, const char *) = apr_pstrdup(result_pool,
-                                                               item.key);
-    }
-
-  return result_array;
-}

Modified: subversion/trunk/subversion/svn/resolve-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/resolve-cmd.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/resolve-cmd.c (original)
+++ subversion/trunk/subversion/svn/resolve-cmd.c Wed Sep 26 15:42:40 2012
@@ -57,6 +57,7 @@ svn_cl__resolve(apr_getopt_t *os,
   svn_boolean_t had_error = FALSE;
   svn_wc_conflict_resolver_func2_t conflict_func2;
   void *conflict_baton2;
+  svn_cl__interactive_conflict_baton_t *b;
 
   switch (opt_state->accept_which)
     {
@@ -79,7 +80,7 @@ svn_cl__resolve(apr_getopt_t *os,
       conflict_choice = svn_wc_conflict_choose_mine_full;
       break;
     case svn_cl__accept_unspecified:
-      if (opt_state->conflict_func == NULL)
+      if (opt_state->non_interactive)
         return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
                                 _("missing --accept option"));
       conflict_choice = svn_wc_conflict_choose_unspecified;
@@ -112,9 +113,16 @@ svn_cl__resolve(apr_getopt_t *os,
   conflict_func2 = ctx->conflict_func2;
   conflict_baton2 = ctx->conflict_baton2;
 
-  /* Store interactive resolver */
-  ctx->conflict_func2 = opt_state->conflict_func;
-  ctx->conflict_baton2 = opt_state->conflict_baton;
+  /* This subcommand always uses the interactive resolver function. */
+  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,
+                                                      ctx->cancel_func,
+                                                      ctx->cancel_baton,
+                                                      scratch_pool));
+  ctx->conflict_baton2 = b;
 
   iterpool = svn_pool_create(scratch_pool);
   for (i = 0; i < targets->nelts; i++)

Modified: subversion/trunk/subversion/svn/switch-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/switch-cmd.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/switch-cmd.c (original)
+++ subversion/trunk/subversion/svn/switch-cmd.c Wed Sep 26 15:42:40 2012
@@ -192,16 +192,11 @@ svn_cl__switch(apr_getopt_t *os,
         return svn_error_compose_create(externals_err, err);
     }
 
-  if (opt_state->conflict_func
-      && svn_cl__notifier_check_conflicts(nwb.wrapped_baton))
-    {
-      err = svn_cl__resolve_conflicts(
-              svn_cl__notifier_get_conflicted_paths(nwb.wrapped_baton,
-                                                    scratch_pool),
-              depth, opt_state, ctx, scratch_pool);
-      if (err)
-        return svn_error_compose_create(externals_err, err);
-    }
+  err = svn_cl__resolve_postponed_conflicts(ctx->conflict_baton2,
+                                            opt_state->depth,
+                                            opt_state->accept_which,
+                                            opt_state->editor_cmd,
+                                            ctx, scratch_pool);
 
   return svn_error_compose_create(externals_err, err);
 }

Modified: subversion/trunk/subversion/svn/update-cmd.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svn/update-cmd.c?rev=1390572&r1=1390571&r2=1390572&view=diff
==============================================================================
--- subversion/trunk/subversion/svn/update-cmd.c (original)
+++ subversion/trunk/subversion/svn/update-cmd.c Wed Sep 26 15:42:40 2012
@@ -110,8 +110,6 @@ svn_cl__update(apr_getopt_t *os,
   svn_boolean_t depth_is_sticky;
   struct svn_cl__check_externals_failed_notify_baton nwb;
   apr_array_header_t *result_revs;
-  svn_wc_conflict_resolver_func2_t conflict_func2 = ctx->conflict_func2;
-  void *conflict_baton2 = ctx->conflict_baton2;
   svn_error_t *err = SVN_NO_ERROR;
   svn_error_t *externals_err = SVN_NO_ERROR;
 
@@ -189,18 +187,11 @@ svn_cl__update(apr_getopt_t *os,
         return svn_error_compose_create(externals_err, err);
     }
 
-  if (opt_state->conflict_func
-      && svn_cl__notifier_check_conflicts(nwb.wrapped_baton))
-    {
-      ctx->conflict_func2 = conflict_func2;
-      ctx->conflict_baton2 = conflict_baton2;
-      err = svn_cl__resolve_conflicts(
-              svn_cl__notifier_get_conflicted_paths(nwb.wrapped_baton,
-                                                    scratch_pool),
-              depth, opt_state, ctx, scratch_pool);
-      if (err)
-        return svn_error_compose_create(externals_err, err);
-    }
+  err = svn_cl__resolve_postponed_conflicts(ctx->conflict_baton2,
+                                            opt_state->depth,
+                                            opt_state->accept_which,
+                                            opt_state->editor_cmd,
+                                            ctx, scratch_pool);
 
   return svn_error_compose_create(externals_err, err);
 }