summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/wc_db_update_move.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/wc_db_update_move.c')
-rw-r--r--subversion/libsvn_wc/wc_db_update_move.c2828
1 files changed, 1423 insertions, 1405 deletions
diff --git a/subversion/libsvn_wc/wc_db_update_move.c b/subversion/libsvn_wc/wc_db_update_move.c
index 7f4f853..46cbeae 100644
--- a/subversion/libsvn_wc/wc_db_update_move.c
+++ b/subversion/libsvn_wc/wc_db_update_move.c
@@ -46,7 +46,7 @@
* layer. The destination may have additional higher op-depths
* representing adds, deletes, moves within the move destination. [2]
*
- * After the intial move an update has modified the NODES in the move
+ * After the initial move an update has modified the NODES in the move
* source and may have introduced a tree-conflict since the source and
* destination trees are no longer equivalent. The source is a
* different revision and may have text, property and tree changes
@@ -88,9 +88,9 @@
#include "svn_sorts.h"
#include "private/svn_skel.h"
+#include "private/svn_sorts_private.h"
#include "private/svn_sqlite.h"
#include "private/svn_wc_private.h"
-#include "private/svn_editor.h"
#include "wc.h"
#include "props.h"
@@ -100,6 +100,80 @@
#include "workqueue.h"
#include "token-map.h"
+/* Helper functions */
+/* Return the absolute path, in local path style, of LOCAL_RELPATH
+ in WCROOT. */
+static const char *
+path_for_error_message(const svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *result_pool)
+{
+ const char *local_abspath
+ = svn_dirent_join(wcroot->abspath, local_relpath, result_pool);
+
+ return svn_dirent_local_style(local_abspath, result_pool);
+}
+
+/* Ensure that there is a working copy lock for LOCAL_RELPATH in WCROOT */
+static svn_error_t *
+verify_write_lock(svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ svn_boolean_t locked;
+
+ SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot, local_relpath,
+ FALSE, scratch_pool));
+ if (!locked)
+ {
+ return svn_error_createf(SVN_ERR_WC_NOT_LOCKED, NULL,
+ _("No write-lock in '%s'"),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* In our merge conflicts we record the move_op_src path, which is essentially
+ the depth at which what was moved is marked deleted. The problem is that
+ this depth is not guaranteed to be stable, because somebody might just
+ remove another ancestor, or revert one.
+
+ To work around this problem we locate the layer below this path, and use
+ that to pinpoint whatever is moved.
+
+ For a path SRC_RELPATH that was deleted by an operation rooted at
+ DELETE_OP_DEPTH find the op-depth at which the node was originally added.
+ */
+static svn_error_t *
+find_src_op_depth(int *src_op_depth,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *src_relpath,
+ int delete_op_depth,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_HIGHEST_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ src_relpath, delete_op_depth));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ *src_op_depth = svn_sqlite__column_int(stmt, 0);
+ SVN_ERR(svn_sqlite__reset(stmt));
+ if (!have_row)
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("'%s' is not deleted"),
+ path_for_error_message(wcroot, src_relpath,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/*
* Receiver code.
*
@@ -113,20 +187,34 @@
* be made at the move destination.
*/
-struct tc_editor_baton {
+typedef struct update_move_baton_t {
svn_wc__db_t *db;
svn_wc__db_wcroot_t *wcroot;
- const char *move_root_dst_relpath;
- /* The most recent conflict raised during this drive. We rely on the
- non-Ev2, depth-first, drive for this to make sense. */
- const char *conflict_root_relpath;
+ int src_op_depth;
+ int dst_op_depth;
svn_wc_operation_t operation;
svn_wc_conflict_version_t *old_version;
svn_wc_conflict_version_t *new_version;
- apr_pool_t *result_pool; /* For things that live as long as the baton. */
-};
+
+ svn_cancel_func_t cancel_func;
+ void *cancel_baton;
+} update_move_baton_t;
+
+/* Per node flags for tree conflict collection */
+typedef struct node_move_baton_t
+{
+ svn_boolean_t skip;
+ svn_boolean_t shadowed;
+ svn_boolean_t edited;
+
+ const char *src_relpath;
+ const char *dst_relpath;
+
+ update_move_baton_t *umb;
+ struct node_move_baton_t *pb;
+} node_move_baton_t;
/*
* Notifications are delayed until the entire update-move transaction
@@ -135,24 +223,52 @@ struct tc_editor_baton {
* and spooling notifications out of that table after the transaction.
*/
-/* Add an entry to the notification list. */
+/* Add an entry to the notification list, and at the same time install
+ a conflict and/or work items. */
static svn_error_t *
update_move_list_add(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
+ svn_wc__db_t *db,
svn_wc_notify_action_t action,
svn_node_kind_t kind,
svn_wc_notify_state_t content_state,
- svn_wc_notify_state_t prop_state)
-
+ svn_wc_notify_state_t prop_state,
+ svn_skel_t *conflict,
+ svn_skel_t *work_item,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
+ if (conflict)
+ {
+ svn_boolean_t tree_conflict;
+
+ SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, NULL,
+ &tree_conflict,
+ db, wcroot->abspath, conflict,
+ scratch_pool, scratch_pool));
+ if (tree_conflict)
+ {
+ action = svn_wc_notify_tree_conflict;
+ content_state = svn_wc_notify_state_inapplicable;
+ prop_state = svn_wc_notify_state_inapplicable;
+ }
+ }
+
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_INSERT_UPDATE_MOVE_LIST));
- SVN_ERR(svn_sqlite__bindf(stmt, "sdddd", local_relpath,
- action, kind, content_state, prop_state));
+ SVN_ERR(svn_sqlite__bindf(stmt, "sdtdd", local_relpath,
+ action, kind_map_none, kind,
+ content_state, prop_state));
SVN_ERR(svn_sqlite__step_done(stmt));
+ if (conflict)
+ SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath, conflict,
+ scratch_pool));
+
+ if (work_item)
+ SVN_ERR(svn_wc__db_wq_add_internal(wcroot, work_item, scratch_pool));
+
return SVN_NO_ERROR;
}
@@ -192,7 +308,7 @@ svn_wc__db_update_move_list_notify(svn_wc__db_wcroot_t *wcroot,
local_relpath,
iterpool),
action, iterpool);
- notify->kind = svn_sqlite__column_int(stmt, 2);
+ notify->kind = svn_sqlite__column_token(stmt, 2, kind_map_none);
notify->content_state = svn_sqlite__column_int(stmt, 3);
notify->prop_state = svn_sqlite__column_int(stmt, 4);
notify->old_revision = old_revision;
@@ -212,23 +328,25 @@ svn_wc__db_update_move_list_notify(svn_wc__db_wcroot_t *wcroot,
return SVN_NO_ERROR;
}
-/* Mark a tree-conflict on LOCAL_RELPATH if such a tree-conflict does
- not already exist. */
+/* Create a tree-conflict for recording on LOCAL_RELPATH if such
+ a tree-conflict does not already exist. */
static svn_error_t *
-mark_tree_conflict(const char *local_relpath,
- svn_wc__db_wcroot_t *wcroot,
- svn_wc__db_t *db,
- const svn_wc_conflict_version_t *old_version,
- const svn_wc_conflict_version_t *new_version,
- const char *move_root_dst_relpath,
- svn_wc_operation_t operation,
- svn_node_kind_t old_kind,
- svn_node_kind_t new_kind,
- const char *old_repos_relpath,
- svn_wc_conflict_reason_t reason,
- svn_wc_conflict_action_t action,
- const char *move_src_op_root_relpath,
- apr_pool_t *scratch_pool)
+create_tree_conflict(svn_skel_t **conflict_p,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ const char *dst_op_root_relpath,
+ svn_wc__db_t *db,
+ const svn_wc_conflict_version_t *old_version,
+ const svn_wc_conflict_version_t *new_version,
+ svn_wc_operation_t operation,
+ svn_node_kind_t old_kind,
+ svn_node_kind_t new_kind,
+ const char *old_repos_relpath,
+ svn_wc_conflict_reason_t reason,
+ svn_wc_conflict_action_t action,
+ const char *move_src_op_root_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_error_t *err;
svn_skel_t *conflict;
@@ -250,14 +368,18 @@ mark_tree_conflict(const char *local_relpath,
: NULL;
if (!new_repos_relpath)
- new_repos_relpath
- = svn_relpath_join(new_version->path_in_repos,
- svn_relpath_skip_ancestor(move_root_dst_relpath,
- local_relpath),
- scratch_pool);
-
- err = svn_wc__db_read_conflict_internal(&conflict, wcroot, local_relpath,
- scratch_pool, scratch_pool);
+ {
+ const char *child_relpath = svn_relpath_skip_ancestor(
+ dst_op_root_relpath,
+ local_relpath);
+ SVN_ERR_ASSERT(child_relpath != NULL);
+ new_repos_relpath = svn_relpath_join(new_version->path_in_repos,
+ child_relpath, scratch_pool);
+ }
+
+ err = svn_wc__db_read_conflict_internal(&conflict, NULL, NULL,
+ wcroot, local_relpath,
+ result_pool, scratch_pool);
if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
else if (err)
@@ -280,7 +402,7 @@ mark_tree_conflict(const char *local_relpath,
&& conflict_operation != svn_wc_operation_switch)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("'%s' already in conflict"),
- svn_dirent_local_style(local_relpath,
+ path_for_error_message(wcroot, local_relpath,
scratch_pool));
if (tree_conflicted)
@@ -302,17 +424,19 @@ mark_tree_conflict(const char *local_relpath,
&& strcmp(move_src_op_root_relpath,
svn_dirent_skip_ancestor(wcroot->abspath,
existing_abspath))))
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ return svn_error_createf(SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
_("'%s' already in conflict"),
- svn_dirent_local_style(local_relpath,
+ path_for_error_message(wcroot,
+ local_relpath,
scratch_pool));
/* Already a suitable tree-conflict. */
+ *conflict_p = conflict;
return SVN_NO_ERROR;
}
}
else
- conflict = svn_wc__conflict_skel_create(scratch_pool);
+ conflict = svn_wc__conflict_skel_create(result_pool);
SVN_ERR(svn_wc__conflict_skel_add_tree_conflict(
conflict, db,
@@ -321,19 +445,13 @@ mark_tree_conflict(const char *local_relpath,
reason,
action,
move_src_op_root_abspath,
- scratch_pool,
+ result_pool,
scratch_pool));
- if (reason != svn_wc_conflict_reason_unversioned
- && old_repos_relpath != NULL /* no local additions */)
- {
- conflict_old_version = svn_wc_conflict_version_create2(
+ conflict_old_version = svn_wc_conflict_version_create2(
old_version->repos_url, old_version->repos_uuid,
old_repos_relpath, old_version->peg_rev,
old_kind, scratch_pool);
- }
- else
- conflict_old_version = NULL;
conflict_new_version = svn_wc_conflict_version_create2(
new_version->repos_url, new_version->repos_uuid,
@@ -344,312 +462,368 @@ mark_tree_conflict(const char *local_relpath,
{
SVN_ERR(svn_wc__conflict_skel_set_op_update(
conflict, conflict_old_version, conflict_new_version,
- scratch_pool, scratch_pool));
+ result_pool, scratch_pool));
}
else
{
assert(operation == svn_wc_operation_switch);
SVN_ERR(svn_wc__conflict_skel_set_op_switch(
conflict, conflict_old_version, conflict_new_version,
- scratch_pool, scratch_pool));
+ result_pool, scratch_pool));
}
- SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
- conflict, scratch_pool));
-
- SVN_ERR(update_move_list_add(wcroot, local_relpath,
- svn_wc_notify_tree_conflict,
- new_kind,
- svn_wc_notify_state_inapplicable,
- svn_wc_notify_state_inapplicable));
+ *conflict_p = conflict;
return SVN_NO_ERROR;
}
-/* If LOCAL_RELPATH is a child of the most recently raised
- tree-conflict or is shadowed then set *IS_CONFLICTED to TRUE and
- raise a tree-conflict on the root of the obstruction if such a
- tree-conflict does not already exist. KIND is the kind of the
- incoming LOCAL_RELPATH. This relies on the non-Ev2, depth-first,
- drive. */
static svn_error_t *
-check_tree_conflict(svn_boolean_t *is_conflicted,
- struct tc_editor_baton *b,
+create_node_tree_conflict(svn_skel_t **conflict_p,
+ node_move_baton_t *nmb,
+ const char *dst_local_relpath,
+ svn_node_kind_t old_kind,
+ svn_node_kind_t new_kind,
+ svn_wc_conflict_reason_t reason,
+ svn_wc_conflict_action_t action,
+ const char *move_src_op_root_relpath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ update_move_baton_t *umb = nmb->umb;
+ const char *dst_repos_relpath;
+ const char *dst_root_relpath = svn_relpath_prefix(nmb->dst_relpath,
+ nmb->umb->dst_op_depth,
+ scratch_pool);
+
+ dst_repos_relpath =
+ svn_relpath_join(nmb->umb->old_version->path_in_repos,
+ svn_relpath_skip_ancestor(dst_root_relpath,
+ nmb->dst_relpath),
+ scratch_pool);
+
+
+
+ return svn_error_trace(
+ create_tree_conflict(conflict_p, umb->wcroot, dst_local_relpath,
+ svn_relpath_prefix(dst_local_relpath,
+ umb->dst_op_depth,
+ scratch_pool),
+ umb->db,
+ umb->old_version, umb->new_version,
+ umb->operation, old_kind, new_kind,
+ dst_repos_relpath,
+ reason, action, move_src_op_root_relpath,
+ result_pool, scratch_pool));
+}
+
+/* Checks if a specific local path is shadowed as seen from the move root.
+ Helper for update_moved_away_node() */
+static svn_error_t *
+check_node_shadowed(svn_boolean_t *shadowed,
+ svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
- svn_node_kind_t old_kind,
- svn_node_kind_t new_kind,
- const char *old_repos_relpath,
- svn_wc_conflict_action_t action,
+ int move_root_dst_op_depth,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- int dst_op_depth = relpath_depth(b->move_root_dst_relpath);
- int op_depth;
- const char *conflict_root_relpath = local_relpath;
- const char *move_dst_relpath, *dummy1;
- const char *dummy2, *move_src_op_root_relpath;
- if (b->conflict_root_relpath)
- {
- if (svn_relpath_skip_ancestor(b->conflict_root_relpath, local_relpath))
- {
- *is_conflicted = TRUE;
- return SVN_NO_ERROR;
- }
- b->conflict_root_relpath = NULL;
- }
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_WORKING_NODE));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_SELECT_LOWEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, local_relpath,
- dst_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
if (have_row)
- op_depth = svn_sqlite__column_int(stmt, 0);
+ {
+ int op_depth = svn_sqlite__column_int(stmt, 0);
+
+ *shadowed = (op_depth > move_root_dst_op_depth);
+ }
+ else
+ *shadowed = FALSE;
SVN_ERR(svn_sqlite__reset(stmt));
- if (!have_row)
+ return SVN_NO_ERROR;
+}
+
+/* Set a tree conflict for the shadowed node LOCAL_RELPATH, which is
+ the ROOT OF THE OBSTRUCTION if such a tree-conflict does not
+ already exist. KIND is the kind of the incoming LOCAL_RELPATH. */
+static svn_error_t *
+mark_tc_on_op_root(node_move_baton_t *nmb,
+ svn_node_kind_t old_kind,
+ svn_node_kind_t new_kind,
+ svn_wc_conflict_action_t action,
+ apr_pool_t *scratch_pool)
+{
+ update_move_baton_t *b = nmb->umb;
+ const char *move_dst_relpath;
+ svn_skel_t *conflict;
+
+ SVN_ERR_ASSERT(nmb->shadowed && !nmb->pb->shadowed);
+
+ nmb->skip = TRUE;
+
+ if (old_kind == svn_node_none)
+ move_dst_relpath = NULL;
+ else
+ SVN_ERR(svn_wc__db_scan_moved_to_internal(NULL, &move_dst_relpath, NULL,
+ b->wcroot, nmb->dst_relpath,
+ b->dst_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(create_node_tree_conflict(&conflict, nmb, nmb->dst_relpath,
+ old_kind, new_kind,
+ (move_dst_relpath
+ ? svn_wc_conflict_reason_moved_away
+ : svn_wc_conflict_reason_deleted),
+ action, move_dst_relpath
+ ? nmb->dst_relpath
+ : NULL,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(update_move_list_add(b->wcroot, nmb->dst_relpath, b->db,
+ svn_wc_notify_tree_conflict,
+ new_kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ conflict, NULL, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+mark_node_edited(node_move_baton_t *nmb,
+ apr_pool_t *scratch_pool)
+{
+ if (nmb->edited)
+ return SVN_NO_ERROR;
+
+ if (nmb->pb)
{
- *is_conflicted = FALSE;
- return SVN_NO_ERROR;
+ SVN_ERR(mark_node_edited(nmb->pb, scratch_pool));
+
+ if (nmb->pb->skip)
+ nmb->skip = TRUE;
}
- *is_conflicted = TRUE;
+ nmb->edited = TRUE;
- while (relpath_depth(conflict_root_relpath) > op_depth)
+ if (nmb->skip)
+ return SVN_NO_ERROR;
+
+ if (nmb->shadowed && !(nmb->pb && nmb->pb->shadowed))
{
- conflict_root_relpath = svn_relpath_dirname(conflict_root_relpath,
- scratch_pool);
- old_kind = new_kind = svn_node_dir;
- if (old_repos_relpath)
- old_repos_relpath = svn_relpath_dirname(old_repos_relpath,
- scratch_pool);
- action = svn_wc_conflict_action_edit;
+ svn_node_kind_t dst_kind, src_kind;
+
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, &dst_kind, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ nmb->umb->wcroot, nmb->dst_relpath,
+ nmb->umb->dst_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, &src_kind, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ nmb->umb->wcroot, nmb->src_relpath,
+ nmb->umb->src_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(mark_tc_on_op_root(nmb,
+ dst_kind, src_kind,
+ svn_wc_conflict_action_edit,
+ scratch_pool));
}
- SVN_ERR(svn_wc__db_op_depth_moved_to(&move_dst_relpath,
- &dummy1,
- &dummy2,
- &move_src_op_root_relpath,
- dst_op_depth,
- b->wcroot, conflict_root_relpath,
- scratch_pool, scratch_pool));
-
- SVN_ERR(mark_tree_conflict(conflict_root_relpath,
- b->wcroot, b->db, b->old_version, b->new_version,
- b->move_root_dst_relpath, b->operation,
- old_kind, new_kind,
- old_repos_relpath,
- (move_dst_relpath
- ? svn_wc_conflict_reason_moved_away
- : svn_wc_conflict_reason_deleted),
- action, move_src_op_root_relpath,
- scratch_pool));
- b->conflict_root_relpath = apr_pstrdup(b->result_pool, conflict_root_relpath);
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+mark_parent_edited(node_move_baton_t *nmb,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR_ASSERT(nmb && nmb->pb);
+
+ SVN_ERR(mark_node_edited(nmb->pb, scratch_pool));
+
+ if (nmb->pb->skip)
+ nmb->skip = TRUE;
return SVN_NO_ERROR;
}
static svn_error_t *
-tc_editor_add_directory(void *baton,
+tc_editor_add_directory(node_move_baton_t *nmb,
const char *relpath,
- const apr_array_header_t *children,
+ svn_node_kind_t old_kind,
apr_hash_t *props,
- svn_revnum_t replaces_rev,
apr_pool_t *scratch_pool)
{
- struct tc_editor_baton *b = baton;
- int op_depth = relpath_depth(b->move_root_dst_relpath);
- const char *move_dst_repos_relpath;
- svn_node_kind_t move_dst_kind;
- svn_boolean_t is_conflicted;
- const char *abspath;
- svn_node_kind_t old_kind;
- svn_skel_t *work_item;
- svn_wc_notify_action_t action = svn_wc_notify_update_add;
- svn_error_t *err;
+ update_move_baton_t *b = nmb->umb;
+ const char *local_abspath;
+ svn_node_kind_t wc_kind;
+ svn_skel_t *work_item = NULL;
+ svn_skel_t *conflict = NULL;
+ svn_wc_conflict_reason_t reason = svn_wc_conflict_reason_unversioned;
+
+ SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+ if (nmb->skip)
+ return SVN_NO_ERROR;
- /* Update NODES, only the bits not covered by the later call to
- replace_moved_layer. */
- SVN_ERR(svn_wc__db_extend_parent_delete(b->wcroot, relpath, svn_node_dir,
- op_depth, scratch_pool));
-
- err = svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
- &move_dst_repos_relpath, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- b->wcroot, relpath,
- relpath_depth(b->move_root_dst_relpath),
- scratch_pool, scratch_pool);
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ if (nmb->shadowed)
{
- svn_error_clear(err);
- old_kind = svn_node_none;
- move_dst_repos_relpath = NULL;
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info_internal(&status, &wc_kind, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ b->wcroot, relpath,
+ scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_deleted)
+ reason = svn_wc_conflict_reason_deleted;
+ else if (status != svn_wc__db_status_added)
+ wc_kind = svn_node_none;
+ else if (old_kind == svn_node_none)
+ reason = svn_wc_conflict_reason_added;
+ else
+ reason = svn_wc_conflict_reason_replaced;
}
else
+ wc_kind = svn_node_none;
+
+ local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
+
+ if (wc_kind == svn_node_none)
{
- SVN_ERR(err);
- old_kind = move_dst_kind;
+ /* Check for unversioned tree-conflict */
+ SVN_ERR(svn_io_check_path(local_abspath, &wc_kind, scratch_pool));
}
- /* Check for NODES tree-conflict. */
- SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
- old_kind, svn_node_dir,
- move_dst_repos_relpath,
- svn_wc_conflict_action_add,
- scratch_pool));
- if (is_conflicted)
- return SVN_NO_ERROR;
+ if (!nmb->shadowed && wc_kind == old_kind)
+ wc_kind = svn_node_none; /* Node will be gone once we install */
- /* Check for unversioned tree-conflict */
- abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
- SVN_ERR(svn_io_check_path(abspath, &old_kind, scratch_pool));
-
- switch (old_kind)
+ if (wc_kind != svn_node_none
+ && (nmb->shadowed || wc_kind != old_kind)) /* replace */
{
- case svn_node_file:
- default:
- SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
- b->new_version, b->move_root_dst_relpath,
- b->operation, old_kind, svn_node_dir,
- move_dst_repos_relpath,
- svn_wc_conflict_reason_unversioned,
- svn_wc_conflict_action_add, NULL,
- scratch_pool));
- b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
- action = svn_wc_notify_tree_conflict;
- is_conflicted = TRUE;
- break;
-
- case svn_node_none:
- SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, abspath,
+ SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+ old_kind, svn_node_dir,
+ reason,
+ (old_kind == svn_node_none)
+ ? svn_wc_conflict_action_add
+ : svn_wc_conflict_action_replace,
+ NULL,
+ scratch_pool, scratch_pool));
+ nmb->skip = TRUE;
+ }
+ else
+ {
+ SVN_ERR(svn_wc__wq_build_dir_install(&work_item, b->db, local_abspath,
scratch_pool, scratch_pool));
-
- SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
- scratch_pool));
- /* Fall through */
- case svn_node_dir:
- break;
}
- if (!is_conflicted)
- SVN_ERR(update_move_list_add(b->wcroot, relpath,
- action,
- svn_node_dir,
- svn_wc_notify_state_inapplicable,
- svn_wc_notify_state_inapplicable));
+ SVN_ERR(update_move_list_add(b->wcroot, relpath, b->db,
+ (old_kind == svn_node_none)
+ ? svn_wc_notify_update_add
+ : svn_wc_notify_update_replace,
+ svn_node_dir,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ conflict, work_item, scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
-tc_editor_add_file(void *baton,
+tc_editor_add_file(node_move_baton_t *nmb,
const char *relpath,
+ svn_node_kind_t old_kind,
const svn_checksum_t *checksum,
- svn_stream_t *contents,
apr_hash_t *props,
- svn_revnum_t replaces_rev,
apr_pool_t *scratch_pool)
{
- struct tc_editor_baton *b = baton;
- int op_depth = relpath_depth(b->move_root_dst_relpath);
- const char *move_dst_repos_relpath;
- svn_node_kind_t move_dst_kind;
- svn_node_kind_t old_kind;
- svn_boolean_t is_conflicted;
- const char *abspath;
- svn_skel_t *work_item;
- svn_error_t *err;
+ update_move_baton_t *b = nmb->umb;
+ svn_wc_conflict_reason_t reason = svn_wc_conflict_reason_unversioned;
+ svn_node_kind_t wc_kind;
+ const char *local_abspath;
+ svn_skel_t *work_item = NULL;
+ svn_skel_t *conflict = NULL;
+
+ SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+ if (nmb->skip)
+ return SVN_NO_ERROR;
- /* Update NODES, only the bits not covered by the later call to
- replace_moved_layer. */
- SVN_ERR(svn_wc__db_extend_parent_delete(b->wcroot, relpath, svn_node_file,
- op_depth, scratch_pool));
-
- err = svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
- &move_dst_repos_relpath, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- b->wcroot, relpath,
- relpath_depth(b->move_root_dst_relpath),
- scratch_pool, scratch_pool);
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ if (nmb->shadowed)
{
- svn_error_clear(err);
- old_kind = svn_node_none;
- move_dst_repos_relpath = NULL;
+ svn_wc__db_status_t status;
+
+ SVN_ERR(svn_wc__db_read_info_internal(&status, &wc_kind, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ b->wcroot, relpath,
+ scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_deleted)
+ reason = svn_wc_conflict_reason_deleted;
+ else if (status != svn_wc__db_status_added)
+ wc_kind = svn_node_none;
+ else if (old_kind == svn_node_none)
+ reason = svn_wc_conflict_reason_added;
+ else
+ reason = svn_wc_conflict_reason_replaced;
}
else
- {
- SVN_ERR(err);
- old_kind = move_dst_kind;
- }
-
- /* Check for NODES tree-conflict. */
- SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
- old_kind, svn_node_file, move_dst_repos_relpath,
- svn_wc_conflict_action_add,
- scratch_pool));
- if (is_conflicted)
- return SVN_NO_ERROR;
+ wc_kind = svn_node_none;
- /* Check for unversioned tree-conflict */
- abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
- SVN_ERR(svn_io_check_path(abspath, &old_kind, scratch_pool));
+ local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
- if (old_kind != svn_node_none)
+ if (wc_kind == svn_node_none)
{
- SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
- b->new_version, b->move_root_dst_relpath,
- b->operation, old_kind, svn_node_file,
- move_dst_repos_relpath,
- svn_wc_conflict_reason_unversioned,
- svn_wc_conflict_action_add, NULL,
- scratch_pool));
- b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
- return SVN_NO_ERROR;
+ /* Check for unversioned tree-conflict */
+ SVN_ERR(svn_io_check_path(local_abspath, &wc_kind, scratch_pool));
}
- /* Update working file. */
- SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
- svn_dirent_join(b->wcroot->abspath,
- relpath,
- scratch_pool),
+ if (wc_kind != svn_node_none
+ && (nmb->shadowed || wc_kind != old_kind)) /* replace */
+ {
+ SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+ old_kind, svn_node_file,
+ reason,
+ (old_kind == svn_node_none)
+ ? svn_wc_conflict_action_add
+ : svn_wc_conflict_action_replace,
NULL,
- FALSE /* FIXME: use_commit_times? */,
- TRUE /* record_file_info */,
scratch_pool, scratch_pool));
+ nmb->skip = TRUE;
+ }
+ else
+ {
+ /* Update working file. */
+ SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
+ svn_dirent_join(b->wcroot->abspath,
+ relpath,
+ scratch_pool),
+ NULL,
+ FALSE /*FIXME: use_commit_times?*/,
+ TRUE /* record_file_info */,
+ scratch_pool, scratch_pool));
+ }
- SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
- scratch_pool));
-
- SVN_ERR(update_move_list_add(b->wcroot, relpath,
- svn_wc_notify_update_add,
+ SVN_ERR(update_move_list_add(b->wcroot, relpath, b->db,
+ (old_kind == svn_node_none)
+ ? svn_wc_notify_update_add
+ : svn_wc_notify_update_replace,
svn_node_file,
svn_wc_notify_state_inapplicable,
- svn_wc_notify_state_inapplicable));
+ svn_wc_notify_state_inapplicable,
+ conflict, work_item, scratch_pool));
return SVN_NO_ERROR;
}
-static svn_error_t *
-tc_editor_add_symlink(void *baton,
- const char *relpath,
- const char *target,
- apr_hash_t *props,
- svn_revnum_t replaces_rev,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
-tc_editor_add_absent(void *baton,
- const char *relpath,
- svn_node_kind_t kind,
- svn_revnum_t replaces_rev,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
/* All the info we need about one version of a working node. */
typedef struct working_node_version_t
{
@@ -669,6 +843,7 @@ create_conflict_markers(svn_skel_t **work_items,
const working_node_version_t *old_version,
const working_node_version_t *new_version,
svn_node_kind_t kind,
+ svn_boolean_t set_operation,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -689,19 +864,22 @@ create_conflict_markers(svn_skel_t **work_items,
= svn_relpath_join(conflicted_version->path_in_repos, part, scratch_pool);
original_version->path_in_repos = repos_relpath;
- if (operation == svn_wc_operation_update)
+ if (set_operation)
{
- SVN_ERR(svn_wc__conflict_skel_set_op_update(
- conflict_skel, original_version,
- conflicted_version,
- scratch_pool, scratch_pool));
- }
- else
- {
- SVN_ERR(svn_wc__conflict_skel_set_op_switch(
- conflict_skel, original_version,
- conflicted_version,
- scratch_pool, scratch_pool));
+ if (operation == svn_wc_operation_update)
+ {
+ SVN_ERR(svn_wc__conflict_skel_set_op_update(
+ conflict_skel, original_version,
+ conflicted_version,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ SVN_ERR(svn_wc__conflict_skel_set_op_switch(
+ conflict_skel, original_version,
+ conflicted_version,
+ scratch_pool, scratch_pool));
+ }
}
/* According to this func's doc string, it is "Currently only used for
@@ -720,8 +898,8 @@ update_working_props(svn_wc_notify_state_t *prop_state,
svn_skel_t **conflict_skel,
apr_array_header_t **propchanges,
apr_hash_t **actual_props,
- svn_wc__db_t *db,
- const char *local_abspath,
+ update_move_baton_t *b,
+ const char *local_relpath,
const struct working_node_version_t *old_version,
const struct working_node_version_t *new_version,
apr_pool_t *result_pool,
@@ -736,139 +914,123 @@ update_working_props(svn_wc_notify_state_t *prop_state,
* merge-left version, and the current props of the
* moved-here working file as the merge-right version.
*/
- SVN_ERR(svn_wc__db_read_props(actual_props,
- db, local_abspath,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_props_internal(actual_props,
+ b->wcroot, local_relpath,
+ result_pool, scratch_pool));
SVN_ERR(svn_prop_diffs(propchanges, new_version->props, old_version->props,
result_pool));
SVN_ERR(svn_wc__merge_props(conflict_skel, prop_state,
&new_actual_props,
- db, local_abspath,
+ b->db, svn_dirent_join(b->wcroot->abspath,
+ local_relpath,
+ scratch_pool),
old_version->props, old_version->props,
*actual_props, *propchanges,
result_pool, scratch_pool));
- /* Setting properties in ACTUAL_NODE with svn_wc__db_op_set_props
- relies on NODES row having been updated first which we don't do
- at present. So this extra property diff has the same effect.
+ /* Setting properties in ACTUAL_NODE with svn_wc__db_op_set_props_internal
+ relies on NODES row being updated via a different route .
- ### Perhaps we should update NODES first (but after
- ### svn_wc__db_read_props above)? */
+ This extra property diff makes sure we clear the actual row when
+ the final result is unchanged properties. */
SVN_ERR(svn_prop_diffs(&new_propchanges, new_actual_props, new_version->props,
scratch_pool));
if (!new_propchanges->nelts)
new_actual_props = NULL;
- /* Install the new actual props. Don't set the conflict_skel yet, because
- we might need to add a text conflict to it as well. */
- SVN_ERR(svn_wc__db_op_set_props(db, local_abspath,
- new_actual_props,
- svn_wc__has_magic_property(*propchanges),
- NULL/*conflict_skel*/, NULL/*work_items*/,
- scratch_pool));
+ /* Install the new actual props. */
+ SVN_ERR(svn_wc__db_op_set_props_internal(b->wcroot, local_relpath,
+ new_actual_props,
+ svn_wc__has_magic_property(
+ *propchanges),
+ scratch_pool));
return SVN_NO_ERROR;
}
static svn_error_t *
-tc_editor_alter_directory(void *baton,
+tc_editor_alter_directory(node_move_baton_t *nmb,
const char *dst_relpath,
- svn_revnum_t expected_move_dst_revision,
- const apr_array_header_t *children,
+ apr_hash_t *old_props,
apr_hash_t *new_props,
apr_pool_t *scratch_pool)
{
- struct tc_editor_baton *b = baton;
- const char *move_dst_repos_relpath;
- svn_revnum_t move_dst_revision;
- svn_node_kind_t move_dst_kind;
+ update_move_baton_t *b = nmb->umb;
working_node_version_t old_version, new_version;
- svn_wc__db_status_t status;
- svn_boolean_t is_conflicted;
-
- SVN_ERR_ASSERT(expected_move_dst_revision == b->old_version->peg_rev);
-
- SVN_ERR(svn_wc__db_depth_get_info(&status, &move_dst_kind, &move_dst_revision,
- &move_dst_repos_relpath, NULL, NULL, NULL,
- NULL, NULL, &old_version.checksum, NULL,
- NULL, &old_version.props,
- b->wcroot, dst_relpath,
- relpath_depth(b->move_root_dst_relpath),
- scratch_pool, scratch_pool));
+ svn_skel_t *work_items = NULL;
+ svn_skel_t *conflict_skel = NULL;
+ const char *local_abspath = svn_dirent_join(b->wcroot->abspath, dst_relpath,
+ scratch_pool);
+ svn_wc_notify_state_t prop_state;
+ apr_hash_t *actual_props;
+ apr_array_header_t *propchanges;
+ svn_node_kind_t wc_kind;
+ svn_boolean_t obstructed = FALSE;
- /* If the node would be recorded as svn_wc__db_status_base_deleted it
- wouldn't have a repos_relpath */
- /* ### Can svn_wc__db_depth_get_info() do this for us without this hint? */
- if (status == svn_wc__db_status_deleted && move_dst_repos_relpath)
- status = svn_wc__db_status_not_present;
-
- /* There might be not-present nodes of a different revision as the same
- depth as a copy. This is commonly caused by copying/moving mixed revision
- directories */
- SVN_ERR_ASSERT(move_dst_revision == expected_move_dst_revision
- || status == svn_wc__db_status_not_present);
- SVN_ERR_ASSERT(move_dst_kind == svn_node_dir);
-
- SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
- move_dst_kind,
- svn_node_dir,
- move_dst_repos_relpath,
- svn_wc_conflict_action_edit,
- scratch_pool));
- if (is_conflicted)
+ SVN_ERR(mark_node_edited(nmb, scratch_pool));
+ if (nmb->skip)
return SVN_NO_ERROR;
+ SVN_ERR(svn_io_check_path(local_abspath, &wc_kind, scratch_pool));
+ if (wc_kind != svn_node_none && wc_kind != svn_node_dir)
+ {
+ SVN_ERR(create_node_tree_conflict(&conflict_skel, nmb, dst_relpath,
+ svn_node_dir, svn_node_dir,
+ svn_wc_conflict_reason_obstructed,
+ svn_wc_conflict_action_edit,
+ NULL,
+ scratch_pool, scratch_pool));
+ obstructed = TRUE;
+ }
+
old_version.location_and_kind = b->old_version;
new_version.location_and_kind = b->new_version;
+ old_version.checksum = NULL; /* not a file */
+ old_version.props = old_props;
new_version.checksum = NULL; /* not a file */
- new_version.props = new_props ? new_props : old_version.props;
+ new_version.props = new_props;
- if (new_props)
+ SVN_ERR(update_working_props(&prop_state, &conflict_skel,
+ &propchanges, &actual_props,
+ b, dst_relpath,
+ &old_version, &new_version,
+ scratch_pool, scratch_pool));
+
+ if (prop_state == svn_wc_notify_state_conflicted)
{
- const char *dst_abspath = svn_dirent_join(b->wcroot->abspath,
- dst_relpath,
- scratch_pool);
- svn_wc_notify_state_t prop_state;
- svn_skel_t *conflict_skel = NULL;
- apr_hash_t *actual_props;
- apr_array_header_t *propchanges;
-
- SVN_ERR(update_working_props(&prop_state, &conflict_skel,
- &propchanges, &actual_props,
- b->db, dst_abspath,
- &old_version, &new_version,
- scratch_pool, scratch_pool));
-
- if (conflict_skel)
- {
- svn_skel_t *work_items;
-
- SVN_ERR(create_conflict_markers(&work_items, dst_abspath,
- b->db, move_dst_repos_relpath,
- conflict_skel, b->operation,
- &old_version, &new_version,
- svn_node_dir,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_wc__db_mark_conflict_internal(b->wcroot, dst_relpath,
- conflict_skel,
- scratch_pool));
- SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_items,
- scratch_pool));
- }
+ const char *move_dst_repos_relpath;
- SVN_ERR(update_move_list_add(b->wcroot, dst_relpath,
- svn_wc_notify_update_update,
- svn_node_dir,
- svn_wc_notify_state_inapplicable,
- prop_state));
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, NULL,
+ &move_dst_repos_relpath, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ b->wcroot, dst_relpath,
+ b->dst_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(create_conflict_markers(&work_items, local_abspath,
+ b->db, move_dst_repos_relpath,
+ conflict_skel, b->operation,
+ &old_version, &new_version,
+ svn_node_dir, !obstructed,
+ scratch_pool, scratch_pool));
}
+ SVN_ERR(update_move_list_add(b->wcroot, dst_relpath, b->db,
+ svn_wc_notify_update_update,
+ svn_node_dir,
+ svn_wc_notify_state_inapplicable,
+ prop_state,
+ conflict_skel, work_items, scratch_pool));
+
return SVN_NO_ERROR;
}
-
-/* Merge the difference between OLD_VERSION and NEW_VERSION into
+/* Edit the file found at the move destination, which is initially at
+ * the old state. Merge the changes into the "working"/"actual" file.
+ *
+ * Merge the difference between OLD_VERSION and NEW_VERSION into
* the working file at LOCAL_RELPATH.
*
* The term 'old' refers to the pre-update state, which is the state of
@@ -883,17 +1045,18 @@ tc_editor_alter_directory(void *baton,
* Set *WORK_ITEMS to any required work items, allocated in RESULT_POOL.
* Use SCRATCH_POOL for temporary allocations. */
static svn_error_t *
-update_working_file(const char *local_relpath,
- const char *repos_relpath,
- svn_wc_operation_t operation,
- const working_node_version_t *old_version,
- const working_node_version_t *new_version,
- svn_wc__db_wcroot_t *wcroot,
- svn_wc__db_t *db,
- apr_pool_t *scratch_pool)
+tc_editor_alter_file(node_move_baton_t *nmb,
+ const char *dst_relpath,
+ const svn_checksum_t *old_checksum,
+ const svn_checksum_t *new_checksum,
+ apr_hash_t *old_props,
+ apr_hash_t *new_props,
+ apr_pool_t *scratch_pool)
{
- const char *local_abspath = svn_dirent_join(wcroot->abspath,
- local_relpath,
+ update_move_baton_t *b = nmb->umb;
+ working_node_version_t old_version, new_version;
+ const char *local_abspath = svn_dirent_join(b->wcroot->abspath,
+ dst_relpath,
scratch_pool);
const char *old_pristine_abspath;
const char *new_pristine_abspath;
@@ -903,23 +1066,51 @@ update_working_file(const char *local_relpath,
enum svn_wc_merge_outcome_t merge_outcome;
svn_wc_notify_state_t prop_state, content_state;
svn_skel_t *work_item, *work_items = NULL;
+ svn_node_kind_t wc_kind;
+ svn_boolean_t obstructed = FALSE;
+ SVN_ERR(mark_node_edited(nmb, scratch_pool));
+ if (nmb->skip)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_io_check_path(local_abspath, &wc_kind, scratch_pool));
+ if (wc_kind != svn_node_none && wc_kind != svn_node_file)
+ {
+ SVN_ERR(create_node_tree_conflict(&conflict_skel, nmb, dst_relpath,
+ svn_node_file, svn_node_file,
+ svn_wc_conflict_reason_obstructed,
+ svn_wc_conflict_action_edit,
+ NULL,
+ scratch_pool, scratch_pool));
+ obstructed = TRUE;
+ }
+
+ old_version.location_and_kind = b->old_version;
+ new_version.location_and_kind = b->new_version;
+
+ old_version.checksum = old_checksum;
+ old_version.props = old_props;
+ new_version.checksum = new_checksum;
+ new_version.props = new_props;
+
+ /* ### TODO: Only do this when there is no higher WORKING layer */
SVN_ERR(update_working_props(&prop_state, &conflict_skel, &propchanges,
- &actual_props, db, local_abspath,
- old_version, new_version,
+ &actual_props, b, dst_relpath,
+ &old_version, &new_version,
scratch_pool, scratch_pool));
- if (!svn_checksum_match(new_version->checksum, old_version->checksum))
+ if (!obstructed
+ && !svn_checksum_match(new_version.checksum, old_version.checksum))
{
svn_boolean_t is_locally_modified;
SVN_ERR(svn_wc__internal_file_modified_p(&is_locally_modified,
- db, local_abspath,
+ b->db, local_abspath,
FALSE /* exact_comparison */,
scratch_pool));
if (!is_locally_modified)
{
- SVN_ERR(svn_wc__wq_build_file_install(&work_item, db,
+ SVN_ERR(svn_wc__wq_build_file_install(&work_item, b->db,
local_abspath,
NULL,
FALSE /* FIXME: use_commit_times? */,
@@ -939,15 +1130,15 @@ update_working_file(const char *local_relpath,
* moved-here working file as the merge-right version.
*/
SVN_ERR(svn_wc__db_pristine_get_path(&old_pristine_abspath,
- db, wcroot->abspath,
- old_version->checksum,
+ b->db, b->wcroot->abspath,
+ old_version.checksum,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
- db, wcroot->abspath,
- new_version->checksum,
+ b->db, b->wcroot->abspath,
+ new_version.checksum,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__internal_merge(&work_item, &conflict_skel,
- &merge_outcome, db,
+ &merge_outcome, b->db,
old_pristine_abspath,
new_pristine_abspath,
local_abspath,
@@ -958,7 +1149,7 @@ update_working_file(const char *local_relpath,
NULL, /* diff3-cmd */
NULL, /* merge options */
propchanges,
- NULL, NULL, /* cancel_func + baton */
+ b->cancel_func, b->cancel_baton,
scratch_pool, scratch_pool));
work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
@@ -976,207 +1167,113 @@ update_working_file(const char *local_relpath,
* too. */
if (conflict_skel)
{
- SVN_ERR(create_conflict_markers(&work_item, local_abspath, db,
- repos_relpath, conflict_skel,
- operation, old_version, new_version,
- svn_node_file,
- scratch_pool, scratch_pool));
+ const char *move_dst_repos_relpath;
- SVN_ERR(svn_wc__db_mark_conflict_internal(wcroot, local_relpath,
- conflict_skel,
- scratch_pool));
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, NULL, NULL,
+ &move_dst_repos_relpath, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ b->wcroot, dst_relpath,
+ b->dst_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(create_conflict_markers(&work_item, local_abspath, b->db,
+ move_dst_repos_relpath, conflict_skel,
+ b->operation, &old_version, &new_version,
+ svn_node_file, !obstructed,
+ scratch_pool, scratch_pool));
work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
}
- SVN_ERR(svn_wc__db_wq_add(db, wcroot->abspath, work_items, scratch_pool));
-
- SVN_ERR(update_move_list_add(wcroot, local_relpath,
+ SVN_ERR(update_move_list_add(b->wcroot, dst_relpath, b->db,
svn_wc_notify_update_update,
svn_node_file,
content_state,
- prop_state));
+ prop_state,
+ conflict_skel, work_items, scratch_pool));
return SVN_NO_ERROR;
}
-
-/* Edit the file found at the move destination, which is initially at
- * the old state. Merge the changes into the "working"/"actual" file.
- */
static svn_error_t *
-tc_editor_alter_file(void *baton,
- const char *dst_relpath,
- svn_revnum_t expected_move_dst_revision,
- apr_hash_t *new_props,
- const svn_checksum_t *new_checksum,
- svn_stream_t *new_contents,
- apr_pool_t *scratch_pool)
-{
- struct tc_editor_baton *b = baton;
- const char *move_dst_repos_relpath;
- svn_revnum_t move_dst_revision;
- svn_node_kind_t move_dst_kind;
- working_node_version_t old_version, new_version;
- svn_boolean_t is_conflicted;
- svn_wc__db_status_t status;
-
- SVN_ERR(svn_wc__db_depth_get_info(&status, &move_dst_kind, &move_dst_revision,
- &move_dst_repos_relpath, NULL, NULL, NULL,
- NULL, NULL, &old_version.checksum, NULL,
- NULL, &old_version.props,
- b->wcroot, dst_relpath,
- relpath_depth(b->move_root_dst_relpath),
- scratch_pool, scratch_pool));
-
- /* If the node would be recorded as svn_wc__db_status_base_deleted it
- wouldn't have a repos_relpath */
- /* ### Can svn_wc__db_depth_get_info() do this for us without this hint? */
- if (status == svn_wc__db_status_deleted && move_dst_repos_relpath)
- status = svn_wc__db_status_not_present;
-
- SVN_ERR_ASSERT(move_dst_revision == expected_move_dst_revision
- || status == svn_wc__db_status_not_present);
- SVN_ERR_ASSERT(move_dst_kind == svn_node_file);
-
- SVN_ERR(check_tree_conflict(&is_conflicted, b, dst_relpath,
- move_dst_kind,
- svn_node_file,
- move_dst_repos_relpath,
- svn_wc_conflict_action_edit,
- scratch_pool));
- if (is_conflicted)
- return SVN_NO_ERROR;
-
- old_version.location_and_kind = b->old_version;
- new_version.location_and_kind = b->new_version;
-
- /* If new checksum is null that means no change; similarly props. */
- new_version.checksum = new_checksum ? new_checksum : old_version.checksum;
- new_version.props = new_props ? new_props : old_version.props;
-
- /* Update file and prop contents if the update has changed them. */
- if (!svn_checksum_match(new_checksum, old_version.checksum) || new_props)
- {
- SVN_ERR(update_working_file(dst_relpath, move_dst_repos_relpath,
- b->operation, &old_version, &new_version,
- b->wcroot, b->db,
- scratch_pool));
- }
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-tc_editor_alter_symlink(void *baton,
- const char *relpath,
- svn_revnum_t revision,
- apr_hash_t *props,
- const char *target,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
-tc_editor_delete(void *baton,
+tc_editor_delete(node_move_baton_t *nmb,
const char *relpath,
- svn_revnum_t revision,
+ svn_node_kind_t old_kind,
+ svn_node_kind_t new_kind,
apr_pool_t *scratch_pool)
{
- struct tc_editor_baton *b = baton;
+ update_move_baton_t *b = nmb->umb;
svn_sqlite__stmt_t *stmt;
- int op_depth = relpath_depth(b->move_root_dst_relpath);
- const char *move_dst_repos_relpath;
- svn_node_kind_t move_dst_kind;
- svn_boolean_t is_conflicted;
- svn_boolean_t must_delete_working_nodes = FALSE;
- const char *local_abspath = svn_dirent_join(b->wcroot->abspath, relpath,
- scratch_pool);
- const char *parent_relpath = svn_relpath_dirname(relpath, scratch_pool);
- int op_depth_below;
- svn_boolean_t have_row;
+ const char *local_abspath;
+ svn_boolean_t is_modified, is_all_deletes;
+ svn_skel_t *work_items = NULL;
+ svn_skel_t *conflict = NULL;
- SVN_ERR(svn_wc__db_depth_get_info(NULL, &move_dst_kind, NULL,
- &move_dst_repos_relpath, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- b->wcroot, relpath,
- relpath_depth(b->move_root_dst_relpath),
- scratch_pool, scratch_pool));
+ SVN_ERR(mark_parent_edited(nmb, scratch_pool));
+ if (nmb->skip)
+ return SVN_NO_ERROR;
/* Check before retracting delete to catch delete-delete
conflicts. This catches conflicts on the node itself; deleted
children are caught as local modifications below.*/
- SVN_ERR(check_tree_conflict(&is_conflicted, b, relpath,
- move_dst_kind,
- svn_node_unknown,
- move_dst_repos_relpath,
- svn_wc_conflict_action_delete,
- scratch_pool));
+ if (nmb->shadowed)
+ {
+ SVN_ERR(mark_tc_on_op_root(nmb,
+ old_kind, new_kind,
+ svn_wc_conflict_action_delete,
+ scratch_pool));
+ return SVN_NO_ERROR;
+ }
- if (!is_conflicted)
+ local_abspath = svn_dirent_join(b->wcroot->abspath, relpath, scratch_pool);
+ SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes,
+ nmb->umb->db, local_abspath, FALSE,
+ NULL, NULL, scratch_pool));
+ if (is_modified)
{
- svn_boolean_t is_modified, is_all_deletes;
+ svn_wc_conflict_reason_t reason;
- SVN_ERR(svn_wc__node_has_local_mods(&is_modified, &is_all_deletes, b->db,
- local_abspath,
- NULL, NULL, scratch_pool));
- if (is_modified)
- {
- svn_wc_conflict_reason_t reason;
+ /* No conflict means no NODES rows at the relpath op-depth
+ so it's easy to convert the modified tree into a copy.
- if (!is_all_deletes)
- {
- /* No conflict means no NODES rows at the relpath op-depth
- so it's easy to convert the modified tree into a copy. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_UPDATE_OP_DEPTH_RECURSIVE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath,
- op_depth, relpath_depth(relpath)));
- SVN_ERR(svn_sqlite__step_done(stmt));
-
- reason = svn_wc_conflict_reason_edited;
- }
- else
- {
+ Note the following assumptions for relpath:
+ * it is not shadowed
+ * it is not the/an op-root. (or we can't make us a copy)
+ */
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_DELETE_WORKING_OP_DEPTH_ABOVE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
- op_depth));
- SVN_ERR(svn_sqlite__step_done(stmt));
+ SVN_ERR(svn_wc__db_op_make_copy_internal(b->wcroot, relpath, FALSE,
+ NULL, NULL, scratch_pool));
- reason = svn_wc_conflict_reason_deleted;
- must_delete_working_nodes = TRUE;
- }
- is_conflicted = TRUE;
- SVN_ERR(mark_tree_conflict(relpath, b->wcroot, b->db, b->old_version,
- b->new_version, b->move_root_dst_relpath,
- b->operation,
- move_dst_kind,
- svn_node_none,
- move_dst_repos_relpath, reason,
- svn_wc_conflict_action_delete, NULL,
- scratch_pool));
- b->conflict_root_relpath = apr_pstrdup(b->result_pool, relpath);
- }
- }
+ reason = svn_wc_conflict_reason_edited;
- if (!is_conflicted || must_delete_working_nodes)
+ SVN_ERR(create_node_tree_conflict(&conflict, nmb, relpath,
+ old_kind, new_kind, reason,
+ (new_kind == svn_node_none)
+ ? svn_wc_conflict_action_delete
+ : svn_wc_conflict_action_replace,
+ NULL,
+ scratch_pool, scratch_pool));
+ nmb->skip = TRUE;
+ }
+ else
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- svn_skel_t *work_item;
- svn_node_kind_t del_kind;
const char *del_abspath;
+ svn_boolean_t have_row;
+ /* Get all descendants of the node in reverse order (so children are
+ handled before their parents, but not strictly depth first) */
SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_SELECT_CHILDREN_OP_DEPTH));
+ STMT_SELECT_DESCENDANTS_OP_DEPTH_RV));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
- op_depth));
+ b->dst_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
svn_error_t *err;
+ svn_skel_t *work_item;
+ svn_node_kind_t del_kind;
svn_pool_clear(iterpool);
@@ -1194,8 +1291,7 @@ tc_editor_delete(void *baton,
b->wcroot->abspath, del_abspath,
iterpool, iterpool);
if (!err)
- err = svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
- iterpool);
+ err = svn_wc__db_wq_add_internal(b->wcroot, work_item, iterpool);
if (err)
return svn_error_compose_create(err, svn_sqlite__reset(stmt));
@@ -1203,139 +1299,34 @@ tc_editor_delete(void *baton,
}
SVN_ERR(svn_sqlite__reset(stmt));
- SVN_ERR(svn_wc__db_depth_get_info(NULL, &del_kind, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL,
- b->wcroot, relpath, op_depth,
- iterpool, iterpool));
- if (del_kind == svn_node_dir)
- SVN_ERR(svn_wc__wq_build_dir_remove(&work_item, b->db,
+ if (old_kind == svn_node_dir)
+ SVN_ERR(svn_wc__wq_build_dir_remove(&work_items, b->db,
b->wcroot->abspath, local_abspath,
FALSE /* recursive */,
- iterpool, iterpool));
+ scratch_pool, iterpool));
else
- SVN_ERR(svn_wc__wq_build_file_remove(&work_item, b->db,
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_items, b->db,
b->wcroot->abspath, local_abspath,
- iterpool, iterpool));
- SVN_ERR(svn_wc__db_wq_add(b->db, b->wcroot->abspath, work_item,
- iterpool));
-
- if (!is_conflicted)
- SVN_ERR(update_move_list_add(b->wcroot, relpath,
- svn_wc_notify_update_delete,
- del_kind,
- svn_wc_notify_state_inapplicable,
- svn_wc_notify_state_inapplicable));
- svn_pool_destroy(iterpool);
- }
+ scratch_pool, iterpool));
- /* Deleting the ROWS is valid so long as we update the parent before
- committing the transaction. The removed rows could have been
- replacing a lower layer in which case we need to add base-deleted
- rows. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_SELECT_HIGHEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, parent_relpath,
- op_depth));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- op_depth_below = svn_sqlite__column_int(stmt, 0);
- SVN_ERR(svn_sqlite__reset(stmt));
- if (have_row)
- {
- /* Remove non-shadowing nodes. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_DELETE_NO_LOWER_LAYER));
- SVN_ERR(svn_sqlite__bindf(stmt, "isdd", b->wcroot->wc_id, relpath,
- op_depth, op_depth_below));
- SVN_ERR(svn_sqlite__step_done(stmt));
-
- /* Convert remaining shadowing nodes to presence='base-deleted'. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_REPLACE_WITH_BASE_DELETED));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
- op_depth));
- SVN_ERR(svn_sqlite__step_done(stmt));
- }
- else
- {
- SVN_ERR(svn_sqlite__get_statement(&stmt, b->wcroot->sdb,
- STMT_DELETE_WORKING_OP_DEPTH));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", b->wcroot->wc_id, relpath,
- op_depth));
- SVN_ERR(svn_sqlite__step_done(stmt));
+ svn_pool_destroy(iterpool);
}
- /* Retract any base-delete. */
- SVN_ERR(svn_wc__db_retract_parent_delete(b->wcroot, relpath, op_depth,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-tc_editor_copy(void *baton,
- const char *src_relpath,
- svn_revnum_t src_revision,
- const char *dst_relpath,
- svn_revnum_t replaces_rev,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
-tc_editor_move(void *baton,
- const char *src_relpath,
- svn_revnum_t src_revision,
- const char *dst_relpath,
- svn_revnum_t replaces_rev,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
-tc_editor_rotate(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- return svn_error_create(SVN_ERR_UNSUPPORTED_FEATURE, NULL, NULL);
-}
-
-static svn_error_t *
-tc_editor_complete(void *baton,
- apr_pool_t *scratch_pool)
-{
- return SVN_NO_ERROR;
-}
+ /* Only notify if add_file/add_dir is not going to notify */
+ if (conflict || (new_kind == svn_node_none))
+ SVN_ERR(update_move_list_add(b->wcroot, relpath, b->db,
+ svn_wc_notify_update_delete,
+ new_kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ conflict, work_items, scratch_pool));
+ else if (work_items)
+ SVN_ERR(svn_wc__db_wq_add_internal(b->wcroot, work_items,
+ scratch_pool));
-static svn_error_t *
-tc_editor_abort(void *baton,
- apr_pool_t *scratch_pool)
-{
return SVN_NO_ERROR;
}
-/* The editor callback table implementing the receiver. */
-static const svn_editor_cb_many_t editor_ops = {
- tc_editor_add_directory,
- tc_editor_add_file,
- tc_editor_add_symlink,
- tc_editor_add_absent,
- tc_editor_alter_directory,
- tc_editor_alter_file,
- tc_editor_alter_symlink,
- tc_editor_delete,
- tc_editor_copy,
- tc_editor_move,
- tc_editor_rotate,
- tc_editor_complete,
- tc_editor_abort
-};
-
-
/*
* Driver code.
*
@@ -1352,73 +1343,11 @@ static const svn_editor_cb_many_t editor_ops = {
* single-revision.
*/
-/* Set *OPERATION, *LOCAL_CHANGE, *INCOMING_CHANGE, *OLD_VERSION, *NEW_VERSION
- * to reflect the tree conflict on the victim SRC_ABSPATH in DB.
- *
- * If SRC_ABSPATH is not a tree-conflict victim, return an error.
- */
-static svn_error_t *
-get_tc_info(svn_wc_operation_t *operation,
- svn_wc_conflict_reason_t *local_change,
- svn_wc_conflict_action_t *incoming_change,
- const char **move_src_op_root_abspath,
- svn_wc_conflict_version_t **old_version,
- svn_wc_conflict_version_t **new_version,
- svn_wc__db_t *db,
- const char *src_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const apr_array_header_t *locations;
- svn_boolean_t tree_conflicted;
- svn_skel_t *conflict_skel;
-
- /* Check for tree conflict on src. */
- SVN_ERR(svn_wc__db_read_conflict(&conflict_skel, db,
- src_abspath,
- scratch_pool, scratch_pool));
- if (!conflict_skel)
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("'%s' is not in conflict"),
- svn_dirent_local_style(src_abspath,
- scratch_pool));
-
- SVN_ERR(svn_wc__conflict_read_info(operation, &locations,
- NULL, NULL, &tree_conflicted,
- db, src_abspath,
- conflict_skel, result_pool,
- scratch_pool));
- if ((*operation != svn_wc_operation_update
- && *operation != svn_wc_operation_switch)
- || !tree_conflicted)
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("'%s' is not a tree-conflict victim"),
- svn_dirent_local_style(src_abspath,
- scratch_pool));
- if (locations)
- {
- SVN_ERR_ASSERT(locations->nelts >= 2);
- *old_version = APR_ARRAY_IDX(locations, 0,
- svn_wc_conflict_version_t *);
- *new_version = APR_ARRAY_IDX(locations, 1,
- svn_wc_conflict_version_t *);
- }
-
- SVN_ERR(svn_wc__conflict_read_tree_conflict(local_change,
- incoming_change,
- move_src_op_root_abspath,
- db, src_abspath,
- conflict_skel, scratch_pool,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
/* Return *PROPS, *CHECKSUM, *CHILDREN and *KIND for LOCAL_RELPATH at
OP_DEPTH provided the row exists. Return *KIND of svn_node_none if
- the row does not exist. *CHILDREN is a sorted array of basenames of
- type 'const char *', rather than a hash, to allow the driver to
- process children in a defined order. */
+ the row does not exist, or only describes a delete of a lower op-depth.
+ *CHILDREN is a sorted array of basenames of type 'const char *', rather
+ than a hash, to allow the driver to process children in a defined order. */
static svn_error_t *
get_info(apr_hash_t **props,
const svn_checksum_t **checksum,
@@ -1430,64 +1359,68 @@ get_info(apr_hash_t **props,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_hash_t *hash_children;
- apr_array_header_t *sorted_children;
+ svn_wc__db_status_t status;
+ const char *repos_relpath;
+ svn_node_kind_t db_kind;
svn_error_t *err;
- int i;
- err = svn_wc__db_depth_get_info(NULL, kind, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, checksum, NULL, NULL, props,
+ err = svn_wc__db_depth_get_info(&status, &db_kind, NULL, &repos_relpath, NULL,
+ NULL, NULL, NULL, NULL, checksum, NULL,
+ NULL, props,
wcroot, local_relpath, op_depth,
result_pool, scratch_pool);
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+
+ /* If there is no node at this depth, or only a node that describes a delete
+ of a lower layer we report this node as not existing. */
+ if ((err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ || (!err && status != svn_wc__db_status_added
+ && status != svn_wc__db_status_normal))
{
svn_error_clear(err);
- *kind = svn_node_none;
+
+ if (kind)
+ *kind = svn_node_none;
+ if (checksum)
+ *checksum = NULL;
+ if (props)
+ *props = NULL;
+ if (children)
+ *children = apr_array_make(result_pool, 0, sizeof(const char *));
+
+ return SVN_NO_ERROR;
}
else
SVN_ERR(err);
+ if (kind)
+ *kind = db_kind;
- SVN_ERR(svn_wc__db_get_children_op_depth(&hash_children, wcroot,
- local_relpath, op_depth,
- scratch_pool, scratch_pool));
-
- sorted_children = svn_sort__hash(hash_children,
- svn_sort_compare_items_lexically,
- scratch_pool);
-
- *children = apr_array_make(result_pool, sorted_children->nelts,
- sizeof(const char *));
- for (i = 0; i < sorted_children->nelts; ++i)
- APR_ARRAY_PUSH(*children, const char *)
- = apr_pstrdup(result_pool, APR_ARRAY_IDX(sorted_children, i,
- svn_sort__item_t).key);
-
- return SVN_NO_ERROR;
-}
-
-/* Return TRUE if SRC_CHILDREN and DST_CHILDREN represent the same
- children, FALSE otherwise. SRC_CHILDREN and DST_CHILDREN are
- sorted arrays of basenames of type 'const char *'. */
-static svn_boolean_t
-children_match(apr_array_header_t *src_children,
- apr_array_header_t *dst_children) { int i;
+ if (children && db_kind == svn_node_dir)
+ {
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
- if (src_children->nelts != dst_children->nelts)
- return FALSE;
+ *children = apr_array_make(result_pool, 16, sizeof(const char *));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_OP_DEPTH_CHILDREN_EXISTS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ op_depth));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ while (have_row)
+ {
+ const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
- for(i = 0; i < src_children->nelts; ++i)
- {
- const char *src_child =
- APR_ARRAY_IDX(src_children, i, const char *);
- const char *dst_child =
- APR_ARRAY_IDX(dst_children, i, const char *);
+ APR_ARRAY_PUSH(*children, const char *)
+ = svn_relpath_basename(child_relpath, result_pool);
- if (strcmp(src_child, dst_child))
- return FALSE;
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
}
+ else if (children)
+ *children = apr_array_make(result_pool, 0, sizeof(const char *));
- return TRUE;
+ return SVN_NO_ERROR;
}
/* Return TRUE if SRC_PROPS and DST_PROPS contain the same properties,
@@ -1516,97 +1449,77 @@ props_match(svn_boolean_t *match,
/* ### Drive TC_EDITOR so as to ...
*/
static svn_error_t *
-update_moved_away_node(svn_editor_t *tc_editor,
+update_moved_away_node(node_move_baton_t *nmb,
+ svn_wc__db_wcroot_t *wcroot,
const char *src_relpath,
const char *dst_relpath,
- int src_op_depth,
- const char *move_root_dst_relpath,
- svn_revnum_t move_root_dst_revision,
- svn_wc__db_t *db,
- svn_wc__db_wcroot_t *wcroot,
apr_pool_t *scratch_pool)
{
+ update_move_baton_t *b = nmb->umb;
svn_node_kind_t src_kind, dst_kind;
const svn_checksum_t *src_checksum, *dst_checksum;
apr_hash_t *src_props, *dst_props;
apr_array_header_t *src_children, *dst_children;
- int dst_op_depth = relpath_depth(move_root_dst_relpath);
+
+ if (b->cancel_func)
+ SVN_ERR(b->cancel_func(b->cancel_baton));
SVN_ERR(get_info(&src_props, &src_checksum, &src_children, &src_kind,
- src_relpath, src_op_depth,
+ src_relpath, b->src_op_depth,
wcroot, scratch_pool, scratch_pool));
SVN_ERR(get_info(&dst_props, &dst_checksum, &dst_children, &dst_kind,
- dst_relpath, dst_op_depth,
+ dst_relpath, b->dst_op_depth,
wcroot, scratch_pool, scratch_pool));
if (src_kind == svn_node_none
|| (dst_kind != svn_node_none && src_kind != dst_kind))
{
- SVN_ERR(svn_editor_delete(tc_editor, dst_relpath,
- move_root_dst_revision));
+ SVN_ERR(tc_editor_delete(nmb, dst_relpath, dst_kind, src_kind,
+ scratch_pool));
}
+ if (nmb->skip)
+ return SVN_NO_ERROR;
+
if (src_kind != svn_node_none && src_kind != dst_kind)
{
if (src_kind == svn_node_file || src_kind == svn_node_symlink)
{
- svn_stream_t *contents;
-
- SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db,
- wcroot->abspath, src_checksum,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_editor_add_file(tc_editor, dst_relpath,
- src_checksum, contents, src_props,
- move_root_dst_revision));
+ SVN_ERR(tc_editor_add_file(nmb, dst_relpath, dst_kind,
+ src_checksum, src_props, scratch_pool));
}
else if (src_kind == svn_node_dir)
{
- SVN_ERR(svn_editor_add_directory(tc_editor, dst_relpath,
- src_children, src_props,
- move_root_dst_revision));
+ SVN_ERR(tc_editor_add_directory(nmb, dst_relpath, dst_kind,
+ src_props, scratch_pool));
}
}
else if (src_kind != svn_node_none)
{
- svn_boolean_t match;
- apr_hash_t *props;
-
- SVN_ERR(props_match(&match, src_props, dst_props, scratch_pool));
- props = match ? NULL: src_props;
+ svn_boolean_t props_equal;
+ SVN_ERR(props_match(&props_equal, src_props, dst_props, scratch_pool));
if (src_kind == svn_node_file || src_kind == svn_node_symlink)
{
- svn_stream_t *contents;
-
- if (svn_checksum_match(src_checksum, dst_checksum))
- src_checksum = NULL;
-
- if (src_checksum)
- SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, db,
- wcroot->abspath, src_checksum,
- scratch_pool, scratch_pool));
- else
- contents = NULL;
-
- if (props || src_checksum)
- SVN_ERR(svn_editor_alter_file(tc_editor, dst_relpath,
- move_root_dst_revision,
- props, src_checksum, contents));
+ if (!props_equal || !svn_checksum_match(src_checksum, dst_checksum))
+ SVN_ERR(tc_editor_alter_file(nmb, dst_relpath,
+ dst_checksum, src_checksum,
+ dst_props, src_props, scratch_pool));
}
else if (src_kind == svn_node_dir)
{
- apr_array_header_t *children
- = children_match(src_children, dst_children) ? NULL : src_children;
-
- if (props || children)
- SVN_ERR(svn_editor_alter_directory(tc_editor, dst_relpath,
- move_root_dst_revision,
- children, props));
+ if (!props_equal)
+ SVN_ERR(tc_editor_alter_directory(nmb, dst_relpath,
+ dst_props, src_props,
+ scratch_pool));
}
}
+ if (nmb->skip)
+ return SVN_NO_ERROR;
+
if (src_kind == svn_node_dir)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -1615,8 +1528,12 @@ update_moved_away_node(svn_editor_t *tc_editor,
while (i < src_children->nelts || j < dst_children->nelts)
{
const char *child_name;
- const char *src_child_relpath, *dst_child_relpath;
svn_boolean_t src_only = FALSE, dst_only = FALSE;
+ node_move_baton_t cnmb = { 0 };
+
+ cnmb.pb = nmb;
+ cnmb.umb = nmb->umb;
+ cnmb.shadowed = nmb->shadowed;
svn_pool_clear(iterpool);
if (i >= src_children->nelts)
@@ -1645,130 +1562,28 @@ update_moved_away_node(svn_editor_t *tc_editor,
child_name = dst_only ? dst_name : src_name;
}
- src_child_relpath = svn_relpath_join(src_relpath, child_name,
- iterpool);
- dst_child_relpath = svn_relpath_join(dst_relpath, child_name,
- iterpool);
+ cnmb.src_relpath = svn_relpath_join(src_relpath, child_name,
+ iterpool);
+ cnmb.dst_relpath = svn_relpath_join(dst_relpath, child_name,
+ iterpool);
- SVN_ERR(update_moved_away_node(tc_editor, src_child_relpath,
- dst_child_relpath, src_op_depth,
- move_root_dst_relpath,
- move_root_dst_revision,
- db, wcroot, scratch_pool));
+ if (!cnmb.shadowed)
+ SVN_ERR(check_node_shadowed(&cnmb.shadowed, wcroot,
+ cnmb.dst_relpath, b->dst_op_depth,
+ iterpool));
+
+ SVN_ERR(update_moved_away_node(&cnmb, wcroot, cnmb.src_relpath,
+ cnmb.dst_relpath, iterpool));
if (!dst_only)
++i;
if (!src_only)
++j;
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/* Update the single op-depth layer in the move destination subtree
- rooted at DST_RELPATH to make it match the move source subtree
- rooted at SRC_RELPATH. */
-static svn_error_t *
-replace_moved_layer(const char *src_relpath,
- const char *dst_relpath,
- int src_op_depth,
- svn_wc__db_wcroot_t *wcroot,
- apr_pool_t *scratch_pool)
-{
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- int dst_op_depth = relpath_depth(dst_relpath);
- /* Replace entire subtree at one op-depth. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_LOCAL_RELPATH_OP_DEPTH));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
- src_relpath, src_op_depth));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- while (have_row)
- {
- svn_error_t *err;
- svn_sqlite__stmt_t *stmt2;
- const char *src_cp_relpath = svn_sqlite__column_text(stmt, 0, NULL);
- const char *dst_cp_relpath
- = svn_relpath_join(dst_relpath,
- svn_relpath_skip_ancestor(src_relpath,
- src_cp_relpath),
- scratch_pool);
-
- err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
- STMT_COPY_NODE_MOVE);
- if (!err)
- err = svn_sqlite__bindf(stmt2, "isdsds", wcroot->wc_id,
- src_cp_relpath, src_op_depth,
- dst_cp_relpath, dst_op_depth,
- svn_relpath_dirname(dst_cp_relpath,
- scratch_pool));
- if (!err)
- err = svn_sqlite__step_done(stmt2);
- if (err)
- return svn_error_compose_create(err, svn_sqlite__reset(stmt));
-
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (nmb->skip) /* Does parent now want a skip? */
+ break;
+ }
}
- SVN_ERR(svn_sqlite__reset(stmt));
-
- return SVN_NO_ERROR;
-}
-
-/* Transfer changes from the move source to the move destination.
- *
- * Drive the editor TC_EDITOR with the difference between DST_RELPATH
- * (at its own op-depth) and SRC_RELPATH (at op-depth zero).
- *
- * Then update the single op-depth layer in the move destination subtree
- * rooted at DST_RELPATH to make it match the move source subtree
- * rooted at SRC_RELPATH.
- *
- * ### And the other params?
- */
-static svn_error_t *
-drive_tree_conflict_editor(svn_editor_t *tc_editor,
- const char *src_relpath,
- const char *dst_relpath,
- int src_op_depth,
- svn_wc_operation_t operation,
- svn_wc_conflict_reason_t local_change,
- svn_wc_conflict_action_t incoming_change,
- svn_wc_conflict_version_t *old_version,
- svn_wc_conflict_version_t *new_version,
- svn_wc__db_t *db,
- svn_wc__db_wcroot_t *wcroot,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
-{
- /*
- * Refuse to auto-resolve unsupported tree conflicts.
- */
- /* ### Only handle conflicts created by update/switch operations for now. */
- if (operation != svn_wc_operation_update &&
- operation != svn_wc_operation_switch)
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("Cannot auto-resolve tree-conflict on '%s'"),
- svn_dirent_local_style(
- svn_dirent_join(wcroot->abspath,
- src_relpath, scratch_pool),
- scratch_pool));
-
- /* We walk the move source (i.e. the post-update tree), comparing each node
- * with the equivalent node at the move destination and applying the update
- * to nodes at the move destination. */
- SVN_ERR(update_moved_away_node(tc_editor, src_relpath, dst_relpath,
- src_op_depth,
- dst_relpath, old_version->peg_rev,
- db, wcroot, scratch_pool));
-
- SVN_ERR(replace_moved_layer(src_relpath, dst_relpath, src_op_depth,
- wcroot, scratch_pool));
-
- SVN_ERR(svn_editor_complete(tc_editor));
return SVN_NO_ERROR;
}
@@ -1788,14 +1603,13 @@ suitable_for_move(svn_wc__db_wcroot_t *wcroot,
STMT_SELECT_BASE_NODE));
SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- {
- revision = svn_sqlite__column_revnum(stmt, 4);
- repos_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
- }
- SVN_ERR(svn_sqlite__reset(stmt));
if (!have_row)
- return SVN_NO_ERROR; /* Return an error? */
+ return svn_error_trace(svn_sqlite__reset(stmt));
+
+ revision = svn_sqlite__column_revnum(stmt, 4);
+ repos_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
+
+ SVN_ERR(svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_REPOS_PATH_REVISION));
@@ -1816,22 +1630,17 @@ suitable_for_move(svn_wc__db_wcroot_t *wcroot,
svn_sqlite__reset(stmt),
_("Cannot apply update because move source "
"%s' is a mixed-revision working copy"),
- svn_dirent_local_style(svn_dirent_join(
- wcroot->abspath,
- local_relpath,
- scratch_pool),
- scratch_pool));
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
if (strcmp(relpath, svn_sqlite__column_text(stmt, 1, NULL)))
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
svn_sqlite__reset(stmt),
_("Cannot apply update because move source "
"'%s' is a switched subtree"),
- svn_dirent_local_style(svn_dirent_join(
- wcroot->abspath,
- local_relpath,
- scratch_pool),
- scratch_pool));
+ path_for_error_message(wcroot,
+ local_relpath,
+ scratch_pool));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
@@ -1845,96 +1654,113 @@ suitable_for_move(svn_wc__db_wcroot_t *wcroot,
/* The body of svn_wc__db_update_moved_away_conflict_victim(), which see.
*/
static svn_error_t *
-update_moved_away_conflict_victim(svn_wc__db_t *db,
+update_moved_away_conflict_victim(svn_revnum_t *old_rev,
+ svn_revnum_t *new_rev,
+ svn_wc__db_t *db,
svn_wc__db_wcroot_t *wcroot,
- const char *victim_relpath,
+ const char *local_relpath,
+ const char *delete_relpath,
svn_wc_operation_t operation,
- svn_wc_conflict_reason_t local_change,
- svn_wc_conflict_action_t incoming_change,
- const char *move_src_op_root_relpath,
- svn_wc_conflict_version_t *old_version,
- svn_wc_conflict_version_t *new_version,
+ svn_wc_conflict_action_t action,
+ svn_wc_conflict_reason_t reason,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_editor_t *tc_editor;
- struct tc_editor_baton *tc_editor_baton;
- svn_sqlite__stmt_t *stmt;
- svn_boolean_t have_row;
- const char *dummy1, *dummy2, *dummy3;
- int src_op_depth;
- const char *move_root_dst_abspath;
+ update_move_baton_t umb = { NULL };
+ const char *src_relpath, *dst_relpath;
+ svn_wc_conflict_version_t old_version;
+ svn_wc_conflict_version_t new_version;
+ apr_int64_t repos_id;
+ node_move_baton_t nmb = { 0 };
- /* ### assumes wc write lock already held */
+ SVN_ERR_ASSERT(svn_relpath_skip_ancestor(delete_relpath, local_relpath));
/* Construct editor baton. */
- tc_editor_baton = apr_pcalloc(scratch_pool, sizeof(*tc_editor_baton));
- SVN_ERR(svn_wc__db_op_depth_moved_to(
- &dummy1, &tc_editor_baton->move_root_dst_relpath, &dummy2, &dummy3,
- relpath_depth(move_src_op_root_relpath) - 1,
- wcroot, victim_relpath, scratch_pool, scratch_pool));
- if (tc_editor_baton->move_root_dst_relpath == NULL)
+
+ SVN_ERR(find_src_op_depth(&umb.src_op_depth, wcroot,
+ local_relpath, relpath_depth(delete_relpath),
+ scratch_pool));
+
+ SVN_ERR(svn_wc__db_scan_moved_to_internal(&src_relpath, &dst_relpath, NULL,
+ wcroot, local_relpath,
+ umb.src_op_depth,
+ scratch_pool, scratch_pool));
+
+ if (dst_relpath == NULL)
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("The node '%s' has not been moved away"),
- svn_dirent_local_style(
- svn_dirent_join(wcroot->abspath, victim_relpath,
- scratch_pool),
- scratch_pool));
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
- move_root_dst_abspath
- = svn_dirent_join(wcroot->abspath, tc_editor_baton->move_root_dst_relpath,
- scratch_pool);
- SVN_ERR(svn_wc__write_check(db, move_root_dst_abspath, scratch_pool));
+ umb.dst_op_depth = relpath_depth(dst_relpath);
- tc_editor_baton->operation = operation;
- tc_editor_baton->old_version= old_version;
- tc_editor_baton->new_version= new_version;
- tc_editor_baton->db = db;
- tc_editor_baton->wcroot = wcroot;
- tc_editor_baton->result_pool = scratch_pool;
+ SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+ SVN_ERR(verify_write_lock(wcroot, dst_relpath, scratch_pool));
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_HIGHEST_WORKING_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
- move_src_op_root_relpath,
- relpath_depth(move_src_op_root_relpath)));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- if (have_row)
- src_op_depth = svn_sqlite__column_int(stmt, 0);
- SVN_ERR(svn_sqlite__reset(stmt));
- if (!have_row)
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("'%s' is not deleted"),
- svn_dirent_local_style(
- svn_dirent_join(wcroot->abspath, victim_relpath,
- scratch_pool),
- scratch_pool));
- if (src_op_depth == 0)
- SVN_ERR(suitable_for_move(wcroot, victim_relpath, scratch_pool));
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, &new_version.node_kind,
+ &new_version.peg_rev,
+ &new_version.path_in_repos, &repos_id,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ wcroot, src_relpath, umb.src_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__db_fetch_repos_info(&new_version.repos_url,
+ &new_version.repos_uuid,
+ wcroot, repos_id,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, &old_version.node_kind,
+ &old_version.peg_rev,
+ &old_version.path_in_repos, &repos_id,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ wcroot, dst_relpath, umb.dst_op_depth,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__db_fetch_repos_info(&old_version.repos_url,
+ &old_version.repos_uuid,
+ wcroot, repos_id,
+ scratch_pool));
+ *old_rev = old_version.peg_rev;
+ *new_rev = new_version.peg_rev;
+
+ umb.operation = operation;
+ umb.old_version= &old_version;
+ umb.new_version= &new_version;
+ umb.db = db;
+ umb.wcroot = wcroot;
+ umb.cancel_func = cancel_func;
+ umb.cancel_baton = cancel_baton;
+
+ if (umb.src_op_depth == 0)
+ SVN_ERR(suitable_for_move(wcroot, src_relpath, scratch_pool));
/* Create a new, and empty, list for notification information. */
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_UPDATE_MOVE_LIST));
- /* Create the editor... */
- SVN_ERR(svn_editor_create(&tc_editor, tc_editor_baton,
- cancel_func, cancel_baton,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_editor_setcb_many(tc_editor, &editor_ops, scratch_pool));
-
- /* ... and drive it. */
- SVN_ERR(drive_tree_conflict_editor(tc_editor,
- victim_relpath,
- tc_editor_baton->move_root_dst_relpath,
- src_op_depth,
- operation,
- local_change, incoming_change,
- tc_editor_baton->old_version,
- tc_editor_baton->new_version,
- db, wcroot,
- cancel_func, cancel_baton,
- scratch_pool));
+
+ /* Drive the editor... */
+
+ nmb.umb = &umb;
+ nmb.src_relpath = src_relpath;
+ nmb.dst_relpath = dst_relpath;
+ /* nmb.shadowed = FALSE; */
+ /* nmb.edited = FALSE; */
+ /* nmb.skip_children = FALSE; */
+
+ /* We walk the move source (i.e. the post-update tree), comparing each node
+ * with the equivalent node at the move destination and applying the update
+ * to nodes at the move destination. */
+ SVN_ERR(update_moved_away_node(&nmb, wcroot, src_relpath, dst_relpath,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__db_op_copy_layer_internal(wcroot, src_relpath,
+ umb.src_op_depth,
+ dst_relpath, NULL, NULL,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -1942,58 +1768,43 @@ update_moved_away_conflict_victim(svn_wc__db_t *db,
svn_error_t *
svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db,
- const char *victim_abspath,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
+ const char *local_abspath,
+ const char *delete_op_abspath,
+ svn_wc_operation_t operation,
+ svn_wc_conflict_action_t action,
+ svn_wc_conflict_reason_t reason,
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__db_wcroot_t *wcroot;
+ svn_revnum_t old_rev, new_rev;
const char *local_relpath;
- svn_wc_operation_t operation;
- svn_wc_conflict_reason_t local_change;
- svn_wc_conflict_action_t incoming_change;
- svn_wc_conflict_version_t *old_version;
- svn_wc_conflict_version_t *new_version;
- const char *move_src_op_root_abspath, *move_src_op_root_relpath;
+ const char *delete_relpath;
/* ### Check for mixed-rev src or dst? */
- SVN_ERR(get_tc_info(&operation, &local_change, &incoming_change,
- &move_src_op_root_abspath,
- &old_version, &new_version,
- db, victim_abspath,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_wc__write_check(db, move_src_op_root_abspath, scratch_pool));
-
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
- db, victim_abspath,
+ db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- move_src_op_root_relpath
- = svn_dirent_skip_ancestor(wcroot->abspath, move_src_op_root_abspath);
+ delete_relpath
+ = svn_dirent_skip_ancestor(wcroot->abspath, delete_op_abspath);
SVN_WC__DB_WITH_TXN(
update_moved_away_conflict_victim(
- db, wcroot, local_relpath,
- operation, local_change, incoming_change,
- move_src_op_root_relpath,
- old_version, new_version,
+ &old_rev, &new_rev,
+ db, wcroot, local_relpath, delete_relpath,
+ operation, action, reason,
cancel_func, cancel_baton,
scratch_pool),
wcroot);
/* Send all queued up notifications. */
- SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,
- (old_version
- ? old_version->peg_rev
- : SVN_INVALID_REVNUM),
- (new_version
- ? new_version->peg_rev
- : SVN_INVALID_REVNUM),
+ SVN_ERR(svn_wc__db_update_move_list_notify(wcroot, old_rev, new_rev,
notify_func, notify_baton,
scratch_pool));
if (notify_func)
@@ -2008,7 +1819,7 @@ svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db,
notify->kind = svn_node_none;
notify->content_state = svn_wc_notify_state_inapplicable;
notify->prop_state = svn_wc_notify_state_inapplicable;
- notify->revision = new_version->peg_rev;
+ notify->revision = new_rev;
notify_func(notify_baton, notify, scratch_pool);
}
@@ -2017,11 +1828,12 @@ svn_wc__db_update_moved_away_conflict_victim(svn_wc__db_t *db,
}
/* Set *CAN_BUMP to TRUE if DEPTH is sufficient to cover the entire
- BASE tree at LOCAL_RELPATH, to FALSE otherwise. */
+ tree LOCAL_RELPATH at OP_DEPTH, to FALSE otherwise. */
static svn_error_t *
depth_sufficient_to_bump(svn_boolean_t *can_bump,
- const char *local_relpath,
svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int op_depth,
svn_depth_t depth,
apr_pool_t *scratch_pool)
{
@@ -2038,21 +1850,21 @@ depth_sufficient_to_bump(svn_boolean_t *can_bump,
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_OP_DEPTH_CHILDREN));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
- local_relpath, 0));
+ local_relpath, op_depth));
break;
case svn_depth_files:
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_HAS_NON_FILE_CHILDREN));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
- local_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ local_relpath, op_depth));
break;
case svn_depth_immediates:
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_SELECT_HAS_GRANDCHILDREN));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
- local_relpath));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+ local_relpath, op_depth));
break;
default:
SVN_ERR_MALFUNCTION();
@@ -2068,6 +1880,7 @@ depth_sufficient_to_bump(svn_boolean_t *can_bump,
static svn_error_t *
bump_mark_tree_conflict(svn_wc__db_wcroot_t *wcroot,
const char *move_src_root_relpath,
+ int src_op_depth,
const char *move_src_op_root_relpath,
const char *move_dst_op_root_relpath,
svn_wc__db_t *db,
@@ -2084,18 +1897,29 @@ bump_mark_tree_conflict(svn_wc__db_wcroot_t *wcroot,
svn_node_kind_t new_kind;
svn_wc_conflict_version_t *old_version;
svn_wc_conflict_version_t *new_version;
+ svn_skel_t *conflict;
+
+ /* Verify precondition: We are allowed to set a tree conflict here. */
+ SVN_ERR(verify_write_lock(wcroot, move_src_root_relpath, scratch_pool));
/* Read new (post-update) information from the new move source BASE node. */
- SVN_ERR(svn_wc__db_base_get_info_internal(NULL, &new_kind, &new_rev,
- &new_repos_relpath, &repos_id,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- wcroot, move_src_op_root_relpath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_depth_get_info(NULL, &new_kind, &new_rev,
+ &new_repos_relpath, &repos_id,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ wcroot, move_src_op_root_relpath,
+ src_op_depth, scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_fetch_repos_info(&repos_root_url, &repos_uuid,
- wcroot->sdb, repos_id, scratch_pool));
+ wcroot, repos_id, scratch_pool));
+
+ /* Read old (pre-update) information from the move destination node.
- /* Read old (pre-update) information from the move destination node. */
+ This potentially touches nodes that aren't locked by us, but that is not
+ a problem because we have a SQLite write lock here, and all sqlite
+ operations that affect move stability use a sqlite lock as well.
+ (And affecting the move itself requires a write lock on the node that
+ we do own the lock for: the move source)
+ */
SVN_ERR(svn_wc__db_depth_get_info(NULL, &old_kind, &old_rev,
&old_repos_relpath, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
@@ -2103,6 +1927,21 @@ bump_mark_tree_conflict(svn_wc__db_wcroot_t *wcroot,
relpath_depth(move_dst_op_root_relpath),
scratch_pool, scratch_pool));
+ if (strcmp(move_src_root_relpath, move_src_op_root_relpath))
+ {
+ /* We have information for the op-root, but need it for the node that
+ we are putting the tree conflict on. Luckily we know that we have
+ a clean BASE */
+
+ const char *rpath = svn_relpath_skip_ancestor(move_src_op_root_relpath,
+ move_src_root_relpath);
+
+ old_repos_relpath = svn_relpath_join(old_repos_relpath, rpath,
+ scratch_pool);
+ new_repos_relpath = svn_relpath_join(new_repos_relpath, rpath,
+ scratch_pool);
+ }
+
old_version = svn_wc_conflict_version_create2(
repos_root_url, repos_uuid, old_repos_relpath, old_rev,
old_kind, scratch_pool);
@@ -2110,38 +1949,202 @@ bump_mark_tree_conflict(svn_wc__db_wcroot_t *wcroot,
repos_root_url, repos_uuid, new_repos_relpath, new_rev,
new_kind, scratch_pool);
- SVN_ERR(mark_tree_conflict(move_src_root_relpath,
- wcroot, db, old_version, new_version,
- move_dst_op_root_relpath,
- svn_wc_operation_update,
- old_kind, new_kind,
- old_repos_relpath,
- svn_wc_conflict_reason_moved_away,
- svn_wc_conflict_action_edit,
- move_src_op_root_relpath,
- scratch_pool));
+ SVN_ERR(create_tree_conflict(&conflict, wcroot, move_src_root_relpath,
+ move_dst_op_root_relpath,
+ db, old_version, new_version,
+ svn_wc_operation_update,
+ old_kind, new_kind,
+ old_repos_relpath,
+ svn_wc_conflict_reason_moved_away,
+ svn_wc_conflict_action_edit,
+ move_src_op_root_relpath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(update_move_list_add(wcroot, move_src_root_relpath, db,
+ svn_wc_notify_tree_conflict,
+ new_kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ conflict, NULL, scratch_pool));
return SVN_NO_ERROR;
}
-/* Bump LOCAL_RELPATH, and all the children of LOCAL_RELPATH, that are
- moved-to at op-depth greater than OP_DEPTH. SRC_DONE is a hash
- with keys that are 'const char *' relpaths that have already been
- bumped. Any bumped paths are added to SRC_DONE. */
+/* Checks if SRC_RELPATH is within BUMP_DEPTH from BUMP_ROOT. Sets
+ * *SKIP to TRUE if the node should be skipped, otherwise to FALSE.
+ * Sets *SRC_DEPTH to the remaining depth at SRC_RELPATH.
+ */
+static svn_error_t *
+check_bump_layer(svn_boolean_t *skip,
+ svn_depth_t *src_depth,
+ const char *bump_root,
+ svn_depth_t bump_depth,
+ const char *src_relpath,
+ svn_node_kind_t src_kind,
+ apr_pool_t *scratch_pool)
+{
+ const char *relpath;
+
+ *skip = FALSE;
+ *src_depth = bump_depth;
+
+ relpath = svn_relpath_skip_ancestor(bump_root, src_relpath);
+
+ if (!relpath)
+ *skip = TRUE;
+
+ if (bump_depth == svn_depth_infinity)
+ return SVN_NO_ERROR;
+
+ if (relpath && *relpath == '\0')
+ return SVN_NO_ERROR;
+
+ switch (bump_depth)
+ {
+ case svn_depth_empty:
+ *skip = TRUE;
+ break;
+
+ case svn_depth_files:
+ if (src_kind != svn_node_file)
+ {
+ *skip = TRUE;
+ break;
+ }
+ /* Fallthrough */
+ case svn_depth_immediates:
+ if (!relpath || relpath_depth(relpath) > 1)
+ *skip = TRUE;
+
+ *src_depth = svn_depth_empty;
+ break;
+ default:
+ SVN_ERR_MALFUNCTION();
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* The guts of bump_moved_away: Determines if a move can be bumped to match
+ * the move origin and if so performs this bump.
+ */
+static svn_error_t *
+bump_moved_layer(svn_boolean_t *recurse,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int op_depth,
+ const char *src_relpath,
+ int src_del_depth,
+ svn_depth_t src_depth,
+ const char *dst_relpath,
+ svn_wc__db_t *db,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ svn_skel_t *conflict;
+ svn_boolean_t can_bump;
+ const char *src_root_relpath;
+
+ SVN_ERR(verify_write_lock(wcroot, local_relpath, scratch_pool));
+
+ *recurse = FALSE;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_HAS_LAYER_BETWEEN));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id, local_relpath,
+ op_depth, src_del_depth));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ if (have_row)
+ return SVN_NO_ERROR;
+
+ if (op_depth == 0)
+ SVN_ERR(depth_sufficient_to_bump(&can_bump, wcroot, src_relpath,
+ op_depth, src_depth, scratch_pool));
+ else
+ /* Having chosen to bump an entire BASE tree move we
+ always have sufficient depth to bump subtree moves. */
+ can_bump = TRUE;
+
+ /* Are we allowed to bump */
+ if (can_bump)
+ {
+ svn_boolean_t locked;
+
+ SVN_ERR(svn_wc__db_wclock_owns_lock_internal(&locked, wcroot,
+ dst_relpath,
+ FALSE, scratch_pool));
+
+ if (!locked)
+ can_bump = FALSE;
+ }
+
+ src_root_relpath = svn_relpath_prefix(src_relpath, src_del_depth,
+ scratch_pool);
+
+ if (!can_bump)
+ {
+ SVN_ERR(bump_mark_tree_conflict(wcroot, src_relpath, op_depth,
+ src_root_relpath, dst_relpath,
+ db, scratch_pool));
+
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, NULL,
+ wcroot, src_root_relpath,
+ scratch_pool, scratch_pool));
+
+ /* ### TODO: check this is the right sort of tree-conflict? */
+ if (!conflict)
+ {
+ /* ### TODO: verify moved_here? */
+
+ SVN_ERR(verify_write_lock(wcroot, src_relpath, scratch_pool));
+
+ SVN_ERR(svn_wc__db_op_copy_layer_internal(wcroot,
+ src_relpath, op_depth,
+ dst_relpath, NULL, NULL,
+ scratch_pool));
+
+ *recurse = TRUE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Internal storage for bump_moved_away() */
+struct bump_pair_t
+{
+ const char *src_relpath;
+ const char *dst_relpath;
+ int src_del_op_depth;
+ svn_node_kind_t src_kind;
+};
+
+/* Bump moves of LOCAL_RELPATH and all its descendants that were
+ originally below LOCAL_RELPATH at op-depth OP_DEPTH.
+ */
static svn_error_t *
bump_moved_away(svn_wc__db_wcroot_t *wcroot,
const char *local_relpath,
int op_depth,
- apr_hash_t *src_done,
svn_depth_t depth,
svn_wc__db_t *db,
- apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool;
+ int i;
+ apr_array_header_t *pairs = apr_array_make(scratch_pool, 32,
+ sizeof(struct bump_pair_t*));
+ /* Build an array, as we can't execute the same Sqlite query recursively */
iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -2151,126 +2154,48 @@ bump_moved_away(svn_wc__db_wcroot_t *wcroot,
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while(have_row)
{
- svn_sqlite__stmt_t *stmt2;
- const char *src_relpath, *dst_relpath;
- int src_op_depth = svn_sqlite__column_int(stmt, 2);
- svn_error_t *err;
- svn_skel_t *conflict;
- svn_depth_t src_depth = depth;
-
- svn_pool_clear(iterpool);
+ struct bump_pair_t *bp = apr_pcalloc(scratch_pool, sizeof(*bp));
- src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
- dst_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+ bp->src_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+ bp->dst_relpath = svn_sqlite__column_text(stmt, 1, scratch_pool);
+ bp->src_del_op_depth = svn_sqlite__column_int(stmt, 2);
+ bp->src_kind = svn_sqlite__column_token(stmt, 3, kind_map);
- if (depth != svn_depth_infinity)
- {
- svn_boolean_t skip_this_src = FALSE;
- svn_node_kind_t src_kind;
+ APR_ARRAY_PUSH(pairs, struct bump_pair_t *) = bp;
- if (strcmp(src_relpath, local_relpath))
- {
- switch (depth)
- {
- case svn_depth_empty:
- skip_this_src = TRUE;
- break;
- case svn_depth_files:
- src_kind = svn_sqlite__column_token(stmt, 3, kind_map);
- if (src_kind != svn_node_file)
- {
- skip_this_src = TRUE;
- break;
- }
- /* Fallthrough */
- case svn_depth_immediates:
- if (strcmp(svn_relpath_dirname(src_relpath, scratch_pool),
- local_relpath))
- skip_this_src = TRUE;
- src_depth = svn_depth_empty;
- break;
- default:
- SVN_ERR_MALFUNCTION();
- }
- }
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
- if (skip_this_src)
- {
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- continue;
- }
- }
+ SVN_ERR(svn_sqlite__reset(stmt));
- err = svn_sqlite__get_statement(&stmt2, wcroot->sdb,
- STMT_HAS_LAYER_BETWEEN);
- if (!err)
- err = svn_sqlite__bindf(stmt2, "isdd", wcroot->wc_id, local_relpath,
- op_depth, src_op_depth);
- if (!err)
- err = svn_sqlite__step(&have_row, stmt2);
- if (!err)
- err = svn_sqlite__reset(stmt2);
- if (!err && !have_row)
- {
- svn_boolean_t can_bump;
- const char *src_root_relpath = src_relpath;
+ for (i = 0; i < pairs->nelts; i++)
+ {
+ struct bump_pair_t *bp = APR_ARRAY_IDX(pairs, i, struct bump_pair_t *);
+ svn_boolean_t skip;
+ svn_depth_t src_wc_depth;
- if (op_depth == 0)
- err = depth_sufficient_to_bump(&can_bump, src_relpath, wcroot,
- src_depth, scratch_pool);
- else
- /* Having chosen to bump an entire BASE tree move we
- always have sufficient depth to bump subtree moves. */
- can_bump = TRUE;
+ svn_pool_clear(iterpool);
- if (!err)
- {
- if (!can_bump)
- {
- err = bump_mark_tree_conflict(wcroot, src_relpath,
- src_root_relpath, dst_relpath,
- db, scratch_pool);
- if (err)
- return svn_error_compose_create(err,
- svn_sqlite__reset(stmt));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- continue;
- }
- while (relpath_depth(src_root_relpath) > src_op_depth)
- src_root_relpath = svn_relpath_dirname(src_root_relpath,
- iterpool);
+ SVN_ERR(check_bump_layer(&skip, &src_wc_depth, local_relpath, depth,
+ bp->src_relpath, bp->src_kind, iterpool));
- if (!svn_hash_gets(src_done, src_relpath))
- {
- svn_hash_sets(src_done,
- apr_pstrdup(result_pool, src_relpath), "");
- err = svn_wc__db_read_conflict_internal(&conflict, wcroot,
- src_root_relpath,
- iterpool, iterpool);
- /* ### TODO: check this is the right sort of tree-conflict? */
- if (!err && !conflict)
- {
- /* ### TODO: verify moved_here? */
- err = replace_moved_layer(src_relpath, dst_relpath,
- op_depth, wcroot, iterpool);
-
- if (!err)
- err = bump_moved_away(wcroot, dst_relpath,
- relpath_depth(dst_relpath),
- src_done, depth, db,
- result_pool, iterpool);
- }
- }
- }
+ if (!skip)
+ {
+ svn_boolean_t recurse;
+
+ SVN_ERR(bump_moved_layer(&recurse, wcroot,
+ local_relpath, op_depth,
+ bp->src_relpath, bp->src_del_op_depth,
+ src_wc_depth, bp->dst_relpath,
+ db, iterpool));
+
+ if (recurse)
+ SVN_ERR(bump_moved_away(wcroot, bp->dst_relpath,
+ relpath_depth(bp->dst_relpath),
+ depth, db, iterpool));
}
-
- if (err)
- return svn_error_compose_create(err, svn_sqlite__reset(stmt));
-
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
- SVN_ERR(svn_sqlite__reset(stmt));
svn_pool_destroy(iterpool);
@@ -2284,84 +2209,216 @@ svn_wc__db_bump_moved_away(svn_wc__db_wcroot_t *wcroot,
svn_wc__db_t *db,
apr_pool_t *scratch_pool)
{
- apr_hash_t *src_done;
-
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_UPDATE_MOVE_LIST));
if (local_relpath[0] != '\0')
{
- const char *dummy1, *move_dst_op_root_relpath;
- const char *move_src_root_relpath, *move_src_op_root_relpath;
+ const char *move_dst_op_root_relpath;
+ const char *move_src_root_relpath, *delete_relpath;
+ svn_error_t *err;
/* Is the root of the update moved away? (Impossible for the wcroot) */
- SVN_ERR(svn_wc__db_op_depth_moved_to(&dummy1, &move_dst_op_root_relpath,
- &move_src_root_relpath,
- &move_src_op_root_relpath, 0,
- wcroot, local_relpath,
- scratch_pool, scratch_pool));
- if (move_src_root_relpath)
+ err = svn_wc__db_scan_moved_to_internal(&move_src_root_relpath,
+ &move_dst_op_root_relpath,
+ &delete_relpath,
+ wcroot, local_relpath,
+ 0 /* BASE */,
+ scratch_pool, scratch_pool);
+
+ if (err)
+ {
+ if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ }
+ else if (move_src_root_relpath)
{
if (strcmp(move_src_root_relpath, local_relpath))
{
- SVN_ERR(bump_mark_tree_conflict(wcroot, move_src_root_relpath,
- move_src_op_root_relpath,
- move_dst_op_root_relpath,
- db, scratch_pool));
+ /* An ancestor of the path that was updated is moved away.
+
+ If we have a lock on that ancestor, we can mark a tree
+ conflict on it, if we don't we ignore this case. A future
+ update of the ancestor will handle this. */
+ svn_boolean_t locked;
+
+ SVN_ERR(svn_wc__db_wclock_owns_lock_internal(
+ &locked, wcroot,
+ move_src_root_relpath,
+ FALSE, scratch_pool));
+
+ if (locked)
+ {
+ SVN_ERR(bump_mark_tree_conflict(wcroot,
+ move_src_root_relpath, 0,
+ delete_relpath,
+ move_dst_op_root_relpath,
+ db, scratch_pool));
+ }
return SVN_NO_ERROR;
}
}
}
- src_done = apr_hash_make(scratch_pool);
- SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, src_done, depth, db,
- scratch_pool, scratch_pool));
+ SVN_ERR(bump_moved_away(wcroot, local_relpath, 0, depth, db, scratch_pool));
return SVN_NO_ERROR;
}
+/* Set *OPERATION, *LOCAL_CHANGE, *INCOMING_CHANGE, *OLD_VERSION, *NEW_VERSION
+ * to reflect the tree conflict on the victim SRC_ABSPATH in DB.
+ *
+ * If SRC_ABSPATH is not a tree-conflict victim, return an error.
+ */
static svn_error_t *
-resolve_delete_raise_moved_away(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- svn_wc__db_t *db,
- svn_wc_operation_t operation,
- svn_wc_conflict_action_t action,
- svn_wc_conflict_version_t *old_version,
- svn_wc_conflict_version_t *new_version,
- apr_pool_t *scratch_pool)
+fetch_conflict_details(int *src_op_depth,
+ svn_wc_operation_t *operation,
+ svn_wc_conflict_action_t *action,
+ svn_wc_conflict_version_t **left_version,
+ svn_wc_conflict_version_t **right_version,
+ svn_wc__db_wcroot_t *wcroot,
+ svn_wc__db_t *db,
+ const char *local_relpath,
+ const svn_skel_t *conflict_skel,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const apr_array_header_t *locations;
+ svn_boolean_t text_conflicted;
+ svn_boolean_t prop_conflicted;
+ svn_boolean_t tree_conflicted;
+ const char *move_src_op_root_abspath;
+ svn_wc_conflict_reason_t reason;
+ const char *local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
+ scratch_pool);
+
+ if (!conflict_skel)
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("'%s' is not in conflict"),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__conflict_read_info(operation, &locations,
+ &text_conflicted, &prop_conflicted,
+ &tree_conflicted,
+ db, local_abspath,
+ conflict_skel, result_pool,
+ scratch_pool));
+
+ if (text_conflicted || prop_conflicted || !tree_conflicted)
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("'%s' is not a valid tree-conflict victim"),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason,
+ action,
+ &move_src_op_root_abspath,
+ db, local_abspath,
+ conflict_skel, result_pool,
+ scratch_pool));
+
+ if (reason == svn_wc_conflict_reason_moved_away)
+ return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("'%s' is already a moved away tree-conflict"),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
+ if (left_version)
+ {
+ if (locations && locations->nelts > 0)
+ *left_version = APR_ARRAY_IDX(locations, 0,
+ svn_wc_conflict_version_t *);
+ else
+ *left_version = NULL;
+ }
+
+ if (right_version)
+ {
+ if (locations && locations->nelts > 1)
+ *right_version = APR_ARRAY_IDX(locations, 1,
+ svn_wc_conflict_version_t *);
+ else
+ *right_version = NULL;
+ }
+
+ {
+ int del_depth = relpath_depth(local_relpath);
+
+ if (move_src_op_root_abspath)
+ del_depth = relpath_depth(
+ svn_dirent_skip_ancestor(wcroot->abspath,
+ move_src_op_root_abspath));
+
+ SVN_ERR(find_src_op_depth(src_op_depth, wcroot, local_relpath, del_depth,
+ scratch_pool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__db_op_raise_moved_away_internal(
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ int src_op_depth,
+ svn_wc__db_t *db,
+ svn_wc_operation_t operation,
+ svn_wc_conflict_action_t action,
+ const svn_wc_conflict_version_t *old_version,
+ const svn_wc_conflict_version_t *new_version,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- int op_depth = relpath_depth(local_relpath);
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_UPDATE_MOVE_LIST));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_OP_DEPTH_MOVED_PAIR));
+ STMT_SELECT_MOVED_DESCENDANTS_SRC));
SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
- op_depth));
+ src_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while(have_row)
{
- const char *moved_relpath = svn_sqlite__column_text(stmt, 0, NULL);
- const char *move_root_dst_relpath = svn_sqlite__column_text(stmt, 1,
- NULL);
- const char *moved_dst_repos_relpath = svn_sqlite__column_text(stmt, 2,
- NULL);
+ svn_error_t *err;
+ int delete_op_depth = svn_sqlite__column_int(stmt, 0);
+ const char *src_relpath = svn_sqlite__column_text(stmt, 1, NULL);
+ svn_node_kind_t src_kind = svn_sqlite__column_token(stmt, 2, kind_map);
+ const char *src_repos_relpath = svn_sqlite__column_text(stmt, 3, NULL);
+ const char *dst_relpath = svn_sqlite__column_text(stmt, 4, NULL);
+ svn_skel_t *conflict;
svn_pool_clear(iterpool);
- SVN_ERR(mark_tree_conflict(moved_relpath,
- wcroot, db, old_version, new_version,
- move_root_dst_relpath, operation,
- svn_node_dir /* ### ? */,
- svn_node_dir /* ### ? */,
- moved_dst_repos_relpath,
+ SVN_ERR_ASSERT(src_repos_relpath != NULL);
+
+ err = create_tree_conflict(&conflict, wcroot, src_relpath, dst_relpath,
+ db, old_version, new_version, operation,
+ src_kind /* ### old kind */,
+ src_kind /* ### new kind */,
+ src_repos_relpath,
svn_wc_conflict_reason_moved_away,
- action, local_relpath,
- iterpool));
+ action,
+ svn_relpath_prefix(src_relpath,
+ delete_op_depth,
+ iterpool),
+ iterpool, iterpool);
+
+ if (!err)
+ err = update_move_list_add(wcroot, src_relpath, db,
+ svn_wc_notify_tree_conflict,
+ src_kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ conflict, NULL, scratch_pool);
+
+ if (err)
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
@@ -2373,41 +2430,52 @@ resolve_delete_raise_moved_away(svn_wc__db_wcroot_t *wcroot,
}
svn_error_t *
-svn_wc__db_resolve_delete_raise_moved_away(svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- apr_pool_t *scratch_pool)
+svn_wc__db_op_raise_moved_away(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
svn_wc_operation_t operation;
- svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
- svn_wc_conflict_version_t *old_version, *new_version;
+ svn_wc_conflict_version_t *left_version, *right_version;
+ int move_src_op_depth;
+ svn_skel_t *conflict;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_ERR(get_tc_info(&operation, &reason, &action, NULL,
- &old_version, &new_version,
- db, local_abspath, scratch_pool, scratch_pool));
-
- SVN_WC__DB_WITH_TXN(
- resolve_delete_raise_moved_away(wcroot, local_relpath,
- db, operation, action,
- old_version, new_version,
- scratch_pool),
+ SVN_WC__DB_WITH_TXN4(
+ svn_wc__db_read_conflict_internal(&conflict, NULL, NULL,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool),
+ fetch_conflict_details(&move_src_op_depth,
+ &operation, &action,
+ &left_version, &right_version,
+ wcroot, db, local_relpath, conflict,
+ scratch_pool, scratch_pool),
+ svn_wc__db_op_mark_resolved_internal(wcroot, local_relpath, db,
+ FALSE, FALSE, TRUE,
+ NULL, scratch_pool),
+ svn_wc__db_op_raise_moved_away_internal(wcroot, local_relpath,
+ move_src_op_depth,
+ db, operation, action,
+ left_version, right_version,
+ scratch_pool),
wcroot);
+ /* These version numbers are valid for update/switch notifications
+ only! */
SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,
- (old_version
- ? old_version->peg_rev
+ (left_version
+ ? left_version->peg_rev
: SVN_INVALID_REVNUM),
- (new_version
- ? new_version->peg_rev
+ (right_version
+ ? right_version->peg_rev
: SVN_INVALID_REVNUM),
notify_func, notify_baton,
scratch_pool));
@@ -2416,159 +2484,109 @@ svn_wc__db_resolve_delete_raise_moved_away(svn_wc__db_t *db,
}
static svn_error_t *
-break_move(svn_wc__db_wcroot_t *wcroot,
- const char *src_relpath,
- int src_op_depth,
- const char *dst_relpath,
- int dst_op_depth,
- apr_pool_t *scratch_pool)
-{
- svn_sqlite__stmt_t *stmt;
-
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_CLEAR_MOVED_TO_RELPATH));
- SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, src_relpath,
- src_op_depth));
- SVN_ERR(svn_sqlite__step_done(stmt));
-
- /* This statement clears moved_here. */
- SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_UPDATE_OP_DEPTH_RECURSIVE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isdd", wcroot->wc_id,
- dst_relpath, dst_op_depth, dst_op_depth));
- SVN_ERR(svn_sqlite__step_done(stmt));
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__db_resolve_break_moved_away_internal(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- int op_depth,
- apr_pool_t *scratch_pool)
-{
- const char *dummy1, *move_dst_op_root_relpath;
- const char *dummy2, *move_src_op_root_relpath;
-
- /* We want to include the passed op-depth, but the function does a > check */
- SVN_ERR(svn_wc__db_op_depth_moved_to(&dummy1, &move_dst_op_root_relpath,
- &dummy2,
- &move_src_op_root_relpath,
- op_depth - 1,
- wcroot, local_relpath,
- scratch_pool, scratch_pool));
-
- SVN_ERR_ASSERT(move_src_op_root_relpath != NULL
- && move_dst_op_root_relpath != NULL);
-
- SVN_ERR(break_move(wcroot, local_relpath,
- relpath_depth(move_src_op_root_relpath),
- move_dst_op_root_relpath,
- relpath_depth(move_dst_op_root_relpath),
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-break_moved_away_children_internal(svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
+break_moved_away(svn_wc__db_wcroot_t *wcroot,
+ svn_wc__db_t *db,
+ const char *local_relpath,
+ int parent_src_op_depth,
+ apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
apr_pool_t *iterpool;
+ svn_error_t *err = NULL;
SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb,
STMT_CREATE_UPDATE_MOVE_LIST));
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
- STMT_SELECT_MOVED_PAIR2));
- SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
+ STMT_SELECT_MOVED_DESCENDANTS_SRC));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+ parent_src_op_depth));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
iterpool = svn_pool_create(scratch_pool);
while (have_row)
{
- const char *src_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
- const char *dst_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
- int src_op_depth = svn_sqlite__column_int(stmt, 2);
+ int src_op_depth = svn_sqlite__column_int(stmt, 0);
+ const char *src_relpath = svn_sqlite__column_text(stmt, 1, NULL);
+ svn_node_kind_t src_kind = svn_sqlite__column_token(stmt, 2, kind_map);
+ const char *dst_relpath = svn_sqlite__column_text(stmt, 4, NULL);
svn_pool_clear(iterpool);
- SVN_ERR(break_move(wcroot, src_relpath, src_op_depth, dst_relpath,
- relpath_depth(dst_relpath), iterpool));
- SVN_ERR(update_move_list_add(wcroot, src_relpath,
- svn_wc_notify_move_broken,
- svn_node_unknown,
- svn_wc_notify_state_inapplicable,
- svn_wc_notify_state_inapplicable));
- SVN_ERR(svn_sqlite__step(&have_row, stmt));
- }
- svn_pool_destroy(iterpool);
+ err = verify_write_lock(wcroot, src_relpath, iterpool);
- SVN_ERR(svn_sqlite__reset(stmt));
+ if (!err)
+ err = verify_write_lock(wcroot, dst_relpath, iterpool);
- return SVN_NO_ERROR;
-}
+ if (err)
+ break;
-svn_error_t *
-svn_wc__db_resolve_break_moved_away(svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_wcroot_t *wcroot;
- const char *local_relpath;
+ err = svn_error_trace(
+ svn_wc__db_op_break_move_internal(wcroot,
+ src_relpath, src_op_depth,
+ dst_relpath, NULL, iterpool));
- SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
- db, local_abspath,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_WCROOT(wcroot);
+ if (err)
+ break;
- SVN_WC__DB_WITH_TXN(
- svn_wc__db_resolve_break_moved_away_internal(wcroot, local_relpath,
- relpath_depth(local_relpath),
- scratch_pool),
- wcroot);
+ err = svn_error_trace(
+ update_move_list_add(wcroot, src_relpath, db,
+ svn_wc_notify_move_broken,
+ src_kind,
+ svn_wc_notify_state_inapplicable,
+ svn_wc_notify_state_inapplicable,
+ NULL, NULL, scratch_pool));
- if (notify_func)
- {
- svn_wc_notify_t *notify;
+ if (err)
+ break;
- notify = svn_wc_create_notify(svn_dirent_join(wcroot->abspath,
- local_relpath,
- scratch_pool),
- svn_wc_notify_move_broken,
- scratch_pool);
- notify->kind = svn_node_unknown;
- notify->content_state = svn_wc_notify_state_inapplicable;
- notify->prop_state = svn_wc_notify_state_inapplicable;
- notify->revision = SVN_INVALID_REVNUM;
- notify_func(notify_baton, notify, scratch_pool);
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
+ svn_pool_destroy(iterpool);
- return SVN_NO_ERROR;
+ return svn_error_compose_create(err, svn_sqlite__reset(stmt));
}
svn_error_t *
-svn_wc__db_resolve_break_moved_away_children(svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- apr_pool_t *scratch_pool)
+svn_wc__db_op_break_moved_away(svn_wc__db_t *db,
+ const char *local_abspath,
+ const char *del_op_root_abspath,
+ svn_boolean_t mark_tc_resolved,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
{
svn_wc__db_wcroot_t *wcroot;
const char *local_relpath;
+ const char *del_relpath;
+ int src_op_depth;
SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
db, local_abspath,
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(wcroot);
- SVN_WC__DB_WITH_TXN(
- break_moved_away_children_internal(wcroot, local_relpath, scratch_pool),
+ if (del_op_root_abspath)
+ del_relpath = svn_dirent_skip_ancestor(wcroot->abspath,
+ del_op_root_abspath);
+ else
+ del_relpath = NULL;
+
+
+ SVN_WC__DB_WITH_TXN4(
+ find_src_op_depth(&src_op_depth, wcroot, local_relpath,
+ del_relpath ? relpath_depth(del_relpath)
+ : relpath_depth(local_relpath),
+ scratch_pool),
+ break_moved_away(wcroot, db, local_relpath, src_op_depth,
+ scratch_pool),
+ mark_tc_resolved
+ ? svn_wc__db_op_mark_resolved_internal(wcroot, local_relpath, db,
+ FALSE, FALSE, TRUE,
+ NULL, scratch_pool)
+ : SVN_NO_ERROR,
+ SVN_NO_ERROR,
wcroot);
SVN_ERR(svn_wc__db_update_move_list_notify(wcroot,