#include "svn_wc.h"
#include "svn_diff.h"
#include "svn_path.h"
#include "wc.h"
#include "entries.h"
#include "translate.h"
#include "questions.h"
#include "log.h"
#include "svn_private_config.h"
svn_error_t *
svn_wc__merge_internal(svn_stringbuf_t **log_accum,
enum svn_wc_merge_outcome_t *merge_outcome,
const char *left,
const char *right,
const char *merge_target,
svn_wc_adm_access_t *adm_access,
const char *left_label,
const char *right_label,
const char *target_label,
svn_boolean_t dry_run,
const char *diff3_cmd,
const apr_array_header_t *merge_options,
apr_pool_t *pool)
{
const char *tmp_target, *result_target, *tmp_left, *tmp_right;
const char *mt_pt, *mt_bn;
const char *adm_path = svn_wc_adm_access_path(adm_access);
const char *log_merge_target =
svn_path_is_child(adm_path, merge_target, pool);
apr_file_t *result_f;
svn_boolean_t is_binary;
const svn_wc_entry_t *entry;
svn_boolean_t contains_conflicts;
svn_path_split(merge_target, &mt_pt, &mt_bn, pool);
SVN_ERR(svn_wc_entry(&entry, merge_target, adm_access, FALSE, pool));
if (! entry)
{
*merge_outcome = svn_wc_merge_no_merge;
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc_has_binary_prop(&is_binary, merge_target, adm_access, pool));
if (! is_binary)
{
SVN_ERR(svn_wc_translated_file2
(&tmp_target, merge_target,
merge_target, adm_access,
SVN_WC_TRANSLATE_TO_NF
| SVN_WC_TRANSLATE_FORCE_COPY, pool));
SVN_ERR(svn_wc_create_tmp_file2(&result_f, &result_target,
adm_path, svn_io_file_del_none,
pool));
SVN_ERR(svn_io_open_unique_file2(NULL, &tmp_left,
tmp_target,
SVN_WC__TMP_EXT,
svn_io_file_del_on_pool_cleanup,
pool));
SVN_ERR(svn_io_open_unique_file2(NULL, &tmp_right,
tmp_target,
SVN_WC__TMP_EXT,
svn_io_file_del_on_pool_cleanup,
pool));
SVN_ERR(svn_io_copy_file(left, tmp_left, TRUE, pool));
SVN_ERR(svn_io_copy_file(right, tmp_right, TRUE, pool));
if (diff3_cmd)
{
int exit_code;
SVN_ERR(svn_io_run_diff3_2(&exit_code, ".",
tmp_target, tmp_left, tmp_right,
target_label, left_label, right_label,
result_f, diff3_cmd,
merge_options, pool));
contains_conflicts = exit_code == 1;
}
else
{
svn_diff_t *diff;
const char *target_marker;
const char *left_marker;
const char *right_marker;
svn_stream_t *ostream;
svn_diff_file_options_t *options;
ostream = svn_stream_from_aprfile(result_f, pool);
options = svn_diff_file_options_create(pool);
if (merge_options)
SVN_ERR(svn_diff_file_options_parse(options, merge_options, pool));
SVN_ERR(svn_diff_file_diff3_2(&diff,
tmp_left, tmp_target, tmp_right,
options, pool));
if (target_label)
target_marker = apr_psprintf(pool, "<<<<<<< %s", target_label);
else
target_marker = "<<<<<<< .working";
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_diff_file_output_merge(ostream, diff,
tmp_left, tmp_target, tmp_right,
left_marker,
target_marker,
right_marker,
"=======",
FALSE,
FALSE,
pool));
SVN_ERR(svn_stream_close(ostream));
contains_conflicts = svn_diff_contains_conflicts(diff);
}
SVN_ERR(svn_io_file_close(result_f, pool));
if (contains_conflicts && ! dry_run)
{
const char *left_copy, *right_copy, *target_copy;
const char *xtmp_left, *xtmp_right;
const char *parentt, *left_base, *right_base, *target_base;
svn_wc_adm_access_t *parent_access;
svn_wc_entry_t tmp_entry;
SVN_ERR(svn_io_open_unique_file2(NULL,
&left_copy,
merge_target,
left_label,
svn_io_file_del_none,
pool));
SVN_ERR(svn_io_open_unique_file2(NULL,
&right_copy,
merge_target,
right_label,
svn_io_file_del_none,
pool));
SVN_ERR(svn_io_open_unique_file2(NULL,
&target_copy,
merge_target,
target_label,
svn_io_file_del_none,
pool));
svn_path_split(target_copy, &parentt, &target_base, pool);
SVN_ERR(svn_wc_adm_retrieve(&parent_access, adm_access, parentt,
pool));
xtmp_left = svn_path_is_child(adm_path, left, pool);
if (! xtmp_left)
{
SVN_ERR(svn_wc_create_tmp_file2
(NULL, &xtmp_left,
adm_path, svn_io_file_del_none, pool));
SVN_ERR(svn_io_copy_file(left, xtmp_left, TRUE, pool));
xtmp_left = svn_path_is_child(adm_path, xtmp_left, pool);
}
xtmp_right = svn_path_is_child(adm_path, right, pool);
if (! xtmp_right)
{
SVN_ERR(svn_wc_create_tmp_file2
(NULL, &xtmp_right,
adm_path, svn_io_file_del_none, pool));
SVN_ERR(svn_io_copy_file(right, xtmp_right, TRUE, pool));
xtmp_right = svn_path_is_child(adm_path, xtmp_right, pool);
}
left_base = svn_path_is_child(adm_path, left_copy, pool);
right_base = svn_path_is_child(adm_path, right_copy, pool);
SVN_ERR(svn_wc__loggy_translated_file(log_accum,
adm_access,
left_base, xtmp_left,
log_merge_target, pool));
SVN_ERR(svn_wc__loggy_translated_file(log_accum,
adm_access,
right_base, xtmp_right,
log_merge_target, pool));
SVN_ERR(svn_io_copy_file(merge_target,
target_copy, TRUE, pool));
tmp_entry.conflict_old = left_base;
tmp_entry.conflict_new = right_base;
tmp_entry.conflict_wrk = target_base;
SVN_ERR(svn_wc__loggy_entry_modify
(log_accum, adm_access,
log_merge_target, &tmp_entry,
SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
| SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
| SVN_WC__ENTRY_MODIFY_CONFLICT_WRK,
pool));
*merge_outcome = svn_wc_merge_conflict;
}
else if (contains_conflicts && dry_run)
{
*merge_outcome = svn_wc_merge_conflict;
}
else
{
svn_boolean_t same;
SVN_ERR(svn_io_files_contents_same_p(&same, result_target,
merge_target, pool));
*merge_outcome = same ? svn_wc_merge_unchanged : svn_wc_merge_merged;
}
if (*merge_outcome != svn_wc_merge_unchanged && ! dry_run)
{
const char *log_result_target =
svn_path_is_child(adm_path, result_target, pool);
SVN_ERR(svn_wc__loggy_copy(log_accum, NULL,
adm_access,
svn_wc__copy_translate,
log_result_target,
svn_path_is_child(adm_path,
merge_target, pool),
FALSE, pool));
}
}
else if (! dry_run)
{
const char *left_copy, *right_copy;
const char *parentt, *left_base, *right_base;
svn_wc_entry_t tmp_entry;
SVN_ERR(svn_io_open_unique_file2(NULL,
&left_copy,
merge_target,
left_label,
svn_io_file_del_none,
pool));
SVN_ERR(svn_io_open_unique_file2(NULL,
&right_copy,
merge_target,
right_label,
svn_io_file_del_none,
pool));
SVN_ERR(svn_io_copy_file(left,
left_copy, TRUE, pool));
SVN_ERR(svn_io_copy_file(right,
right_copy, TRUE, pool));
svn_path_split(left_copy, &parentt, &left_base, pool);
svn_path_split(right_copy, &parentt, &right_base, pool);
tmp_entry.conflict_old = left_base;
tmp_entry.conflict_new = right_base;
tmp_entry.conflict_wrk = NULL;
SVN_ERR(svn_wc__loggy_entry_modify
(log_accum,
adm_access, log_merge_target,
&tmp_entry,
SVN_WC__ENTRY_MODIFY_CONFLICT_OLD
| SVN_WC__ENTRY_MODIFY_CONFLICT_NEW
| SVN_WC__ENTRY_MODIFY_CONFLICT_WRK,
pool));
*merge_outcome = svn_wc_merge_conflict;
}
else
*merge_outcome = svn_wc_merge_conflict;
if (! dry_run)
{
SVN_ERR(svn_wc__loggy_maybe_set_executable(log_accum,
adm_access, log_merge_target,
pool));
SVN_ERR(svn_wc__loggy_maybe_set_readonly(log_accum,
adm_access, log_merge_target,
pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_merge2(enum svn_wc_merge_outcome_t *merge_outcome,
const char *left,
const char *right,
const char *merge_target,
svn_wc_adm_access_t *adm_access,
const char *left_label,
const char *right_label,
const char *target_label,
svn_boolean_t dry_run,
const char *diff3_cmd,
const apr_array_header_t *merge_options,
apr_pool_t *pool)
{
svn_stringbuf_t *log_accum = svn_stringbuf_create("", pool);
SVN_ERR(svn_wc__merge_internal(&log_accum, merge_outcome,
left, right, merge_target,
adm_access,
left_label, right_label, target_label,
dry_run,
diff3_cmd,
merge_options,
pool));
SVN_ERR(svn_wc__write_log(adm_access, 0, log_accum, pool));
SVN_ERR(svn_wc__run_log(adm_access, NULL, pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_merge(const char *left,
const char *right,
const char *merge_target,
svn_wc_adm_access_t *adm_access,
const char *left_label,
const char *right_label,
const char *target_label,
svn_boolean_t dry_run,
enum svn_wc_merge_outcome_t *merge_outcome,
const char *diff3_cmd,
apr_pool_t *pool)
{
return svn_wc_merge2(merge_outcome,
left, right, merge_target, adm_access,
left_label, right_label, target_label,
dry_run, diff3_cmd, NULL, pool);
}