[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: [PATCH] Implement (l)aunch an external merge tool

From: Eric Gillespie <epg_at_google.com>
Date: 2007-10-04 00:53:10 CEST

Augie Fackler <durin42@gmail.com> writes:

> I've actually thought about adding some tests to the interactive
> conflict resolution using python and pexpect. Would it be alright to
> add the dependency on pexpect in order to run those tests?

I'm not sure about the pyexpect dependency in general, but I
think in this case it is not needed. I have implemented --accept
using the same callback, and include unit tests for all
combinations (including your new merge tool launcher).

Here's the current patch, if you're curious:

Index: subversion/include/svn_types.h
===================================================================
--- subversion/include/svn_types.h (revision 26914)
+++ subversion/include/svn_types.h (working copy)
@@ -221,37 +221,6 @@
   svn_recursive
 };
 
-/** The concept of automatic conflict resolution.
- *
- * @since New in 1.5.
- */
-typedef enum
-{
- /* Invalid accept flag */
- svn_accept_invalid = -1,
-
- /* Resolve the conflict as usual */
- svn_accept_none,
-
- /* Resolve the conflict with the pre-conflict base file */
- svn_accept_left,
-
- /* Resolve the conflict with the pre-conflict working copy file */
- svn_accept_working,
-
- /* Resolve the conflict with the post-conflict base file */
- svn_accept_right,
-
-} svn_accept_t;
-
-/** Return the appropriate accept for @a accept_str. @a word is as
- * returned from svn_accept_to_word().
- *
- * @since New in 1.5.
- */
-svn_accept_t
-svn_accept_from_word(const char *word);
-
 /** The concept of depth for directories.
  *
  * @note This is similar to, but not exactly the same as, the WebDAV
Index: subversion/include/svn_wc.h
===================================================================
--- subversion/include/svn_wc.h (revision 26914)
+++ subversion/include/svn_wc.h (working copy)
@@ -1011,8 +1011,8 @@
    * they default to NULL.) */
 
   const char *base_file; /* common ancestor of the two files being merged */
- const char *repos_file; /* repository's version of the file */
- const char *user_file; /* user's locally-edited version of the file */
+ const char *their_file; /* their version of the file */
+ const char *my_file; /* my locally-edited version of the file */
   const char *merged_file; /* merged version of file; has conflict markers */
 
 } svn_wc_conflict_description_t;
@@ -1040,8 +1040,8 @@
      "installing" the chosen file as the final version of the file.*/
 
   svn_wc_conflict_result_choose_base, /* user chooses the base file */
- svn_wc_conflict_result_choose_repos, /* user chooses the repository file */
- svn_wc_conflict_result_choose_user, /* user chooses own version of file */
+ svn_wc_conflict_result_choose_theirs, /* user chooses their file */
+ svn_wc_conflict_result_choose_mine, /* user chooses own version of file */
   svn_wc_conflict_result_choose_merged /* user chooses the merged-file
                                            (which she may have
                                            manually edited) */
@@ -2666,15 +2666,12 @@
  * if any); if @c svn_depth_infinity, resolve @a path and every
  * conflicted file or directory anywhere beneath it.
  *
- * @a accept_ is the argument used to facilitate automatic conflict resolution.
- * If @a accept_ is svn_accept_left, the contents of the conflicted file will
- * be replaced with the prestine contents of the pre-modification base file
- * contents. If @a accept_ is svn_accept_right, the contents of the conflicted
- * file will be replaced with the post-conflict base file contents. If @a
- * accept_ is svn_accept_working, the contents of the conflicted file will be
- * the content of the pre-conflict working copy file. If @a accept_ is
- * svn_accept_default, conflict resolution will be handled just like before
- * automatic conflict resolution was availble.
+ * If @a conflict_result is svn_wc_conflict_result_choose_base, resolve the
+ * conflict with the old file contents; if
+ * svn_wc_conflict_result_choose_user, use the original working contents;
+ * if svn_wc_conflict_result_choose_theirs, the new contents; and if
+ * svn_wc_conflict_result_choose_merged, don't change the contents at all,
+ * just remove the conflict status (i.e. pre-1.5 behavior).
  *
  * @a adm_access is an access baton, with a write lock, for @a path.
  *
@@ -2704,7 +2701,7 @@
                                        svn_boolean_t resolve_text,
                                        svn_boolean_t resolve_props,
                                        svn_depth_t depth,
- svn_accept_t accept_,
+ svn_wc_conflict_result_t conflict_result,
                                        svn_wc_notify_func2_t notify_func,
                                        void *notify_baton,
                                        svn_cancel_func_t cancel_func,
Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h (revision 26914)
+++ subversion/include/svn_client.h (working copy)
@@ -2707,17 +2707,12 @@
  * if any); if @c svn_depth_infinity, resolve @a path and every
  * conflicted file or directory anywhere beneath it.
  *
- * @a accept_which is the argument used to facilitate automatic
- * conflict resolution. If @a accept_which is svn_accept_left, the
- * contents of the conflicted file will be replaced with the prestine
- * contents of the pre-modification base file contents. If @a
- * accept_which is svn_accept_right, the contents of the conflicted
- * file will be replaced with the post-conflict base file contents. If @a
- * accept_which is svn_accept_working, the contents of the conflicted
- * file will be the content of the pre-conflict working copy file. If
- * @a accept_which is svn_accept_default, conflict resolution will
- * be handled just like before automatic conflict resolution was
- * availble.
+ * If @a conflict_result is svn_wc_conflict_result_choose_base, resolve the
+ * conflict with the old file contents; if
+ * svn_wc_conflict_result_choose_user, use the original working contents;
+ * if svn_wc_conflict_result_choose_theirs, the new contents; and if
+ * svn_wc_conflict_result_choose_merged, don't change the contents at all,
+ * just remove the conflict status (i.e. pre-1.5 behavior).
  *
  * If @a path is not in a state of conflict to begin with, do nothing.
  * If @a path's conflict state is removed and @a ctx->notify_func2 is non-null,
@@ -2728,7 +2723,7 @@
 svn_error_t *
 svn_client_resolved2(const char *path,
                      svn_depth_t depth,
- svn_accept_t accept_which,
+ svn_wc_conflict_result_t conflict_result,
                      svn_client_ctx_t *ctx,
                      apr_pool_t *pool);
 
Index: subversion/libsvn_wc/merge.c
===================================================================
--- subversion/libsvn_wc/merge.c (revision 26914)
+++ subversion/libsvn_wc/merge.c (working copy)
@@ -416,8 +416,8 @@
               cdesc.action = svn_wc_conflict_action_edit;
               cdesc.reason = svn_wc_conflict_reason_edited;
               cdesc.base_file = left;
- cdesc.repos_file = right;
- cdesc.user_file = tmp_target;
+ cdesc.their_file = right;
+ cdesc.my_file = tmp_target;
               cdesc.merged_file = result_target;
 
               SVN_ERR(conflict_func(&result, &cdesc, conflict_baton, pool));
@@ -436,7 +436,7 @@
                       contains_conflicts = FALSE;
                       goto merge_complete;
                     }
