You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/02/04 21:48:13 UTC
svn commit: r1442344 [20/39] - in /subversion/branches/fsfs-format7: ./
build/ build/ac-macros/ build/generator/ build/generator/templates/
build/win32/ contrib/client-side/emacs/
contrib/server-side/fsfsfixer/fixer/ contrib/server-side/svncutter/ doc/...
Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/update_editor.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/update_editor.c Mon Feb 4 20:48:05 2013
@@ -34,7 +34,6 @@
#include "svn_types.h"
#include "svn_pools.h"
-#include "svn_delta.h"
#include "svn_hash.h"
#include "svn_string.h"
#include "svn_dirent_uri.h"
@@ -47,12 +46,13 @@
#include "wc.h"
#include "adm_files.h"
#include "conflicts.h"
-#include "entries.h"
#include "translate.h"
#include "workqueue.h"
#include "private/svn_subr_private.h"
#include "private/svn_wc_private.h"
+#include "private/svn_editor.h"
+
/* Checks whether a svn_wc__db_status_t indicates whether a node is
present in a working copy. Used by the editor implementation */
#define IS_NODE_PRESENT(status) \
@@ -322,6 +322,10 @@ struct dir_baton
marked as deleted. */
svn_boolean_t shadowed;
+ /* Set on a node when the existing node is obstructed, and the edit operation
+ continues as semi-shadowed update */
+ svn_boolean_t edit_obstructed;
+
/* The (new) changed_* information, cached to avoid retrieving it later */
svn_revnum_t changed_rev;
apr_time_t changed_date;
@@ -496,19 +500,6 @@ cleanup_edit_baton(void *edit_baton)
return APR_SUCCESS;
}
-/* An APR pool cleanup handler. This is a child handler, it removes
- the mail pool handler.
- <stsp> mail pool?
- <hwright> that's where the missing commit mails are going! */
-static apr_status_t
-cleanup_edit_baton_child(void *edit_baton)
-{
- struct edit_baton *eb = edit_baton;
- apr_pool_cleanup_kill(eb->pool, eb, cleanup_edit_baton);
- return APR_SUCCESS;
-}
-
-
/* Make a new dir baton in a subpool of PB->pool. PB is the parent baton.
If PATH and PB are NULL, this is the root directory of the edit; in this
case, make the new dir baton in a subpool of EB->pool.
@@ -634,7 +625,7 @@ make_dir_baton(struct dir_baton **d_p,
if (pb)
{
d->skip_this = pb->skip_this;
- d->shadowed = pb->shadowed;
+ d->shadowed = pb->shadowed || pb->edit_obstructed;
}
/* The caller of this function needs to fill these in. */
@@ -747,6 +738,10 @@ struct file_baton
in the working copy (replaced, deleted, etc.). */
svn_boolean_t shadowed;
+ /* Set on a node when the existing node is obstructed, and the edit operation
+ continues as semi-shadowed update */
+ svn_boolean_t edit_obstructed;
+
/* The (new) changed_* information, cached to avoid retrieving it later */
svn_revnum_t changed_rev;
apr_time_t changed_date;
@@ -843,7 +838,7 @@ make_file_baton(struct file_baton **f_p,
f->obstruction_found = FALSE;
f->add_existed = FALSE;
f->skip_this = pb->skip_this;
- f->shadowed = pb->shadowed;
+ f->shadowed = pb->shadowed || pb->edit_obstructed;
f->dir_baton = pb;
f->changed_rev = SVN_INVALID_REVNUM;
@@ -856,6 +851,9 @@ make_file_baton(struct file_baton **f_p,
/* Complete a conflict skel by describing the update.
*
+ * LOCAL_KIND is the node kind of the tree conflict victim in the
+ * working copy.
+ *
* All temporary allocations are be made in SCRATCH_POOL, while allocations
* needed for the returned conflict struct are made in RESULT_POOL.
*/
@@ -865,11 +863,15 @@ complete_conflict(svn_skel_t *conflict,
const char *local_abspath,
const char *old_repos_relpath,
svn_revnum_t old_revision,
- svn_node_kind_t kind,
- apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+ const char *new_repos_relpath,
+ svn_node_kind_t local_kind,
+ svn_node_kind_t target_kind,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
const struct edit_baton *eb = pb->edit_baton;
- svn_wc_conflict_version_t *src_left_version;
+ svn_wc_conflict_version_t *original_version;
+ svn_wc_conflict_version_t *target_version;
svn_boolean_t is_complete;
if (!conflict)
@@ -881,23 +883,34 @@ complete_conflict(svn_skel_t *conflict,
return SVN_NO_ERROR; /* Already completed */
if (old_repos_relpath)
- src_left_version = svn_wc_conflict_version_create2(eb->repos_root,
+ original_version = svn_wc_conflict_version_create2(eb->repos_root,
eb->repos_uuid,
old_repos_relpath,
old_revision,
- kind,
+ local_kind,
result_pool);
else
- src_left_version = NULL;
+ original_version = NULL;
+ if (new_repos_relpath)
+ target_version = svn_wc_conflict_version_create2(eb->repos_root,
+ eb->repos_uuid,
+ new_repos_relpath,
+ *eb->target_revision,
+ target_kind,
+ result_pool);
+ else
+ target_version = NULL;
if (eb->switch_relpath)
SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict,
- src_left_version,
+ original_version,
+ target_version,
result_pool, scratch_pool));
else
SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict,
- src_left_version,
+ original_version,
+ target_version,
result_pool, scratch_pool));
return SVN_NO_ERROR;
@@ -922,8 +935,10 @@ mark_directory_edited(struct dir_baton *
/* We have a (delayed) tree conflict to install */
SVN_ERR(complete_conflict(db->edit_conflict, db->parent_baton,
- db->local_abspath, db->old_repos_relpath,
- db->old_revision, svn_node_dir,
+ db->local_abspath,
+ db->old_repos_relpath, db->old_revision,
+ db->new_relpath,
+ svn_node_dir, svn_node_dir,
db->pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_conflict(db->edit_baton->db,
db->local_abspath,
@@ -956,7 +971,8 @@ mark_file_edited(struct file_baton *fb,
SVN_ERR(complete_conflict(fb->edit_conflict, fb->dir_baton,
fb->local_abspath, fb->old_repos_relpath,
- fb->old_revision, svn_node_file,
+ fb->old_revision, fb->new_relpath,
+ svn_node_file, svn_node_file,
fb->pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_conflict(fb->edit_baton->db,
@@ -1159,6 +1175,8 @@ open_root(void *edit_baton,
svn_boolean_t already_conflicted;
svn_error_t *err;
svn_wc__db_status_t status;
+ svn_kind_t kind;
+ svn_boolean_t have_work;
/* Note that something interesting is actually happening in this
edit run. */
@@ -1191,19 +1209,48 @@ open_root(void *edit_baton,
return SVN_NO_ERROR;
}
+
+ SVN_ERR(svn_wc__db_read_info(&status, &kind, &db->old_revision,
+ &db->old_repos_relpath, NULL, NULL,
+ &db->changed_rev, &db->changed_date,
+ &db->changed_author, &db->ambient_depth,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, &have_work,
+ eb->db, db->local_abspath,
+ db->pool, pool));
+
+ if (have_work)
+ db->shadowed = TRUE; /* Needed for the close_directory() on the root, to
+ make sure it doesn't use the ACTUAL tree */
+
if (*eb->target_basename == '\0')
{
+ svn_wc__db_status_t base_status;
/* For an update with a NULL target, this is equivalent to open_dir(): */
- /* Read the depth from the entry. */
- SVN_ERR(svn_wc__db_base_get_info(&status, NULL, &db->old_revision,
- &db->old_repos_relpath, NULL, NULL,
- &db->changed_rev, &db->changed_date,
- &db->changed_author, &db->ambient_depth,
- NULL, NULL, NULL, NULL, NULL,
- eb->db, db->local_abspath,
- db->pool, pool));
- db->was_incomplete = (status == svn_wc__db_status_incomplete);
+ if (! have_work)
+ base_status = status;
+ else
+ {
+ SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &db->old_revision,
+ &db->old_repos_relpath, NULL, NULL,
+ &db->changed_rev, &db->changed_date,
+ &db->changed_author, &db->ambient_depth,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ eb->db, db->local_abspath,
+ db->pool, pool));
+ }
+ db->was_incomplete = (base_status == svn_wc__db_status_incomplete);
+
+ /* ### TODO: Add some tree conflict and obstruction detection, etc. like
+ open_directory() does.
+ (or find a way to reuse that code here)
+
+ ### BH 2013: I don't think we need all of the detection here, as the
+ user explicitly asked to update this node. So we don't
+ have to tell that it is a local replacement/delete.
+ */
SVN_ERR(svn_wc__db_temp_op_start_directory_update(eb->db,
db->local_abspath,
@@ -1224,8 +1271,6 @@ typedef struct modcheck_baton_t {
svn_wc__db_t *db; /* wc_db to access nodes */
svn_boolean_t found_mod; /* whether a modification has been found */
svn_boolean_t found_not_delete; /* Found a not-delete modification */
- svn_boolean_t is_copy; /* check for post-copy modifications only */
- const char *modcheck_root_abspath;
} modcheck_baton_t;
/* An implementation of svn_wc_status_func4_t. */
@@ -1253,30 +1298,13 @@ modcheck_callback(void *baton,
case svn_wc_status_missing:
case svn_wc_status_obstructed:
- if (status->prop_status != svn_wc_status_modified)
- break;
-
mb->found_mod = TRUE;
mb->found_not_delete = TRUE;
/* Exit from the status walker: We know what we want to know */
return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
- case svn_wc_status_added:
- /* Ignore the copy status if we expect a copy, but don't ignore
- other changes */
- if (!mb->is_copy
- || status->text_status == svn_wc_status_modified
- || status->prop_status == svn_wc_status_modified
- || strcmp(mb->modcheck_root_abspath, local_abspath) != 0)
- {
- mb->found_mod = TRUE;
- mb->found_not_delete = TRUE;
- /* Exit from the status walker: We know what we want to know */
- return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
- }
- break;
-
default:
+ case svn_wc_status_added:
case svn_wc_status_replaced:
case svn_wc_status_modified:
mb->found_mod = TRUE;
@@ -1293,25 +1321,20 @@ modcheck_callback(void *baton,
* tree rooted at LOCAL_ABSPATH, using DB. If *MODIFIED
* is set to true and all the local modifications were deletes then set
* *ALL_EDITS_ARE_DELETES to true, set it to false otherwise. LOCAL_ABSPATH
- * may be a file or a directory. If IS_COPY is TRUE, LOCAL_ABSPATH is a
- * copied (or moved) node, and nodes at or within LOCAL_ABSPATH are only
- * considered modified if they were modified post-copy. */
-static svn_error_t *
-node_has_local_mods(svn_boolean_t *modified,
- svn_boolean_t *all_edits_are_deletes,
- svn_boolean_t is_copy,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
+ * may be a file or a directory. */
+svn_error_t *
+svn_wc__node_has_local_mods(svn_boolean_t *modified,
+ svn_boolean_t *all_edits_are_deletes,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
{
- modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE, FALSE };
+ modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE };
svn_error_t *err;
modcheck_baton.db = db;
- modcheck_baton.is_copy = is_copy;
- modcheck_baton.modcheck_root_abspath = local_abspath;
/* Walk the WC tree for status with depth infinity, looking for any local
* modifications. If it's a "sparse" directory, that's OK: there can be
@@ -1330,7 +1353,8 @@ node_has_local_mods(svn_boolean_t *modif
SVN_ERR(err);
*modified = modcheck_baton.found_mod;
- *all_edits_are_deletes = !modcheck_baton.found_not_delete;
+ *all_edits_are_deletes = (modcheck_baton.found_mod
+ && !modcheck_baton.found_not_delete);
return SVN_NO_ERROR;
}
@@ -1345,9 +1369,9 @@ node_has_local_mods(svn_boolean_t *modif
* The edit baton EB gives information including whether the operation is
* an update or a switch.
*
- * WORKING_STATUS and WORKING_KIND are the current node status of LOCAL_ABSPATH
+ * WORKING_STATUS is the current node status of LOCAL_ABSPATH
* and EXISTS_IN_REPOS specifies whether a BASE_NODE representation for exists
- * for this node.
+ * for this node. In that case the on disk type is compared to EXPECTED_KIND.
*
* If a tree conflict reason was found for the incoming action, the resulting
* tree conflict info is returned in *PCONFLICT. PCONFLICT must be non-NULL,
@@ -1361,8 +1385,8 @@ check_tree_conflict(svn_skel_t **pconfli
struct edit_baton *eb,
const char *local_abspath,
svn_wc__db_status_t working_status,
- svn_kind_t working_kind,
svn_boolean_t exists_in_repos,
+ svn_node_kind_t expected_kind,
svn_wc_conflict_action_t action,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -1370,6 +1394,7 @@ check_tree_conflict(svn_skel_t **pconfli
svn_wc_conflict_reason_t reason = SVN_WC_CONFLICT_REASON_NONE;
svn_boolean_t modified = FALSE;
svn_boolean_t all_mods_are_deletes = FALSE;
+ const char *moved_away_op_root_abspath = NULL;
*pconflict = NULL;
@@ -1407,21 +1432,26 @@ check_tree_conflict(svn_skel_t **pconfli
}
else
{
- /* The node is locally replaced. */
- reason = svn_wc_conflict_reason_replaced;
+ /* The node is locally replaced but could also be moved-away. */
+ SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL,
+ &moved_away_op_root_abspath,
+ eb->db, local_abspath,
+ scratch_pool, scratch_pool));
+ if (moved_away_op_root_abspath)
+ reason = svn_wc_conflict_reason_moved_away;
+ else
+ reason = svn_wc_conflict_reason_replaced;
}
break;
case svn_wc__db_status_deleted:
{
- const char *moved_to_abspath;
-
- SVN_ERR(svn_wc__db_scan_deletion(NULL, &moved_to_abspath,
- NULL, NULL, eb->db,
- local_abspath,
+ SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL,
+ &moved_away_op_root_abspath,
+ eb->db, local_abspath,
scratch_pool, scratch_pool));
- if (moved_to_abspath)
+ if (moved_away_op_root_abspath)
reason = svn_wc_conflict_reason_moved_away;
else
reason = svn_wc_conflict_reason_deleted;
@@ -1437,10 +1467,29 @@ check_tree_conflict(svn_skel_t **pconfli
* missing information (hopefully). */
case svn_wc__db_status_normal:
if (action == svn_wc_conflict_action_edit)
- /* An edit onto a local edit or onto *no* local changes is no
- * tree-conflict. (It's possibly a text- or prop-conflict,
- * but we don't handle those here.) */
- return SVN_NO_ERROR;
+ {
+ /* An edit onto a local edit or onto *no* local changes is no
+ * tree-conflict. (It's possibly a text- or prop-conflict,
+ * but we don't handle those here.)
+ *
+ * Except when there is a local obstruction
+ */
+ if (exists_in_repos)
+ {
+ svn_node_kind_t disk_kind;
+
+ SVN_ERR(svn_io_check_path(local_abspath, &disk_kind,
+ scratch_pool));
+
+ if (disk_kind != expected_kind && disk_kind != svn_node_none)
+ {
+ reason = svn_wc_conflict_reason_obstructed;
+ break;
+ }
+
+ }
+ return SVN_NO_ERROR;
+ }
/* Replace is handled as delete and then specifically in
add_directory() and add_file(), so we only expect deletes here */
@@ -1454,10 +1503,10 @@ check_tree_conflict(svn_skel_t **pconfli
* not visit the subdirectories of a directory that it wants to delete.
* Therefore, we need to start a separate crawl here. */
- SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes, FALSE,
- eb->db, local_abspath,
- eb->cancel_func, eb->cancel_baton,
- scratch_pool));
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_mods_are_deletes,
+ eb->db, local_abspath,
+ eb->cancel_func, eb->cancel_baton,
+ scratch_pool));
if (modified)
{
@@ -1493,6 +1542,7 @@ check_tree_conflict(svn_skel_t **pconfli
/* Sanity checks. Note that if there was no action on the node, this function
* would not have been called in the first place.*/
if (reason == svn_wc_conflict_reason_edited
+ || reason == svn_wc_conflict_reason_obstructed
|| reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away
|| reason == svn_wc_conflict_reason_replaced)
@@ -1516,6 +1566,7 @@ check_tree_conflict(svn_skel_t **pconfli
eb->db, local_abspath,
reason,
action,
+ moved_away_op_root_abspath,
result_pool, scratch_pool));
return SVN_NO_ERROR;
@@ -1609,7 +1660,9 @@ delete_entry(const char *path,
svn_wc__db_status_t base_status;
apr_pool_t *scratch_pool;
svn_boolean_t deleting_target;
+ svn_boolean_t deleting_switched;
svn_boolean_t keep_as_working = FALSE;
+ svn_boolean_t queue_deletes = TRUE;
if (pb->skip_this)
return SVN_NO_ERROR;
@@ -1660,10 +1713,22 @@ delete_entry(const char *path,
SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, &old_revision,
&repos_relpath,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
eb->db, local_abspath,
scratch_pool, scratch_pool));
+ if (pb->old_repos_relpath && repos_relpath)
+ {
+ const char *expected_name;
+
+ expected_name = svn_relpath_skip_ancestor(pb->old_repos_relpath,
+ repos_relpath);
+
+ deleting_switched = (!expected_name || strcmp(expected_name, base) != 0);
+ }
+ else
+ deleting_switched = FALSE;
+
/* Is this path a conflict victim? */
if (conflicted)
SVN_ERR(node_already_conflicted(&conflicted, eb->db, local_abspath,
@@ -1690,7 +1755,9 @@ delete_entry(const char *path,
|| base_status == svn_wc__db_status_server_excluded)
{
SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
- FALSE, SVN_INVALID_REVNUM,
+ FALSE /* keep_as_working */,
+ FALSE /* queue_deletes */,
+ SVN_INVALID_REVNUM /* not_present_rev */,
NULL, NULL,
scratch_pool));
@@ -1709,13 +1776,18 @@ delete_entry(const char *path,
/* Check for conflicts only when we haven't already recorded
* a tree-conflict on a parent node. */
- if (!pb->shadowed)
+ if (!pb->shadowed && !pb->edit_obstructed)
{
SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
- status, kind, TRUE,
+ status, TRUE,
+ (kind == svn_kind_dir)
+ ? svn_node_dir
+ : svn_node_file,
svn_wc_conflict_action_delete,
pb->pool, scratch_pool));
}
+ else
+ queue_deletes = FALSE; /* There is no in-wc representation */
if (tree_conflict != NULL)
{
@@ -1730,12 +1802,13 @@ delete_entry(const char *path,
apr_hash_set(pb->deletion_conflicts, apr_pstrdup(pb->pool, base),
APR_HASH_KEY_STRING, tree_conflict);
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
eb->db, local_abspath,
tree_conflict,
scratch_pool, scratch_pool));
- if (reason == svn_wc_conflict_reason_edited)
+ if (reason == svn_wc_conflict_reason_edited
+ || reason == svn_wc_conflict_reason_obstructed)
{
/* The item exists locally and has some sort of local mod.
* It no longer exists in the repository at its target URL@REV.
@@ -1763,10 +1836,11 @@ delete_entry(const char *path,
}
SVN_ERR(complete_conflict(tree_conflict, pb, local_abspath, repos_relpath,
- old_revision,
+ old_revision, NULL,
(kind == svn_kind_dir)
? svn_node_dir
: svn_node_file,
+ svn_node_none,
pb->pool, scratch_pool));
/* Issue a wq operation to delete the BASE_NODE data and to delete actual
@@ -1777,11 +1851,12 @@ delete_entry(const char *path,
If the thing being deleted is the *target* of this update, then
we need to recreate a 'deleted' entry, so that the parent can give
accurate reports about itself in the future. */
- if (! deleting_target)
+ if (! deleting_target && ! deleting_switched)
{
/* Delete, and do not leave a not-present node. */
SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
- keep_as_working, SVN_INVALID_REVNUM,
+ keep_as_working, queue_deletes,
+ SVN_INVALID_REVNUM /* not_present_rev */,
tree_conflict, NULL,
scratch_pool));
}
@@ -1789,10 +1864,17 @@ delete_entry(const char *path,
{
/* Delete, leaving a not-present node. */
SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
- keep_as_working, *eb->target_revision,
+ keep_as_working, queue_deletes,
+ *eb->target_revision,
tree_conflict, NULL,
scratch_pool));
- eb->target_deleted = TRUE;
+ if (deleting_target)
+ eb->target_deleted = TRUE;
+ else
+ {
+ /* Don't remove the not-present marker at the final bump */
+ SVN_ERR(remember_skipped_tree(eb, local_abspath, pool));
+ }
}
SVN_ERR(svn_wc__wq_run(eb->db, pb->local_abspath,
@@ -1808,7 +1890,7 @@ delete_entry(const char *path,
svn_wc_notify_action_t action = svn_wc_notify_update_delete;
svn_node_kind_t node_kind;
- if (pb->shadowed)
+ if (pb->shadowed || pb->edit_obstructed)
action = svn_wc_notify_update_shadowed_delete;
if (kind == svn_kind_dir)
@@ -1976,7 +2058,7 @@ add_directory(const char *path,
/* ### Should store the conflict in DB to allow reinstalling
### with theoretically more data in close_directory() */
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
eb->db,
db->local_abspath,
tree_conflict,
@@ -1988,6 +2070,7 @@ add_directory(const char *path,
tree_conflict,
eb->db, db->local_abspath,
reason, svn_wc_conflict_action_replace,
+ NULL,
db->pool, db->pool));
/* And now stop checking for conflicts here and just perform
@@ -2083,7 +2166,7 @@ add_directory(const char *path,
{
SVN_ERR(check_tree_conflict(&tree_conflict, eb,
db->local_abspath,
- status, wc_kind, FALSE,
+ status, FALSE, svn_node_none,
svn_wc_conflict_action_add,
pool, pool));
}
@@ -2112,15 +2195,19 @@ add_directory(const char *path,
tree_conflict,
eb->db, db->local_abspath,
svn_wc_conflict_reason_unversioned,
- svn_wc_conflict_action_add,
+ svn_wc_conflict_action_add, NULL,
db->pool, pool));
db->edit_conflict = tree_conflict;
}
}
- SVN_ERR(complete_conflict(tree_conflict, pb, db->local_abspath,
- db->old_repos_relpath, db->old_revision,
- svn_node_dir, db->pool, pool));
+ if (tree_conflict)
+ SVN_ERR(complete_conflict(tree_conflict, pb, db->local_abspath,
+ db->old_repos_relpath, db->old_revision,
+ db->new_relpath,
+ svn__node_kind_from_kind(wc_kind),
+ svn_node_dir,
+ db->pool, pool));
SVN_ERR(svn_wc__db_base_add_incomplete_directory(
eb->db, db->local_abspath,
@@ -2149,7 +2236,7 @@ add_directory(const char *path,
/* If this add was obstructed by dir scheduled for addition without
- history let close_file() handle the notification because there
+ history let close_directory() handle the notification because there
might be properties to deal with. If PATH was added inside a locally
deleted tree, then suppress notification, a tree conflict was already
issued. */
@@ -2159,7 +2246,7 @@ add_directory(const char *path,
if (db->shadowed)
action = svn_wc_notify_update_shadowed_add;
- else if (db->obstruction_found)
+ else if (db->obstruction_found || db->add_existed)
action = svn_wc_notify_exists;
else
action = svn_wc_notify_update_add;
@@ -2236,7 +2323,7 @@ open_directory(const char *path,
&db->old_repos_relpath, NULL, NULL,
&db->changed_rev, &db->changed_date,
&db->changed_author, &db->ambient_depth,
- NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
eb->db, db->local_abspath,
db->pool, pool));
@@ -2266,7 +2353,7 @@ open_directory(const char *path,
* a tree-conflict on a parent node. */
if (!db->shadowed)
SVN_ERR(check_tree_conflict(&tree_conflict, eb, db->local_abspath,
- status, wc_kind, TRUE,
+ status, TRUE, svn_node_dir,
svn_wc_conflict_action_edit,
db->pool, pool));
@@ -2277,16 +2364,20 @@ open_directory(const char *path,
db->edit_conflict = tree_conflict;
/* Other modifications wouldn't be a tree conflict */
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
eb->db, db->local_abspath,
tree_conflict,
db->pool, db->pool));
SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away
- || reason == svn_wc_conflict_reason_replaced);
+ || reason == svn_wc_conflict_reason_replaced
+ || reason == svn_wc_conflict_reason_obstructed);
/* Continue updating BASE */
- db->shadowed = TRUE;
+ if (reason == svn_wc_conflict_reason_obstructed)
+ db->edit_obstructed = TRUE;
+ else
+ db->shadowed = TRUE;
}
/* Mark directory as being at target_revision and URL, but incomplete. */
@@ -2394,9 +2485,9 @@ close_directory(void *dir_baton,
if (db->add_existed)
{
/* This node already exists. Grab the current pristine properties. */
- SVN_ERR(svn_wc__get_pristine_props(&base_props,
- eb->db, db->local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_pristine_props(&base_props,
+ eb->db, db->local_abspath,
+ scratch_pool, scratch_pool));
}
else if (!db->adding_dir)
{
@@ -2494,23 +2585,18 @@ close_directory(void *dir_baton,
actual_props = base_props;
}
- /* Merge pending properties into temporary files (ignoring
- conflicts). */
+ /* Merge pending properties. */
+ new_base_props = svn_prop__patch(base_props, regular_prop_changes,
+ db->pool);
SVN_ERR_W(svn_wc__merge_props(&conflict_skel,
&prop_state,
- &new_base_props,
&new_actual_props,
eb->db,
db->local_abspath,
- svn_kind_dir,
NULL /* use baseprops */,
base_props,
actual_props,
regular_prop_changes,
- TRUE /* base_merge */,
- FALSE /* dry_run */,
- eb->cancel_func,
- eb->cancel_baton,
db->pool,
scratch_pool),
_("Couldn't do property merge"));
@@ -2563,7 +2649,7 @@ close_directory(void *dir_baton,
/* ### We just check if there is some node in BASE at this path */
err = svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
eb->db, child_abspath,
iterpool, iterpool);
@@ -2696,7 +2782,8 @@ close_directory(void *dir_baton,
db->local_abspath,
db->old_repos_relpath,
db->old_revision,
- svn_node_dir,
+ db->new_relpath,
+ svn_node_dir, svn_node_dir,
db->pool, scratch_pool));
SVN_ERR(svn_wc__conflict_create_markers(&work_item,
@@ -2757,6 +2844,8 @@ close_directory(void *dir_baton,
NULL /* merge_options */,
eb->conflict_func,
eb->conflict_baton,
+ eb->cancel_func,
+ eb->conflict_baton,
scratch_pool));
/* Notify of any prop changes on this directory -- but do nothing if
@@ -2769,7 +2858,7 @@ close_directory(void *dir_baton,
svn_wc_notify_t *notify;
svn_wc_notify_action_t action;
- if (db->shadowed)
+ if (db->shadowed || db->edit_obstructed)
action = svn_wc_notify_update_shadowed_update;
else if (db->obstruction_found || db->add_existed)
action = svn_wc_notify_exists;
@@ -3055,7 +3144,7 @@ add_file(const char *path,
/* ### Should store the conflict in DB to allow reinstalling
### with theoretically more data in close_directory() */
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
eb->db,
fb->local_abspath,
tree_conflict,
@@ -3067,6 +3156,7 @@ add_file(const char *path,
tree_conflict,
eb->db, fb->local_abspath,
reason, svn_wc_conflict_action_replace,
+ NULL,
fb->pool, fb->pool));
/* And now stop checking for conflicts here and just perform
@@ -3158,7 +3248,7 @@ add_file(const char *path,
{
SVN_ERR(check_tree_conflict(&tree_conflict, eb,
fb->local_abspath,
- status, wc_kind, FALSE,
+ status, FALSE, svn_node_none,
svn_wc_conflict_action_add,
scratch_pool, scratch_pool));
}
@@ -3189,6 +3279,7 @@ add_file(const char *path,
eb->db, fb->local_abspath,
svn_wc_conflict_reason_unversioned,
svn_wc_conflict_action_add,
+ NULL,
fb->pool, scratch_pool));
}
}
@@ -3211,6 +3302,8 @@ add_file(const char *path,
fb->local_abspath,
fb->old_repos_relpath,
fb->old_revision,
+ fb->new_relpath,
+ svn__node_kind_from_kind(wc_kind),
svn_node_file,
fb->pool, scratch_pool));
@@ -3298,7 +3391,7 @@ open_file(const char *path,
&fb->changed_rev, &fb->changed_date,
&fb->changed_author, NULL,
&fb->original_checksum, NULL, NULL,
- NULL, NULL,
+ NULL, NULL, NULL,
eb->db, fb->local_abspath,
fb->pool, scratch_pool));
@@ -3321,13 +3414,11 @@ open_file(const char *path,
return SVN_NO_ERROR;
}
- fb->shadowed = pb->shadowed;
-
/* Check for conflicts only when we haven't already recorded
* a tree-conflict on a parent node. */
if (!fb->shadowed)
SVN_ERR(check_tree_conflict(&tree_conflict, eb, fb->local_abspath,
- status, wc_kind, TRUE,
+ status, TRUE, svn_node_file,
svn_wc_conflict_action_edit,
fb->pool, scratch_pool));
@@ -3338,16 +3429,20 @@ open_file(const char *path,
fb->edit_conflict = tree_conflict;
/* Other modifications wouldn't be a tree conflict */
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, NULL, NULL,
eb->db, fb->local_abspath,
tree_conflict,
- fb->pool, fb->pool));
+ scratch_pool, scratch_pool));
SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away
- || reason == svn_wc_conflict_reason_replaced);
+ || reason == svn_wc_conflict_reason_replaced
+ || reason == svn_wc_conflict_reason_obstructed);
/* Continue updating BASE */
- fb->shadowed = TRUE;
+ if (reason == svn_wc_conflict_reason_obstructed)
+ fb->edit_obstructed = TRUE;
+ else
+ fb->shadowed = TRUE;
}
svn_pool_destroy(scratch_pool);
@@ -3570,11 +3665,13 @@ change_file_prop(void *file_baton,
eb->db, fb->local_abspath,
svn_wc_conflict_reason_edited,
svn_wc_conflict_action_replace,
+ NULL,
fb->pool, scratch_pool));
SVN_ERR(complete_conflict(fb->edit_conflict, fb->dir_baton,
fb->local_abspath, fb->old_repos_relpath,
- fb->old_revision, svn_node_file,
+ fb->old_revision, fb->new_relpath,
+ svn_node_file, svn_node_file,
fb->pool, scratch_pool));
/* Create a copy of the existing (pre update) BASE node in WORKING,
@@ -3606,18 +3703,18 @@ change_file_prop(void *file_baton,
identified by WRI_ABSPATH. Use OLD_REVISION and TARGET_REVISION for naming
the intermediate files.
- The rest of the arguments are passed to svn_wc__internal_merge.
+ The rest of the arguments are passed to svn_wc__internal_merge().
*/
svn_error_t *
svn_wc__perform_file_merge(svn_skel_t **work_items,
svn_skel_t **conflict_skel,
- enum svn_wc_merge_outcome_t *merge_outcome,
+ svn_boolean_t *found_conflict,
svn_wc__db_t *db,
const char *local_abspath,
const char *wri_abspath,
const svn_checksum_t *new_checksum,
const svn_checksum_t *original_checksum,
- apr_hash_t *actual_props,
+ apr_hash_t *old_actual_props,
const apr_array_header_t *ext_patterns,
svn_revnum_t old_revision,
svn_revnum_t target_revision,
@@ -3629,13 +3726,14 @@ svn_wc__perform_file_merge(svn_skel_t **
apr_pool_t *scratch_pool)
{
/* Actual file exists and has local mods:
- Now we need to let loose svn_wc__merge_internal() to merge
+ Now we need to let loose svn_wc__internal_merge() to merge
the textual changes into the working file. */
const char *oldrev_str, *newrev_str, *mine_str;
const char *merge_left;
svn_boolean_t delete_left = FALSE;
const char *path_ext = "";
const char *new_text_base_tmp_abspath;
+ enum svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_unchanged;
svn_skel_t *work_item;
*work_items = NULL;
@@ -3690,20 +3788,21 @@ svn_wc__perform_file_merge(svn_skel_t **
Remember that this function wants full paths! */
SVN_ERR(svn_wc__internal_merge(&work_item,
conflict_skel,
- merge_outcome,
+ &merge_outcome,
db,
merge_left,
new_text_base_tmp_abspath,
local_abspath,
wri_abspath,
oldrev_str, newrev_str, mine_str,
- actual_props,
+ old_actual_props,
FALSE /* dry_run */,
diff3_cmd, NULL, propchanges,
cancel_func, cancel_baton,
result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+ *found_conflict = (merge_outcome == svn_wc_merge_conflict);
/* If we created a temporary left merge file, get rid of it. */
if (delete_left)
@@ -3755,9 +3854,11 @@ merge_file(svn_skel_t **work_items,
struct edit_baton *eb = fb->edit_baton;
struct dir_baton *pb = fb->dir_baton;
svn_boolean_t is_locally_modified;
- enum svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_unchanged;
+ svn_boolean_t found_text_conflict = FALSE;
- SVN_ERR_ASSERT(! fb->shadowed && !fb->obstruction_found);
+ SVN_ERR_ASSERT(! fb->shadowed
+ && ! fb->obstruction_found
+ && ! fb->edit_obstructed);
/*
When this function is called on file F, we assume the following
@@ -3843,7 +3944,7 @@ merge_file(svn_skel_t **work_items,
the textual changes into the working file. */
SVN_ERR(svn_wc__perform_file_merge(work_items,
conflict_skel,
- &merge_outcome,
+ &found_text_conflict,
eb->db,
fb->local_abspath,
pb->local_abspath,
@@ -3926,14 +4027,7 @@ merge_file(svn_skel_t **work_items,
/* Set the returned content state. */
- /* This is kind of interesting. Even if no new text was
- installed (i.e., NEW_TEXT_BASE_ABSPATH was null), we could still
- report a pre-existing conflict state. Say a file, already
- in a state of textual conflict, receives prop mods during an
- update. Then we'll notify that it has text conflicts. This
- seems okay to me. I guess. I dunno. You? */
-
- if (merge_outcome == svn_wc_merge_conflict)
+ if (found_text_conflict)
*content_state = svn_wc_notify_state_conflicted;
else if (fb->new_text_base_sha1_checksum)
{
@@ -4043,11 +4137,17 @@ close_file(void *file_baton,
and we should likewise remove our cached copy of it. */
if (! strcmp(prop->name, SVN_PROP_ENTRY_LOCK_TOKEN))
{
- SVN_ERR_ASSERT(prop->value == NULL);
- SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath,
- scratch_pool));
+ /* If we lose the lock, but not because we are switching to
+ another url, remove the state lock from the wc */
+ if (! eb->switch_relpath
+ || strcmp(fb->new_relpath, fb->old_repos_relpath) == 0)
+ {
+ SVN_ERR_ASSERT(prop->value == NULL);
+ SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath,
+ scratch_pool));
- lock_state = svn_wc_notify_lock_state_unlocked;
+ lock_state = svn_wc_notify_lock_state_unlocked;
+ }
break;
}
}
@@ -4077,9 +4177,9 @@ close_file(void *file_baton,
if (fb->add_existed)
{
/* This node already exists. Grab the current pristine properties. */
- SVN_ERR(svn_wc__get_pristine_props(¤t_base_props,
- eb->db, fb->local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_pristine_props(¤t_base_props,
+ eb->db, fb->local_abspath,
+ scratch_pool, scratch_pool));
current_actual_props = local_actual_props;
}
else if (!fb->adding_file)
@@ -4111,27 +4211,24 @@ close_file(void *file_baton,
/* This will merge the old and new props into a new prop db, and
write <cp> commands to the logfile to install the merged
props. */
+ new_base_props = svn_prop__patch(current_base_props, regular_prop_changes,
+ scratch_pool);
SVN_ERR(svn_wc__merge_props(&conflict_skel,
&prop_state,
- &new_base_props,
&new_actual_props,
eb->db,
fb->local_abspath,
- svn_kind_file,
NULL /* server_baseprops (update, not merge) */,
current_base_props,
current_actual_props,
regular_prop_changes, /* propchanges */
- TRUE /* base_merge */,
- FALSE /* dry_run */,
- eb->cancel_func, eb->cancel_baton,
scratch_pool,
scratch_pool));
/* We will ALWAYS have properties to save (after a not-dry-run merge). */
SVN_ERR_ASSERT(new_base_props != NULL && new_actual_props != NULL);
/* Merge the text. This will queue some additional work. */
- if (!fb->obstruction_found)
+ if (!fb->obstruction_found && !fb->edit_obstructed)
{
svn_error_t *err;
err = merge_file(&work_item, &conflict_skel,
@@ -4246,20 +4343,17 @@ close_file(void *file_baton,
/* Store the incoming props (sent as propchanges) in new_base_props
and create a set of new actual props to use for notifications */
+ new_base_props = svn_prop__patch(current_base_props, regular_prop_changes,
+ scratch_pool);
SVN_ERR(svn_wc__merge_props(&conflict_skel,
&prop_state,
- &new_base_props,
&new_actual_props,
eb->db,
fb->local_abspath,
- svn_kind_file,
NULL /* server_baseprops (not merging) */,
current_base_props /* pristine_props */,
fake_actual_props /* actual_props */,
regular_prop_changes, /* propchanges */
- TRUE /* base_merge */,
- FALSE /* dry_run */,
- eb->cancel_func, eb->cancel_baton,
scratch_pool,
scratch_pool));
@@ -4288,7 +4382,8 @@ close_file(void *file_baton,
fb->local_abspath,
fb->old_repos_relpath,
fb->old_revision,
- svn_node_file,
+ fb->new_relpath,
+ svn_node_file, svn_node_file,
fb->pool, scratch_pool));
SVN_ERR(svn_wc__conflict_create_markers(&work_item,
@@ -4347,6 +4442,8 @@ close_file(void *file_baton,
NULL /* merge_options */,
eb->conflict_func,
eb->conflict_baton,
+ eb->cancel_func,
+ eb->cancel_baton,
scratch_pool));
/* Deal with the WORKING tree, based on updates to the BASE tree. */
@@ -4364,7 +4461,7 @@ close_file(void *file_baton,
if (fb->edited)
{
- if (fb->shadowed)
+ if (fb->shadowed || fb->edit_obstructed)
action = fb->adding_file
? svn_wc_notify_update_shadowed_add
: svn_wc_notify_update_shadowed_update;
@@ -4476,7 +4573,7 @@ close_edit(void *edit_baton,
have to worry about removing it. */
err = svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
eb->db, eb->target_abspath,
scratch_pool, scratch_pool);
if (err)
@@ -4495,7 +4592,9 @@ close_edit(void *edit_baton,
If so, we should get rid of this excluded node now. */
SVN_ERR(svn_wc__db_base_remove(eb->db, eb->target_abspath,
- FALSE, SVN_INVALID_REVNUM,
+ FALSE /* keep_as_working */,
+ FALSE /* queue_deletes */,
+ SVN_INVALID_REVNUM,
NULL, NULL, scratch_pool));
}
}
@@ -4633,7 +4732,7 @@ make_editor(svn_revnum_t *target_revisio
eb->ext_patterns = preserved_exts;
apr_pool_cleanup_register(edit_pool, eb, cleanup_edit_baton,
- cleanup_edit_baton_child);
+ apr_pool_cleanup_null);
/* Construct an editor. */
tree_editor->set_target_revision = set_target_revision;
@@ -4674,7 +4773,7 @@ make_editor(svn_revnum_t *target_revisio
err = svn_wc__db_base_get_info(&dir_status, &dir_kind, NULL,
&dir_repos_relpath, NULL, NULL, NULL,
NULL, NULL, &dir_depth, NULL, NULL, NULL,
- NULL, NULL,
+ NULL, NULL, NULL,
db, eb->target_abspath,
scratch_pool, scratch_pool);
@@ -4730,7 +4829,7 @@ make_editor(svn_revnum_t *target_revisio
NULL, &dir_repos_relpath,
NULL, NULL, NULL, NULL,
NULL, &dir_depth, NULL,
- NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
NULL,
db, child_abspath,
iterpool, iterpool));
@@ -4904,207 +5003,6 @@ svn_wc__get_switch_editor(const svn_delt
result_pool, scratch_pool);
}
-/* ABOUT ANCHOR AND TARGET, AND svn_wc_get_actual_target2()
-
- THE GOAL
-
- Note the following actions, where X is the thing we wish to update,
- P is a directory whose repository URL is the parent of
- X's repository URL, N is directory whose repository URL is *not*
- the parent directory of X (including the case where N is not a
- versioned resource at all):
-
- 1. `svn up .' from inside X.
- 2. `svn up ...P/X' from anywhere.
- 3. `svn up ...N/X' from anywhere.
-
- For the purposes of the discussion, in the '...N/X' situation, X is
- said to be a "working copy (WC) root" directory.
-
- Now consider the four cases for X's type (file/dir) in the working
- copy vs. the repository:
-
- A. dir in working copy, dir in repos.
- B. dir in working copy, file in repos.
- C. file in working copy, dir in repos.
- D. file in working copy, file in repos.
-
- Here are the results we expect for each combination of the above:
-
- 1A. Successfully update X.
- 1B. Error (you don't want to remove your current working
- directory out from underneath the application).
- 1C. N/A (you can't be "inside X" if X is a file).
- 1D. N/A (you can't be "inside X" if X is a file).
-
- 2A. Successfully update X.
- 2B. Successfully update X.
- 2C. Successfully update X.
- 2D. Successfully update X.
-
- 3A. Successfully update X.
- 3B. Error (you can't create a versioned file X inside a
- non-versioned directory).
- 3C. N/A (you can't have a versioned file X in directory that is
- not its repository parent).
- 3D. N/A (you can't have a versioned file X in directory that is
- not its repository parent).
-
- To summarize, case 2 always succeeds, and cases 1 and 3 always fail
- (or can't occur) *except* when the target is a dir that remains a
- dir after the update.
-
- ACCOMPLISHING THE GOAL
-
- Updates are accomplished by driving an editor, and an editor is
- "rooted" on a directory. So, in order to update a file, we need to
- break off the basename of the file, rooting the editor in that
- file's parent directory, and then updating only that file, not the
- other stuff in its parent directory.
-
- Secondly, we look at the case where we wish to update a directory.
- This is typically trivial. However, one problematic case, exists
- when we wish to update a directory that has been removed from the
- repository and replaced with a file of the same name. If we root
- our edit at the initial directory, there is no editor mechanism for
- deleting that directory and replacing it with a file (this would be
- like having an editor now anchored on a file, which is disallowed).
-
- All that remains is to have a function with the knowledge required
- to properly decide where to root our editor, and what to act upon
- with that now-rooted editor. Given a path to be updated, this
- function should conditionally split that path into an "anchor" and
- a "target", where the "anchor" is the directory at which the update
- editor is rooted (meaning, editor->open_root() is called with
- this directory in mind), and the "target" is the actual intended
- subject of the update.
-
- svn_wc_get_actual_target2() is that function.
-
- So, what are the conditions?
-
- Case I: Any time X is '.' (implying it is a directory), we won't
- lop off a basename. So we'll root our editor at X, and update all
- of X.
-
- Cases II & III: Any time we are trying to update some path ...N/X,
- we again will not lop off a basename. We can't root an editor at
- ...N with X as a target, either because ...N isn't a versioned
- resource at all (Case II) or because X is X is not a child of ...N
- in the repository (Case III). We root at X, and update X.
-
- Cases IV-???: We lop off a basename when we are updating a
- path ...P/X, rooting our editor at ...P and updating X, or when X
- is missing from disk.
-
- These conditions apply whether X is a file or directory.
-
- ---
-
- As it turns out, commits need to have a similar check in place,
- too, specifically for the case where a single directory is being
- committed (we have to anchor at that directory's parent in case the
- directory itself needs to be modified).
-*/
-
-
-svn_error_t *
-svn_wc__check_wc_root(svn_boolean_t *wc_root,
- svn_kind_t *kind,
- svn_boolean_t *switched,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(
- svn_wc__db_is_switched(wc_root, switched, kind,
- db, local_abspath,
- scratch_pool));
-}
-
-svn_error_t *
-svn_wc_check_root(svn_boolean_t *is_wcroot,
- svn_boolean_t *is_switched,
- svn_kind_t *kind,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- return svn_error_trace(svn_wc__db_is_switched(is_wcroot,is_switched, kind,
- wc_ctx->db, local_abspath,
- scratch_pool));
-}
-
-svn_error_t*
-svn_wc__strictly_is_wc_root(svn_boolean_t *wc_root,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(svn_wc__db_is_wcroot(wc_root,
- wc_ctx->db,
- local_abspath,
- scratch_pool));
-}
-
-
-svn_error_t *
-svn_wc__get_wc_root(const char **wcroot_abspath,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- return svn_wc__db_get_wcroot(wcroot_abspath, wc_ctx->db,
- local_abspath, result_pool, scratch_pool);
-}
-
-
-svn_error_t *
-svn_wc_get_actual_target2(const char **anchor,
- const char **target,
- svn_wc_context_t *wc_ctx,
- const char *path,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_boolean_t is_wc_root, is_switched;
- svn_kind_t kind;
- const char *local_abspath;
- svn_error_t *err;
-
- SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
-
- err = svn_wc__check_wc_root(&is_wc_root, &kind, &is_switched,
- wc_ctx->db, local_abspath,
- scratch_pool);
-
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND &&
- err->apr_err != SVN_ERR_WC_NOT_WORKING_COPY)
- return svn_error_trace(err);
-
- svn_error_clear(err);
- is_wc_root = FALSE;
- is_switched = FALSE;
- }
-
- /* If PATH is not a WC root, or if it is a file, lop off a basename. */
- if (!(is_wc_root || is_switched) || (kind != svn_kind_dir))
- {
- svn_dirent_split(anchor, target, path, result_pool);
- }
- else
- {
- *anchor = apr_pstrdup(result_pool, path);
- *target = "";
- }
-
- return SVN_NO_ERROR;
-}
/* ### Note that this function is completely different from the rest of the
@@ -5339,7 +5237,7 @@ svn_wc_add_repos_file4(svn_wc_context_t
/* If new contents were provided, then we do NOT want to record the
file information. We assume the new contents do not match the
- "proper" values for TRANSLATED_SIZE and LAST_MOD_TIME. */
+ "proper" values for RECORDED_SIZE and RECORDED_TIME. */
record_fileinfo = (new_contents == NULL);
/* Install the working copy file (with appropriate translation) from
@@ -5391,3 +5289,90 @@ svn_wc_add_repos_file4(svn_wc_context_t
cancel_func, cancel_baton,
pool));
}
+
+svn_error_t *
+svn_wc__complete_directory_add(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_hash_t *new_original_props,
+ const char *copyfrom_url,
+ svn_revnum_t copyfrom_rev,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_status_t status;
+ svn_kind_t kind;
+ const char *original_repos_relpath;
+ const char *original_root_url;
+ const char *original_uuid;
+ svn_boolean_t had_props;
+ svn_boolean_t props_mod;
+
+ svn_revnum_t original_revision;
+ svn_revnum_t changed_rev;
+ apr_time_t changed_date;
+ const char *changed_author;
+
+ SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ &original_repos_relpath, &original_root_url,
+ &original_uuid, &original_revision, NULL, NULL,
+ NULL, NULL, NULL, NULL, &had_props, &props_mod,
+ NULL, NULL, NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (status != svn_wc__db_status_added
+ || kind != svn_kind_dir
+ || had_props
+ || props_mod
+ || !original_repos_relpath)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
+ _("'%s' is not an unmodified copied directory"),
+ svn_dirent_local_style(local_abspath, scratch_pool));
+ }
+ if (original_revision != copyfrom_rev
+ || strcmp(copyfrom_url,
+ svn_path_url_add_component2(original_root_url,
+ original_repos_relpath,
+ scratch_pool)))
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_COPYFROM_PATH_NOT_FOUND, NULL,
+ _("Copyfrom '%s' doesn't match original location of '%s'"),
+ copyfrom_url,
+ svn_dirent_local_style(local_abspath, scratch_pool));
+ }
+
+ {
+ apr_array_header_t *regular_props;
+ apr_array_header_t *entry_props;
+
+ SVN_ERR(svn_categorize_props(svn_prop_hash_to_array(new_original_props,
+ scratch_pool),
+ &entry_props, NULL, ®ular_props,
+ scratch_pool));
+
+ /* Put regular props back into a hash table. */
+ new_original_props = svn_prop_array_to_hash(regular_props, scratch_pool);
+
+ /* Get the change_* info from the entry props. */
+ SVN_ERR(accumulate_last_change(&changed_rev,
+ &changed_date,
+ &changed_author,
+ entry_props, scratch_pool, scratch_pool));
+ }
+
+ return svn_error_trace(
+ svn_wc__db_op_copy_dir(wc_ctx->db, local_abspath,
+ new_original_props,
+ changed_rev, changed_date, changed_author,
+ original_repos_relpath, original_root_url,
+ original_uuid, original_revision,
+ NULL /* children */,
+ FALSE /* is_move */,
+ svn_depth_infinity,
+ NULL /* conflict */,
+ NULL /* work_items */,
+ scratch_pool));
+}
Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/upgrade.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/upgrade.c Mon Feb 4 20:48:05 2013
@@ -1169,7 +1169,8 @@ bump_to_23(void *baton, svn_sqlite__db_t
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_HAS_WORKING_NODES));
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_UPGRADE_23_HAS_WORKING_NODES));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
SVN_ERR(svn_sqlite__reset(stmt));
if (have_row)
@@ -1456,6 +1457,7 @@ svn_wc__upgrade_conflict_skel_from_raw(s
db, wri_abspath,
tc->reason,
tc->action,
+ NULL,
scratch_pool,
scratch_pool));
@@ -1465,12 +1467,14 @@ svn_wc__upgrade_conflict_skel_from_raw(s
default:
SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data,
tc->src_left_version,
+ tc->src_right_version,
scratch_pool,
scratch_pool));
break;
case svn_wc_operation_switch:
SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict_data,
tc->src_left_version,
+ tc->src_right_version,
scratch_pool,
scratch_pool));
break;
@@ -1485,7 +1489,7 @@ svn_wc__upgrade_conflict_skel_from_raw(s
}
else if (conflict_data)
{
- SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL,
+ SVN_ERR(svn_wc__conflict_skel_set_op_update(conflict_data, NULL, NULL,
scratch_pool,
scratch_pool));
}
@@ -1494,6 +1498,51 @@ svn_wc__upgrade_conflict_skel_from_raw(s
return SVN_NO_ERROR;
}
+/* Helper function to upgrade a single conflict from bump_to_30 */
+static svn_error_t *
+bump_30_upgrade_one_conflict(svn_wc__db_t *wc_db,
+ const char *wcroot_abspath,
+ svn_sqlite__stmt_t *stmt,
+ svn_sqlite__db_t *sdb,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt_store;
+ svn_stringbuf_t *skel_data;
+ svn_skel_t *conflict_data;
+ apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
+ const char *local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
+ const char *conflict_old = svn_sqlite__column_text(stmt, 2, NULL);
+ const char *conflict_wrk = svn_sqlite__column_text(stmt, 3, NULL);
+ const char *conflict_new = svn_sqlite__column_text(stmt, 4, NULL);
+ const char *prop_reject = svn_sqlite__column_text(stmt, 5, NULL);
+ apr_size_t tree_conflict_size;
+ const char *tree_conflict_data = svn_sqlite__column_blob(stmt, 6,
+ &tree_conflict_size, NULL);
+
+ SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data,
+ wc_db, wcroot_abspath,
+ local_relpath,
+ conflict_old,
+ conflict_wrk,
+ conflict_new,
+ prop_reject,
+ tree_conflict_data,
+ tree_conflict_size,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR_ASSERT(conflict_data != NULL);
+
+ skel_data = svn_skel__unparse(conflict_data, scratch_pool);
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt_store, sdb,
+ STMT_UPGRADE_30_SET_CONFLICT));
+ SVN_ERR(svn_sqlite__bindf(stmt_store, "isb", wc_id, local_relpath,
+ skel_data->data, skel_data->len));
+ SVN_ERR(svn_sqlite__step_done(stmt_store));
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
bump_to_30(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
{
@@ -1501,54 +1550,30 @@ bump_to_30(void *baton, svn_sqlite__db_t
svn_boolean_t have_row;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_sqlite__stmt_t *stmt;
- svn_sqlite__stmt_t *stmt_store;
svn_wc__db_t *db; /* Read only temp db */
- const char *wri_abspath = bb->wcroot_abspath;
- SVN_ERR(svn_wc__db_open(&db, NULL, FALSE, FALSE,
+ SVN_ERR(svn_wc__db_open(&db, NULL, TRUE /* open_without_upgrade */, FALSE,
scratch_pool, scratch_pool));
- SVN_ERR(svn_sqlite__get_statement(&stmt_store, sdb,
- STMT_UPGRADE_30_SET_CONFLICT));
-
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
STMT_UPGRADE_30_SELECT_CONFLICT_SEPARATE));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
while (have_row)
{
- svn_stringbuf_t *skel_data;
- svn_skel_t *conflict_data;
- apr_int64_t wc_id = svn_sqlite__column_int64(stmt, 0);
- const char *local_relpath = svn_sqlite__column_text(stmt, 1, NULL);
- const char *conflict_old = svn_sqlite__column_text(stmt, 2, NULL);
- const char *conflict_wrk = svn_sqlite__column_text(stmt, 3, NULL);
- const char *conflict_new = svn_sqlite__column_text(stmt, 4, NULL);
- const char *prop_reject = svn_sqlite__column_text(stmt, 5, NULL);
- apr_size_t tree_conflict_size;
- const char *tree_conflict_data = svn_sqlite__column_blob(stmt, 6,
- &tree_conflict_size, NULL);
-
+ svn_error_t *err;
svn_pool_clear(iterpool);
- SVN_ERR(svn_wc__upgrade_conflict_skel_from_raw(&conflict_data,
- db, wri_abspath,
- local_relpath,
- conflict_old,
- conflict_wrk,
- conflict_new,
- prop_reject,
- tree_conflict_data,
- tree_conflict_size,
- iterpool, iterpool));
-
- SVN_ERR_ASSERT(conflict_data != NULL);
-
- skel_data = svn_skel__unparse(conflict_data, iterpool);
-
- SVN_ERR(svn_sqlite__bindf(stmt_store, "isb", wc_id, local_relpath,
- skel_data->data, skel_data->len));
- SVN_ERR(svn_sqlite__step_done(stmt_store));
+ err = bump_30_upgrade_one_conflict(db, bb->wcroot_abspath, stmt, sdb,
+ iterpool);
+
+ if (err)
+ {
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_sqlite__reset(stmt)));
+ }
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
@@ -1753,16 +1778,8 @@ upgrade_to_wcng(void **dir_baton,
return SVN_NO_ERROR;
}
-
-/* Return a string indicating the released version (or versions) of
- * Subversion that used WC format number WC_FORMAT, or some other
- * suitable string if no released version used WC_FORMAT.
- *
- * ### It's not ideal to encode this sort of knowledge in this low-level
- * library. On the other hand, it doesn't need to be updated often and
- * should be easily found when it does need to be updated. */
-static const char *
-version_string_from_format(int wc_format)
+const char *
+svn_wc__version_string_from_format(int wc_format)
{
switch (wc_format)
{
@@ -1770,6 +1787,7 @@ version_string_from_format(int wc_format
case 8: return "1.4";
case 9: return "1.5";
case 10: return "1.6";
+ case SVN_WC__WC_NG_VERSION: return "1.7";
}
return _("(unreleased development version)");
}
@@ -1792,7 +1810,7 @@ svn_wc__upgrade_sdb(int *result_format,
svn_dirent_local_style(wcroot_abspath,
scratch_pool),
start_format,
- version_string_from_format(start_format));
+ svn_wc__version_string_from_format(start_format));
/* Early WCNG formats no longer supported. */
if (start_format < 19)
@@ -2138,17 +2156,21 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_wc__db_open(&db, NULL /* ### config */, TRUE, FALSE,
scratch_pool, scratch_pool));
+
err = svn_wc__db_bump_format(&result_format, local_abspath, db,
scratch_pool);
if (err)
{
- if (err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED) /* pre-1.7 WC */
+ if (err->apr_err != SVN_ERR_WC_UPGRADE_REQUIRED)
{
- svn_error_clear(err);
- SVN_ERR(svn_wc__db_close(db));
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_wc__db_close(db)));
}
- else
- return svn_error_trace(err);
+
+ svn_error_clear(err);
+ /* Pre 1.7: Fall through */
}
else
{
@@ -2171,10 +2193,6 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
'cleanup' with a new client will complete any outstanding
upgrade. */
- SVN_ERR(svn_wc__db_open(&db,
- NULL /* ### config */, TRUE, FALSE,
- scratch_pool, scratch_pool));
-
SVN_ERR(svn_wc__read_entries_old(&entries, local_abspath,
scratch_pool, scratch_pool));
Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/util.c?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/util.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/util.c Mon Feb 4 20:48:05 2013
@@ -610,8 +610,9 @@ svn_wc__fetch_base_func(const char **fil
err = svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, &checksum,
- NULL, NULL, NULL, NULL, sfb->db,
- local_abspath, scratch_pool, scratch_pool);
+ NULL, NULL, NULL, NULL, NULL,
+ sfb->db, local_abspath,
+ scratch_pool, scratch_pool);
if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
{
svn_error_clear(err);
Modified: subversion/branches/fsfs-format7/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_wc/wc-metadata.sql?rev=1442344&r1=1442343&r2=1442344&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_wc/wc-metadata.sql Mon Feb 4 20:48:05 2013
@@ -181,8 +181,8 @@ CREATE TABLE ACTUAL_NODE (
PRIMARY KEY (wc_id, local_relpath)
);
-CREATE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath);
-CREATE INDEX I_ACTUAL_CHANGELIST ON ACTUAL_NODE (changelist);
+CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath,
+ local_relpath);
/* ------------------------------------------------------------------------- */
@@ -253,19 +253,10 @@ PRAGMA user_version =
op_depth values are not normally visible to the user but may become
visible after reverting local changes.
- ### The following text needs revision
-
- Each row in BASE_NODE has an associated row NODE_DATA. Additionally, each
- row in WORKING_NODE has one or more associated rows in NODE_DATA.
-
This table contains full node descriptions for nodes in either the BASE
or WORKING trees as described in notes/wc-ng/design. Fields relate
both to BASE and WORKING trees, unless documented otherwise.
- ### This table is to be integrated into the SCHEMA statement as soon
- the experimental status of NODES is lifted.
- ### This table superseeds NODE_DATA
-
For illustration, with a scenario like this:
# (0)
@@ -275,12 +266,11 @@ PRAGMA user_version =
touch foo/bar
svn add foo/bar # (2)
- , these are the NODES for the path foo/bar (before single-db, the
- numbering of op_depth is still a bit different):
+ , these are the NODES table rows for the path foo/bar:
- (0) BASE_NODE -----> NODES (op_depth == 0)
- (1) NODES (op_depth == 1) ( <----_ )
- (2) NODES (op_depth == 2) <----- WORKING_NODE
+ (0) "BASE" ---> NODES (op_depth == 0)
+ (1) NODES (op_depth == 1)
+ (2) NODES (op_depth == 2)
0 is the original data for foo/bar before 'svn rm foo' (if it existed).
1 is the data for foo/bar copied in from ^/moo/bar.
@@ -408,8 +398,11 @@ CREATE TABLE NODES (
/* the kind of the new node. may be "unknown" if the node is not present. */
kind TEXT NOT NULL,
- /* serialized skel of this node's properties. NULL if we
- have no information about the properties (a non-present node). */
+ /* serialized skel of this node's properties (when presence is 'normal' or
+ 'incomplete'); an empty skel or NULL indicates no properties. NULL if
+ we have no information about the properties (any other presence).
+ TODO: Choose & require a single representation for 'no properties'.
+ */
properties BLOB,
/* NULL depth means "default" (typically svn_depth_infinity) */
@@ -483,7 +476,8 @@ CREATE TABLE NODES (
);
-CREATE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath, op_depth);
+CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath,
+ local_relpath, op_depth);
/* I_NODES_MOVED is introduced in format 30 */
CREATE UNIQUE INDEX I_NODES_MOVED ON NODES (wc_id, moved_to, op_depth);
@@ -553,7 +547,7 @@ CREATE TABLE EXTERNALS (
/* Repository location fields */
repos_id INTEGER NOT NULL REFERENCES REPOSITORY (id),
- /* Either 'normal' or 'excluded' */
+ /* Either MAP_NORMAL or MAP_EXCLUDED */
presence TEXT NOT NULL,
/* the kind of the external. */
@@ -574,7 +568,6 @@ CREATE TABLE EXTERNALS (
PRIMARY KEY (wc_id, local_relpath)
);
-CREATE INDEX I_EXTERNALS_PARENT ON EXTERNALS (wc_id, parent_relpath);
CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id,
def_local_relpath,
local_relpath);
@@ -667,6 +660,9 @@ PRAGMA user_version = 22;
-- STMT_UPGRADE_TO_23
PRAGMA user_version = 23;
+-- STMT_UPGRADE_23_HAS_WORKING_NODES
+SELECT 1 FROM nodes WHERE op_depth > 0
+LIMIT 1
/* ------------------------------------------------------------------------- */
@@ -820,6 +816,8 @@ WHERE wc_id = ?1 and local_relpath = ?2
inherited properties */
-- STMT_UPGRADE_TO_31
ALTER TABLE NODES ADD COLUMN inherited_props BLOB;
+DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST;
+DROP INDEX IF EXISTS I_EXTERNALS_PARENT;
PRAGMA user_version = 31;
@@ -846,6 +844,23 @@ WHERE (l.local_relpath = '' AND l.repos_
'/'))
/* ------------------------------------------------------------------------- */
+/* Format 32 .... */
+-- STMT_UPGRADE_TO_32
+
+/* Drop old index. ### Remove this part from the upgrade to 31 once bumped */
+DROP INDEX IF EXISTS I_ACTUAL_CHANGELIST;
+DROP INDEX IF EXISTS I_EXTERNALS_PARENT;
+CREATE INDEX I_EXTERNALS_PARENT ON EXTERNALS (wc_id, parent_relpath);
+
+DROP INDEX I_NODES_PARENT;
+CREATE UNIQUE INDEX I_NODES_PARENT ON NODES (wc_id, parent_relpath,
+ local_relpath, op_depth);
+
+DROP INDEX I_ACTUAL_PARENT;
+CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL (wc_id, parent_relpath,
+ local_relpath);
+
+/* ------------------------------------------------------------------------- */
/* Format YYY introduces new handling for conflict information. */
-- format: YYY
@@ -902,8 +917,8 @@ CREATE TABLE ACTUAL_NODE (
PRIMARY KEY (wc_id, local_relpath)
);
-CREATE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath);
-CREATE INDEX I_ACTUAL_CHANGELIST ON ACTUAL_NODE (changelist);
+CREATE UNIQUE INDEX I_ACTUAL_PARENT ON ACTUAL_NODE (wc_id, parent_relpath,
+ local_relpath);
INSERT INTO ACTUAL_NODE SELECT
wc_id, local_relpath, parent_relpath, properties, conflict_old,