* subversion/libsvn_wc/merge.c
(svn_wc_merge): If there was no external merge command specified, use
the internal diff lib to do the merging. Else, fall back to
svn_io_run_diff3.
* subversion/clients/cmdline/cl.h
(svn_cl__longopt_t, svn_cl__opt_state_t): Add merge-cmd option and
placeholder for argument.
* subversion/clients/cmdline/main.c
(svn_cl__option, svn_cl__cmd_table): Add 'diff3-cmd' (merge).
(main): Add 'diff-cmd' (merge) processing. Also override the value of
diff3-cmd in the config if it was passed on the commandline.
* subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
Update expected output to current output.
git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/issue-405-internal-diff@844983 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/subversion/clients/cmdline/cl.h b/subversion/clients/cmdline/cl.h
index c1a2d46..cf8bb51 100644
--- a/subversion/clients/cmdline/cl.h
+++ b/subversion/clients/cmdline/cl.h
@@ -60,7 +60,8 @@
svn_cl__no_diff_deleted,
svn_cl__dry_run_opt,
svn_cl__revprop_opt,
- svn_cl__diff_cmd_opt
+ svn_cl__diff_cmd_opt,
+ svn_cl__merge_cmd_opt
} svn_cl__longopt_t;
@@ -105,6 +106,7 @@
svn_boolean_t dry_run; /* try operation but make no changes */
svn_boolean_t revprop; /* operate on a revision property */
const char *diff_cmd; /* the external diff command to use */
+ const char *merge_cmd; /* the external merge command to use */
} svn_cl__opt_state_t;
diff --git a/subversion/clients/cmdline/main.c b/subversion/clients/cmdline/main.c
index 2a45197..4bd0a41 100644
--- a/subversion/clients/cmdline/main.c
+++ b/subversion/clients/cmdline/main.c
@@ -100,6 +100,8 @@
"do not print differences for deleted files"},
{"diff-cmd", svn_cl__diff_cmd_opt, 1,
"Use \"ARG\" as diff command"},
+ {"diff3-cmd", svn_cl__merge_cmd_opt, 1,
+ "Use \"ARG\" as merge command"},
/* ### Perhaps the option should be named "--rev-prop" instead?
Generally, we do include the hyphen; the only reason not to
@@ -299,7 +301,8 @@
" If omitted, a default value of '.' is assumed.\n\n",
{'r', 'N', 'q', svn_cl__force_opt, svn_cl__dry_run_opt,
svn_cl__auth_username_opt, svn_cl__auth_password_opt,
- svn_cl__no_auth_cache_opt, svn_cl__non_interactive_opt} },
+ svn_cl__no_auth_cache_opt, svn_cl__non_interactive_opt,
+ svn_cl__merge_cmd_opt } },
{ "mkdir", svn_cl__mkdir, {0},
"Create a new directory under revision control.\n"
@@ -477,7 +480,7 @@
" Note: this is the way to move a working copy to a new branch.\n",
{ 'r', 'N', 'q', svn_cl__auth_username_opt,
svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
- svn_cl__non_interactive_opt } },
+ svn_cl__non_interactive_opt, svn_cl__merge_cmd_opt } },
{ "update", svn_cl__update, {"up"},
"Bring changes from the repository into the working copy.\n"
@@ -498,7 +501,7 @@
" while updates to the file's props are shown in the second column.\n",
{'r', 'N', 'q', svn_cl__auth_username_opt,
svn_cl__auth_password_opt, svn_cl__no_auth_cache_opt,
- svn_cl__non_interactive_opt } },
+ svn_cl__non_interactive_opt, svn_cl__merge_cmd_opt } },
{ NULL, NULL, {0}, NULL, {0} }
};
@@ -747,6 +750,9 @@
case svn_cl__diff_cmd_opt:
opt_state.diff_cmd = apr_pstrdup (pool, opt_arg);
break;
+ case svn_cl__merge_cmd_opt:
+ opt_state.merge_cmd = apr_pstrdup (pool, opt_arg);
+ break;
default:
/* Hmmm. Perhaps this would be a good place to squirrel away
opts that commands like svn diff might need. Hmmm indeed. */
@@ -929,8 +935,12 @@
/* XXX: Only diff_cmd for now, overlay rest later and stop passing
opt_state altogether? */
if (opt_state.diff_cmd)
- svn_config_set (cfg, "helpers", "diff-cmd", opt_state.diff_cmd);
-
+ svn_config_set (cfg, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF_CMD, opt_state.diff_cmd);
+ if (opt_state.merge_cmd)
+ svn_config_set (cfg, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF3_CMD, opt_state.merge_cmd);
+
ctx.log_msg_func = svn_cl__get_log_message;
ctx.log_msg_baton = svn_cl__make_log_msg_baton (&opt_state, NULL,
ctx.config, pool);
diff --git a/subversion/libsvn_wc/merge.c b/subversion/libsvn_wc/merge.c
index d5cd423..fa724cf 100644
--- a/subversion/libsvn_wc/merge.c
+++ b/subversion/libsvn_wc/merge.c
@@ -20,6 +20,7 @@
#include "svn_wc.h"
#include "svn_diff.h"
+#include "svn_config.h"
#include "wc.h"
#include "entries.h"
#include "translate.h"
@@ -49,10 +50,8 @@
const char *eol;
apr_status_t apr_err;
const svn_wc_entry_t *entry;
- svn_diff_t *diff;
- const char *target_marker;
- const char *left_marker;
- const char *right_marker;
+ const char *merge_cmd = NULL;
+ svn_boolean_t contains_conflicts;
svn_path_split (merge_target, &mt_pt, &mt_bn, pool);
@@ -126,32 +125,67 @@
SVN_ERR (svn_io_copy_file (left, tmp_left, TRUE, pool));
SVN_ERR (svn_io_copy_file (right, tmp_right, TRUE, pool));
- /* Do the Deed, using all four scratch files. */
- SVN_ERR (svn_diff3_file (&diff, tmp_left, tmp_target, tmp_right, pool));
+ /* Find out if we need to run an external merge */
+ if (config)
+ {
+ svn_config_t *cfg = apr_hash_get (config,
+ SVN_CONFIG_CATEGORY_CONFIG,
+ APR_HASH_KEY_STRING);
+ svn_config_get (cfg, &merge_cmd, SVN_CONFIG_SECTION_HELPERS,
+ SVN_CONFIG_OPTION_DIFF3_CMD, NULL);
+ }
- /* Labels fall back to sensible defaults if not specified. */
- if (target_label)
- target_marker = apr_psprintf(pool, "<<<<<<< %s", target_label);
+ if (merge_cmd)
+ {
+ int exit_code;
+
+ SVN_ERR (svn_io_run_diff3 (".",
+ tmp_target, tmp_left, tmp_right,
+ target_label, left_label, right_label,
+ result_f, &exit_code, config,
+ pool));
+
+ contains_conflicts = exit_code == 1;
+ }
else
- target_marker = "<<<<<<< .working";
+ {
+ svn_diff_t *diff;
+ const char *target_marker;
+ const char *left_marker;
+ const char *right_marker;
- if (left_label)
- left_marker = apr_psprintf(pool, "||||||| %s", left_label);
- else
- left_marker = "||||||| .old";
+ SVN_ERR (svn_diff3_file (&diff,
+ tmp_left, tmp_target, tmp_right,
+ pool));
- if (right_label)
- right_marker = apr_psprintf(pool, ">>>>>>> %s", right_label);
- else
- right_marker = ">>>>>>> .new";
+ /* Labels fall back to sensible defaults if not specified. */
+ if (target_label)
+ target_marker = apr_psprintf (pool, "<<<<<<< %s", target_label);
+ else
+ target_marker = "<<<<<<< .working";
- SVN_ERR (svn_diff3_file_output (result_f, diff,
- tmp_left, tmp_target, tmp_right,
- left_marker, target_marker, right_marker,
- "=======", /* seperator */
- FALSE, /* display original in conflict */
- FALSE, /* try to resolve conflicts */
- pool));
+ if (left_label)
+ left_marker = apr_psprintf (pool, "||||||| %s", left_label);
+ else
+ left_marker = "||||||| .old";
+
+ if (right_label)
+ right_marker = apr_psprintf (pool, ">>>>>>> %s", right_label);
+ else
+ right_marker = ">>>>>>> .new";
+
+ SVN_ERR (svn_diff3_file_output (result_f, diff,
+ tmp_left, tmp_target, tmp_right,
+ left_marker,
+ target_marker,
+ right_marker,
+ "=======", /* seperator */
+ FALSE, /* display original */
+ FALSE, /* resolve conflicts */
+ pool));
+
+ contains_conflicts = svn_diff_contains_conflicts (diff);
+ }
/* Close the output file */
apr_err = apr_file_close (result_f);
@@ -160,7 +194,7 @@
(apr_err, NULL,
"svn_wc_merge: unable to close tmp file `%s'", result_target);
- if (svn_diff_contains_conflicts (diff) && ! dry_run) /* got a conflict */
+ if (contains_conflicts && ! dry_run) /* got a conflict */
{
/* Preserve the three pre-merge files, and modify the
entry (mark as conflicted, track the preserved files). */
@@ -274,7 +308,7 @@
*merge_outcome = svn_wc_merge_conflict;
}
- else if (svn_diff_contains_conflicts (diff) && dry_run)
+ else if (contains_conflicts && dry_run)
{
*merge_outcome = svn_wc_merge_conflict;
} /* end of conflict handling */
diff --git a/subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout b/subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
index 09ab6da..088c72e 100644
--- a/subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
+++ b/subversion/tests/clients/cmdline/getopt_tests_data/svn_help_log_switch_stdout
@@ -52,4 +52,5 @@
--password arg : specify a password ARG
--no-auth-cache : do not cache authentication tokens
--non-interactive : do no interactive prompting
+ --diff3-cmd arg : Use "ARG" as merge command