- case svn_wc_conflict_result_choose_repos:
+ case svn_wc_conflict_result_choose_theirs:
                     {
                       SVN_ERR(svn_wc__loggy_copy
                               (log_accum, NULL, adm_access,
@@ -447,7 +447,7 @@
                       contains_conflicts = FALSE;
                       goto merge_complete;
                     }
- case svn_wc_conflict_result_choose_user:
+ case svn_wc_conflict_result_choose_mine:
                     {
                       /* Do nothing to merge_target, let it live untouched! */
                       *merge_outcome = svn_wc_merge_merged;
@@ -648,8 +648,8 @@
           cdesc.action = svn_wc_conflict_action_edit;
           cdesc.reason = svn_wc_conflict_reason_edited;
           cdesc.base_file = left;
- cdesc.repos_file = right;
- cdesc.user_file = tmp_target;
+ cdesc.their_file = right;
+ cdesc.my_file = tmp_target;
           cdesc.merged_file = NULL; /* notice there is NO merged file! */
 
           SVN_ERR(conflict_func(&result, &cdesc, conflict_baton, pool));
@@ -669,7 +669,7 @@
                   contains_conflicts = FALSE;
                   goto merge_complete;
                 }
- case svn_wc_conflict_result_choose_repos:
+ case svn_wc_conflict_result_choose_theirs:
                 {
                   SVN_ERR(svn_wc__loggy_copy
                           (log_accum, NULL, adm_access,
@@ -685,7 +685,7 @@
                    the response claims to have already resolved the
                    problem.*/
               case svn_wc_conflict_result_resolved:
- case svn_wc_conflict_result_choose_user:
+ case svn_wc_conflict_result_choose_mine:
                 {
                   *merge_outcome = svn_wc_merge_merged;
                   contains_conflicts = FALSE;
Index: subversion/libsvn_wc/adm_crawler.c
===================================================================
--- subversion/libsvn_wc/adm_crawler.c (revision 26914)
+++ subversion/libsvn_wc/adm_crawler.c (working copy)
@@ -88,7 +88,8 @@
 
   /* Remove any text conflict */
   SVN_ERR(svn_wc_resolved_conflict3(file_path, adm_access, TRUE, FALSE,
- svn_depth_empty, svn_accept_left,
+ svn_depth_empty,
+ svn_wc_conflict_result_choose_merged,
                                     NULL, NULL, NULL, NULL, pool));
 
   if (use_commit_times)
Index: subversion/libsvn_wc/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c (revision 26914)
+++ subversion/libsvn_wc/adm_ops.c (working copy)
@@ -2546,9 +2546,12 @@
 
 /* Conflict resolution involves removing the conflict files, if they exist,
    and clearing the conflict filenames from the entry. The latter needs to
- be done whether or not the conflict files exist. If @a accept is anything
- but svn_accept_default, automatically resolve the
- conflict with the respective temporary file contents.
+ be done whether or not the conflict files exist. If @a conflict_result
+ is svn_wc_conflict_result_choose_base, resolve the conflict with the old
+ file contents; if svn_wc_conflict_result_choose_user, use the original
+ working contents; if svn_wc_conflict_result_choose_theirs, the new
+ contents; and if svn_wc_conflict_result_choose_merged, don't change the
+ contents at all, just remove the conflict status (i.e. pre-1.5 behavior).
 
    @since 1.5 Automatic Conflict Resolution (Issue 2784)
 
@@ -2563,7 +2566,7 @@
                           const char *base_name,
                           svn_boolean_t resolve_text,
                           svn_boolean_t resolve_props,
- svn_accept_t accept_which,
+ svn_wc_conflict_result_t conflict_result,
                           svn_wc_notify_func2_t notify_func,
                           void *notify_baton,
                           apr_pool_t *pool)
@@ -2575,23 +2578,23 @@
 
   /* Handle automatic conflict resolution before the temporary files are
    * deleted, if necessary. */
- switch (accept_which)
+ switch (conflict_result)
     {
- case svn_accept_left:
- auto_resolve_src = entry->conflict_old;
- break;
- case svn_accept_working:
- auto_resolve_src = entry->conflict_wrk;
- break;
- case svn_accept_right:
- auto_resolve_src = entry->conflict_new;
- break;
- case svn_accept_none:
- auto_resolve_src = NULL;
- break;
- case svn_accept_invalid:
- return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Invalid 'accept' argument"));
+ case svn_wc_conflict_result_choose_base:
+ auto_resolve_src = entry->conflict_old;
+ break;
+ case svn_wc_conflict_result_choose_mine:
+ auto_resolve_src = entry->conflict_wrk;
+ break;
+ case svn_wc_conflict_result_choose_theirs:
+ auto_resolve_src = entry->conflict_new;
+ break;
+ case svn_wc_conflict_result_choose_merged:
+ auto_resolve_src = NULL;
+ break;
+ default:
+ return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
+ _("Invalid 'conflict_result' argument"));
     }
 
     if (auto_resolve_src)
@@ -2675,7 +2678,7 @@
   /* TRUE if property conflicts are to be resolved. */
   svn_boolean_t resolve_props;
   /* The type of automatic conflict resolution to perform */
- svn_accept_t accept_;
+ svn_wc_conflict_result_t conflict_result;
   /* An access baton for the tree, with write access */
   svn_wc_adm_access_t *adm_access;
   /* Notification function and baton */
@@ -2710,7 +2713,7 @@
 
   return resolve_conflict_on_entry(path, entry, adm_access, base_name,
                                    baton->resolve_text, baton->resolve_props,
- baton->accept_, baton->notify_func,
+ baton->conflict_result, baton->notify_func,
                                    baton->notify_baton, pool);
 }
 
@@ -2758,7 +2761,8 @@
                           apr_pool_t *pool)
 {
   return svn_wc_resolved_conflict3(path, adm_access, resolve_text,
- resolve_props, recurse, svn_accept_none,
+ resolve_props, recurse,
+ svn_wc_conflict_result_choose_merged,
                                    notify_func, notify_baton, cancel_func,
                                    cancel_baton, pool);
 }
@@ -2769,7 +2773,7 @@
                           svn_boolean_t resolve_text,
                           svn_boolean_t resolve_props,
                           svn_depth_t depth,
- svn_accept_t accept_,
+ svn_wc_conflict_result_t conflict_result,
                           svn_wc_notify_func2_t notify_func,
                           void *notify_baton,
                           svn_cancel_func_t cancel_func,
@@ -2783,7 +2787,7 @@
   baton->adm_access = adm_access;
   baton->notify_func = notify_func;
   baton->notify_baton = notify_baton;
- baton->accept_ = accept_;
+ baton->conflict_result = conflict_result;
 
   if (depth == svn_depth_empty)
     {
Index: subversion/libsvn_subr/kitchensink.c
===================================================================
--- subversion/libsvn_subr/kitchensink.c (revision 26914)
+++ subversion/libsvn_subr/kitchensink.c (working copy)
@@ -68,20 +68,6 @@
   return uuid_str;
 }
 
-svn_accept_t
-svn_accept_from_word(const char *word)
-{
- if (strcmp(word, "left") == 0)
- return svn_accept_left;
- if (strcmp(word, "working") == 0)
- return svn_accept_working;
- if (strcmp(word, "right") == 0)
- return svn_accept_right;
- /* Return svn_accept_invalid which means that the passed string is not
- * a recognized accept option. */
- return svn_accept_invalid;
-}
-
 const char *
 svn_depth_to_word(svn_depth_t depth)
 {
Index: subversion/libsvn_client/resolved.c
===================================================================
--- subversion/libsvn_client/resolved.c (revision 26914)
+++ subversion/libsvn_client/resolved.c (working copy)
@@ -39,13 +39,14 @@
                     apr_pool_t *pool)
 {
   svn_depth_t depth = (recursive ? svn_depth_infinity : svn_depth_empty);
- return svn_client_resolved2(path, depth, svn_accept_none, ctx, pool);
+ return svn_client_resolved2(path, depth,
+ svn_wc_conflict_result_choose_merged, ctx, pool);
 }
 
 svn_error_t *
 svn_client_resolved2(const char *path,
                      svn_depth_t depth,
- svn_accept_t accept_which,
+ svn_wc_conflict_result_t conflict_result,
                      svn_client_ctx_t *ctx,
                      apr_pool_t *pool)
 {
@@ -61,7 +62,7 @@
                                  pool));
 
   SVN_ERR(svn_wc_resolved_conflict3(path, adm_access, TRUE, TRUE, depth,
- accept_which,
+ conflict_result,
                                     ctx->notify_func2, ctx->notify_baton2,
                                     ctx->cancel_func, ctx->cancel_baton,
                                     pool));
Index: subversion/bindings/javahl/native/ConflictResolverCallback.cpp
===================================================================
--- subversion/bindings/javahl/native/ConflictResolverCallback.cpp (revision 26914)
+++ subversion/bindings/javahl/native/ConflictResolverCallback.cpp (working copy)
@@ -210,10 +210,10 @@
       return svn_wc_conflict_result_resolved;
     case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_base:
       return svn_wc_conflict_result_choose_base;
- case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_repos:
- return svn_wc_conflict_result_choose_repos;
- case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_user:
- return svn_wc_conflict_result_choose_user;
+ case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_theirs:
+ return svn_wc_conflict_result_choose_theirs;
+ case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_mine:
+ return svn_wc_conflict_result_choose_mine;
     case org_tigris_subversion_javahl_ConflictResolverCallback_Result_choose_merged:
       return svn_wc_conflict_result_choose_merged;
     }
Index: subversion/bindings/javahl/src/org/tigris/subversion/javahl/ConflictResolverCallback.java
===================================================================
--- subversion/bindings/javahl/src/org/tigris/subversion/javahl/ConflictResolverCallback.java (revision 26914)
+++ subversion/bindings/javahl/src/org/tigris/subversion/javahl/ConflictResolverCallback.java (working copy)
@@ -67,12 +67,12 @@
         /**
          * User chooses the repository file.
          */
- public static final int choose_repos = 3;
+ public static final int choose_theirs = 3;
 
         /**
          * User chooses own version of file.
          */
- public static final int choose_user = 4;
+ public static final int choose_mine = 4;
 
         /**
          * User chooses the merged-file (which she may have manually
Index: subversion/tests/cmdline/svneditor.py
===================================================================
--- subversion/tests/cmdline/svneditor.py (revision 26914)
+++ subversion/tests/cmdline/svneditor.py (working copy)
@@ -20,11 +20,12 @@
 import os
 
 def main():
- if len(sys.argv) != 2:
+ if len(sys.argv) not in [2, 5]:
         print "usage: svneditor.py file"
+ print " svneditor.py base theirs mine merged"
         sys.exit(1)
 
- filename = sys.argv[1]
+ filename = sys.argv[-1]
 
     # Read in the input file.
     f = open(filename)
Index: subversion/tests/cmdline/basic_tests.py
===================================================================
--- subversion/tests/cmdline/basic_tests.py (revision 26914)
+++ subversion/tests/cmdline/basic_tests.py (working copy)
@@ -2138,30 +2138,40 @@
   # So now lambda, mu and rho are all in a "conflicted" state. Run 'svn
   # resolved' with the respective "--accept[mine|orig|repo]" flag.
 
+ # But first, check --accept actions resolved does not accept.
+ svntest.actions.run_and_verify_svn(None,
+ # stdout, stderr
+ None,
+ ".*invalid 'accept' ARG",
+ 'resolved', '--accept=postpone')
+ svntest.actions.run_and_verify_svn(None,
+ # stdout, stderr
+ None,
+ ".*invalid 'accept' ARG",
+ 'resolved', '--accept=edit')
+ svntest.actions.run_and_verify_svn(None,
+ # stdout, stderr
+ None,
+ ".*invalid 'accept' ARG",
+ 'resolved', '--accept=launch')
   # Run 'svn resolved --accept=NOTVALID. Using omega for the test.
   svntest.actions.run_and_verify_svn("Resolved command", None,
- "svn: 'NOTVALID' is not a valid accept value; "
- "try 'left', 'right', or 'working'\n",
+ ".*NOTVALID' is not a valid accept value",
                                      'resolved',
                                      '--accept=NOTVALID',
                                      omega_path_backup)
 
- # Run 'svn resolved --accept=left. Using lambda for the test.
+ # Resolve lambda, mu, and rho with different --accept options.
   svntest.actions.run_and_verify_svn("Resolved command", None, [],
- 'resolved',
- '--accept=left',
+ 'resolved', '--accept=base',
                                      lambda_path_backup)
-
- # Run 'svn resolved --accept=working. Using mu for the test.
   svntest.actions.run_and_verify_svn("Resolved command", None, [],
                                      'resolved',
- '--accept=working',
+ '--accept=mine',
                                      mu_path_backup)
-
- # Run 'svn resolved --accept=right. Using rho for the test.
   svntest.actions.run_and_verify_svn("Resolved command", None, [],
                                      'resolved',
- '--accept=right',
+ '--accept=theirs',
                                      rho_path_backup)
 
   # Set the expected disk contents for the test
Index: subversion/tests/cmdline/update_tests.py
===================================================================
--- subversion/tests/cmdline/update_tests.py (revision 26914)
+++ subversion/tests/cmdline/update_tests.py (working copy)
@@ -3248,7 +3248,216 @@
                                         expected_disk,
                                         expected_status)
 
+#----------------------------------------------------------------------
 
+def update_accept_conflicts(sbox):
+ "update --accept automatic conflict resolution"
+
+ sbox.build()
+ wc_dir = sbox.wc_dir
+
+ # Make a backup copy of the working copy
+ wc_backup = sbox.add_wc_path('backup')
+ svntest.actions.duplicate_dir(wc_dir, wc_backup)
+
+ # Make a few local mods to files which will be committed
+ iota_path = os.path.join(wc_dir, 'iota')
+ lambda_path = os.path.join(wc_dir, 'A', 'B', 'lambda')
+ mu_path = os.path.join(wc_dir, 'A', 'mu')
+ alpha_path = os.path.join(wc_dir, 'A', 'B', 'E', 'alpha')
+ beta_path = os.path.join(wc_dir, 'A', 'B', 'E', 'beta')
+ pi_path = os.path.join(wc_dir, 'A', 'D', 'G', 'pi')
+ rho_path = os.path.join(wc_dir, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append(lambda_path, 'Their appended text for lambda\n')
+ svntest.main.file_append(iota_path, 'Their appended text for iota\n')
+ svntest.main.file_append(mu_path, 'Their appended text for mu\n')
+ svntest.main.file_append(alpha_path, 'Their appended text for alpha\n')
+ svntest.main.file_append(beta_path, 'Their appended text for beta\n')
+ svntest.main.file_append(pi_path, 'Their appended text for pi\n')
+ svntest.main.file_append(rho_path, 'Their appended text for rho\n')
+
+ # Make a few local mods to files which will be conflicted
+ iota_path_backup = os.path.join(wc_backup, 'iota')
+ lambda_path_backup = os.path.join(wc_backup, 'A', 'B', 'lambda')
+ mu_path_backup = os.path.join(wc_backup, 'A', 'mu')
+ alpha_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'alpha')
+ beta_path_backup = os.path.join(wc_backup, 'A', 'B', 'E', 'beta')
+ pi_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'pi')
+ rho_path_backup = os.path.join(wc_backup, 'A', 'D', 'G', 'rho')
+ svntest.main.file_append(iota_path_backup,
+ 'My appended text for iota\n')
+ svntest.main.file_append(lambda_path_backup,
+ 'My appended text for lambda\n')
+ svntest.main.file_append(mu_path_backup,
+ 'My appended text for mu\n')
+ svntest.main.file_append(alpha_path_backup,
+ 'My appended text for alpha\n')
+ svntest.main.file_append(beta_path_backup,
+ 'My appended text for beta\n')
+ svntest.main.file_append(pi_path_backup,
+ 'My appended text for pi\n')
+ svntest.main.file_append(rho_path_backup,
+ 'My appended text for rho\n')
+
+ # Created expected output tree for 'svn ci'
+ expected_output = svntest.wc.State(wc_dir, {
+ 'iota' : Item(verb='Sending'),
+ 'A/B/lambda' : Item(verb='Sending'),
+ 'A/mu' : Item(verb='Sending'),
+ 'A/B/E/alpha': Item(verb='Sending'),
+ 'A/B/E/beta': Item(verb='Sending'),
+ 'A/D/G/pi' : Item(verb='Sending'),
+ 'A/D/G/rho' : Item(verb='Sending'),
+ })
+
+ expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
+ expected_status.tweak('iota', wc_rev=2)
+ expected_status.tweak('A/B/lambda', wc_rev=2)
+ expected_status.tweak('A/mu', wc_rev=2)
+ expected_status.tweak('A/B/E/alpha', wc_rev=2)
+ expected_status.tweak('A/B/E/beta', wc_rev=2)
+ expected_status.tweak('A/D/G/pi', wc_rev=2)
+ expected_status.tweak('A/D/G/rho', wc_rev=2)
+
+ # Commit.
+ svntest.actions.run_and_verify_commit(wc_dir, expected_output,
+ expected_status, None,
+ None, None, None, None, wc_dir)
+
+ # Now we'll update each of our 5 files in wc_backup; each one will get
+ # conflicts, and we'll handle each with a different --accept option.
+
+ # Setup SVN_EDITOR and SVN_MERGE for --accept={edit,launch}.
+ svntest.main.use_editor('append_foo')
+
+ # iota: no accept option
+ # Just leave the conflicts alone, since run_and_verify_svn already uses
+ # the --non-interactive option.
+ svntest.actions.run_and_verify_svn(None,
+ ['C %s\n' % (iota_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', iota_path_backup)
+
+ # lambda: --accept=postpone
+ # Just leave the conflicts alone.
+ svntest.actions.run_and_verify_svn(None,
+ ['C %s\n' % (lambda_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=postpone',
+ lambda_path_backup)
+
+ # mu: --accept=base
+ # Accept the pre-update base file.
+ svntest.actions.run_and_verify_svn(None,
+ ['G %s\n' % (mu_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=base',
+ mu_path_backup)
+
+ # alpha: --accept=mine
+ # Accept the user's working file.
+ svntest.actions.run_and_verify_svn(None,
+ ['G %s\n' % (alpha_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=mine',
+ alpha_path_backup)
+
+ # beta: --accept=theirs
+ # Accept their file.
+ svntest.actions.run_and_verify_svn(None,
+ ['G %s\n' % (beta_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=theirs',
+ beta_path_backup)
+
+ # pi: --accept=edit
+ # Run editor and accept the edited file.
+ svntest.actions.run_and_verify_svn(None,
+ ['G %s\n' % (pi_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=edit',
+ pi_path_backup)
+
+ # rho: --accept=launch
+ # Run SVN_MERGE and accept the merged file.
+ svntest.actions.run_and_verify_svn(None,
+ ['G %s\n' % (rho_path_backup,),
+ 'Updated to revision 2.\n'],
+ [],
+ 'update', '--accept=launch',
+ rho_path_backup)
+
+ # Set the expected disk contents for the test
+ expected_disk = svntest.main.greek_state.copy()
+
+ expected_disk.tweak('iota', contents=("This is the file 'iota'.\n"
+ '<<<<<<< .mine\n'
+ 'My appended text for iota\n'
+ '=======\n'
+ 'Their appended text for iota\n'
+ '>>>>>>> .r2\n'))
+ expected_disk.tweak('A/B/lambda', contents=("This is the file 'lambda'.\n"
+ '<<<<<<< .mine\n'
+ 'My appended text for lambda\n'
+ '=======\n'
+ 'Their appended text for lambda\n'
+ '>>>>>>> .r2\n'))
+ expected_disk.tweak('A/mu', contents="This is the file 'mu'.\n")
+ expected_disk.tweak('A/B/E/alpha', contents=("This is the file 'alpha'.\n"
+ 'My appended text for alpha\n'))
+ expected_disk.tweak('A/B/E/beta', contents=("This is the file 'beta'.\n"
+ 'Their appended text for beta\n'))
+ expected_disk.tweak('A/D/G/pi', contents=("This is the file 'pi'.\n"
+ '<<<<<<< .mine\n'
+ 'My appended text for pi\n'
+ '=======\n'
+ 'Their appended text for pi\n'
+ '>>>>>>> .r2\n'
+ 'foo\n'))
+ expected_disk.tweak('A/D/G/rho', contents=("This is the file 'rho'.\n"
+ '<<<<<<< .mine\n'
+ 'My appended text for rho\n'
+ '=======\n'
+ 'Their appended text for rho\n'
+ '>>>>>>> .r2\n'
+ 'foo\n'))
+
+ # Set the expected extra files for the test
+ extra_files = ['iota.*\.r1', 'iota.*\.r2', 'iota.*\.mine',
+ 'lambda.*\.r1', 'lambda.*\.r2', 'lambda.*\.mine']
+
+ # Set the expected status for the test
+ expected_status = svntest.actions.get_virginal_state(wc_backup, 2)
+ expected_status.tweak('iota', 'A/B/lambda', 'A/mu',
+ 'A/B/E/alpha', 'A/B/E/beta',
+ 'A/D/G/pi', 'A/D/G/rho', wc_rev=2)
+ expected_status.tweak('iota', status='C ')
+ expected_status.tweak('A/B/lambda', status='C ')
+ expected_status.tweak('A/mu', status='M ')
+ expected_status.tweak('A/B/E/alpha', status='M ')
+ expected_status.tweak('A/B/E/beta', status=' ')
+ expected_status.tweak('A/D/G/pi', status='M ')
+ expected_status.tweak('A/D/G/rho', status='M ')
+
+ # Set the expected output for the test
+ expected_output = wc.State(wc_backup, {})
+
+ # Do the update and check the results in three ways.
+ svntest.actions.run_and_verify_update(wc_backup,
+ expected_output,
+ expected_disk,
+ expected_status,
+ None,
+ svntest.tree.detect_conflict_files,
+ extra_files)
+
+
 #######################################################################
 # Run the tests
 
@@ -3292,6 +3501,7 @@
               update_conflicted,
               mergeinfo_update_elision,
               XFail(update_handles_copyfrom),
+ update_accept_conflicts,
              ]
 
 if __name__ == '__main__':
Index: subversion/tests/cmdline/svntest/main.py
===================================================================
--- subversion/tests/cmdline/svntest/main.py (revision 26914)
+++ subversion/tests/cmdline/svntest/main.py (working copy)
@@ -668,6 +668,7 @@
 
 def use_editor(func):
   os.environ['SVN_EDITOR'] = svneditor_script
+ os.environ['SVN_MERGE'] = svneditor_script
   os.environ['SVNTEST_EDITOR_FUNC'] = func
 
 
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h (revision 26914)
+++ subversion/svn/cl.h (working copy)
@@ -32,6 +32,7 @@
 #include "svn_string.h"
 #include "svn_opt.h"
 #include "svn_auth.h"
+#include "svn_cmdline.h"
 
 #ifdef __cplusplus
 extern "C" {
@@ -90,6 +91,44 @@
 } svn_cl__longopt_t;
 
 
+/* --accept actions */
+typedef enum
+{
+ /* invalid or unspecified accept action */
+ svn_cl__accept_invalid = -1,
+
+ /* Leave conflicts alone, for later resolution. */
+ svn_cl__accept_postpone,
+
+ /* Resolve the conflict with the pre-conflict base file. */
+ svn_cl__accept_base,
+
+ /* Resolve the conflict with the pre-conflict working copy file. */
+ svn_cl__accept_mine,
+
+ /* Resolve the conflict with the post-conflict base file. */
+ svn_cl__accept_theirs,
+
+ /* Launch user's editor and resolve conflict with edited file. */
+ svn_cl__accept_edit,
+
+ /* Launch user's resolver and resolve conflict with edited file. */
+ svn_cl__accept_launch,
+} svn_cl__accept_t;
+
+/* --accept action user input words */
+#define SVN_CL__ACCEPT_POSTPONE "postpone"
+#define SVN_CL__ACCEPT_BASE "base"
+#define SVN_CL__ACCEPT_MINE "mine"
+#define SVN_CL__ACCEPT_THEIRS "theirs"
+#define SVN_CL__ACCEPT_EDIT "edit"
+#define SVN_CL__ACCEPT_LAUNCH "launch"
+
+/* Return svn_cl__accept_t value corresponding to word. */
+svn_cl__accept_t
+svn_cl__accept_from_word(const char *word);
+
+
 
 /*** Command dispatch. ***/
 
@@ -161,7 +200,7 @@
   apr_hash_t *revprop_table; /* table of revision properties to get/set */
   svn_boolean_t parents; /* create intermediate directories */
   svn_boolean_t use_merge_history; /* use/display extra merge information */
- svn_accept_t accept_which; /* automatically resolve conflict */
+ svn_cl__accept_t accept_which; /* how to handle conflicts */
 
 } svn_cl__opt_state_t;
 
