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