You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by vm...@apache.org on 2012/12/23 19:34:20 UTC

svn commit: r1425508 [13/17] - in /subversion/branches/javahl-ra: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/hudson/ notes/ notes/api-errata/1.8/ notes/obliterate/ notes/tree-conflicts/ subversion/ subversion/bindings/...

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/mod_dav_svn.c Sun Dec 23 18:34:14 2012
@@ -88,6 +88,7 @@ typedef struct dir_conf_t {
   enum conf_flag autoversioning;     /* whether autoversioning is active */
   enum conf_flag bulk_updates;       /* whether bulk updates are allowed */
   enum conf_flag v2_protocol;        /* whether HTTP v2 is advertised */
+  enum conf_flag ephemeral_txnprops; /* advertise ephemeral txnprop support? */
   enum path_authz_conf path_authz_method; /* how GET subrequests are handled */
   enum conf_flag list_parentpath;    /* whether to allow GET of parentpath */
   const char *root_dir;              /* our top-level directory */
@@ -96,7 +97,7 @@ typedef struct dir_conf_t {
   enum conf_flag txdelta_cache;      /* whether to enable txdelta caching */
   enum conf_flag fulltext_cache;     /* whether to enable fulltext caching */
   enum conf_flag revprop_cache;      /* whether to enable revprop caching */
-  apr_hash_t *hooks_env;             /* environment for hook scripts */
+  const char *hooks_env;             /* path to hook script env config file */
 } dir_conf_t;
 
 
@@ -196,6 +197,7 @@ create_dir_config(apr_pool_t *p, char *d
     conf->root_dir = svn_urlpath__canonicalize(dir, p);
   conf->bulk_updates = CONF_FLAG_ON;
   conf->v2_protocol = CONF_FLAG_ON;
+  conf->ephemeral_txnprops = CONF_FLAG_ON;
   conf->hooks_env = NULL;
 
   return conf;
@@ -221,6 +223,8 @@ merge_dir_config(apr_pool_t *p, void *ba
   newconf->autoversioning = INHERIT_VALUE(parent, child, autoversioning);
   newconf->bulk_updates = INHERIT_VALUE(parent, child, bulk_updates);
   newconf->v2_protocol = INHERIT_VALUE(parent, child, v2_protocol);
+  newconf->ephemeral_txnprops = INHERIT_VALUE(parent, child,
+                                              ephemeral_txnprops);
   newconf->path_authz_method = INHERIT_VALUE(parent, child, path_authz_method);
   newconf->list_parentpath = INHERIT_VALUE(parent, child, list_parentpath);
   newconf->txdelta_cache = INHERIT_VALUE(parent, child, txdelta_cache);
@@ -346,6 +350,20 @@ SVNAdvertiseV2Protocol_cmd(cmd_parms *cm
 
 
 static const char *
+SVNAdvertiseEphemeralTXNProps_cmd(cmd_parms *cmd, void *config, int arg)
+{
+  dir_conf_t *conf = config;
+
+  if (arg)
+    conf->ephemeral_txnprops = CONF_FLAG_ON;
+  else
+    conf->ephemeral_txnprops = CONF_FLAG_OFF;
+
+  return NULL;
+}
+
+
+static const char *
 SVNPathAuthz_cmd(cmd_parms *cmd, void *config, const char *arg1)
 {
   dir_conf_t *conf = config;
@@ -550,43 +568,9 @@ SVNUseUTF8_cmd(cmd_parms *cmd, void *con
 static const char *
 SVNHooksEnv_cmd(cmd_parms *cmd, void *config, const char *arg1)
 {
-  apr_array_header_t *var;
-
-  var = svn_cstring_split(arg1, "=", TRUE, cmd->pool);
-  if (var && var->nelts >= 2)
-    {
-      dir_conf_t *conf = config;
-      const char *name;
-      const char *val;
-
-      if (! conf->hooks_env)
-        conf->hooks_env = apr_hash_make(cmd->pool);
-
-      name = apr_pstrdup(apr_hash_pool_get(conf->hooks_env),
-                         APR_ARRAY_IDX(var, 0, const char *));
-
-      /* Special case for values which contain '='. */
-      if (var->nelts > 2)
-        {
-          svn_stringbuf_t *buf;
-          int i;
-
-          buf = svn_stringbuf_create(APR_ARRAY_IDX(var, 1, const char *),
-                                     cmd->pool);
-          for (i = 2; i < var->nelts; i++)
-            {
-              svn_stringbuf_appendbyte(buf, '=');
-              svn_stringbuf_appendcstr(buf, APR_ARRAY_IDX(var, i, const char *));
-            }
-
-          val = apr_pstrdup(apr_hash_pool_get(conf->hooks_env), buf->data);
-        }
-      else
-        val = apr_pstrdup(apr_hash_pool_get(conf->hooks_env),
-                          APR_ARRAY_IDX(var, 1, const char *));
+  dir_conf_t *conf = config;
 
-      apr_hash_set(conf->hooks_env, name, APR_HASH_KEY_STRING, val);
-    }
+  conf->hooks_env = svn_dirent_internal_style(arg1, cmd->pool);
 
   return NULL;
 }
@@ -795,6 +779,16 @@ dav_svn__get_v2_protocol_flag(request_re
 }
 
 
+svn_boolean_t
+dav_svn__get_ephemeral_txnprops_flag(request_rec *r)
+{
+  dir_conf_t *conf;
+
+  conf = ap_get_module_config(r->per_dir_config, &dav_svn_module);
+  return conf->ephemeral_txnprops == CONF_FLAG_ON;
+}
+
+
 /* FALSE if path authorization should be skipped.
  * TRUE if either the bypass or the apache subrequest methods should be used.
  */
@@ -878,7 +872,7 @@ dav_svn__get_compression_level(void)
   return svn__compression_level;
 }
 
-apr_hash_t *
+const char *
 dav_svn__get_hooks_env(request_rec *r)
 {
   dir_conf_t *conf;
@@ -1095,6 +1089,12 @@ static const command_rec cmds[] =
                "Subversion's HTTP protocol (default values is On)."),
 
   /* per directory/location */
+  AP_INIT_FLAG("SVNAdvertiseEphemeralTXNProps",
+               SVNAdvertiseEphemeralTXNProps_cmd, NULL, ACCESS_CONF|RSRC_CONF,
+               "enables server advertising of support for ephemeral "
+               "commit transaction properties (default value is On)."),
+
+  /* per directory/location */
   AP_INIT_FLAG("SVNCacheTextDeltas", SVNCacheTextDeltas_cmd, NULL,
                ACCESS_CONF|RSRC_CONF,
                "speeds up data access to older revisions by caching "
@@ -1136,10 +1136,12 @@ static const command_rec cmds[] =
                "use UTF-8 as native character encoding (default is ASCII)."),
 
   /* per directory/location */
-  AP_INIT_ITERATE("SVNHooksEnv", SVNHooksEnv_cmd, NULL,
-                  ACCESS_CONF|RSRC_CONF,
-                  "Set the environment of hook scripts via any number of "
-                  "VAR=VAL arguments (the default hook environment is empty)."),
+  AP_INIT_TAKE1("SVNHooksEnv", SVNHooksEnv_cmd, NULL,
+                ACCESS_CONF|RSRC_CONF,
+                "Sets the path to the configuration file for the environment "
+                "of hook scripts. If not absolute, the path is relative to "
+                "the repository's conf directory (by default the hooks-env "
+                "file in the repository is used)."),
   { NULL }
 };
 

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/reports/update.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/reports/update.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/reports/update.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/reports/update.c Sun Dec 23 18:34:14 2012
@@ -1219,7 +1219,7 @@ dav_svn__update_report(const dav_resourc
   editor->close_file = upd_close_file;
   editor->absent_file = upd_absent_file;
   editor->close_edit = upd_close_edit;
-  if ((serr = svn_repos_begin_report2(&rbaton, revnum,
+  if ((serr = svn_repos_begin_report3(&rbaton, revnum,
                                       repos->repos,
                                       src_path, target,
                                       dst_path,
@@ -1230,6 +1230,7 @@ dav_svn__update_report(const dav_resourc
                                       editor, &uc,
                                       dav_svn__authz_read_func(&arb),
                                       &arb,
+                                      0,  /* disable zero-copy for now */
                                       resource->pool)))
     {
       return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/repos.c Sun Dec 23 18:34:14 2012
@@ -1149,8 +1149,11 @@ create_private_resource(const dav_resour
   comb->res.collection = TRUE;                  /* ### always true? */
   /* versioned = baselined = working = FALSE */
 
-  comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path,
-                              path->data, (char *)NULL);
+  if (base->info->repos->root_path[1])
+    comb->res.uri = apr_pstrcat(base->pool, base->info->repos->root_path,
+                                path->data, (char *)NULL);
+  else
+    comb->res.uri = path->data;
   comb->res.info = &comb->priv;
   comb->res.hooks = &dav_svn__hooks_repository;
   comb->res.pool = base->pool;
@@ -1908,9 +1911,11 @@ parse_querystring(request_rec *r, const 
          only use a temporary redirect. */
       apr_table_setn(r->headers_out, "Location",
                      ap_construct_url(r->pool,
-                                      apr_psprintf(r->pool, "%s%s?p=%ld",
-                                                   comb->priv.repos->root_path,
-                                                   newpath, working_rev),
+                                  apr_psprintf(r->pool, "%s%s?p=%ld",
+                                               (comb->priv.repos->root_path[1]
+                                                ? comb->priv.repos->root_path
+                                                : ""),
+                                               newpath, working_rev),
                                       r));
       return dav_svn__new_error(r->pool,
                                 prevstr ? HTTP_MOVED_PERMANENTLY
@@ -2217,8 +2222,9 @@ get_resource(request_rec *r,
                                          HTTP_INTERNAL_SERVER_ERROR, r);
         }
 
-      /* Configure the hooks environment, if not empty. */
-      svn_repos_hooks_setenv(repos->repos, dav_svn__get_hooks_env(r));
+      /* Configure hook script environment variables. */
+      svn_repos_hooks_setenv(repos->repos, dav_svn__get_hooks_env(r),
+                             r->connection->pool, r->pool);
     }
 
   /* cache the filesystem object */
@@ -3077,6 +3083,13 @@ set_headers(request_rec *r, const dav_re
       if ((serr == NULL) && (info.rev != SVN_INVALID_REVNUM))
         {
           mimetype = SVN_SVNDIFF_MIME_TYPE;
+
+          /* Note the base that this svndiff is based on, and tell any
+             intermediate caching proxies that this header is
+             significant.  */
+          apr_table_setn(r->headers_out, "Vary", SVN_DAV_DELTA_BASE_HEADER);
+          apr_table_setn(r->headers_out, SVN_DAV_DELTA_BASE_HEADER,
+                         resource->info->delta_base);
         }
       svn_error_clear(serr);
     }
@@ -4345,8 +4358,11 @@ dav_svn__create_working_resource(dav_res
   res->baselined = base->baselined;
   /* collection = FALSE.   ### not necessarily correct */
 
-  res->uri = apr_pstrcat(base->pool, base->info->repos->root_path,
-                         path, (char *)NULL);
+  if (base->info->repos->root_path[1])
+    res->uri = apr_pstrcat(base->pool, base->info->repos->root_path,
+                           path, (char *)NULL);
+  else
+    res->uri = path;
   res->hooks = &dav_svn__hooks_repository;
   res->pool = base->pool;
 

Modified: subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c (original)
+++ subversion/branches/javahl-ra/subversion/mod_dav_svn/version.c Sun Dec 23 18:34:14 2012
@@ -146,6 +146,7 @@ get_vsn_options(apr_pool_t *p, apr_text_
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_LOG_REVPROPS);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_ATOMIC_REVPROPS);
   apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_PARTIAL_REPLAY);
+  apr_text_append(p, phdr, SVN_DAV_NS_DAV_SVN_INHERITED_PROPS);
   /* Mergeinfo is a special case: here we merely say that the server
    * knows how to handle mergeinfo -- whether the repository does too
    * is a separate matter.
@@ -192,6 +193,14 @@ get_option(const dav_resource *resource,
         }
     }
 
+  /* If we're allowed (by configuration) to do so, advertise support
+     for ephemeral transaction properties. */
+  if (dav_svn__get_ephemeral_txnprops_flag(r))
+    {
+      apr_table_addn(r->headers_out, "DAV",
+                     SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS);
+    }
+
   if (resource->info->repos->fs)
     {
       svn_error_t *serr;
@@ -1112,6 +1121,10 @@ deliver_report(request_rec *r,
         {
           return dav_svn__get_deleted_rev_report(resource, doc, output);
         }
+      else if (strcmp(doc->root->name, SVN_DAV__INHERITED_PROPS_REPORT) == 0)
+        {
+          return dav_svn__get_inherited_props_report(resource, doc, output);
+        }
       /* NOTE: if you add a report, don't forget to add it to the
        *       dav_svn__reports_list[] array.
        */

Modified: subversion/branches/javahl-ra/subversion/svn/cl.h
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svn/cl.h?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svn/cl.h (original)
+++ subversion/branches/javahl-ra/subversion/svn/cl.h Sun Dec 23 18:34:14 2012
@@ -236,11 +236,8 @@ typedef struct svn_cl__opt_state_t
   svn_boolean_t show_diff;        /* produce diff output (maps to --diff) */
   svn_boolean_t allow_mixed_rev; /* Allow operation on mixed-revision WC */
   svn_boolean_t include_externals; /* Recurses (in)to file & dir externals */
-  const char *search_pattern;     /* pattern argument for --search */
-  svn_boolean_t case_insensitive_search; /* perform case-insensitive search */
-
-  svn_wc_conflict_resolver_func2_t conflict_func;
-  void *conflict_baton;
+  svn_boolean_t show_inherited_props; /* get inherited properties */
+  apr_array_header_t* search_patterns; /* pattern arguments for --search */
 } svn_cl__opt_state_t;
 
 
@@ -333,37 +330,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. ***/
@@ -460,12 +478,15 @@ svn_cl__print_prop_hash(svn_stream_t *ou
                         svn_boolean_t names_only,
                         apr_pool_t *pool);
 
-/* Same as svn_cl__print_prop_hash(), only output xml to *OUTSTR.  If *OUTSTR is
-   NULL, allocate it first from POOL, otherwise append to it. */
+/* Similar to svn_cl__print_prop_hash(), only output xml to *OUTSTR.
+   If INHERITED_PROPS is true, then PROP_HASH contains inherited properties,
+   otherwise PROP_HASH contains explicit properties.  If *OUTSTR is NULL,
+   allocate it first from POOL, otherwise append to it. */
 svn_error_t *
 svn_cl__print_xml_prop_hash(svn_stringbuf_t **outstr,
                             apr_hash_t *prop_hash,
                             svn_boolean_t names_only,
+                            svn_boolean_t inherited_props,
                             apr_pool_t *pool);
 
 /* Output a commit xml element to *OUTSTR.  If *OUTSTR is NULL, allocate it
@@ -618,14 +639,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
 {
@@ -873,15 +886,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/branches/javahl-ra/subversion/svn/conflict-callbacks.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svn/conflict-callbacks.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svn/conflict-callbacks.c (original)
+++ subversion/branches/javahl-ra/subversion/svn/conflict-callbacks.c Sun Dec 23 18:34:14 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;
@@ -265,17 +281,359 @@ launch_resolver(svn_boolean_t *performed
   return SVN_NO_ERROR;
 }
 
+/* Ask the user what to do about the text conflict described by DESC.
+ * Return the answer in RESULT. B is the conflict baton for this
+ * conflict resolution session.
+ * SCRATCH_POOL is used for temporary allocations. */
+static svn_error_t *
+handle_text_conflict(svn_wc_conflict_result_t *result,
+                     const svn_wc_conflict_description2_t *desc,
+                     svn_cl__interactive_conflict_baton_t *b,
+                     apr_pool_t *scratch_pool)
+{
+  const char *answer;
+  char *prompt;
+  svn_boolean_t diff_allowed = FALSE;
+  /* Have they done something that might have affected the merged
+     file (so that we need to save a .edited copy)? */
+  svn_boolean_t performed_edit = FALSE;
+  /* Have they done *something* (edit, look at diff, etc) to
+     give them a rational basis for choosing (r)esolved? */
+  svn_boolean_t knows_something = FALSE;
+
+  SVN_ERR_ASSERT(desc->kind == svn_wc_conflict_kind_text);
+
+  SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                              _("Conflict discovered in file '%s'.\n"),
+                              svn_cl__local_style_skip_ancestor(
+                                b->path_prefix, desc->local_abspath,
+                                scratch_pool)));
+
+  /* Diffing can happen between base and merged, to show conflict
+     markers to the user (this is the typical 3-way merge
+     scenario), or if no base is available, we can show a diff
+     between mine and theirs. */
+  if ((desc->merged_file && desc->base_abspath)
+      || (!desc->base_abspath && desc->my_abspath && desc->their_abspath))
+    diff_allowed = TRUE;
+
+  while (TRUE)
+    {
+      svn_pool_clear(scratch_pool);
+
+      prompt = apr_pstrdup(scratch_pool, _("Select: (p) postpone"));
+
+      if (diff_allowed)
+        {
+          prompt = apr_pstrcat(scratch_pool, prompt,
+                               _(", (df) diff-full, (e) edit, (m) merge"),
+                               (char *)NULL);
+
+          if (knows_something)
+            prompt = apr_pstrcat(scratch_pool, prompt, _(", (r) resolved"),
+                                 (char *)NULL);
+
+          if (! desc->is_binary)
+            prompt = apr_pstrcat(scratch_pool, prompt,
+                                 _(",\n        (mc) mine-conflict, "
+                                   "(tc) theirs-conflict"),
+                                 (char *)NULL);
+        }
+      else
+        {
+          if (knows_something)
+            prompt = apr_pstrcat(scratch_pool, prompt, _(", (r) resolved"),
+                                 (char *)NULL);
+          prompt = apr_pstrcat(scratch_pool, prompt,
+                               _(",\n        "
+                                 "(mf) mine-full, (tf) theirs-full"),
+                               (char *)NULL);
+        }
+
+      prompt = apr_pstrcat(scratch_pool, prompt, ",\n        ", (char *)NULL);
+      prompt = apr_pstrcat(scratch_pool, prompt,
+                           _("(s) show all options: "),
+                           (char *)NULL);
+
+      SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, b->pb, scratch_pool));
+
+      if (strcmp(answer, "s") == 0)
+        {
+          /* These are used in svn_cl__accept_from_word(). */
+          SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+          _("\n"
+            "  (e)  edit             - change merged file in an editor\n"
+            "  (df) diff-full        - show all changes made to merged "
+                                      "file\n"
+            "  (r)  resolved         - accept merged version of file\n"
+            "\n"
+            "  (dc) display-conflict - show all conflicts "
+                                      "(ignoring merged version)\n"
+            "  (mc) mine-conflict    - accept my version for all "
+                                      "conflicts (same)\n"
+            "  (tc) theirs-conflict  - accept their version for all "
+                                      "conflicts (same)\n"
+            "\n"
+            "  (mf) mine-full        - accept my version of entire file "
+                                      "(even non-conflicts)\n"
+            "  (tf) theirs-full      - accept their version of entire "
+                                      "file (same)\n"
+            "\n"
+            "  (p)  postpone         - mark the conflict to be "
+                                      "resolved later\n"
+            "  (m)  merge            - use internal merge tool to "
+                                      "resolve conflict\n"
+            "  (l)  launch           - launch external tool to "
+                                      "resolve conflict\n"
+            "  (s)  show all         - show this list\n\n")));
+        }
+      else if (strcmp(answer, "p") == 0 || strcmp(answer, ":-P") == 0)
+        {
+          /* Do nothing, let file be marked conflicted. */
+          result->choice = svn_wc_conflict_choose_postpone;
+          break;
+        }
+      else if (strcmp(answer, "mc") == 0 || strcmp(answer, "X-)") == 0)
+        {
+          if (desc->is_binary)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                          _("Invalid option; cannot choose "
+                                            "based on conflicts in a "
+                                            "binary file.\n\n")));
+              continue;
+            }
+          result->choice = svn_wc_conflict_choose_mine_conflict;
+          if (performed_edit)
+            result->save_merged = TRUE;
+          break;
+        }
+      else if (strcmp(answer, "tc") == 0 || strcmp(answer, "X-(") == 0)
+        {
+          if (desc->is_binary)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                          _("Invalid option; cannot choose "
+                                            "based on conflicts in a "
+                                            "binary file.\n\n")));
+              continue;
+            }
+          result->choice = svn_wc_conflict_choose_theirs_conflict;
+          if (performed_edit)
+            result->save_merged = TRUE;
+          break;
+        }
+      else if (strcmp(answer, "mf") == 0 || strcmp(answer, ":-)") == 0)
+        {
+          result->choice = svn_wc_conflict_choose_mine_full;
+          if (performed_edit)
+            result->save_merged = TRUE;
+          break;
+        }
+      else if (strcmp(answer, "tf") == 0 || strcmp(answer, ":-(") == 0)
+        {
+          result->choice = svn_wc_conflict_choose_theirs_full;
+          if (performed_edit)
+            result->save_merged = TRUE;
+          break;
+        }
+      else if (strcmp(answer, "dc") == 0)
+        {
+          if (desc->is_binary)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                          _("Invalid option; cannot "
+                                            "display conflicts for a "
+                                            "binary file.\n\n")));
+              continue;
+            }
+          else if (! (desc->my_abspath && desc->base_abspath &&
+                      desc->their_abspath))
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                          _("Invalid option; original "
+                                            "files not available.\n\n")));
+              continue;
+            }
+          SVN_ERR(show_conflicts(desc, scratch_pool));
+          knows_something = TRUE;
+        }
+      else if (strcmp(answer, "df") == 0)
+        {
+          if (! diff_allowed)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                             _("Invalid option; there's no "
+                                "merged version to diff.\n\n")));
+              continue;
+            }
+
+          SVN_ERR(show_diff(desc, scratch_pool));
+          knows_something = TRUE;
+        }
+      else if (strcmp(answer, "e") == 0 || strcmp(answer, ":-E") == 0)
+        {
+          SVN_ERR(open_editor(&performed_edit, desc, b, scratch_pool));
+          if (performed_edit)
+            knows_something = TRUE;
+        }
+      else if (strcmp(answer, "m") == 0 || strcmp(answer, ":-g") ||
+               strcmp(answer, "=>-") == 0 || strcmp(answer, ":>.") == 0)
+        {
+          if (desc->kind != svn_wc_conflict_kind_text)
+            {
+              SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                          _("Invalid option; can only "
+                                            "resolve text conflicts with "
+                                            "the internal merge tool."
+                                            "\n\n")));
+              continue;
+            }
+
+          if (desc->base_abspath && desc->their_abspath &&
+              desc->my_abspath && desc->merged_file)
+            {
+              svn_boolean_t remains_in_conflict;
+
+              SVN_ERR(svn_cl__merge_file(desc->base_abspath,
+                                         desc->their_abspath,
+                                         desc->my_abspath,
+                                         desc->merged_file,
+                                         desc->local_abspath,
+                                         b->path_prefix,
+                                         b->editor_cmd,
+                                         b->config,
+                                         &remains_in_conflict,
+                                         scratch_pool));
+              knows_something = !remains_in_conflict;
+            }
+          else
+            SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                        _("Invalid option.\n\n")));
+        }
+      else if (strcmp(answer, "l") == 0 || strcmp(answer, ":-l") == 0)
+        {
+          if (desc->base_abspath && desc->their_abspath &&
+              desc->my_abspath && desc->merged_file)
+            {
+              SVN_ERR(launch_resolver(&performed_edit, desc, b, scratch_pool));
+              if (performed_edit)
+                knows_something = TRUE;
+            }
+          else
+            SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                        _("Invalid option.\n\n")));
+        }
+      else if (strcmp(answer, "r") == 0)
+        {
+          /* We only allow the user accept the merged version of
+             the file if they've edited it, or at least looked at
+             the diff. */
+          if (knows_something)
+            {
+              result->choice = svn_wc_conflict_choose_merged;
+              break;
+            }
+          else
+            SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                        _("Invalid option.\n\n")));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Ask the user what to do about the property conflict described by DESC.
+ * Return the answer in RESULT. B is the conflict baton for this
+ * conflict resolution session.
+ * SCRATCH_POOL is used for temporary allocations. */
+static svn_error_t *
+handle_prop_conflict(svn_wc_conflict_result_t *result,
+                     const svn_wc_conflict_description2_t *desc,
+                     svn_cl__interactive_conflict_baton_t *b,
+                     apr_pool_t *scratch_pool)
+{
+  const char *answer;
+  const char *prompt;
+  svn_stringbuf_t *prop_reject;
+  apr_pool_t *iterpool;
+
+  SVN_ERR_ASSERT(desc->kind == svn_wc_conflict_kind_property);
+
+  SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                              _("Conflict for property '%s' discovered"
+                                " on '%s'.\n"),
+                              desc->property_name,
+                              svn_cl__local_style_skip_ancestor(
+                                b->path_prefix, desc->local_abspath,
+                                scratch_pool)));
+
+  /* ### Currently, the only useful information in a prop conflict
+   * ### description is the .prej file path, which, possibly due to
+   * ### deceitful interference from outer space, is stored in the
+   * ### 'their_abspath' field of the description.
+   * ### This needs to be fixed so we can present better options here. */
+  if (desc->their_abspath)
+    {
+      /* ### The library dumps an svn_string_t into a temp file, and
+       * ### we read it back from the file into an svn_stringbuf_t here.
+       * ### That's rather silly. We should be passed svn_string_t's
+       * ### containing the old/mine/theirs values instead. */
+      SVN_ERR(svn_stringbuf_from_file2(&prop_reject,
+                                       desc->their_abspath,
+                                       scratch_pool));
+      /* Print reject file contents. */
+      SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool,
+                                  "%s\n", prop_reject->data));
+    }
+  else
+    {
+      /* Nothing much we can do without a prej file... */
+      result->choice = svn_wc_conflict_choose_postpone;
+      return SVN_NO_ERROR;
+    }
+
+  iterpool = svn_pool_create(scratch_pool);
+  while (TRUE)
+    {
+      svn_pool_clear(iterpool);
+
+      prompt = _("Select: (p) postpone, (mf) mine-full, (tf) theirs-full: ");
+
+      SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, b->pb, iterpool));
+
+      if (strcmp(answer, "p") == 0 || strcmp(answer, ":-P") == 0)
+        {
+          /* Do nothing, let property be marked conflicted. */
+          result->choice = svn_wc_conflict_choose_postpone;
+          break;
+        }
+      else if (strcmp(answer, "mf") == 0 || strcmp(answer, ":-)") == 0)
+        {
+          result->choice = svn_wc_conflict_choose_mine_full;
+          break;
+        }
+      else if (strcmp(answer, "tf") == 0 || strcmp(answer, ":-(") == 0)
+        {
+          result->choice = svn_wc_conflict_choose_theirs_full;
+          break;
+        }
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
 
 /* 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;
 
@@ -409,333 +767,11 @@ svn_cl__conflict_handler(svn_wc_conflict
   */
   if (((desc->node_kind == svn_node_file)
        && (desc->action == svn_wc_conflict_action_edit)
-       && (desc->reason == svn_wc_conflict_reason_edited))
-      || (desc->kind == svn_wc_conflict_kind_property))
-  {
-      const char *answer;
-      char *prompt;
-      svn_boolean_t diff_allowed = FALSE;
-      /* Have they done something that might have affected the merged
-         file (so that we need to save a .edited copy)? */
-      svn_boolean_t performed_edit = FALSE;
-      /* Have they done *something* (edit, look at diff, etc) to
-         give them a rational basis for choosing (r)esolved? */
-      svn_boolean_t knows_something = FALSE;
-
-      if (desc->kind == svn_wc_conflict_kind_text)
-        SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                    _("Conflict discovered in file '%s'.\n"),
-                                    svn_cl__local_style_skip_ancestor(
-                                      b->path_prefix, desc->local_abspath,
-                                      subpool)));
-      else if (desc->kind == svn_wc_conflict_kind_property)
-        {
-          SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                      _("Conflict for property '%s' discovered"
-                                        " on '%s'.\n"),
-                                      desc->property_name,
-                                      svn_cl__local_style_skip_ancestor(
-                                        b->path_prefix, desc->local_abspath,
-                                        subpool)));
-
-          if ((!desc->my_abspath && desc->their_abspath)
-              || (desc->my_abspath && !desc->their_abspath))
-            {
-              /* One agent wants to change the property, one wants to
-                 delete it.  This is not something we can diff, so we
-                 just tell the user. */
-              svn_stringbuf_t *myval = NULL, *theirval = NULL;
-
-              if (desc->my_abspath)
-                {
-                  SVN_ERR(svn_stringbuf_from_file2(&myval, desc->my_abspath,
-                                                   subpool));
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                        _("They want to delete the property, "
-                          "you want to change the value to '%s'.\n"),
-                          myval->data));
-                }
-              else
-                {
-                  SVN_ERR(svn_stringbuf_from_file2(&theirval,
-                                                   desc->their_abspath,
-                                                   subpool));
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                        _("They want to change the property value to '%s', "
-                          "you want to delete the property.\n"),
-                           theirval->data));
-                }
-            }
-        }
-      else
-        /* We don't recognize any other sort of conflict yet */
-        return SVN_NO_ERROR;
-
-      /* Diffing can happen between base and merged, to show conflict
-         markers to the user (this is the typical 3-way merge
-         scenario), or if no base is available, we can show a diff
-         between mine and theirs. */
-      if ((desc->merged_file && desc->base_abspath)
-          || (!desc->base_abspath && desc->my_abspath && desc->their_abspath))
-        diff_allowed = TRUE;
-
-      while (TRUE)
-        {
-          svn_pool_clear(subpool);
-
-          prompt = apr_pstrdup(subpool, _("Select: (p) postpone"));
-
-          if (diff_allowed)
-            {
-              prompt = apr_pstrcat(subpool, prompt,
-                                   _(", (df) diff-full, (e) edit, (m) merge"),
-                                   (char *)NULL);
-
-              if (knows_something)
-                prompt = apr_pstrcat(subpool, prompt, _(", (r) resolved"),
-                                     (char *)NULL);
-
-              if (! desc->is_binary &&
-                  desc->kind != svn_wc_conflict_kind_property)
-                prompt = apr_pstrcat(subpool, prompt,
-                                     _(",\n        (mc) mine-conflict, "
-                                       "(tc) theirs-conflict"),
-                                     (char *)NULL);
-            }
-          else
-            {
-              if (knows_something)
-                prompt = apr_pstrcat(subpool, prompt, _(", (r) resolved"),
-                                     (char *)NULL);
-              prompt = apr_pstrcat(subpool, prompt,
-                                   _(",\n        "
-                                     "(mf) mine-full, (tf) theirs-full"),
-                                   (char *)NULL);
-            }
-
-          prompt = apr_pstrcat(subpool, prompt, ",\n        ", (char *)NULL);
-          prompt = apr_pstrcat(subpool, prompt,
-                               _("(s) show all options: "),
-                               (char *)NULL);
-
-          SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, b->pb, subpool));
-
-          if (strcmp(answer, "s") == 0)
-            {
-              /* These are used in svn_cl__accept_from_word(). */
-              SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-              _("\n"
-                "  (e)  edit             - change merged file in an editor\n"
-                "  (df) diff-full        - show all changes made to merged "
-                                          "file\n"
-                "  (r)  resolved         - accept merged version of file\n"
-                "\n"
-                "  (dc) display-conflict - show all conflicts "
-                                          "(ignoring merged version)\n"
-                "  (mc) mine-conflict    - accept my version for all "
-                                          "conflicts (same)\n"
-                "  (tc) theirs-conflict  - accept their version for all "
-                                          "conflicts (same)\n"
-                "\n"
-                "  (mf) mine-full        - accept my version of entire file "
-                                          "(even non-conflicts)\n"
-                "  (tf) theirs-full      - accept their version of entire "
-                                          "file (same)\n"
-                "\n"
-                "  (p)  postpone         - mark the conflict to be "
-                                          "resolved later\n"
-                "  (m)  merge            - use internal merge tool to "
-                                          "resolve conflict\n"
-                "  (l)  launch           - launch external tool to "
-                                          "resolve conflict\n"
-                "  (s)  show all         - show this list\n\n")));
-            }
-          else if (strcmp(answer, "p") == 0 || strcmp(answer, ":-P") == 0)
-            {
-              /* Do nothing, let file be marked conflicted. */
-              (*result)->choice = svn_wc_conflict_choose_postpone;
-              break;
-            }
-          else if (strcmp(answer, "mc") == 0 || strcmp(answer, "X-)") == 0)
-            {
-              if (desc->is_binary)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot choose "
-                                                "based on conflicts in a "
-                                                "binary file.\n\n")));
-                  continue;
-                }
-              else if (desc->kind == svn_wc_conflict_kind_property)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot choose "
-                                                "based on conflicts for "
-                                                "properties.\n\n")));
-                  continue;
-                }
-
-              (*result)->choice = svn_wc_conflict_choose_mine_conflict;
-              if (performed_edit)
-                (*result)->save_merged = TRUE;
-              break;
-            }
-          else if (strcmp(answer, "tc") == 0 || strcmp(answer, "X-(") == 0)
-            {
-              if (desc->is_binary)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot choose "
-                                                "based on conflicts in a "
-                                                "binary file.\n\n")));
-                  continue;
-                }
-              else if (desc->kind == svn_wc_conflict_kind_property)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot choose "
-                                                "based on conflicts for "
-                                                "properties.\n\n")));
-                  continue;
-                }
-              (*result)->choice = svn_wc_conflict_choose_theirs_conflict;
-              if (performed_edit)
-                (*result)->save_merged = TRUE;
-              break;
-            }
-          else if (strcmp(answer, "mf") == 0 || strcmp(answer, ":-)") == 0)
-            {
-              (*result)->choice = svn_wc_conflict_choose_mine_full;
-              if (performed_edit)
-                (*result)->save_merged = TRUE;
-              break;
-            }
-          else if (strcmp(answer, "tf") == 0 || strcmp(answer, ":-(") == 0)
-            {
-              (*result)->choice = svn_wc_conflict_choose_theirs_full;
-              if (performed_edit)
-                (*result)->save_merged = TRUE;
-              break;
-            }
-          else if (strcmp(answer, "dc") == 0)
-            {
-              if (desc->is_binary)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot "
-                                                "display conflicts for a "
-                                                "binary file.\n\n")));
-                  continue;
-                }
-              else if (desc->kind == svn_wc_conflict_kind_property)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot "
-                                                "display conflicts for "
-                                                "properties.\n\n")));
-                  continue;
-                }
-              else if (! (desc->my_abspath && desc->base_abspath &&
-                          desc->their_abspath))
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; original "
-                                                "files not available.\n\n")));
-                  continue;
-                }
-              SVN_ERR(show_conflicts(desc, subpool));
-              knows_something = TRUE;
-            }
-          else if (strcmp(answer, "df") == 0)
-            {
-              if (! diff_allowed)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                 _("Invalid option; there's no "
-                                    "merged version to diff.\n\n")));
-                  continue;
-                }
+       && (desc->reason == svn_wc_conflict_reason_edited)))
+    SVN_ERR(handle_text_conflict(*result, desc, b, subpool));
+  else if (desc->kind == svn_wc_conflict_kind_property)
+    SVN_ERR(handle_prop_conflict(*result, desc, b, subpool));
 