@@ -248,6 +287,23 @@
 
 /* Various conflict-resolution callbacks. */
 
+typedef struct {
+ 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;
+} svn_cl__conflict_baton_t;
+
+/* Return address of newly allocated and initialized
+ svn_cl__conflict_baton_t. */
+svn_cl__conflict_baton_t *
+svn_cl__conflict_baton_make(svn_cl__accept_t accept_which,
+ apr_hash_t *config,
+ const char *editor_cmd,
+ svn_cmdline_prompt_baton_t *pb,
+ apr_pool_t *pool);
+
 /* A mindless implementation of svn_wc_conflict_resolver_func_t that
  * does absolutely nothing to resolve conflicts. */
 svn_error_t *
@@ -260,10 +316,10 @@
    one of the 3 fulltexts, edit the merged file on the spot, or just
    skip the conflict (to be resolved later). */
 svn_error_t *
-svn_cl__interactive_conflict_handler(svn_wc_conflict_result_t *result,
- const svn_wc_conflict_description_t *desc,
- void *baton,
- apr_pool_t *pool);
+svn_cl__conflict_handler(svn_wc_conflict_result_t *result,
+ const svn_wc_conflict_description_t *desc,
+ void *baton,
+ apr_pool_t *pool);
 
 
 
@@ -418,12 +474,13 @@
    */
 svn_error_t *
 svn_cl__merge_file_externally(const char *base_path,
- const char *repos_path,
- const char *user_path,
+ const char *their_path,
+ const char *my_path,
                               const char *merged_path,
                               apr_hash_t *config,
                               apr_pool_t *pool);
 
