#include <string.h>
#include <apr_pools.h>
#include <apr_tables.h>
#include <apr_hash.h>
#include <apr_errno.h>
#include "svn_hash.h"
#include "svn_types.h"
#include "svn_pools.h"
#include "svn_string.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
#include "svn_wc.h"
#include "svn_io.h"
#include "svn_diff.h"
#include "wc.h"
#include "wc_db.h"
#include "conflicts.h"
#include "workqueue.h"
#include "props.h"
#include "private/svn_wc_private.h"
#include "private/svn_skel.h"
#include "private/svn_sorts_private.h"
#include "private/svn_string_private.h"
#include "svn_private_config.h"
svn_skel_t *
svn_wc__conflict_skel_create(apr_pool_t *result_pool)
{
svn_skel_t *conflict_skel = svn_skel__make_empty_list(result_pool);
svn_skel__prepend(svn_skel__make_empty_list(result_pool), conflict_skel);
svn_skel__prepend(svn_skel__make_empty_list(result_pool), conflict_skel);
return conflict_skel;
}
svn_error_t *
svn_wc__conflict_skel_is_complete(svn_boolean_t *complete,
const svn_skel_t *conflict_skel)
{
*complete = FALSE;
if (svn_skel__list_length(conflict_skel) < 2)
return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
_("Not a conflict skel"));
if (svn_skel__list_length(conflict_skel->children) < 2)
return SVN_NO_ERROR;
if (svn_skel__list_length(conflict_skel->children->next) == 0)
return SVN_NO_ERROR;
*complete = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
conflict__prepend_location(svn_skel_t *skel,
const svn_wc_conflict_version_t *location,
svn_boolean_t allow_NULL,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *loc;
SVN_ERR_ASSERT(location || allow_NULL);
if (!location)
{
svn_skel__prepend(svn_skel__make_empty_list(result_pool), skel);
return SVN_NO_ERROR;
}
loc = svn_skel__make_empty_list(result_pool);
svn_skel__prepend_str(svn_node_kind_to_word(location->node_kind),
loc, result_pool);
svn_skel__prepend_int(location->peg_rev, loc, result_pool);
svn_skel__prepend_str(apr_pstrdup(result_pool, location->path_in_repos), loc,
result_pool);
if (!location->repos_uuid)
svn_skel__prepend(svn_skel__make_empty_list(result_pool), loc);
else
svn_skel__prepend_str(location->repos_uuid, loc, result_pool);
svn_skel__prepend_str(apr_pstrdup(result_pool, location->repos_url), loc,
result_pool);
svn_skel__prepend_str(SVN_WC__CONFLICT_SRC_SUBVERSION, loc, result_pool);
svn_skel__prepend(loc, skel);
return SVN_NO_ERROR;
}
static svn_error_t *
conflict__read_location(svn_wc_conflict_version_t **location,
const svn_skel_t *skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *repos_root_url;
const char *repos_uuid;
const char *repos_relpath;
svn_revnum_t revision;
apr_int64_t v;
svn_node_kind_t node_kind;
const char *kind_str;
const svn_skel_t *c = skel->children;
if (!svn_skel__matches_atom(c, SVN_WC__CONFLICT_SRC_SUBVERSION))
{
*location = NULL;
return SVN_NO_ERROR;
}
c = c->next;
repos_root_url = apr_pstrmemdup(result_pool, c->data, c->len);
c = c->next;
if (c->is_atom)
repos_uuid = apr_pstrmemdup(result_pool, c->data, c->len);
else
repos_uuid = NULL;
c = c->next;
repos_relpath = apr_pstrmemdup(result_pool, c->data, c->len);
c = c->next;
SVN_ERR(svn_skel__parse_int(&v, c, scratch_pool));
revision = (svn_revnum_t)v;
c = c->next;
kind_str = apr_pstrmemdup(scratch_pool, c->data, c->len);
node_kind = svn_node_kind_from_word(kind_str);
*location = svn_wc_conflict_version_create2(repos_root_url,
repos_uuid,
repos_relpath,
revision,
node_kind,
result_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
conflict__get_operation(svn_skel_t **why,
const svn_skel_t *conflict_skel)
{
SVN_ERR_ASSERT(conflict_skel
&& conflict_skel->children
&& conflict_skel->children->next
&& !conflict_skel->children->next->is_atom);
*why = conflict_skel->children;
if (!(*why)->children)
*why = NULL;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_set_op_update(svn_skel_t *conflict_skel,
const svn_wc_conflict_version_t *original,
const svn_wc_conflict_version_t *target,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *why;
svn_skel_t *origins;
SVN_ERR_ASSERT(conflict_skel
&& conflict_skel->children
&& conflict_skel->children->next
&& !conflict_skel->children->next->is_atom);
SVN_ERR(conflict__get_operation(&why, conflict_skel));
SVN_ERR_ASSERT(why == NULL);
why = conflict_skel->children;
origins = svn_skel__make_empty_list(result_pool);
SVN_ERR(conflict__prepend_location(origins, target, TRUE,
result_pool, scratch_pool));
SVN_ERR(conflict__prepend_location(origins, original, TRUE,
result_pool, scratch_pool));
svn_skel__prepend(origins, why);
svn_skel__prepend_str(SVN_WC__CONFLICT_OP_UPDATE, why, result_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_set_op_switch(svn_skel_t *conflict_skel,
const svn_wc_conflict_version_t *original,
const svn_wc_conflict_version_t *target,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *why;
svn_skel_t *origins;
SVN_ERR_ASSERT(conflict_skel
&& conflict_skel->children
&& conflict_skel->children->next
&& !conflict_skel->children->next->is_atom);
SVN_ERR(conflict__get_operation(&why, conflict_skel));
SVN_ERR_ASSERT(why == NULL);
why = conflict_skel->children;
origins = svn_skel__make_empty_list(result_pool);
SVN_ERR(conflict__prepend_location(origins, target, TRUE,
result_pool, scratch_pool));
SVN_ERR(conflict__prepend_location(origins, original, TRUE,
result_pool, scratch_pool));
svn_skel__prepend(origins, why);
svn_skel__prepend_str(SVN_WC__CONFLICT_OP_SWITCH, why, result_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_set_op_merge(svn_skel_t *conflict_skel,
const svn_wc_conflict_version_t *left,
const svn_wc_conflict_version_t *right,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *why;
svn_skel_t *origins;
SVN_ERR_ASSERT(conflict_skel
&& conflict_skel->children
&& conflict_skel->children->next
&& !conflict_skel->children->next->is_atom);
SVN_ERR(conflict__get_operation(&why, conflict_skel));
SVN_ERR_ASSERT(why == NULL);
why = conflict_skel->children;
origins = svn_skel__make_empty_list(result_pool);
SVN_ERR(conflict__prepend_location(origins, right, TRUE,
result_pool, scratch_pool));
SVN_ERR(conflict__prepend_location(origins, left, TRUE,
result_pool, scratch_pool));
svn_skel__prepend(origins, why);
svn_skel__prepend_str(SVN_WC__CONFLICT_OP_MERGE, why, result_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
conflict__get_conflict(svn_skel_t **conflict,
const svn_skel_t *conflict_skel,
const char *conflict_type)
{
svn_skel_t *c;
SVN_ERR_ASSERT(conflict_skel
&& conflict_skel->children
&& conflict_skel->children->next
&& !conflict_skel->children->next->is_atom);
for(c = conflict_skel->children->next->children;
c;
c = c->next)
{
if (svn_skel__matches_atom(c->children, conflict_type))
{
*conflict = c;
return SVN_NO_ERROR;
}
}
*conflict = NULL;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_add_text_conflict(svn_skel_t *conflict_skel,
svn_wc__db_t *db,
const char *wri_abspath,
const char *mine_abspath,
const char *their_old_abspath,
const char *their_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *text_conflict;
svn_skel_t *markers;
SVN_ERR(conflict__get_conflict(&text_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_TEXT));
SVN_ERR_ASSERT(!text_conflict);
text_conflict = svn_skel__make_empty_list(result_pool);
markers = svn_skel__make_empty_list(result_pool);
if (their_abspath)
{
const char *their_relpath;
SVN_ERR(svn_wc__db_to_relpath(&their_relpath,
db, wri_abspath, their_abspath,
result_pool, scratch_pool));
svn_skel__prepend_str(their_relpath, markers, result_pool);
}
else
svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
if (mine_abspath)
{
const char *mine_relpath;
SVN_ERR(svn_wc__db_to_relpath(&mine_relpath,
db, wri_abspath, mine_abspath,
result_pool, scratch_pool));
svn_skel__prepend_str(mine_relpath, markers, result_pool);
}
else
svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
if (their_old_abspath)
{
const char *original_relpath;
SVN_ERR(svn_wc__db_to_relpath(&original_relpath,
db, wri_abspath, their_old_abspath,
result_pool, scratch_pool));
svn_skel__prepend_str(original_relpath, markers, result_pool);
}
else
svn_skel__prepend(svn_skel__make_empty_list(result_pool), markers);
svn_skel__prepend(markers, text_conflict);
svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_TEXT, text_conflict,
result_pool);
svn_skel__prepend(text_conflict, conflict_skel->children->next);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_add_prop_conflict(svn_skel_t *conflict_skel,
svn_wc__db_t *db,
const char *wri_abspath,
const char *marker_abspath,
const apr_hash_t *mine_props,
const apr_hash_t *their_old_props,
const apr_hash_t *their_props,
const apr_hash_t *conflicted_prop_names,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *prop_conflict;
svn_skel_t *props;
svn_skel_t *conflict_names;
svn_skel_t *markers;
apr_hash_index_t *hi;
SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_PROP));
SVN_ERR_ASSERT(!prop_conflict);
prop_conflict = svn_skel__make_empty_list(result_pool);
if (their_props)
{
SVN_ERR(svn_skel__unparse_proplist(&props, their_props, result_pool));
svn_skel__prepend(props, prop_conflict);
}
else
svn_skel__prepend_str("", prop_conflict, result_pool);
if (mine_props)
{
SVN_ERR(svn_skel__unparse_proplist(&props, mine_props, result_pool));
svn_skel__prepend(props, prop_conflict);
}
else
svn_skel__prepend_str("", prop_conflict, result_pool);
if (their_old_props)
{
SVN_ERR(svn_skel__unparse_proplist(&props, their_old_props,
result_pool));
svn_skel__prepend(props, prop_conflict);
}
else
svn_skel__prepend_str("", prop_conflict, result_pool);
conflict_names = svn_skel__make_empty_list(result_pool);
for (hi = apr_hash_first(scratch_pool, (apr_hash_t *)conflicted_prop_names);
hi;
hi = apr_hash_next(hi))
{
svn_skel__prepend_str(apr_pstrdup(result_pool, apr_hash_this_key(hi)),
conflict_names,
result_pool);
}
svn_skel__prepend(conflict_names, prop_conflict);
markers = svn_skel__make_empty_list(result_pool);
if (marker_abspath)
{
const char *marker_relpath;
SVN_ERR(svn_wc__db_to_relpath(&marker_relpath, db, wri_abspath,
marker_abspath,
result_pool, scratch_pool));
svn_skel__prepend_str(marker_relpath, markers, result_pool);
}
svn_skel__prepend(markers, prop_conflict);
svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_PROP, prop_conflict, result_pool);
svn_skel__prepend(prop_conflict, conflict_skel->children->next);
return SVN_NO_ERROR;
}
static const svn_token_map_t reason_map[] =
{
{ "edited", svn_wc_conflict_reason_edited },
{ "obstructed", svn_wc_conflict_reason_obstructed },
{ "deleted", svn_wc_conflict_reason_deleted },
{ "missing", svn_wc_conflict_reason_missing },
{ "unversioned", svn_wc_conflict_reason_unversioned },
{ "added", svn_wc_conflict_reason_added },
{ "replaced", svn_wc_conflict_reason_replaced },
{ "moved-away", svn_wc_conflict_reason_moved_away },
{ "moved-here", svn_wc_conflict_reason_moved_here },
{ NULL }
};
static const svn_token_map_t action_map[] =
{
{ "edited", svn_wc_conflict_action_edit },
{ "added", svn_wc_conflict_action_add },
{ "deleted", svn_wc_conflict_action_delete },
{ "replaced", svn_wc_conflict_action_replace },
{ NULL }
};
svn_error_t *
svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel,
svn_wc__db_t *db,
const char *wri_abspath,
svn_wc_conflict_reason_t reason,
svn_wc_conflict_action_t action,
const char *move_src_op_root_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *tree_conflict;
svn_skel_t *markers;
SVN_ERR(conflict__get_conflict(&tree_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_TREE));
SVN_ERR_ASSERT(!tree_conflict);
SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_moved_away
|| !move_src_op_root_abspath);
tree_conflict = svn_skel__make_empty_list(result_pool);
if (reason == svn_wc_conflict_reason_moved_away
&& move_src_op_root_abspath)
{
const char *move_src_op_root_relpath;
SVN_ERR(svn_wc__db_to_relpath(&move_src_op_root_relpath,
db, wri_abspath,
move_src_op_root_abspath,
result_pool, scratch_pool));
svn_skel__prepend_str(move_src_op_root_relpath, tree_conflict,
result_pool);
}
svn_skel__prepend_str(svn_token__to_word(action_map, action),
tree_conflict, result_pool);
svn_skel__prepend_str(svn_token__to_word(reason_map, reason),
tree_conflict, result_pool);
markers = svn_skel__make_empty_list(result_pool);
svn_skel__prepend(markers, tree_conflict);
svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_TREE, tree_conflict,
result_pool);
svn_skel__prepend(tree_conflict, conflict_skel->children->next);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_skel_resolve(svn_boolean_t *completely_resolved,
svn_skel_t *conflict_skel,
svn_wc__db_t *db,
const char *wri_abspath,
svn_boolean_t resolve_text,
const char *resolve_prop,
svn_boolean_t resolve_tree,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *op;
svn_skel_t **pconflict;
SVN_ERR(conflict__get_operation(&op, conflict_skel));
if (!op)
return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
_("Not a completed conflict skel"));
pconflict = &(conflict_skel->children->next->children);
while (*pconflict)
{
svn_skel_t *c = (*pconflict)->children;
if (resolve_text
&& svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_TEXT))
{
*pconflict = (*pconflict)->next;
continue;
}
else if (resolve_prop
&& svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_PROP))
{
svn_skel_t **ppropnames = &(c->next->next->children);
if (resolve_prop[0] == '\0')
*ppropnames = NULL;
else
while (*ppropnames)
{
if (svn_skel__matches_atom(*ppropnames, resolve_prop))
{
*ppropnames = (*ppropnames)->next;
break;
}
ppropnames = &((*ppropnames)->next);
}
if (!c->next->next->children)
{
*pconflict = (*pconflict)->next;
continue;
}
}
else if (resolve_tree
&& svn_skel__matches_atom(c, SVN_WC__CONFLICT_KIND_TREE))
{
*pconflict = (*pconflict)->next;
continue;
}
pconflict = &((*pconflict)->next);
}
if (completely_resolved)
{
svn_boolean_t complete_conflict;
SVN_ERR(svn_wc__conflict_skel_is_complete(&complete_conflict,
conflict_skel));
*completely_resolved = !complete_conflict;
}
return SVN_NO_ERROR;
}
static const svn_token_map_t operation_map[] =
{
{ "", svn_wc_operation_none },
{ SVN_WC__CONFLICT_OP_UPDATE, svn_wc_operation_update },
{ SVN_WC__CONFLICT_OP_SWITCH, svn_wc_operation_switch },
{ SVN_WC__CONFLICT_OP_MERGE, svn_wc_operation_merge },
{ NULL }
};
svn_error_t *
svn_wc__conflict_read_info(svn_wc_operation_t *operation,
const apr_array_header_t **locations,
svn_boolean_t *text_conflicted,
svn_boolean_t *prop_conflicted,
svn_boolean_t *tree_conflicted,
svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *op;
const svn_skel_t *c;
SVN_ERR(conflict__get_operation(&op, conflict_skel));
if (!op)
return svn_error_create(SVN_ERR_INCOMPLETE_DATA, NULL,
_("Not a completed conflict skel"));
c = op->children;
if (operation)
{
int value = svn_token__from_mem(operation_map, c->data, c->len);
if (value != SVN_TOKEN_UNKNOWN)
*operation = value;
else
*operation = svn_wc_operation_none;
}
c = c->next;
if (locations && c->children)
{
const svn_skel_t *loc_skel;
svn_wc_conflict_version_t *loc;
apr_array_header_t *locs = apr_array_make(result_pool, 2, sizeof(loc));
for (loc_skel = c->children; loc_skel; loc_skel = loc_skel->next)
{
SVN_ERR(conflict__read_location(&loc, loc_skel, result_pool,
scratch_pool));
APR_ARRAY_PUSH(locs, svn_wc_conflict_version_t *) = loc;
}
*locations = locs;
}
else if (locations)
*locations = NULL;
if (text_conflicted)
{
svn_skel_t *c_skel;
SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
SVN_WC__CONFLICT_KIND_TEXT));
*text_conflicted = (c_skel != NULL);
}
if (prop_conflicted)
{
svn_skel_t *c_skel;
SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
SVN_WC__CONFLICT_KIND_PROP));
*prop_conflicted = (c_skel != NULL);
}
if (tree_conflicted)
{
svn_skel_t *c_skel;
SVN_ERR(conflict__get_conflict(&c_skel, conflict_skel,
SVN_WC__CONFLICT_KIND_TREE));
*tree_conflicted = (c_skel != NULL);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_read_text_conflict(const char **mine_abspath,
const char **their_old_abspath,
const char **their_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *text_conflict;
const svn_skel_t *m;
SVN_ERR(conflict__get_conflict(&text_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_TEXT));
if (!text_conflict)
return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
m = text_conflict->children->next->children;
if (their_old_abspath)
{
if (m->is_atom)
{
const char *original_relpath;
original_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
SVN_ERR(svn_wc__db_from_relpath(their_old_abspath,
db, wri_abspath, original_relpath,
result_pool, scratch_pool));
}
else
*their_old_abspath = NULL;
}
m = m->next;
if (mine_abspath)
{
if (m->is_atom)
{
const char *mine_relpath;
mine_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
SVN_ERR(svn_wc__db_from_relpath(mine_abspath,
db, wri_abspath, mine_relpath,
result_pool, scratch_pool));
}
else
*mine_abspath = NULL;
}
m = m->next;
if (their_abspath)
{
if (m->is_atom)
{
const char *their_relpath;
their_relpath = apr_pstrmemdup(scratch_pool, m->data, m->len);
SVN_ERR(svn_wc__db_from_relpath(their_abspath,
db, wri_abspath, their_relpath,
result_pool, scratch_pool));
}
else
*their_abspath = NULL;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_read_prop_conflict(const char **marker_abspath,
apr_hash_t **mine_props,
apr_hash_t **their_old_props,
apr_hash_t **their_props,
apr_hash_t **conflicted_prop_names,
svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *prop_conflict;
const svn_skel_t *c;
SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_PROP));
if (!prop_conflict)
return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
c = prop_conflict->children;
c = c->next;
if (marker_abspath)
{
const char *marker_relpath;
if (c->children && c->children->is_atom)
{
marker_relpath = apr_pstrmemdup(result_pool, c->children->data,
c->children->len);
SVN_ERR(svn_wc__db_from_relpath(marker_abspath, db, wri_abspath,
marker_relpath,
result_pool, scratch_pool));
}
else
*marker_abspath = NULL;
}
c = c->next;
if (conflicted_prop_names)
{
const svn_skel_t *name;
*conflicted_prop_names = apr_hash_make(result_pool);
for (name = c->children; name; name = name->next)
{
svn_hash_sets(*conflicted_prop_names,
apr_pstrmemdup(result_pool, name->data, name->len),
"");
}
}
c = c->next;
if (their_old_props)
{
if (c->is_atom)
*their_old_props = apr_hash_make(result_pool);
else
SVN_ERR(svn_skel__parse_proplist(their_old_props, c, result_pool));
}
c = c->next;
if (mine_props)
{
if (c->is_atom)
*mine_props = apr_hash_make(result_pool);
else
SVN_ERR(svn_skel__parse_proplist(mine_props, c, result_pool));
}
c = c->next;
if (their_props)
{
if (c->is_atom)
*their_props = apr_hash_make(result_pool);
else
SVN_ERR(svn_skel__parse_proplist(their_props, c, result_pool));
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *reason,
svn_wc_conflict_action_t *action,
const char **move_src_op_root_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *tree_conflict;
const svn_skel_t *c;
svn_boolean_t is_moved_away = FALSE;
SVN_ERR(conflict__get_conflict(&tree_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_TREE));
if (!tree_conflict)
return svn_error_create(SVN_ERR_WC_MISSING, NULL, _("Conflict not set"));
c = tree_conflict->children;
c = c->next;
c = c->next;
{
int value = svn_token__from_mem(reason_map, c->data, c->len);
if (reason)
{
if (value != SVN_TOKEN_UNKNOWN)
*reason = value;
else
*reason = svn_wc_conflict_reason_edited;
}
is_moved_away = (value == svn_wc_conflict_reason_moved_away);
}
c = c->next;
if (action)
{
int value = svn_token__from_mem(action_map, c->data, c->len);
if (value != SVN_TOKEN_UNKNOWN)
*action = value;
else
*action = svn_wc_conflict_action_edit;
}
c = c->next;
if (move_src_op_root_abspath)
{
if (c && is_moved_away)
{
const char *move_src_op_root_relpath
= apr_pstrmemdup(scratch_pool, c->data, c->len);
SVN_ERR(svn_wc__db_from_relpath(move_src_op_root_abspath,
db, wri_abspath,
move_src_op_root_relpath,
result_pool, scratch_pool));
}
else
*move_src_op_root_abspath = NULL;
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_read_markers(const apr_array_header_t **markers,
svn_wc__db_t *db,
const char *wri_abspath,
const svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const svn_skel_t *conflict;
apr_array_header_t *list = NULL;
SVN_ERR_ASSERT(conflict_skel != NULL);
for (conflict = conflict_skel->children->next->children;
conflict;
conflict = conflict->next)
{
const svn_skel_t *marker;
for (marker = conflict->children->next->children;
marker;
marker = marker->next)
{
if (! marker->is_atom)
continue;
if (! list)
list = apr_array_make(result_pool, 4, sizeof(const char *));
SVN_ERR(svn_wc__db_from_relpath(
&APR_ARRAY_PUSH(list, const char*),
db, wri_abspath,
apr_pstrmemdup(scratch_pool, marker->data,
marker->len),
result_pool, scratch_pool));
}
}
*markers = list;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_create_markers(svn_skel_t **work_items,
svn_wc__db_t *db,
const char *local_abspath,
svn_skel_t *conflict_skel,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_boolean_t prop_conflicted;
svn_wc_operation_t operation;
*work_items = NULL;
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL,
NULL, &prop_conflicted, NULL,
db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (prop_conflicted)
{
const char *marker_abspath = NULL;
svn_node_kind_t kind;
const char *marker_dir;
const char *marker_name;
const char *marker_relpath;
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
if (kind == svn_node_dir)
{
marker_dir = local_abspath;
marker_name = SVN_WC__THIS_DIR_PREJ;
}
else
svn_dirent_split(&marker_dir, &marker_name, local_abspath,
scratch_pool);
SVN_ERR(svn_io_open_uniquely_named(NULL, &marker_abspath,
marker_dir,
marker_name,
SVN_WC__PROP_REJ_EXT,
svn_io_file_del_none,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_to_relpath(&marker_relpath, db, local_abspath,
marker_abspath, result_pool, result_pool));
{
svn_skel_t *prop_conflict;
SVN_ERR(conflict__get_conflict(&prop_conflict, conflict_skel,
SVN_WC__CONFLICT_KIND_PROP));
svn_skel__prepend_str(marker_relpath, prop_conflict->children->next,
result_pool);
}
SVN_ERR(svn_wc__wq_build_prej_install(work_items,
db, local_abspath,
scratch_pool, scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
generate_propconflict(svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
svn_wc_operation_t operation,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
const char *propname,
const svn_string_t *base_val,
const svn_string_t *working_val,
const svn_string_t *incoming_old_val,
const svn_string_t *incoming_new_val,
svn_wc_conflict_resolver_func2_t conflict_func,
void *conflict_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_result_t *result = NULL;
svn_wc_conflict_description2_t *cdesc;
const char *dirpath = svn_dirent_dirname(local_abspath, scratch_pool);
const svn_string_t *new_value = NULL;
cdesc = svn_wc_conflict_description_create_prop2(
local_abspath,
kind,
propname, scratch_pool);
cdesc->operation = operation;
cdesc->src_left_version = left_version;
cdesc->src_right_version = right_version;
if (working_val)
{
const char *file_name;
SVN_ERR(svn_io_write_unique(&file_name, dirpath, working_val->data,
working_val->len,
svn_io_file_del_on_pool_cleanup,
scratch_pool));
cdesc->my_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
cdesc->prop_value_working = working_val;
}
if (incoming_new_val)
{
const char *file_name;
SVN_ERR(svn_io_write_unique(&file_name, dirpath, incoming_new_val->data,
incoming_new_val->len,
svn_io_file_del_on_pool_cleanup,
scratch_pool));
cdesc->merged_file = svn_dirent_join(dirpath, file_name, scratch_pool);
cdesc->prop_value_incoming_new = incoming_new_val;
}
if (!base_val && !incoming_old_val)
{
}
else if ((base_val && !incoming_old_val)
|| (!base_val && incoming_old_val))
{
const svn_string_t *conflict_base_val = base_val ? base_val
: incoming_old_val;
const char *file_name;
SVN_ERR(svn_io_write_unique(&file_name, dirpath,
conflict_base_val->data,
conflict_base_val->len,
svn_io_file_del_on_pool_cleanup,
scratch_pool));
cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
}
else
{
const svn_string_t *conflict_base_val;
const char *file_name;
if (! svn_string_compare(base_val, incoming_old_val))
{
if (working_val && svn_string_compare(base_val, working_val))
conflict_base_val = incoming_old_val;
else
conflict_base_val = base_val;
}
else
{
conflict_base_val = base_val;
}
SVN_ERR(svn_io_write_unique(&file_name, dirpath, conflict_base_val->data,
conflict_base_val->len,
svn_io_file_del_on_pool_cleanup, scratch_pool));
cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
cdesc->prop_value_base = base_val;
cdesc->prop_value_incoming_old = incoming_old_val;
if (working_val && incoming_new_val)
{
svn_stream_t *mergestream;
svn_diff_t *diff;
svn_diff_file_options_t *options =
svn_diff_file_options_create(scratch_pool);
SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->prop_reject_abspath,
NULL, svn_io_file_del_on_pool_cleanup,
scratch_pool, scratch_pool));
SVN_ERR(svn_diff_mem_string_diff3(&diff, conflict_base_val,
working_val,
incoming_new_val, options, scratch_pool));
SVN_ERR(svn_diff_mem_string_output_merge3(mergestream, diff,
conflict_base_val, working_val,
incoming_new_val, NULL, NULL, NULL, NULL,
svn_diff_conflict_display_modified_latest,
cancel_func, cancel_baton, scratch_pool));
SVN_ERR(svn_stream_close(mergestream));
cdesc->their_abspath = cdesc->prop_reject_abspath;
}
}
if (!incoming_old_val && incoming_new_val)
cdesc->action = svn_wc_conflict_action_add;
else if (incoming_old_val && !incoming_new_val)
cdesc->action = svn_wc_conflict_action_delete;
else
cdesc->action = svn_wc_conflict_action_edit;
if (base_val && !working_val)
cdesc->reason = svn_wc_conflict_reason_deleted;
else if (!base_val && working_val)
cdesc->reason = svn_wc_conflict_reason_obstructed;
else
cdesc->reason = svn_wc_conflict_reason_edited;
SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
scratch_pool));
if (result == NULL)
{
*conflict_remains = TRUE;
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL, _("Conflict callback violated API:"
" returned no results"));
}
switch (result->choice)
{
default:
case svn_wc_conflict_choose_postpone:
{
*conflict_remains = TRUE;
break;
}
case svn_wc_conflict_choose_mine_full:
{
*conflict_remains = FALSE;
new_value = working_val;
break;
}
case svn_wc_conflict_choose_theirs_full:
{
*conflict_remains = FALSE;
new_value = incoming_new_val;
break;
}
case svn_wc_conflict_choose_base:
{
*conflict_remains = FALSE;
new_value = base_val;
break;
}
case svn_wc_conflict_choose_merged:
{
if (!cdesc->merged_file
&& (!result->merged_file && !result->merged_value))
return svn_error_create
(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL, _("Conflict callback violated API:"
" returned no merged file"));
if (result->merged_value)
new_value = result->merged_value;
else
{
svn_stringbuf_t *merged_stringbuf;
SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
result->merged_file ?
result->merged_file :
cdesc->merged_file,
scratch_pool));
new_value = svn_stringbuf__morph_into_string(merged_stringbuf);
}
*conflict_remains = FALSE;
break;
}
}
if (!*conflict_remains)
{
apr_hash_t *props;
SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath, scratch_pool,
scratch_pool));
svn_hash_sets(props, propname, new_value);
SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, props,
FALSE, NULL, NULL,
scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
merge_showing_conflicts(const char **chosen_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
svn_diff_conflict_display_style_t style,
const apr_array_header_t *merge_options,
const char *left_abspath,
const char *detranslated_target,
const char *right_abspath,
svn_io_file_del_t delete_when,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *temp_dir;
svn_stream_t *chosen_stream;
svn_diff_t *diff;
svn_diff_file_options_t *diff3_options;
diff3_options = svn_diff_file_options_create(scratch_pool);
if (merge_options)
SVN_ERR(svn_diff_file_options_parse(diff3_options,
merge_options,
scratch_pool));
SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
wri_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_stream_open_unique(&chosen_stream, chosen_abspath,
temp_dir, delete_when,
result_pool, scratch_pool));
SVN_ERR(svn_diff_file_diff3_2(&diff,
left_abspath,
detranslated_target, right_abspath,
diff3_options, scratch_pool));
SVN_ERR(svn_diff_file_output_merge3(chosen_stream, diff,
left_abspath,
detranslated_target,
right_abspath,
NULL, NULL, NULL, NULL,
style, cancel_func, cancel_baton,
scratch_pool));
SVN_ERR(svn_stream_close(chosen_stream));
return SVN_NO_ERROR;
}
static svn_error_t *
remove_artifact_file_if_exists(svn_skel_t **work_items,
svn_boolean_t *file_found,
svn_wc__db_t *db,
const char *wri_abspath,
const char *artifact_file_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
*work_items = NULL;
if (artifact_file_abspath)
{
svn_node_kind_t node_kind;
SVN_ERR(svn_io_check_path(artifact_file_abspath, &node_kind,
scratch_pool));
if (node_kind == svn_node_file)
{
SVN_ERR(svn_wc__wq_build_file_remove(work_items,
db, wri_abspath,
artifact_file_abspath,
result_pool, scratch_pool));
if (file_found)
*file_found = TRUE;
}
}
return SVN_NO_ERROR;
}
static svn_error_t *
save_merge_result(svn_skel_t **work_item,
svn_wc__db_t *db,
const char *local_abspath,
const char *source_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *edited_copy_abspath;
const char *dir_abspath;
const char *filename;
svn_dirent_split(&dir_abspath, &filename, local_abspath, scratch_pool);
SVN_ERR(svn_io_open_uniquely_named(NULL,
&edited_copy_abspath,
dir_abspath,
filename,
".edited",
svn_io_file_del_none,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__wq_build_file_copy_translated(work_item,
db, local_abspath,
source_abspath,
edited_copy_abspath,
result_pool, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
build_text_conflict_resolve_items(svn_skel_t **work_items,
svn_boolean_t *found_artifact,
svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflict,
svn_wc_conflict_choice_t choice,
const char *merged_file,
svn_boolean_t save_merged,
const apr_array_header_t *merge_options,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *mine_abspath;
const char *their_old_abspath;
const char *their_abspath;
svn_skel_t *work_item;
const char *install_from_abspath = NULL;
svn_boolean_t remove_source = FALSE;
*work_items = NULL;
if (found_artifact)
*found_artifact = FALSE;
SVN_ERR(svn_wc__conflict_read_text_conflict(&mine_abspath,
&their_old_abspath,
&their_abspath,
db, local_abspath,
conflict,
scratch_pool, scratch_pool));
if (save_merged)
SVN_ERR(save_merge_result(work_items,
db, local_abspath,
merged_file
? merged_file
: local_abspath,
result_pool, scratch_pool));
if (choice == svn_wc_conflict_choose_postpone)
return SVN_NO_ERROR;
switch (choice)
{
case svn_wc_conflict_choose_base:
{
install_from_abspath = their_old_abspath;
break;
}
case svn_wc_conflict_choose_theirs_full:
{
install_from_abspath = their_abspath;
break;
}
case svn_wc_conflict_choose_mine_full:
{
install_from_abspath = mine_abspath
? mine_abspath
: local_abspath;
break;
}
case svn_wc_conflict_choose_theirs_conflict:
case svn_wc_conflict_choose_mine_conflict:
{
svn_diff_conflict_display_style_t style
= choice == svn_wc_conflict_choose_theirs_conflict
? svn_diff_conflict_display_latest
: svn_diff_conflict_display_modified;
if (mine_abspath == NULL)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Conflict on '%s' cannot be resolved to "
"'theirs-conflict' or 'mine-conflict' "
"because a merged version of the file "
"cannot be created."),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(merge_showing_conflicts(&install_from_abspath,
db, local_abspath,
style, merge_options,
their_old_abspath,
mine_abspath,
their_abspath,
svn_io_file_del_none,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
remove_source = TRUE;
break;
}
case svn_wc_conflict_choose_merged:
{
install_from_abspath = merged_file
? merged_file
: local_abspath;
break;
}
case svn_wc_conflict_choose_postpone:
{
return SVN_NO_ERROR;
}
default:
SVN_ERR_ASSERT(choice == svn_wc_conflict_choose_postpone);
}
if (install_from_abspath == NULL)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Conflict on '%s' could not be resolved "
"because the chosen version of the file "
"is not available."),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_wc__wq_build_file_install(&work_item,
db, local_abspath,
install_from_abspath,
FALSE ,
FALSE ,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
if (remove_source)
{
SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
db, local_abspath,
install_from_abspath,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
}
SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
db, local_abspath,
their_old_abspath,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
db, local_abspath,
their_abspath,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
db, local_abspath,
mine_abspath,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
return SVN_NO_ERROR;
}
static svn_error_t *
read_text_conflict_desc(svn_wc_conflict_description2_t **desc,
svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflict_skel,
const char *mime_type,
svn_wc_operation_t operation,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
*desc = svn_wc_conflict_description_create_text2(local_abspath, result_pool);
(*desc)->mime_type = mime_type;
(*desc)->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
(*desc)->operation = operation;
(*desc)->src_left_version = left_version;
(*desc)->src_right_version = right_version;
SVN_ERR(svn_wc__conflict_read_text_conflict(&(*desc)->my_abspath,
&(*desc)->base_abspath,
&(*desc)->their_abspath,
db, local_abspath,
conflict_skel,
result_pool, scratch_pool));
(*desc)->merged_file = apr_pstrdup(result_pool, local_abspath);
return SVN_NO_ERROR;
}
static svn_error_t *
read_tree_conflict_desc(svn_wc_conflict_description2_t **desc,
svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t node_kind,
const svn_skel_t *conflict_skel,
svn_wc_operation_t operation,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_node_kind_t local_kind;
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
SVN_ERR(svn_wc__conflict_read_tree_conflict(
&reason, &action, NULL,
db, local_abspath, conflict_skel, scratch_pool, scratch_pool));
if (reason == svn_wc_conflict_reason_missing)
local_kind = svn_node_none;
else if (reason == svn_wc_conflict_reason_unversioned ||
reason == svn_wc_conflict_reason_obstructed)
SVN_ERR(svn_io_check_path(local_abspath, &local_kind, scratch_pool));
else if (action == svn_wc_conflict_action_delete
&& left_version
&& (operation == svn_wc_operation_update
||operation == svn_wc_operation_switch)
&& (reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away))
{
local_kind = left_version->node_kind;
}
else
local_kind = node_kind;
*desc = svn_wc_conflict_description_create_tree2(local_abspath, local_kind,
operation,
left_version, right_version,
result_pool);
(*desc)->reason = reason;
(*desc)->action = action;
return SVN_NO_ERROR;
}
static svn_error_t *
resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflict,
svn_wc_conflict_choice_t conflict_choice,
apr_hash_t *resolve_later,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool);
svn_error_t *
svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
const svn_skel_t *conflict_skel,
const apr_array_header_t *merge_options,
svn_wc_conflict_resolver_func2_t resolver_func,
void *resolver_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_boolean_t text_conflicted;
svn_boolean_t prop_conflicted;
svn_boolean_t tree_conflicted;
svn_wc_operation_t operation;
const apr_array_header_t *locations;
const svn_wc_conflict_version_t *left_version = NULL;
const svn_wc_conflict_version_t *right_version = NULL;
SVN_ERR(svn_wc__conflict_read_info(&operation, &locations,
&text_conflicted, &prop_conflicted,
&tree_conflicted,
db, local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (locations && locations->nelts > 0)
left_version = APR_ARRAY_IDX(locations, 0, const svn_wc_conflict_version_t *);
if (locations && locations->nelts > 1)
right_version = APR_ARRAY_IDX(locations, 1, const svn_wc_conflict_version_t *);
if (prop_conflicted)
{
apr_hash_t *old_props;
apr_hash_t *mine_props;
apr_hash_t *their_props;
apr_hash_t *old_their_props;
apr_hash_t *conflicted;
apr_pool_t *iterpool;
apr_hash_index_t *hi;
svn_boolean_t mark_resolved = TRUE;
SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
&mine_props,
&old_their_props,
&their_props,
&conflicted,
db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation == svn_wc_operation_merge)
SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
scratch_pool, scratch_pool));
else
old_props = old_their_props;
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, conflicted);
hi;
hi = apr_hash_next(hi))
{
const char *propname = apr_hash_this_key(hi);
svn_boolean_t conflict_remains = TRUE;
svn_pool_clear(iterpool);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
SVN_ERR(generate_propconflict(&conflict_remains,
db, local_abspath, kind,
operation,
left_version,
right_version,
propname,
old_props
? svn_hash_gets(old_props, propname)
: NULL,
mine_props
? svn_hash_gets(mine_props, propname)
: NULL,
old_their_props
? svn_hash_gets(old_their_props, propname)
: NULL,
their_props
? svn_hash_gets(their_props, propname)
: NULL,
resolver_func, resolver_baton,
cancel_func, cancel_baton,
iterpool));
if (conflict_remains)
mark_resolved = FALSE;
}
if (mark_resolved)
{
SVN_ERR(svn_wc__mark_resolved_prop_conflicts(db, local_abspath,
scratch_pool));
}
svn_pool_destroy(iterpool);
}
if (text_conflicted)
{
svn_skel_t *work_items;
svn_boolean_t was_resolved;
svn_wc_conflict_description2_t *desc;
apr_hash_t *props;
svn_wc_conflict_result_t *result;
SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(read_text_conflict_desc(&desc,
db, local_abspath, conflict_skel,
svn_prop_get_value(props,
SVN_PROP_MIME_TYPE),
operation, left_version, right_version,
scratch_pool, scratch_pool));
work_items = NULL;
was_resolved = FALSE;
SVN_ERR(resolver_func(&result, desc, resolver_baton, scratch_pool,
scratch_pool));
if (result == NULL)
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Conflict callback violated API:"
" returned no results"));
SVN_ERR(build_text_conflict_resolve_items(&work_items, &was_resolved,
db, local_abspath,
conflict_skel, result->choice,
result->merged_file,
result->save_merged,
merge_options,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
if (result->choice != svn_wc_conflict_choose_postpone)
{
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
TRUE, FALSE, FALSE,
work_items, scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath,
cancel_func, cancel_baton,
scratch_pool));
}
}
if (tree_conflicted)
{
svn_wc_conflict_result_t *result;
svn_wc_conflict_description2_t *desc;
svn_boolean_t resolved;
svn_node_kind_t node_kind;
SVN_ERR(svn_wc__db_read_kind(&node_kind, db, local_abspath, TRUE,
TRUE, FALSE, scratch_pool));
SVN_ERR(read_tree_conflict_desc(&desc,
db, local_abspath, node_kind,
conflict_skel,
operation, left_version, right_version,
scratch_pool, scratch_pool));
SVN_ERR(resolver_func(&result, desc, resolver_baton, scratch_pool,
scratch_pool));
if (result == NULL)
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Conflict callback violated API:"
" returned no results"));
if (result->choice != svn_wc_conflict_choose_postpone)
SVN_ERR(resolve_tree_conflict_on_node(&resolved,
db, local_abspath, conflict_skel,
result->choice,
apr_hash_make(scratch_pool),
NULL, NULL,
cancel_func, cancel_baton,
scratch_pool));
}
return SVN_NO_ERROR;
}
static svn_error_t *
read_prop_conflict_descs(apr_array_header_t *conflicts,
svn_wc__db_t *db,
const char *local_abspath,
svn_skel_t *conflict_skel,
svn_boolean_t create_tempfiles,
svn_node_kind_t node_kind,
svn_wc_operation_t operation,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
const char *prop_reject_abspath;
apr_hash_t *base_props;
apr_hash_t *my_props;
apr_hash_t *their_old_props;
apr_hash_t *their_props;
apr_hash_t *conflicted_props;
apr_hash_index_t *hi;
apr_pool_t *iterpool;
svn_boolean_t prop_conflicted;
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, &prop_conflicted,
NULL, db, local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!prop_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_prop_conflict(&prop_reject_abspath,
&my_props,
&their_old_props,
&their_props,
&conflicted_props,
db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
prop_reject_abspath = apr_pstrdup(result_pool, prop_reject_abspath);
if (apr_hash_count(conflicted_props) == 0)
{
svn_wc_conflict_description2_t *desc;
desc = svn_wc_conflict_description_create_prop2(local_abspath,
node_kind,
"", result_pool);
desc->prop_reject_abspath = prop_reject_abspath;
desc->their_abspath = desc->prop_reject_abspath;
desc->operation = operation;
desc->src_left_version = left_version;
desc->src_right_version = right_version;
APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t *) = desc;
return SVN_NO_ERROR;
}
if (operation == svn_wc_operation_merge)
SVN_ERR(svn_wc__db_read_pristine_props(&base_props, db, local_abspath,
result_pool, scratch_pool));
else
base_props = NULL;
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, conflicted_props);
hi;
hi = apr_hash_next(hi))
{
const char *propname = apr_hash_this_key(hi);
svn_string_t *old_value;
svn_string_t *my_value;
svn_string_t *their_value;
svn_wc_conflict_description2_t *desc;
svn_pool_clear(iterpool);
desc = svn_wc_conflict_description_create_prop2(local_abspath,
node_kind,
propname,
result_pool);
desc->operation = operation;
desc->src_left_version = left_version;
desc->src_right_version = right_version;
desc->property_name = apr_pstrdup(result_pool, propname);
my_value = svn_hash_gets(my_props, propname);
their_value = svn_hash_gets(their_props, propname);
old_value = svn_hash_gets(their_old_props, propname);
if (their_value == NULL)
desc->action = svn_wc_conflict_action_delete;
else if (old_value == NULL)
desc->action = svn_wc_conflict_action_add;
else
desc->action = svn_wc_conflict_action_edit;
if (my_value == NULL)
desc->reason = svn_wc_conflict_reason_deleted;
else if (old_value == NULL)
desc->reason = svn_wc_conflict_reason_added;
else
desc->reason = svn_wc_conflict_reason_edited;
desc->prop_reject_abspath = prop_reject_abspath;
desc->their_abspath = desc->prop_reject_abspath;
desc->prop_value_base = base_props ? svn_hash_gets(base_props, propname)
: desc->prop_value_incoming_old;
if (my_value)
{
svn_stream_t *s;
apr_size_t len;
if (create_tempfiles)
{
SVN_ERR(svn_stream_open_unique(&s, &desc->my_abspath, NULL,
svn_io_file_del_on_pool_cleanup,
result_pool, iterpool));
len = my_value->len;
SVN_ERR(svn_stream_write(s, my_value->data, &len));
SVN_ERR(svn_stream_close(s));
}
desc->prop_value_working = svn_string_dup(my_value, result_pool);
}
if (their_value)
{
svn_stream_t *s;
apr_size_t len;
if (create_tempfiles)
{
SVN_ERR(svn_stream_open_unique(&s, &desc->merged_file, NULL,
svn_io_file_del_on_pool_cleanup,
result_pool, iterpool));
len = their_value->len;
SVN_ERR(svn_stream_write(s, their_value->data, &len));
SVN_ERR(svn_stream_close(s));
}
desc->prop_value_incoming_new = svn_string_dup(their_value, result_pool);
}
if (old_value)
{
svn_stream_t *s;
apr_size_t len;
if (create_tempfiles)
{
SVN_ERR(svn_stream_open_unique(&s, &desc->base_abspath, NULL,
svn_io_file_del_on_pool_cleanup,
result_pool, iterpool));
len = old_value->len;
SVN_ERR(svn_stream_write(s, old_value->data, &len));
SVN_ERR(svn_stream_close(s));
}
desc->prop_value_incoming_old = svn_string_dup(old_value, result_pool);
}
APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t *) = desc;
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__read_conflicts(const apr_array_header_t **conflicts,
svn_skel_t **conflict_skel,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t create_tempfiles,
svn_boolean_t only_tree_conflict,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_skel_t *the_conflict_skel;
apr_array_header_t *cflcts;
svn_boolean_t prop_conflicted;
svn_boolean_t text_conflicted;
svn_boolean_t tree_conflicted;
svn_wc_operation_t operation;
const apr_array_header_t *locations;
const svn_wc_conflict_version_t *left_version = NULL;
const svn_wc_conflict_version_t *right_version = NULL;
svn_node_kind_t node_kind;
apr_hash_t *props;
if (!conflict_skel)
conflict_skel = &the_conflict_skel;
SVN_ERR(svn_wc__db_read_conflict(conflict_skel, &node_kind, &props,
db, local_abspath,
(conflict_skel == &the_conflict_skel)
? scratch_pool
: result_pool,
scratch_pool));
if (!*conflict_skel)
{
*conflicts = apr_array_make(result_pool, 0,
sizeof(svn_wc_conflict_description2_t *));
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, &text_conflicted,
&prop_conflicted, &tree_conflicted,
db, local_abspath, *conflict_skel,
result_pool, scratch_pool));
cflcts = apr_array_make(result_pool, 4,
sizeof(svn_wc_conflict_description2_t *));
if (locations && locations->nelts > 0)
left_version = APR_ARRAY_IDX(locations, 0, const svn_wc_conflict_version_t *);
if (locations && locations->nelts > 1)
right_version = APR_ARRAY_IDX(locations, 1, const svn_wc_conflict_version_t *);
if (prop_conflicted && !only_tree_conflict)
{
SVN_ERR(read_prop_conflict_descs(cflcts,
db, local_abspath, *conflict_skel,
create_tempfiles, node_kind,
operation, left_version, right_version,
result_pool, scratch_pool));
}
if (text_conflicted && !only_tree_conflict)
{
svn_wc_conflict_description2_t *desc;
SVN_ERR(read_text_conflict_desc(&desc,
db, local_abspath, *conflict_skel,
svn_prop_get_value(props,
SVN_PROP_MIME_TYPE),
operation, left_version, right_version,
result_pool, scratch_pool));
APR_ARRAY_PUSH(cflcts, svn_wc_conflict_description2_t *) = desc;
}
if (tree_conflicted)
{
svn_wc_conflict_description2_t *desc;
SVN_ERR(read_tree_conflict_desc(&desc,
db, local_abspath, node_kind,
*conflict_skel,
operation, left_version, right_version,
result_pool, scratch_pool));
APR_ARRAY_PUSH(cflcts, const svn_wc_conflict_description2_t *) = desc;
}
*conflicts = cflcts;
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__read_conflict_descriptions2_t(const apr_array_header_t **conflicts,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
return svn_wc__read_conflicts(conflicts, NULL, wc_ctx->db, local_abspath,
FALSE, FALSE, result_pool, scratch_pool);
}
static svn_error_t *
resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
svn_wc__db_t *db,
const char *local_abspath,
svn_skel_t *conflicts,
const char *conflicted_propname,
svn_wc_conflict_choice_t conflict_choice,
const char *merged_file,
const svn_string_t *merged_value,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
const char *prop_reject_file;
apr_hash_t *mine_props;
apr_hash_t *their_old_props;
apr_hash_t *their_props;
apr_hash_t *conflicted_props;
apr_hash_t *old_props;
apr_hash_t *resolve_from = NULL;
svn_skel_t *work_items = NULL;
svn_wc_operation_t operation;
svn_boolean_t prop_conflicted;
apr_hash_t *actual_props;
svn_boolean_t resolved_all, resolved_all_prop;
*did_resolve = FALSE;
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, &prop_conflicted,
NULL, db, local_abspath, conflicts,
scratch_pool, scratch_pool));
if (!prop_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_prop_conflict(&prop_reject_file,
&mine_props, &their_old_props,
&their_props, &conflicted_props,
db, local_abspath, conflicts,
scratch_pool, scratch_pool));
if (!conflicted_props)
{
SVN_ERR(remove_artifact_file_if_exists(&work_items, did_resolve,
db, local_abspath, prop_reject_file,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE, FALSE,
work_items, scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
if (conflicted_propname[0] != '\0'
&& !svn_hash_gets(conflicted_props, conflicted_propname))
{
return SVN_NO_ERROR;
}
if (operation == svn_wc_operation_merge)
SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
scratch_pool, scratch_pool));
else
old_props = their_old_props;
SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
scratch_pool, scratch_pool));
switch (conflict_choice)
{
case svn_wc_conflict_choose_base:
resolve_from = their_old_props ? their_old_props : old_props;
break;
case svn_wc_conflict_choose_mine_full:
case svn_wc_conflict_choose_mine_conflict:
resolve_from = mine_props;
break;
case svn_wc_conflict_choose_theirs_full:
case svn_wc_conflict_choose_theirs_conflict:
resolve_from = their_props;
break;
case svn_wc_conflict_choose_merged:
if ((merged_file || merged_value) && conflicted_propname[0] != '\0')
{
resolve_from = apr_hash_copy(scratch_pool, actual_props);
if (!merged_value)
{
svn_stringbuf_t *merged_propval;
SVN_ERR(svn_stringbuf_from_file2(&merged_propval, merged_file,
scratch_pool));
merged_value = svn_stringbuf__morph_into_string(merged_propval);
}
svn_hash_sets(resolve_from, conflicted_propname, merged_value);
}
else
resolve_from = NULL;
break;
default:
return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
_("Invalid 'conflict_result' argument"));
}
if (resolve_from)
{
apr_hash_index_t *hi;
apr_hash_t *apply_on_props;
if (conflicted_propname[0] == '\0')
{
apply_on_props = conflicted_props;
}
else
{
apply_on_props = apr_hash_make(scratch_pool);
svn_hash_sets(apply_on_props, conflicted_propname, "");
}
for (hi = apr_hash_first(scratch_pool, apply_on_props);
hi;
hi = apr_hash_next(hi))
{
const char *propname = apr_hash_this_key(hi);
svn_string_t *new_value = NULL;
new_value = svn_hash_gets(resolve_from, propname);
svn_hash_sets(actual_props, propname, new_value);
}
}
SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts,
db, local_abspath,
FALSE, conflicted_propname,
FALSE,
scratch_pool, scratch_pool));
if (!resolved_all)
{
SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, &prop_conflicted,
NULL, db, local_abspath, conflicts,
scratch_pool, scratch_pool));
resolved_all_prop = (! prop_conflicted);
}
else
{
resolved_all_prop = TRUE;
conflicts = NULL;
}
if (resolved_all_prop)
{
SVN_ERR(remove_artifact_file_if_exists(&work_items, did_resolve,
db, local_abspath,
prop_reject_file,
scratch_pool, scratch_pool));
}
else
{
SVN_ERR(svn_wc__wq_build_prej_install(&work_items,
db, local_abspath,
scratch_pool, scratch_pool));
*did_resolve = TRUE;
}
SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, actual_props,
FALSE, conflicts, work_items,
scratch_pool));
if (resolved_all)
{
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
FALSE, TRUE, FALSE,
NULL, scratch_pool));
}
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
handle_tree_conflict_resolution_failure(const char *local_abspath,
svn_error_t *err,
apr_hash_t *resolve_later)
{
const char *dup_abspath;
if (!resolve_later
|| (err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE
&& err->apr_err != SVN_ERR_WC_FOUND_CONFLICT))
return svn_error_trace(err);
svn_error_clear(err);
dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
local_abspath);
svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
return SVN_NO_ERROR;
}
static svn_error_t *
resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_wc__db_t *db,
const char *local_abspath,
const svn_skel_t *conflicts,
svn_wc_conflict_choice_t conflict_choice,
apr_hash_t *resolve_later,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const char *src_op_root_abspath;
*did_resolve = FALSE;
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, db, local_abspath,
conflicts, scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
&src_op_root_abspath,
db, local_abspath,
conflicts,
scratch_pool, scratch_pool));
if (operation == svn_wc_operation_update
|| operation == svn_wc_operation_switch)
{
svn_error_t *err;
if (reason == svn_wc_conflict_reason_deleted ||
reason == svn_wc_conflict_reason_replaced)
{
if (conflict_choice == svn_wc_conflict_choose_merged)
{
if (action != svn_wc_conflict_action_delete)
{
SVN_ERR(svn_wc__db_op_break_moved_away(
db, local_abspath, src_op_root_abspath, TRUE,
notify_func, notify_baton,
scratch_pool));
*did_resolve = TRUE;
return SVN_NO_ERROR;
}
*did_resolve = TRUE;
}
else if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
{
svn_skel_t *new_conflicts;
err = svn_wc__db_op_raise_moved_away(
db, local_abspath, notify_func, notify_baton,
scratch_pool);
if (err)
SVN_ERR(handle_tree_conflict_resolution_failure(
local_abspath, err, resolve_later));
SVN_ERR(svn_wc__db_read_conflict(&new_conflicts, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
if (new_conflicts)
SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, NULL,
&tree_conflicted,
db, local_abspath,
new_conflicts,
scratch_pool,
scratch_pool));
if (!new_conflicts || !tree_conflicted)
{
*did_resolve = TRUE;
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
&src_op_root_abspath,
db, local_abspath,
new_conflicts,
scratch_pool,
scratch_pool));
if (reason != svn_wc_conflict_reason_moved_away)
{
*did_resolve = TRUE;
return SVN_NO_ERROR;
}
conflicts = new_conflicts;
}
else
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL,
_("Tree conflict can only be resolved to "
"'working' or 'mine-conflict' state; "
"'%s' not resolved"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
if (reason == svn_wc_conflict_reason_moved_away
&& action == svn_wc_conflict_action_edit)
{
if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
{
err = svn_wc__db_update_moved_away_conflict_victim(
db, local_abspath, src_op_root_abspath,
operation, action, reason,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool);
if (err)
SVN_ERR(handle_tree_conflict_resolution_failure(
local_abspath, err, resolve_later));
else
*did_resolve = TRUE;
}
else if (conflict_choice == svn_wc_conflict_choose_merged)
{
SVN_ERR(svn_wc__db_op_break_moved_away(db, local_abspath,
src_op_root_abspath, TRUE,
notify_func, notify_baton,
scratch_pool));
*did_resolve = TRUE;
return SVN_NO_ERROR;
}
else
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL,
_("Tree conflict can only be resolved to "
"'working' or 'mine-conflict' state; "
"'%s' not resolved"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
else if (reason == svn_wc_conflict_reason_moved_away
&& action != svn_wc_conflict_action_edit)
{
SVN_ERR_ASSERT(action == svn_wc_conflict_action_delete
|| action == svn_wc_conflict_action_replace);
if (conflict_choice == svn_wc_conflict_choose_merged)
{
*did_resolve = TRUE;
}
else if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
{
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL,
_("Tree conflict can only be "
"resolved to 'working' state; "
"'%s' is no longer moved"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
}
}
if (! *did_resolve)
{
if (conflict_choice != svn_wc_conflict_choose_merged)
{
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL,
_("Tree conflict can only be "
"resolved to 'working' state; "
"'%s' not resolved"),
svn_dirent_local_style(local_abspath,
scratch_pool));
}
else
*did_resolve = TRUE;
}
SVN_ERR_ASSERT(*did_resolve);
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, FALSE, TRUE,
NULL, scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__mark_resolved_text_conflict(svn_wc__db_t *db,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_skel_t *work_items;
svn_skel_t *conflict;
SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
if (!conflict)
return SVN_NO_ERROR;
SVN_ERR(build_text_conflict_resolve_items(&work_items, NULL,
db, local_abspath, conflict,
svn_wc_conflict_choose_merged,
NULL, FALSE, NULL,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, TRUE, FALSE, FALSE,
work_items, scratch_pool));
return svn_error_trace(svn_wc__wq_run(db, local_abspath,
cancel_func, cancel_baton,
scratch_pool));
}
svn_error_t *
svn_wc__mark_resolved_prop_conflicts(svn_wc__db_t *db,
const char *local_abspath,
apr_pool_t *scratch_pool)
{
svn_boolean_t ignored_result;
svn_skel_t *conflicts;
SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
if (!conflicts)
return SVN_NO_ERROR;
return svn_error_trace(resolve_prop_conflict_on_node(
&ignored_result,
db, local_abspath, conflicts, "",
svn_wc_conflict_choose_merged,
NULL, NULL,
NULL, NULL,
scratch_pool));
}
struct conflict_status_walker_baton
{
svn_wc__db_t *db;
svn_boolean_t resolve_text;
const char *resolve_prop;
svn_boolean_t resolve_tree;
svn_wc_conflict_choice_t conflict_choice;
svn_wc_conflict_resolver_func2_t conflict_func;
void *conflict_baton;
svn_cancel_func_t cancel_func;
void *cancel_baton;
svn_wc_notify_func2_t notify_func;
void *notify_baton;
svn_boolean_t resolved_one;
apr_hash_t *resolve_later;
};
static void
tree_conflict_collector(void *baton,
const svn_wc_notify_t *notify,
apr_pool_t *pool)
{
struct conflict_status_walker_baton *cswb = baton;
if (cswb->notify_func)
cswb->notify_func(cswb->notify_baton, notify, pool);
if (cswb->resolve_later
&& (notify->action == svn_wc_notify_tree_conflict
|| notify->prop_state == svn_wc_notify_state_conflicted
|| notify->content_state == svn_wc_notify_state_conflicted))
{
if (!svn_hash_gets(cswb->resolve_later, notify->path))
{
const char *dup_path;
dup_path = apr_pstrdup(apr_hash_pool_get(cswb->resolve_later),
notify->path);
svn_hash_sets(cswb->resolve_later, dup_path, dup_path);
}
}
}
static svn_error_t *
conflict_status_walker(void *baton,
const char *local_abspath,
const svn_wc_status3_t *status,
apr_pool_t *scratch_pool)
{
struct conflict_status_walker_baton *cswb = baton;
svn_wc__db_t *db = cswb->db;
svn_wc_notify_action_t notify_action = svn_wc_notify_resolved;
const apr_array_header_t *conflicts;
apr_pool_t *iterpool;
int i;
svn_boolean_t resolved = FALSE;
svn_skel_t *conflict;
const svn_wc_conflict_description2_t *cd;
if (!status->conflicted)
return SVN_NO_ERROR;
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict,
db, local_abspath,
(cswb->conflict_func != NULL) ,
FALSE ,
scratch_pool, iterpool));
for (i = 0; i < conflicts->nelts; i++)
{
svn_boolean_t did_resolve;
svn_wc_conflict_choice_t my_choice = cswb->conflict_choice;
svn_wc_conflict_result_t *result = NULL;
svn_skel_t *work_items;
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
if ((cd->kind == svn_wc_conflict_kind_property
&& (!cswb->resolve_prop
|| (*cswb->resolve_prop != '\0'
&& strcmp(cswb->resolve_prop, cd->property_name) != 0)))
|| (cd->kind == svn_wc_conflict_kind_text && !cswb->resolve_text)
|| (cd->kind == svn_wc_conflict_kind_tree && !cswb->resolve_tree))
{
continue;
}
svn_pool_clear(iterpool);
if (my_choice == svn_wc_conflict_choose_unspecified)
{
if (!cswb->conflict_func)
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("No conflict-callback and no "
"pre-defined conflict-choice provided"));
SVN_ERR(cswb->conflict_func(&result, cd, cswb->conflict_baton,
iterpool, iterpool));
my_choice = result->choice;
}
if (my_choice == svn_wc_conflict_choose_postpone)
continue;
switch (cd->kind)
{
case svn_wc_conflict_kind_tree:
SVN_ERR(resolve_tree_conflict_on_node(&did_resolve,
db,
local_abspath, conflict,
my_choice,
cswb->resolve_later,
tree_conflict_collector,
cswb,
cswb->cancel_func,
cswb->cancel_baton,
iterpool));
if (did_resolve)
{
resolved = TRUE;
notify_action = svn_wc_notify_resolved_tree;
}
break;
case svn_wc_conflict_kind_text:
SVN_ERR(build_text_conflict_resolve_items(
&work_items,
&resolved,
db, local_abspath, conflict,
my_choice,
result ? result->merged_file
: NULL,
result ? result->save_merged
: FALSE,
NULL ,
cswb->cancel_func,
cswb->cancel_baton,
iterpool, iterpool));
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
TRUE, FALSE, FALSE,
work_items, iterpool));
SVN_ERR(svn_wc__wq_run(db, local_abspath,
cswb->cancel_func, cswb->cancel_baton,
iterpool));
if (resolved)
notify_action = svn_wc_notify_resolved_text;
break;
case svn_wc_conflict_kind_property:
SVN_ERR(resolve_prop_conflict_on_node(&did_resolve,
db,
local_abspath,
conflict,
cd->property_name,
my_choice,
result
? result->merged_file
: NULL,
result
? result->merged_value
: NULL,
cswb->cancel_func,
cswb->cancel_baton,
iterpool));
if (did_resolve)
{
resolved = TRUE;
notify_action = svn_wc_notify_resolved_prop;
}
break;
default:
break;
}
}
if (cswb->notify_func && resolved)
{
svn_wc_notify_t *notify;
if (cswb->resolve_text && cswb->resolve_tree &&
(cswb->resolve_prop == NULL || cswb->resolve_prop[0] == '\0'))
notify_action = svn_wc_notify_resolved;
if (notify_action == svn_wc_notify_resolved_prop &&
(cswb->resolve_prop == NULL || cswb->resolve_prop[0] == '\0'))
notify_action = svn_wc_notify_resolved;
notify = svn_wc_create_notify(local_abspath, notify_action, iterpool);
if (notify_action == svn_wc_notify_resolved_prop)
{
notify->prop_name = cd->property_name;
SVN_ERR_ASSERT(strlen(notify->prop_name) > 0);
}
cswb->notify_func(cswb->notify_baton, notify, iterpool);
}
if (resolved)
cswb->resolved_one = TRUE;
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t resolve_text,
const char *resolve_prop,
svn_boolean_t resolve_tree,
svn_wc_conflict_choice_t conflict_choice,
svn_wc_conflict_resolver_func2_t conflict_func,
void *conflict_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
struct conflict_status_walker_baton cswb;
apr_pool_t *iterpool = NULL;
svn_error_t *err;
if (depth == svn_depth_unknown)
depth = svn_depth_infinity;
cswb.db = wc_ctx->db;
cswb.resolve_text = resolve_text;
cswb.resolve_prop = resolve_prop;
cswb.resolve_tree = resolve_tree;
cswb.conflict_choice = conflict_choice;
cswb.conflict_func = conflict_func;
cswb.conflict_baton = conflict_baton;
cswb.cancel_func = cancel_func;
cswb.cancel_baton = cancel_baton;
cswb.notify_func = notify_func;
cswb.notify_baton = notify_baton;
cswb.resolved_one = FALSE;
cswb.resolve_later = (depth != svn_depth_empty)
? apr_hash_make(scratch_pool)
: NULL;
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_conflict_resolver_starting,
scratch_pool),
scratch_pool);
err = svn_wc_walk_status(wc_ctx,
local_abspath,
depth,
FALSE ,
FALSE ,
TRUE ,
NULL ,
conflict_status_walker, &cswb,
cancel_func, cancel_baton,
scratch_pool);
while (!err && cswb.resolve_later && apr_hash_count(cswb.resolve_later))
{
apr_hash_index_t *hi;
svn_wc_status3_t *status = NULL;
const char *tc_abspath = NULL;
if (iterpool)
svn_pool_clear(iterpool);
else
iterpool = svn_pool_create(scratch_pool);
hi = apr_hash_first(scratch_pool, cswb.resolve_later);
cswb.resolve_later = apr_hash_make(scratch_pool);
cswb.resolved_one = FALSE;
for (; hi && !err; hi = apr_hash_next(hi))
{
const char *relpath;
svn_pool_clear(iterpool);
tc_abspath = apr_hash_this_key(hi);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
relpath = svn_dirent_skip_ancestor(local_abspath,
tc_abspath);
if (!relpath
|| (depth >= svn_depth_empty
&& depth < svn_depth_infinity
&& strchr(relpath, '/')))
{
continue;
}
SVN_ERR(svn_wc_status3(&status, wc_ctx, tc_abspath,
iterpool, iterpool));
if (depth == svn_depth_files
&& status->kind == svn_node_dir)
continue;
err = svn_error_trace(conflict_status_walker(&cswb, tc_abspath,
status, scratch_pool));
}
if (!cswb.resolved_one && !err && tc_abspath
&& apr_hash_count(cswb.resolve_later))
{
cswb.resolve_later = NULL;
err = svn_error_trace(conflict_status_walker(&cswb, tc_abspath,
status, scratch_pool));
SVN_ERR_ASSERT(err != NULL);
err = svn_error_createf(
SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
_("Unable to resolve pending conflict on '%s'"),
svn_dirent_local_style(tc_abspath, scratch_pool));
break;
}
}
if (iterpool)
svn_pool_destroy(iterpool);
if (err && err->apr_err != SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE)
err = svn_error_createf(
SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
_("Unable to resolve conflicts on '%s'"),
svn_dirent_local_style(local_abspath, scratch_pool));
SVN_ERR(err);
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_conflict_resolver_done,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc_resolved_conflict5(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t resolve_text,
const char *resolve_prop,
svn_boolean_t resolve_tree,
svn_wc_conflict_choice_t conflict_choice,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
return svn_error_trace(svn_wc__resolve_conflicts(wc_ctx, local_abspath,
depth, resolve_text,
resolve_prop, resolve_tree,
conflict_choice,
NULL, NULL,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
}
svn_wc_conflict_result_t *
svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice,
const char *merged_file,
apr_pool_t *pool)
{
svn_wc_conflict_result_t *result = apr_pcalloc(pool, sizeof(*result));
result->choice = choice;
result->merged_file = apr_pstrdup(pool, merged_file);
result->save_merged = FALSE;
result->merged_value = NULL;
return result;
}
svn_error_t *
svn_wc__conflict_text_mark_resolved(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_wc_conflict_choice_t choice,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_skel_t *work_items;
svn_skel_t *conflict;
svn_boolean_t did_resolve;
SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
wc_ctx->db, local_abspath,
scratch_pool, scratch_pool));
if (!conflict)
return SVN_NO_ERROR;
SVN_ERR(build_text_conflict_resolve_items(&work_items, &did_resolve,
wc_ctx->db, local_abspath,
conflict, choice,
NULL, FALSE, NULL,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath,
TRUE, FALSE, FALSE,
work_items, scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
cancel_func, cancel_baton,
scratch_pool));
if (did_resolve && notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_text,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_prop_mark_resolved(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *propname,
svn_wc_conflict_choice_t choice,
const svn_string_t *merged_value,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_boolean_t did_resolve;
svn_skel_t *conflicts;
SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
wc_ctx->db, local_abspath,
scratch_pool, scratch_pool));
if (!conflicts)
return SVN_NO_ERROR;
SVN_ERR(resolve_prop_conflict_on_node(&did_resolve, wc_ctx->db,
local_abspath, conflicts,
propname, choice, NULL, merged_value,
NULL, NULL, scratch_pool));
if (did_resolve && notify_func)
{
svn_wc_notify_t *notify;
if (propname == NULL || propname[0] == '\0')
{
notify = svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved,
scratch_pool);
}
else
{
notify = svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_prop,
scratch_pool);
notify->prop_name = propname;
}
notify_func(notify_baton, notify, scratch_pool);
}
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_tree_update_break_moved_away(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const char *src_op_root_abspath;
const apr_array_header_t *conflicts;
svn_skel_t *conflict_skel;
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel,
wc_ctx->db, local_abspath,
FALSE,
FALSE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, wc_ctx->db,
local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
&src_op_root_abspath,
wc_ctx->db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation != svn_wc_operation_update &&
operation != svn_wc_operation_switch)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict operation '%s' on '%s'"),
svn_token__to_word(operation_map, operation),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (reason != svn_wc_conflict_reason_deleted &&
reason != svn_wc_conflict_reason_replaced &&
reason != svn_wc_conflict_reason_moved_away)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict reason '%s' on '%s'"),
svn_token__to_word(reason_map, reason),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (action != svn_wc_conflict_action_delete)
{
SVN_ERR(svn_wc__db_op_break_moved_away(
wc_ctx->db, local_abspath, src_op_root_abspath, TRUE,
notify_func, notify_baton, scratch_pool));
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_tree,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath,
FALSE, FALSE, TRUE,
NULL, scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_tree,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_tree_update_raise_moved_away(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const apr_array_header_t *conflicts;
svn_skel_t *conflict_skel;
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel,
wc_ctx->db, local_abspath,
FALSE,
FALSE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, wc_ctx->db,
local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL,
wc_ctx->db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation != svn_wc_operation_update &&
operation != svn_wc_operation_switch)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict operation '%s' on '%s'"),
svn_token__to_word(operation_map, operation),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (reason != svn_wc_conflict_reason_deleted &&
reason != svn_wc_conflict_reason_replaced)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict reason '%s' on '%s'"),
svn_token__to_word(reason_map, reason),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (action != svn_wc_conflict_action_edit)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict action '%s' on '%s'"),
svn_token__to_word(action_map, action),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_wc__db_op_raise_moved_away(wc_ctx->db, local_abspath,
notify_func, notify_baton,
scratch_pool));
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_tree,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_tree_update_moved_away_node(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const char *src_op_root_abspath;
const apr_array_header_t *conflicts;
svn_skel_t *conflict_skel;
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel,
wc_ctx->db, local_abspath,
FALSE,
FALSE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, wc_ctx->db,
local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
&src_op_root_abspath,
wc_ctx->db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation != svn_wc_operation_update &&
operation != svn_wc_operation_switch)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict operation '%s' on '%s'"),
svn_token__to_word(operation_map, operation),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (reason != svn_wc_conflict_reason_moved_away)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict reason '%s' on '%s'"),
svn_token__to_word(reason_map, reason),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (action != svn_wc_conflict_action_edit)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict action '%s' on '%s'"),
svn_token__to_word(action_map, action),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(wc_ctx->db,
local_abspath,
src_op_root_abspath,
operation,
action,
reason,
cancel_func,
cancel_baton,
notify_func,
notify_baton,
scratch_pool));
SVN_ERR(svn_wc__db_op_mark_resolved(wc_ctx->db, local_abspath,
FALSE, FALSE, TRUE,
NULL, scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
svn_wc_notify_resolved_tree,
scratch_pool),
scratch_pool);
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_tree_update_incoming_move(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const char *dest_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t local_change;
svn_wc_conflict_action_t incoming_change;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const apr_array_header_t *conflicts;
svn_skel_t *conflict_skel;
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel,
wc_ctx->db, local_abspath,
FALSE,
FALSE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, wc_ctx->db,
local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change,
NULL, wc_ctx->db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation != svn_wc_operation_update &&
operation != svn_wc_operation_switch &&
operation != svn_wc_operation_merge)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict operation '%s' on '%s'"),
svn_token__to_word(operation_map, operation),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (local_change != svn_wc_conflict_reason_edited)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict reason '%s' on '%s'"),
svn_token__to_word(reason_map, local_change),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (incoming_change != svn_wc_conflict_action_delete)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict action '%s' on '%s'"),
svn_token__to_word(action_map, incoming_change),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_wc__db_update_incoming_move(wc_ctx->db, local_abspath,
dest_abspath, operation,
incoming_change, local_change,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__conflict_tree_update_local_add(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_reason_t local_change;
svn_wc_conflict_action_t incoming_change;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
const apr_array_header_t *conflicts;
svn_skel_t *conflict_skel;
SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict_skel,
wc_ctx->db, local_abspath,
FALSE,
FALSE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, wc_ctx->db,
local_abspath, conflict_skel,
scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change, &incoming_change,
NULL, wc_ctx->db, local_abspath,
conflict_skel,
scratch_pool, scratch_pool));
if (operation != svn_wc_operation_update)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict operation '%s' on '%s'"),
svn_token__to_word(operation_map, operation),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (local_change != svn_wc_conflict_reason_added)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict reason '%s' on '%s'"),
svn_token__to_word(reason_map, local_change),
svn_dirent_local_style(local_abspath,
scratch_pool));
if (incoming_change != svn_wc_conflict_action_add)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("Unexpected conflict action '%s' on '%s'"),
svn_token__to_word(action_map, incoming_change),
svn_dirent_local_style(local_abspath,
scratch_pool));
SVN_ERR(svn_wc__db_update_local_add(wc_ctx->db, local_abspath,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
return SVN_NO_ERROR;
}
svn_error_t *
svn_wc__guess_incoming_move_target_nodes(apr_array_header_t **possible_targets,
svn_wc_context_t *wc_ctx,
const char *victim_abspath,
svn_node_kind_t victim_node_kind,
const char *moved_to_repos_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
apr_array_header_t *candidates;
apr_pool_t *iterpool;
int i;
apr_size_t longest_ancestor_len = 0;
*possible_targets = apr_array_make(result_pool, 1, sizeof(const char *));
SVN_ERR(svn_wc__find_repos_node_in_wc(&candidates, wc_ctx->db, victim_abspath,
moved_to_repos_relpath,
scratch_pool, scratch_pool));
iterpool = svn_pool_create(scratch_pool);
for (i = 0; i < candidates->nelts; i++)
{
const char *local_abspath;
const char *ancestor_abspath;
apr_size_t ancestor_len;
svn_boolean_t tree_conflicted;
svn_wc__db_status_t status;
svn_boolean_t is_wcroot;
svn_boolean_t is_switched;
svn_node_kind_t node_kind;
const char *moved_to_abspath;
int insert_index;
svn_pool_clear(iterpool);
local_abspath = APR_ARRAY_IDX(candidates, i, const char *);
SVN_ERR(svn_wc__internal_conflicted_p(NULL, NULL, &tree_conflicted,
wc_ctx->db, local_abspath,
iterpool));
if (tree_conflicted)
continue;
SVN_ERR(svn_wc__db_read_info(&status, &node_kind,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
wc_ctx->db, local_abspath, iterpool,
iterpool));
if (status != svn_wc__db_status_normal &&
status != svn_wc__db_status_added)
continue;
if (node_kind != victim_node_kind)
continue;
SVN_ERR(svn_wc__db_is_switched(&is_wcroot, &is_switched, NULL,
wc_ctx->db, local_abspath, iterpool));
if (is_wcroot || is_switched)
continue;
moved_to_abspath = apr_pstrdup(result_pool, local_abspath);
ancestor_abspath = svn_dirent_get_longest_ancestor(local_abspath,
victim_abspath,
iterpool);
ancestor_len = strlen(ancestor_abspath);
if (ancestor_len >= longest_ancestor_len)
{
longest_ancestor_len = ancestor_len;
insert_index = 0;
}
else
{
insert_index = (*possible_targets)->nelts;
}
svn_sort__array_insert(*possible_targets, &moved_to_abspath,
insert_index);
}
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
}