-              SVN_ERR(show_diff(desc, subpool));
-              knows_something = TRUE;
-            }
-          else if (strcmp(answer, "e") == 0 || strcmp(answer, ":-E") == 0)
-            {
-              SVN_ERR(open_editor(&performed_edit, desc, b, subpool));
-              if (performed_edit)
-                knows_something = TRUE;
-            }
-          else if (strcmp(answer, "m") == 0 || strcmp(answer, ":-M") == 0)
-            {
-              if (desc->kind != svn_wc_conflict_kind_text)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; can only "
-                                                "resolve text conflicts with "
-                                                "the internal merge tool."
-                                                "\n\n")));
-                  continue;
-                }
-
-              if (desc->base_abspath && desc->their_abspath &&
-                  desc->my_abspath && desc->merged_file)
-                {
-                  svn_boolean_t remains_in_conflict;
-
-                  SVN_ERR(svn_cl__merge_file(desc->base_abspath,
-                                             desc->their_abspath,
-                                             desc->my_abspath,
-                                             desc->merged_file,
-                                             desc->local_abspath,
-                                             b->path_prefix,
-                                             b->editor_cmd,
-                                             b->config,
-                                             &remains_in_conflict,
-                                             subpool));
-                  knows_something = !remains_in_conflict;
-                }
-              else
-                SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                            _("Invalid option.\n\n")));
-            }
-          else if (strcmp(answer, "l") == 0 || strcmp(answer, ":-l") == 0)
-            {
-              if (desc->kind == svn_wc_conflict_kind_property)
-                {
-                  SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                              _("Invalid option; cannot "
-                                                "resolve property conflicts "
-                                                "with an external merge tool."
-                                                "\n\n")));
-                  continue;
-                }
-              if (desc->base_abspath && desc->their_abspath &&
-                  desc->my_abspath && desc->merged_file)
-                {
-                  SVN_ERR(launch_resolver(&performed_edit, desc, b, subpool));
-                  if (performed_edit)
-                    knows_something = TRUE;
-                }
-              else
-                SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                            _("Invalid option.\n\n")));
-            }
-          else if (strcmp(answer, "r") == 0)
-            {
-              /* We only allow the user accept the merged version of
-                 the file if they've edited it, or at least looked at
-                 the diff. */
-              if (knows_something)
-                {
-                  (*result)->choice = svn_wc_conflict_choose_merged;
-                  break;
-                }
-              else
-                SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
-                                            _("Invalid option.\n\n")));
-            }
-        }
-    }
   /*
     Dealing with obstruction of additions can be tricky.  The
     obstructing item could be unversioned, versioned, or even
@@ -856,16 +892,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++)
     {
@@ -874,19 +971,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/branches/javahl-ra/subversion/svn/file-merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svn/file-merge.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svn/file-merge.c (original)
+++ subversion/branches/javahl-ra/subversion/svn/file-merge.c Sun Dec 23 18:34:14 2012
@@ -365,7 +365,7 @@ static const char *
 prepare_line_for_display(const char *line, apr_pool_t *pool)
 {
   svn_stringbuf_t *buf = svn_stringbuf_create(line, pool);
-  int width;
+  size_t width;
   int line_width = LINE_DISPLAY_WIDTH;
   apr_pool_t *iterpool;
 
@@ -596,7 +596,7 @@ merge_chunks(apr_array_header_t **merged
 
   prompt = svn_stringbuf_create(
              apr_psprintf(scratch_pool, "%s\n%s|%s\n%s",
-                          _("Conflicting section found during merge."),
+                          _("Conflicting section found during merge:"),
                           prepare_line_for_display(
                             apr_psprintf(scratch_pool,
                                          _("(1) their version (at line %lu)"),
@@ -851,6 +851,7 @@ svn_cl__merge_file(const char *base_path
   apr_file_t *merged_file;
   const char *merged_file_name;
   struct file_merge_baton fmb;
+  svn_boolean_t executable;
 
 
   SVN_ERR(svn_cmdline_printf(
@@ -912,7 +913,9 @@ svn_cl__merge_file(const char *base_path
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR_W(svn_io_file_move(merged_file_name, merged_path, scratch_pool),
+  SVN_ERR(svn_io_is_file_executable(&executable, merged_path, scratch_pool));
+  SVN_ERR_W(svn_io_copy_file(merged_file_name, merged_path, FALSE,
+                             scratch_pool),
             apr_psprintf(scratch_pool,
                          _("Could not write merged result to '%s', saved "
                            "instead at '%s'.\n'%s' remains in conflict.\n"),
@@ -924,6 +927,9 @@ svn_cl__merge_file(const char *base_path
                          svn_dirent_local_style(
                            svn_dirent_skip_ancestor(path_prefix, wc_path),
                            scratch_pool)));
+  SVN_ERR(svn_io_set_file_executable(merged_path, executable, FALSE,
+                                     scratch_pool));
+  SVN_ERR(svn_io_remove_file2(merged_file_name, TRUE, scratch_pool));
 
   /* The merge was not aborted and we could install the merged result. The
    * file remains in conflict unless all conflicting sections were resolved. */