+
 
 /*** Notification functions to display results on the terminal. */
 
Index: subversion/svn/util.c
===================================================================
--- subversion/svn/util.c (revision 26914)
+++ subversion/svn/util.c (working copy)
@@ -27,9 +27,11 @@
 #include <string.h>
 #include <ctype.h>
 #include <assert.h>
+ #include <unistd.h>
 
 #include <apr_env.h>
 #include <apr_errno.h>
+#include <apr_file_info.h>
 #include <apr_strings.h>
 #include <apr_tables.h>
 #include <apr_general.h>
@@ -196,8 +198,8 @@
 
 svn_error_t *
 svn_cl__merge_file_externally(const char *base_path,
- const char *repos_path,
- const char *user_path,
+ const char *their_path,
+ const char *my_path,
                               const char *merged_path,
                               apr_hash_t *config,
                               apr_pool_t *pool)
@@ -237,8 +239,8 @@
            "configuration option were not set.\n"));
 
   {
- const char *arguments[] = { merge_tool, base_path, repos_path,
- user_path, merged_path, NULL};
+ const char *arguments[] = { merge_tool, base_path, their_path,
+ my_path, merged_path, NULL};
     char *cwd;
     apr_status_t status = apr_filepath_get(&cwd, APR_FILEPATH_NATIVE, pool);
     if (status != 0)
Index: subversion/svn/resolved-cmd.c
===================================================================
--- subversion/svn/resolved-cmd.c (revision 26914)
+++ subversion/svn/resolved-cmd.c (working copy)
@@ -29,7 +29,9 @@
 #include "svn_pools.h"
 #include "cl.h"
 
+#include "svn_private_config.h"
 
+
 
 /*** Code. ***/
 
@@ -41,11 +43,31 @@
 {
   svn_cl__opt_state_t *opt_state = ((svn_cl__cmd_baton_t *) baton)->opt_state;
   svn_client_ctx_t *ctx = ((svn_cl__cmd_baton_t *) baton)->ctx;
+ svn_wc_conflict_result_t conflict_result;
   svn_error_t *err;
   apr_array_header_t *targets;
   int i;
   apr_pool_t *subpool;
 
+ switch (opt_state->accept_which)
+ {
+ case svn_cl__accept_invalid:
+ conflict_result = svn_wc_conflict_result_choose_merged;
+ break;
+ case svn_cl__accept_base:
+ conflict_result = svn_wc_conflict_result_choose_base;
+ break;
+ case svn_cl__accept_theirs:
+ conflict_result = svn_wc_conflict_result_choose_theirs;
+ break;
+ case svn_cl__accept_mine:
+ conflict_result = svn_wc_conflict_result_choose_mine;
+ break;
+ default:
+ return svn_error_create(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("invalid 'accept' ARG"));
+ }
+
   SVN_ERR(svn_opt_args_to_target_array2(&targets, os,
                                         opt_state->targets, pool));
   if (! targets->nelts)
@@ -65,8 +87,7 @@
       svn_pool_clear(subpool);
       SVN_ERR(svn_cl__check_cancel(ctx->cancel_baton));
       err = svn_client_resolved2(target,
- opt_state->depth,
- opt_state->accept_which,
+ opt_state->depth, conflict_result,
                                  ctx,
                                  subpool);
       if (err)
Index: subversion/svn/conflict-callbacks.c
===================================================================
--- subversion/svn/conflict-callbacks.c (revision 26914)
+++ subversion/svn/conflict-callbacks.c (working copy)
@@ -38,6 +38,42 @@
 
 
 
+svn_cl__conflict_baton_t *
+svn_cl__conflict_baton_make(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__conflict_baton_t *b = apr_palloc(pool, sizeof(*b));
+ b->accept_which = accept_which;
+ b->config = config;
+ b->editor_cmd = editor_cmd;
+ b->external_failed = FALSE;
+ b->pb = pb;
+ return b;
+}
+
+svn_cl__accept_t
+svn_cl__accept_from_word(const char *word)
+{
+ if (strcmp(word, SVN_CL__ACCEPT_POSTPONE) == 0)
+ return svn_cl__accept_postpone;
+ if (strcmp(word, SVN_CL__ACCEPT_BASE) == 0)
+ return svn_cl__accept_base;
+ if (strcmp(word, SVN_CL__ACCEPT_MINE) == 0)
+ return svn_cl__accept_mine;
+ if (strcmp(word, SVN_CL__ACCEPT_THEIRS) == 0)
+ return svn_cl__accept_theirs;
+ if (strcmp(word, SVN_CL__ACCEPT_EDIT) == 0)
+ return svn_cl__accept_edit;
+ if (strcmp(word, SVN_CL__ACCEPT_LAUNCH) == 0)
+ return svn_cl__accept_launch;
+ /* word is an invalid action. */
+ return svn_cl__accept_invalid;
+}
+
+
 /* Utility to print a full description of the conflict. */
 static svn_error_t *
 print_conflict_description(const svn_wc_conflict_description_t *desc,
@@ -102,14 +138,14 @@
   }
 
   if (desc->base_file)
- SVN_ERR(svn_cmdline_printf(pool, _(" Ancestor file: %s\n"),
+ SVN_ERR(svn_cmdline_printf(pool, _(" Base file: %s\n"),
                                desc->base_file));
- if (desc->repos_file)
- SVN_ERR(svn_cmdline_printf(pool, _(" Repository's file: %s\n"),
- desc->repos_file));
- if (desc->user_file)
- SVN_ERR(svn_cmdline_printf(pool, _(" User's file: %s\n"),
- desc->user_file));
+ if (desc->their_file)
+ SVN_ERR(svn_cmdline_printf(pool, _(" Their file: %s\n"),
+ desc->their_file));
+ if (desc->my_file)
+ SVN_ERR(svn_cmdline_printf(pool, _(" My file: %s\n"),
+ desc->my_file));
   if (desc->merged_file)
     SVN_ERR(svn_cmdline_printf(pool, _(" File with conflict markers: %s\n"),
                                desc->merged_file));
@@ -135,16 +171,116 @@
 }
 
 
-/* A conflict callback which does real user prompting. */
+/* Implement svn_wc_conflict_resolver_func_t; resolves based on
+ --accept option if given, else by prompting. */
 svn_error_t *
-svn_cl__interactive_conflict_handler(svn_wc_conflict_result_t *result,
- const svn_wc_conflict_description_t *desc,
- void *baton,
- apr_pool_t *pool)
+svn_cl__conflict_handler(svn_wc_conflict_result_t *result,
+ const svn_wc_conflict_description_t *desc,
+ void *baton,
+ apr_pool_t *pool)
 {
- apr_pool_t *subpool = svn_pool_create(pool);
- svn_cmdline_prompt_baton_t *pb = baton;
+ svn_cl__conflict_baton_t *b = baton;
+ svn_error_t *err;
+ apr_pool_t *subpool;
 
+ switch (b->accept_which)
+ {
+ case svn_cl__accept_invalid:
+ /* No --accept option, fall through to prompting. */
+ break;
+ case svn_cl__accept_postpone:
+ *result = svn_wc_conflict_result_conflicted;
+ return SVN_NO_ERROR;
+ case svn_cl__accept_base:
+ *result = svn_wc_conflict_result_choose_base;
+ return SVN_NO_ERROR;
+ case svn_cl__accept_mine:
+ *result = svn_wc_conflict_result_choose_mine;
+ return SVN_NO_ERROR;
+ case svn_cl__accept_theirs:
+ *result = svn_wc_conflict_result_choose_theirs;
+ return SVN_NO_ERROR;
+ case svn_cl__accept_edit:
+ if (desc->merged_file)
+ {
+ if (b->external_failed)
+ {
+ *result = svn_wc_conflict_result_conflicted;
+ return SVN_NO_ERROR;
+ }
+
+ err = svn_cl__edit_file_externally(desc->merged_file,
+ b->editor_cmd, b->config, pool);
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
+ {
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
+ err->message ? err->message :
+ _("No editor found,"
+ " leaving all conflicts.")));
+ svn_error_clear(err);
+ b->external_failed = TRUE;
+ }
+ else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
+ {
+ SVN_ERR(svn_cmdline_fprintf(stderr, pool, "%s\n",
+ err->message ? err->message :
+ _("Error running editor,"
+ " leaving all conflicts.")));
+ svn_error_clear(err);
+ b->external_failed = TRUE;
+ }
+ else if (err)
+ return err;
+ *result = svn_wc_conflict_result_choose_merged;
+ return SVN_NO_ERROR;
+ }
+ /* else, fall through to prompting. */
+ break;
+ case svn_cl__accept_launch:
+ if (desc->base_file && desc->their_file
+ && desc->my_file && desc->merged_file)
+ {
+ if (b->external_failed)
+ {
+ *result = svn_wc_conflict_result_conflicted;
+ return SVN_NO_ERROR;
+ }
+
+ err = svn_cl__merge_file_externally(desc->base_file,
+ desc->their_file,
+ desc->my_file,
+ desc->merged_file,
+ b->config,
+ pool);
+ if (err && err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
+ {
+ SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
+ err->message ? err->message :
+ _("No merge tool found.\n")));
+ svn_error_clear(err);
+ b->external_failed = TRUE;
+ }
+ else if (err && err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
+ {
+ SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
+ err->message ? err->message :
+ _("Error running merge tool.")));
+ svn_error_clear(err);
+ b->external_failed = TRUE;
+ }
+ else if (err)
+ return err;
+ *result = svn_wc_conflict_result_choose_merged;
+ return SVN_NO_ERROR;
+ }
+ /* else, fall through to prompting. */
+ break;
+ }
+
+ /* We're in interactive mode and either the user gave no --accept
+ option or the option did not apply; let's prompt. */
+ subpool = svn_pool_create(pool);
+
   /* Handle conflicting file contents, which is the most common case. */
   if ((desc->node_kind == svn_node_file)
       && (desc->action == svn_wc_conflict_action_edit)
@@ -169,7 +305,7 @@
             prompt = apr_pstrcat(subpool, prompt, _(", (r)esolved"), NULL);
           prompt = apr_pstrcat(subpool, prompt, _(", (h)elp : "), NULL);
 
- SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, pb, subpool));
+ SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, b->pb, subpool));
 
           if ((strcmp(answer, "h") == 0) || (strcmp(answer, "?") == 0))
             {
@@ -179,7 +315,7 @@
                 " (e)dit - change merged file in an editor\n"
                 " (r)esolved - accept merged version of file\n"
                 " (m)ine - accept my version of file\n"
- " (t)heirs - accept repository's version of file\n"
+ " (t)heirs - accept their version of file\n"
                 " (l)aunch - use third-party tool to resolve conflict\n"
                 " (h)elp - show this list\n\n")));
             }
@@ -191,12 +327,12 @@
             }
           if (strcmp(answer, "m") == 0)
             {
- *result = svn_wc_conflict_result_choose_user;
+ *result = svn_wc_conflict_result_choose_mine;
               break;
             }
           if (strcmp(answer, "t") == 0)
             {
- *result = svn_wc_conflict_result_choose_repos;
+ *result = svn_wc_conflict_result_choose_theirs;
               break;
             }
           if (strcmp(answer, "d") == 0)
@@ -228,27 +364,25 @@
             {
               if (desc->merged_file)
                 {
- svn_error_t *eerr;
- eerr = svn_cl__edit_file_externally(desc->merged_file,
- NULL, NULL, subpool);
- if (eerr && (eerr->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
+ err = svn_cl__edit_file_externally(desc->merged_file,
+ b->editor_cmd,
+ b->config, subpool);
+ if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR))
                     {
- SVN_ERR(svn_cmdline_fprintf(
- stderr, subpool, "%s\n",
- eerr->message ? eerr->message :
- _("No editor found.")));
- svn_error_clear(eerr);
+ SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
+ err->message ? err->message :
+ _("No editor found.")));
+ svn_error_clear(err);
                     }
- else if (eerr && (eerr->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
+ else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM))
                     {
- SVN_ERR(svn_cmdline_fprintf(
- stderr, subpool, "%s\n",
- eerr->message ? eerr->message :
- _("Error running editor.")));
- svn_error_clear(eerr);
+ SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
+ err->message ? err->message :
+ _("Error running editor.")));
+ svn_error_clear(err);
                     }