Modified: subversion/branches/javahl-ra/subversion/svn/log-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/javahl-ra/subversion/svn/log-cmd.c?rev=1425508&r1=1425507&r2=1425508&view=diff
==============================================================================
--- subversion/branches/javahl-ra/subversion/svn/log-cmd.c (original)
+++ subversion/branches/javahl-ra/subversion/svn/log-cmd.c Sun Dec 23 18:34:14 2012
@@ -71,10 +71,9 @@ struct log_receiver_baton
   /* Stack which keeps track of merge revision nesting, using svn_revnum_t's */
   apr_array_header_t *merge_stack;
 
-  /* Log message search pattern. Log entries will only be shown if the author,
-   * the log message, or a changed path matches this pattern. */
-  const char *search_pattern;
-  svn_boolean_t case_insensitive_search;
+  /* Log message search patterns. Log entries will only be shown if the author,
+   * the log message, or a changed path matches one of these patterns. */
+  apr_array_header_t *search_patterns;
 
   /* Pool for persistent allocations. */
   apr_pool_t *pool;
@@ -156,12 +155,11 @@ match_search_pattern(const char *search_
                      const char *date,
                      const char *log_message,
                      apr_hash_t *changed_paths,
-                     svn_boolean_t case_insensitive_search,
                      apr_pool_t *pool)
 {
   /* Match any substring containing the pattern, like UNIX 'grep' does. */
   const char *pattern = apr_psprintf(pool, "*%s*", search_pattern);
-  int flags = (case_insensitive_search ? APR_FNM_CASE_BLIND : 0);
+  int flags = APR_FNM_CASE_BLIND;
 
   /* Does the author match the search pattern? */
   if (author && apr_fnmatch(pattern, author, flags) == APR_SUCCESS)
@@ -203,6 +201,50 @@ match_search_pattern(const char *search_
   return FALSE;
 }
 
+/* Match all search patterns in SEARCH_PATTERNS against AUTHOR, DATE, MESSAGE,
+ * and CHANGED_PATHS. Return TRUE if any pattern matches, else FALSE.
+ * SCRACH_POOL is used for temporary allocations. */
+static svn_boolean_t
+match_search_patterns(apr_array_header_t *search_patterns,
+                      const char *author,
+                      const char *date,
+                      const char *message,
+                      apr_hash_t *changed_paths,
+                      apr_pool_t *scratch_pool)
+{
+  int i;
+  svn_boolean_t match = FALSE;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  for (i = 0; i < search_patterns->nelts; i++)
+    {
+      apr_array_header_t *pattern_group;
+      int j;
+
+      pattern_group = APR_ARRAY_IDX(search_patterns, i, apr_array_header_t *);
+
+      /* All patterns within the group must match. */
+      for (j = 0; j < pattern_group->nelts; j++)
+        {
+          const char *pattern;
+
+          svn_pool_clear(iterpool);
+          
+          pattern = APR_ARRAY_IDX(pattern_group, j, const char *);
+          match = match_search_pattern(pattern, author, date, message,
+                                       changed_paths, iterpool);
+          if (!match)
+            break;
+        }
+
+      match = (match && j == pattern_group->nelts);
+      if (match)
+        break;
+    }
+  svn_pool_destroy(iterpool);
+
+  return match;
+}
 
 /* Implement `svn_log_entry_receiver_t', printing the logs in
  * a human-readable and machine-parseable format.
@@ -320,10 +362,9 @@ log_entry_receiver(void *baton,
   if (! lb->omit_log_message && message == NULL)
     message = "";
 
-  if (lb->search_pattern &&
-      ! match_search_pattern(lb->search_pattern, author, date, message,
-                             log_entry->changed_paths2,
-                             lb->case_insensitive_search, pool))
+  if (lb->search_patterns &&
+      ! match_search_patterns(lb->search_patterns, author, date, message,
+                              log_entry->changed_paths2, pool))
     {
       if (log_entry->has_children)
         APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
@@ -505,10 +546,9 @@ log_entry_receiver_xml(void *baton,
     }
 
   /* Match search pattern before XML-escaping. */
-  if (lb->search_pattern &&
-      ! match_search_pattern(lb->search_pattern, author, date, message,
-                             log_entry->changed_paths2,
-                             lb->case_insensitive_search, pool))
+  if (lb->search_patterns &&
+      ! match_search_patterns(lb->search_patterns, author, date, message,
+                              log_entry->changed_paths2, pool))
     {
       if (log_entry->has_children)
         APR_ARRAY_PUSH(lb->merge_stack, svn_revnum_t) = log_entry->revision;
@@ -586,7 +626,13 @@ log_entry_receiver_xml(void *baton,
               /* <path action="X"> */
               svn_xml_make_open_tag(&sb, pool, svn_xml_protect_pcdata, "path",
                                     "action", action,
-                                    "kind", svn_cl__node_kind_str_xml(log_item->node_kind), NULL);
+                                    "kind", svn_cl__node_kind_str_xml(
+                                                     log_item->node_kind),
+                                    "text-mods", svn_tristate__to_word(
+                                                     log_item->text_modified),
+                                    "prop-mods", svn_tristate__to_word(
+                                                     log_item->props_modified),
+                                    NULL);
             }
           /* xxx</path> */
           svn_xml_escape_cdata_cstring(&sb, path, pool);
@@ -609,7 +655,7 @@ log_entry_receiver_xml(void *baton,
       svn_xml_make_open_tag(&sb, pool, svn_xml_normal, "revprops", NULL);
       SVN_ERR(svn_cl__print_xml_prop_hash(&sb, log_entry->revprops,
                                           FALSE, /* name_only */
-                                          pool));
+                                          FALSE, pool));
       svn_xml_make_close_tag(&sb, pool, "revprops");
     }
 
@@ -740,8 +786,7 @@ svn_cl__log(apr_getopt_t *os,
                                                    : opt_state->depth;
   lb.diff_extensions = opt_state->extensions;
   lb.merge_stack = apr_array_make(pool, 0, sizeof(svn_revnum_t));
-  lb.search_pattern = opt_state->search_pattern;
-  lb.case_insensitive_search = opt_state->case_insensitive_search;
+  lb.search_patterns = opt_state->search_patterns;
   lb.pool = pool;
 
   if (opt_state->xml)