- else if (eerr)
- return eerr;
+ else if (err)
+ return err;
                   else
                     performed_edit = TRUE;
                 }
@@ -258,36 +392,31 @@
             }
           if (strcmp(answer, "l") == 0)
             {
- if (desc->base_file && desc->repos_file &&
- desc->user_file && desc->merged_file)
+ if (desc->base_file && desc->their_file &&
+ desc->my_file && desc->merged_file)
                 {
- svn_error_t *merge_err;
- merge_err = svn_cl__merge_file_externally(desc->base_file,
- desc->repos_file,
- desc->user_file,
- desc->merged_file,
- NULL,
- pool);
- if (merge_err &&
- merge_err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
+ err = svn_cl__merge_file_externally(desc->base_file,
+ desc->their_file,
+ desc->my_file,
+ desc->merged_file,
+ b->config,
+ pool);
+ if (err && err->apr_err == SVN_ERR_CL_NO_EXTERNAL_MERGE_TOOL)
                     {
- SVN_ERR(svn_cmdline_fprintf(stderr, subpool,
- merge_err->message ?
- merge_err->message :
- _("No merge tool found.\n")));
- svn_error_clear(merge_err);
+ SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
+ err->message ? err->message :
+ _("No merge tool found.\n")));
+ svn_error_clear(err);
                     }
- else if (merge_err &&
- merge_err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
+ else if (err && err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)
                     {
                       SVN_ERR(svn_cmdline_fprintf(stderr, subpool, "%s\n",
- merge_err->message ?
- merge_err->message :
+ err->message ? err->message :
                                              _("Error running merge tool.")));
- svn_error_clear(merge_err);
+ svn_error_clear(err);
                     }
- else if (merge_err)
- return merge_err;
+ else if (err)
+ return err;
                   else
                     performed_edit = TRUE;
                 }
@@ -319,10 +448,10 @@
 
                          Unversioned Versioned Schedule-Add
 
- choose_user skip addition, skip addition skip addition
+ choose_mine skip addition, skip addition skip addition
                         add existing item
 
- choose_repos destroy file, schedule-delete, revert add,
+ choose_theirs destroy file, schedule-delete, revert add,
                         add new item. add new item. rm file,
                                                             add new item
 
@@ -336,17 +465,17 @@
       const char *prompt;
 
       SVN_ERR(svn_cmdline_fprintf(
- stderr, subpool,
- _("Conflict discovered when trying to add '%s'.\n"
- "An object of the same name already exists.\n"),
- desc->path));
+ stderr, subpool,
+ _("Conflict discovered when trying to add '%s'.\n"
+ "An object of the same name already exists.\n"),
+ desc->path));
       prompt = _("Select: (p)ostpone, (m)ine, (t)heirs, (h)elp :");
 
       while (1)
         {
           svn_pool_clear(subpool);
 
- SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, pb, subpool));
+ SVN_ERR(svn_cmdline_prompt_user2(&answer, prompt, b->pb, subpool));
 
           if ((strcmp(answer, "h") == 0) || (strcmp(answer, "?") == 0))
             {
@@ -363,12 +492,12 @@
             }
           if (strcmp(answer, "m") == 0)
             {
- *result = svn_wc_conflict_result_choose_user;
+ *result = svn_wc_conflict_result_choose_mine;
               break;
             }
           if (strcmp(answer, "t") == 0)
             {
- *result = svn_wc_conflict_result_choose_repos;
+ *result = svn_wc_conflict_result_choose_theirs;
               break;
             }
         }
Index: subversion/svn/main.c
===================================================================
--- subversion/svn/main.c (revision 26914)
+++ subversion/svn/main.c (working copy)
@@ -211,9 +211,14 @@
                        " "
                        "history")},
   {"accept", svn_cl__accept_opt, 1,
- N_("specify automatic conflict resolution source\n"
+ N_("specify automatic conflict resolution action\n"
                        " "
- "('left', 'right', or 'working')")},
+ "('" SVN_CL__ACCEPT_POSTPONE "',"
+ " '" SVN_CL__ACCEPT_BASE "',"
+ " '" SVN_CL__ACCEPT_MINE "',"
+ " '" SVN_CL__ACCEPT_THEIRS "',"
+ " '" SVN_CL__ACCEPT_EDIT "',"
+ " '" SVN_CL__ACCEPT_LAUNCH "')")},
   {0, 0, 0, 0},
 };
 
@@ -309,7 +314,8 @@
      " to the working copy. All properties from the repository are applied\n"
      " to the obstructing path.\n"),
     {'r', 'q', 'N', svn_cl__depth_opt, svn_cl__force_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt, svn_cl__ignore_externals_opt} },
+ svn_cl__config_dir_opt, svn_cl__ignore_externals_opt,
+ svn_cl__accept_opt} },
 
   { "cleanup", svn_cl__cleanup, {0}, N_
     ("Recursively clean up the working copy, removing locks, resuming\n"
@@ -558,7 +564,7 @@
     {'r', 'c', 'N', svn_cl__depth_opt, 'q', svn_cl__force_opt,
      svn_cl__dry_run_opt, svn_cl__merge_cmd_opt, svn_cl__record_only_opt,
      'g', 'x', svn_cl__ignore_ancestry_opt, SVN_CL__AUTH_OPTIONS,
- svn_cl__config_dir_opt} },
+ svn_cl__config_dir_opt, svn_cl__accept_opt} },
 
   { "mergeinfo", svn_cl__mergeinfo, {0}, N_
     ("Query merge-related information.\n"
@@ -715,7 +721,12 @@
      " remove conflict markers; it merely removes the conflict-related\n"
      " artifact files and allows PATH to be committed again.\n"),
     {svn_cl__targets_opt, 'R', svn_cl__depth_opt, 'q',
- svn_cl__config_dir_opt, svn_cl__accept_opt} },
+ svn_cl__config_dir_opt, svn_cl__accept_opt},
+ {{svn_cl__accept_opt, N_("specify automatic conflict resolution source\n"
+ " "
+ " '" SVN_CL__ACCEPT_BASE "',"
+ " '" SVN_CL__ACCEPT_MINE "',"
+ " '" SVN_CL__ACCEPT_THEIRS "')")}} },
 
   { "revert", svn_cl__revert, {0}, N_
     ("Restore pristine working copy file (undo most local edits).\n"
@@ -874,7 +885,8 @@
      " in the first column with code 'E'.\n"),
     {'r', 'N', svn_cl__depth_opt, 'q', svn_cl__merge_cmd_opt,
      svn_cl__force_opt, SVN_CL__AUTH_OPTIONS, svn_cl__config_dir_opt,
- svn_cl__ignore_externals_opt, svn_cl__changelist_opt} },
+ svn_cl__ignore_externals_opt, svn_cl__changelist_opt,
+ svn_cl__editor_cmd_opt, svn_cl__accept_opt} },
 
   { NULL, NULL, {0}, NULL, {0} }
 };
@@ -1031,7 +1043,7 @@
   opt_state.start_revision.kind = svn_opt_revision_unspecified;
   opt_state.end_revision.kind = svn_opt_revision_unspecified;
   opt_state.depth = svn_depth_unknown;
- opt_state.accept_which = svn_accept_none;
+ opt_state.accept_which = svn_cl__accept_invalid;
 
   /* No args? Show usage. */
   if (argc <= 1)
@@ -1388,20 +1400,13 @@
         opt_state.use_merge_history = TRUE;
         break;
       case svn_cl__accept_opt:
- opt_state.accept_which = svn_accept_from_word(opt_arg);
-
- /* We need to make sure that the value passed to the accept flag
- * was one of the available options. Since svn_accept_invalid is what
- * gets set when one of the three expected are not passed, checking
- * for this as part of the command line parsing makes sense. */
- if (opt_state.accept_which == svn_accept_invalid)
- {
- return svn_cmdline_handle_exit_error
+ opt_state.accept_which = svn_cl__accept_from_word(opt_arg);
+ if (opt_state.accept_which == svn_cl__accept_invalid)
+ return svn_cmdline_handle_exit_error
             (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
- _("'%s' is not a valid accept value; try "
- "'left', 'right', or 'working'"),
- opt_arg), pool, "svn: ");
- }
+ _("'%s' is not a valid accept value"), opt_arg),
+ pool, "svn: ");
+ break;
       default:
         /* Hmmm. Perhaps this would be a good place to squirrel away
            opts that commands like svn diff might need. Hmmm indeed. */
@@ -1734,22 +1739,47 @@
                                                  we can change this. */
     svn_handle_error2(err, stderr, TRUE, "svn: ");
 
- if (interactive_conflicts
- && (! opt_state.non_interactive ))
+ if ((opt_state.accept_which == svn_cl__accept_invalid
+ && (!interactive_conflicts || opt_state.non_interactive))
+ || opt_state.accept_which == svn_cl__accept_postpone)
     {
+ /* 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. */
+ ctx->conflict_func = NULL;
+ ctx->conflict_baton = NULL;
+ }
+ else
+ {
       svn_cmdline_prompt_baton_t *pb = apr_palloc(pool, sizeof(*pb));
-
       pb->cancel_func = ctx->cancel_func;
       pb->cancel_baton = ctx->cancel_baton;
 
- ctx->conflict_func = svn_cl__interactive_conflict_handler;
- ctx->conflict_baton = pb;
+ if (opt_state.non_interactive)
+ {
+ if (opt_state.accept_which == svn_cl__accept_edit)
+ return svn_cmdline_handle_exit_error
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--accept=%s incompatible with"
+ " --non-interactive"), SVN_CL__ACCEPT_EDIT),
+ pool, "svn: ");
+ if (opt_state.accept_which == svn_cl__accept_launch)
+ return svn_cmdline_handle_exit_error
+ (svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+ _("--accept=%s incompatible with"
+ " --non-interactive"),
+ SVN_CL__ACCEPT_LAUNCH),
+ pool, "svn: ");
+ }
+
+ ctx->conflict_func = svn_cl__conflict_handler;
+ ctx->conflict_baton = svn_cl__conflict_baton_make(
+ opt_state.accept_which,
+ ctx->config,
+ opt_state.editor_cmd,
+ pb,
+ pool);
     }
- else
- {
- ctx->conflict_func = NULL;
- ctx->conflict_baton = NULL;
- }
 
   /* And now we finally run the subcommand. */
   err = (*subcommand->cmd_func)(os, &command_baton, pool);

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Thu Oct 4 00:53:35 2007

This is an archived mail posted to the Subversion Dev mailing list.

This site is subject to the Apache Privacy Policy and the Apache Public Forum Archive Policy.