You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2011/12/19 19:49:43 UTC
svn commit: r1220893 [11/19] - in /subversion/branches/fs-py: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ contrib/server-side/mod_dontdothat/ notes/
subversion/bindings/javahl/native/ s...
Modified: subversion/branches/fs-py/subversion/libsvn_wc/entries.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/entries.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/entries.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/entries.c Mon Dec 19 18:49:34 2011
@@ -1466,6 +1466,8 @@ insert_node(svn_sqlite__db_t *sdb,
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "incomplete"));
else if (node->presence == svn_wc__db_status_excluded)
SVN_ERR(svn_sqlite__bind_text(stmt, 8, "excluded"));
+ else if (node->presence == svn_wc__db_status_server_excluded)
+ SVN_ERR(svn_sqlite__bind_text(stmt, 8, "absent"));
if (node->kind == svn_node_none)
SVN_ERR(svn_sqlite__bind_text(stmt, 10, "unknown"));
@@ -1474,8 +1476,20 @@ insert_node(svn_sqlite__db_t *sdb,
svn_node_kind_to_word(node->kind)));
if (node->kind == svn_node_file)
- SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, node->checksum,
- scratch_pool));
+ {
+ if (!node->checksum
+ && node->op_depth == 0
+ && node->presence != svn_wc__db_status_not_present
+ && node->presence != svn_wc__db_status_excluded
+ && node->presence != svn_wc__db_status_server_excluded)
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ _("The file '%s' has no checksum"),
+ svn_dirent_local_style(node->local_relpath,
+ scratch_pool));
+
+ SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, node->checksum,
+ scratch_pool));
+ }
if (node->properties) /* ### Never set, props done later */
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, node->properties,
@@ -1670,6 +1684,13 @@ write_entry(struct write_baton **entry_n
case svn_wc_schedule_add:
working_node = MAYBE_ALLOC(working_node, result_pool);
+ if (entry->deleted)
+ {
+ if (parent_node->base)
+ base_node = MAYBE_ALLOC(base_node, result_pool);
+ else
+ below_working_node = MAYBE_ALLOC(below_working_node, result_pool);
+ }
break;
case svn_wc_schedule_delete:
@@ -1693,14 +1714,17 @@ write_entry(struct write_baton **entry_n
BASE node to indicate the not-present node. */
if (entry->deleted)
{
- SVN_ERR_ASSERT(base_node && !working_node && !below_working_node);
+ SVN_ERR_ASSERT(base_node || below_working_node);
SVN_ERR_ASSERT(!entry->incomplete);
- base_node->presence = svn_wc__db_status_not_present;
+ if (base_node)
+ base_node->presence = svn_wc__db_status_not_present;
+ else
+ below_working_node->presence = svn_wc__db_status_not_present;
}
-
- if (entry->absent)
+ else if (entry->absent)
{
- SVN_ERR_ASSERT(base_node && !working_node);
+ SVN_ERR_ASSERT(base_node && !working_node && !below_working_node);
+ SVN_ERR_ASSERT(!entry->incomplete);
base_node->presence = svn_wc__db_status_server_excluded;
}
@@ -1708,16 +1732,10 @@ write_entry(struct write_baton **entry_n
{
if (entry->copyfrom_url)
{
- const char *relpath;
-
working_node->repos_id = repos_id;
- relpath = svn_uri__is_child(this_dir->repos,
- entry->copyfrom_url,
- result_pool);
- if (relpath == NULL)
- working_node->repos_relpath = "";
- else
- working_node->repos_relpath = relpath;
+ working_node->repos_relpath = svn_uri_skip_ancestor(
+ this_dir->repos, entry->copyfrom_url,
+ result_pool);
working_node->revision = entry->copyfrom_rev;
working_node->op_depth
= svn_wc__db_op_depth_for_upgrade(local_relpath);
@@ -1873,10 +1891,23 @@ write_entry(struct write_baton **entry_n
if (entry->deleted)
{
- base_node->presence = svn_wc__db_status_not_present;
+ SVN_ERR_ASSERT(base_node->presence == svn_wc__db_status_not_present);
/* ### should be svn_node_unknown, but let's store what we have. */
base_node->kind = entry->kind;
}
+ else if (entry->absent)
+ {
+ SVN_ERR_ASSERT(base_node->presence
+ == svn_wc__db_status_server_excluded);
+ /* ### should be svn_node_unknown, but let's store what we have. */
+ base_node->kind = entry->kind;
+
+ /* Store the most likely revision in the node to avoid
+ base nodes without a valid revision. Of course
+ we remember that the data is still incomplete. */
+ if (!SVN_IS_VALID_REVNUM(base_node->revision) && parent_node->base)
+ base_node->revision = parent_node->base->revision;
+ }
else
{
base_node->kind = entry->kind;
@@ -1934,9 +1965,20 @@ write_entry(struct write_baton **entry_n
found_md5_checksum = text_base_info->normal_base.md5_checksum;
else
found_md5_checksum = NULL;
- if (entry_md5_checksum && found_md5_checksum)
- SVN_ERR_ASSERT(svn_checksum_match(entry_md5_checksum,
- found_md5_checksum));
+ if (entry_md5_checksum && found_md5_checksum &&
+ !svn_checksum_match(entry_md5_checksum, found_md5_checksum))
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ _("Bad base MD5 checksum for '%s'; "
+ "expected: '%s'; found '%s'; "),
+ svn_dirent_local_style(
+ svn_dirent_join(root_abspath,
+ local_relpath,
+ scratch_pool),
+ scratch_pool),
+ svn_checksum_to_cstring_display(
+ entry_md5_checksum, scratch_pool),
+ svn_checksum_to_cstring_display(
+ found_md5_checksum, scratch_pool));
else
{
/* ### Not sure what conditions this should cover. */
@@ -1951,17 +1993,16 @@ write_entry(struct write_baton **entry_n
if (entry->url != NULL)
{
- const char *relpath = svn_uri__is_child(this_dir->repos,
- entry->url,
- result_pool);
- base_node->repos_relpath = relpath ? relpath : "";
+ base_node->repos_relpath = svn_uri_skip_ancestor(
+ this_dir->repos, entry->url,
+ result_pool);
}
else
{
- const char *relpath = svn_uri__is_child(this_dir->repos,
- this_dir->url,
- scratch_pool);
- if (relpath == NULL)
+ const char *relpath = svn_uri_skip_ancestor(this_dir->repos,
+ this_dir->url,
+ scratch_pool);
+ if (relpath == NULL || *relpath == '\0')
base_node->repos_relpath = entry->name;
else
base_node->repos_relpath =
Modified: subversion/branches/fs-py/subversion/libsvn_wc/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/externals.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/externals.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/externals.c Mon Dec 19 18:49:34 2011
@@ -201,8 +201,7 @@ svn_wc_parse_externals_description3(apr_
for (num_line_parts = 0; line_parts[num_line_parts]; num_line_parts++)
;
- SVN_ERR(svn_wc_external_item_create
- ((const svn_wc_external_item2_t **) &item, pool));
+ SVN_ERR(svn_wc_external_item2_create(&item, pool));
item->revision.kind = svn_opt_revision_unspecified;
item->peg_revision.kind = svn_opt_revision_unspecified;
@@ -301,8 +300,13 @@ svn_wc_parse_externals_description3(apr_
item->target_dir = svn_dirent_internal_style(item->target_dir, pool);
- if (item->target_dir[0] == '\0' || item->target_dir[0] == '/'
- || svn_path_is_backpath_present(item->target_dir))
+ if (item->target_dir[0] == '\0'
+ || svn_dirent_is_absolute(item->target_dir)
+ || svn_path_is_backpath_present(item->target_dir)
+ || !svn_dirent_skip_ancestor("dummy",
+ svn_dirent_join("dummy",
+ item->target_dir,
+ pool)))
return svn_error_createf
(SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
_("Invalid %s property on '%s': "
@@ -610,8 +614,8 @@ close_file(void *file_baton,
const svn_checksum_t *original_checksum = NULL;
svn_boolean_t added = !SVN_IS_VALID_REVNUM(eb->original_revision);
- const char *repos_relpath = svn_uri__is_child(eb->repos_root_url,
- eb->url, pool);
+ const char *repos_relpath = svn_uri_skip_ancestor(eb->repos_root_url,
+ eb->url, pool);
if (! added)
{
@@ -902,8 +906,8 @@ svn_wc__get_file_external_editor(const s
eb->diff3cmd = diff3_cmd;
eb->record_ancestor_abspath = apr_pstrdup(edit_pool,record_ancestor_abspath);
- eb->recorded_repos_relpath = svn_uri__is_child(repos_root_url, recorded_url,
- edit_pool);
+ eb->recorded_repos_relpath = svn_uri_skip_ancestor(repos_root_url, recorded_url,
+ edit_pool);
eb->changed_rev = SVN_INVALID_REVNUM;
@@ -1116,6 +1120,110 @@ svn_wc__read_external_info(svn_node_kind
return SVN_NO_ERROR;
}
+/* Return TRUE in *IS_ROLLED_OUT iff a node exists at XINFO->LOCAL_ABSPATH and
+ * if that node's origin corresponds with XINFO->REPOS_ROOT_URL and
+ * XINFO->REPOS_RELPATH. All allocations are made in SCRATCH_POOL. */
+static svn_error_t *
+is_external_rolled_out(svn_boolean_t *is_rolled_out,
+ svn_wc_context_t *wc_ctx,
+ svn_wc__committable_external_info_t *xinfo,
+ apr_pool_t *scratch_pool)
+{
+ const char *x_repos_relpath;
+ const char *x_repos_root_url;
+ svn_error_t *err;
+
+ *is_rolled_out = FALSE;
+
+ err = svn_wc__node_get_origin(NULL, NULL,
+ &x_repos_relpath,
+ &x_repos_root_url,
+ NULL,
+ wc_ctx, xinfo->local_abspath,
+ FALSE, /* scan_deleted */
+ scratch_pool, scratch_pool);
+
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ return SVN_NO_ERROR;
+ }
+ SVN_ERR(err);
+ }
+
+ *is_rolled_out = (strcmp(xinfo->repos_root_url, x_repos_root_url) == 0 &&
+ strcmp(xinfo->repos_relpath, x_repos_relpath) == 0);
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_wc__committable_externals_below(apr_array_header_t **externals,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_depth_t depth,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ apr_array_header_t *orig_externals;
+ int i;
+ apr_pool_t *iterpool;
+
+ /* For svn_depth_files, this also fetches dirs. They are filtered later. */
+ SVN_ERR(svn_wc__db_committable_externals_below(&orig_externals,
+ wc_ctx->db,
+ local_abspath,
+ depth != svn_depth_infinity,
+ result_pool, scratch_pool));
+
+ if (orig_externals == NULL)
+ return SVN_NO_ERROR;
+
+ iterpool = svn_pool_create(scratch_pool);
+
+ for (i = 0; i < orig_externals->nelts; i++)
+ {
+ svn_boolean_t is_rolled_out;
+
+ svn_wc__committable_external_info_t *xinfo =
+ APR_ARRAY_IDX(orig_externals, i,
+ svn_wc__committable_external_info_t *);
+
+ /* Discard dirs for svn_depth_files (s.a.). */
+ if (depth == svn_depth_files
+ && xinfo->kind == svn_kind_dir)
+ continue;
+
+ svn_pool_clear(iterpool);
+
+ /* Discard those externals that are not currently checked out. */
+ SVN_ERR(is_external_rolled_out(&is_rolled_out, wc_ctx, xinfo,
+ iterpool));
+ if (! is_rolled_out)
+ continue;
+
+ if (*externals == NULL)
+ *externals = apr_array_make(
+ result_pool, 0,
+ sizeof(svn_wc__committable_external_info_t *));
+
+ APR_ARRAY_PUSH(*externals,
+ svn_wc__committable_external_info_t *) = xinfo;
+
+ if (depth != svn_depth_infinity)
+ continue;
+
+ /* Are there any nested externals? */
+ SVN_ERR(svn_wc__committable_externals_below(externals, wc_ctx,
+ xinfo->local_abspath,
+ svn_depth_infinity,
+ result_pool, iterpool));
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_wc__externals_defined_below(apr_hash_t **externals,
svn_wc_context_t *wc_ctx,
Modified: subversion/branches/fs-py/subversion/libsvn_wc/node.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/node.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/node.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/node.c Mon Dec 19 18:49:34 2011
@@ -214,6 +214,8 @@ svn_wc__internal_get_repos_info(const ch
db, local_abspath,
result_pool, scratch_pool));
+ SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
+ SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
return SVN_NO_ERROR;
}
Modified: subversion/branches/fs-py/subversion/libsvn_wc/props.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/props.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/props.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/props.c Mon Dec 19 18:49:34 2011
@@ -145,8 +145,8 @@ diff_mergeinfo_props(svn_mergeinfo_t *de
svn_mergeinfo_t from, to;
SVN_ERR(svn_mergeinfo_parse(&from, from_prop_val->data, pool));
SVN_ERR(svn_mergeinfo_parse(&to, to_prop_val->data, pool));
- SVN_ERR(svn_mergeinfo_diff(deleted, added, from, to,
- TRUE, pool));
+ SVN_ERR(svn_mergeinfo_diff2(deleted, added, from, to,
+ TRUE, pool, pool));
}
return SVN_NO_ERROR;
}
@@ -595,9 +595,9 @@ prop_conflict_from_skel(const svn_string
incoming_base, scratch_pool);
if (mine == NULL)
- mine = svn_string_create("", scratch_pool);
+ mine = svn_string_create_empty(scratch_pool);
if (incoming == NULL)
- incoming = svn_string_create("", scratch_pool);
+ incoming = svn_string_create_empty(scratch_pool);
/* Pick a suitable base for the conflict diff.
* The incoming value is always a change,
@@ -607,7 +607,7 @@ prop_conflict_from_skel(const svn_string
if (incoming_base)
original = incoming_base;
else
- original = svn_string_create("", scratch_pool);
+ original = svn_string_create_empty(scratch_pool);
}
else if (incoming_base && svn_string_compare(original, mine))
original = incoming_base;
Modified: subversion/branches/fs-py/subversion/libsvn_wc/questions.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/questions.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/questions.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/questions.c Mon Dec 19 18:49:34 2011
@@ -531,19 +531,6 @@ svn_wc__min_max_revisions(svn_revnum_t *
svn_error_t *
-svn_wc__is_sparse_checkout(svn_boolean_t *is_sparse_checkout,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(svn_wc__db_is_sparse_checkout(is_sparse_checkout,
- wc_ctx->db,
- local_abspath,
- scratch_pool));
-}
-
-
-svn_error_t *
svn_wc__has_switched_subtrees(svn_boolean_t *is_switched,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
Modified: subversion/branches/fs-py/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/status.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/status.c Mon Dec 19 18:49:34 2011
@@ -2455,7 +2455,10 @@ svn_wc_get_status_editor5(const svn_delt
struct edit_baton *eb;
svn_delta_editor_t *tree_editor = svn_delta_default_editor(result_pool);
void *inner_baton;
+ struct svn_wc__shim_fetch_baton_t *sfb;
const svn_delta_editor_t *inner_editor;
+ svn_delta_shim_callbacks_t *shim_callbacks =
+ svn_delta_shim_callbacks_default(result_pool);
/* Construct an edit baton. */
eb = apr_pcalloc(result_pool, sizeof(*eb));
@@ -2543,8 +2546,20 @@ svn_wc_get_status_editor5(const svn_delt
if (set_locks_baton)
*set_locks_baton = eb;
+ sfb = apr_palloc(result_pool, sizeof(*sfb));
+ sfb->db = wc_ctx->db;
+ sfb->base_abspath = eb->target_abspath;
+ sfb->fetch_base = FALSE;
+
+ shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
+ shim_callbacks->fetch_kind_baton = sfb;
+ shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;
+ shim_callbacks->fetch_props_baton = sfb;
+ shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
+ shim_callbacks->fetch_base_baton = sfb;
+
SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
- NULL, NULL, NULL, NULL,
+ shim_callbacks,
result_pool, scratch_pool));
return SVN_NO_ERROR;
Modified: subversion/branches/fs-py/subversion/libsvn_wc/tree_conflicts.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/tree_conflicts.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/tree_conflicts.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/tree_conflicts.c Mon Dec 19 18:49:34 2011
@@ -76,8 +76,9 @@ const svn_token_map_t svn_wc__conflict_r
{ "added", svn_wc_conflict_reason_added },
{ "replaced", svn_wc_conflict_reason_replaced },
{ "unversioned", svn_wc_conflict_reason_unversioned },
- { "moved-here", svn_wc_conflict_reason_moved_here },
{ "moved-away", svn_wc_conflict_reason_moved_away },
+ { "moved-away-and-edited", svn_wc_conflict_reason_moved_away_and_edited },
+ { "moved-here", svn_wc_conflict_reason_moved_here },
{ NULL }
};
@@ -365,7 +366,7 @@ svn_wc__serialize_conflict(svn_skel_t **
/* Victim path (escaping separator chars). */
victim_basename = svn_dirent_basename(conflict->local_abspath, result_pool);
- SVN_ERR_ASSERT(strlen(victim_basename) > 0);
+ SVN_ERR_ASSERT(victim_basename[0]);
svn_skel__prepend(svn_skel__str_atom(victim_basename, result_pool), c_skel);
svn_skel__prepend(svn_skel__str_atom("conflict", result_pool), c_skel);
Modified: subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/update_editor.c Mon Dec 19 18:49:34 2011
@@ -35,6 +35,7 @@
#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"
#include "svn_path.h"
@@ -283,6 +284,13 @@ struct dir_baton
/* Absolute path of this directory */
const char *local_abspath;
+ /* Absolute path to the new location of the directory if it was moved away,
+ * and the op-root of the move operation.
+ * This is set on the root of a move operation and all children.
+ * If the directory was not moved away, this is NULL. */
+ const char *moved_to_abspath;
+ const char *moved_to_op_root_abspath;
+
/* The repository relative path this directory will correspond to. */
const char *new_relpath;
@@ -617,6 +625,8 @@ make_dir_baton(struct dir_baton **d_p,
d->adding_dir = adding;
d->changed_rev = SVN_INVALID_REVNUM;
d->not_present_files = apr_hash_make(dir_pool);
+ d->moved_to_abspath = NULL;
+ d->moved_to_op_root_abspath = NULL;
/* Copy some flags from the parent baton */
if (pb)
@@ -1083,6 +1093,7 @@ open_root(void *edit_baton,
struct dir_baton *db;
svn_boolean_t already_conflicted;
svn_error_t *err;
+ svn_wc__db_status_t status;
/* Note that something interesting is actually happening in this
edit run. */
@@ -1118,7 +1129,6 @@ open_root(void *edit_baton,
if (*eb->target_basename == '\0')
{
/* For an update with a NULL target, this is equivalent to open_dir(): */
- svn_wc__db_status_t status;
/* Read the depth from the entry. */
SVN_ERR(svn_wc__db_base_get_info(&status, NULL, NULL, NULL, NULL, NULL,
@@ -1136,6 +1146,25 @@ open_root(void *edit_baton,
pool));
}
+ /* Check if this directory was moved away. */
+ err = svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ eb->db, db->local_abspath, pool, pool);
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ svn_error_clear(err);
+ else
+ return svn_error_trace(err);
+ }
+ else if (status == svn_wc__db_status_deleted)
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, &db->moved_to_abspath, NULL,
+ &db->moved_to_op_root_abspath,
+ eb->db, db->local_abspath, db->pool, pool));
+
return SVN_NO_ERROR;
}
@@ -1148,6 +1177,7 @@ 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 */
} modcheck_baton_t;
/* An implementation of svn_wc_status_func4_t. */
@@ -1162,6 +1192,7 @@ modcheck_callback(void *baton,
switch (status->node_status)
{
case svn_wc_status_normal:
+ case svn_wc_status_incomplete:
case svn_wc_status_ignored:
case svn_wc_status_none:
case svn_wc_status_unversioned:
@@ -1178,8 +1209,17 @@ modcheck_callback(void *baton,
break;
/* Fall through in the found modification case */
- default:
case svn_wc_status_added:
+ if (!mb->is_copy)
+ {
+ 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_replaced:
case svn_wc_status_modified:
mb->found_mod = TRUE;
@@ -1196,20 +1236,24 @@ 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. */
+ * 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)
{
- modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE };
+ modcheck_baton_t modcheck_baton = { NULL, FALSE, FALSE, FALSE };
svn_error_t *err;
modcheck_baton.db = db;
+ modcheck_baton.is_copy = is_copy;
/* 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
@@ -1332,6 +1376,7 @@ create_tree_conflict(svn_wc_conflict_des
SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_edited
|| reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away
+ || reason == svn_wc_conflict_reason_moved_away_and_edited
|| reason == svn_wc_conflict_reason_replaced
|| reason == svn_wc_conflict_reason_obstructed);
@@ -1527,6 +1572,26 @@ check_tree_conflict(svn_wc_conflict_desc
case svn_wc__db_status_deleted:
if (!moved_to_abspath)
reason = svn_wc_conflict_reason_deleted;
+ else if (action == svn_wc_conflict_action_delete)
+ {
+ svn_boolean_t all_edits_are_deletes = FALSE;
+
+ /* The update wants to delete a node which was locally moved
+ * away. We allow this only if the node wasn't modified post-move.
+ * If the only post-move changes within a subtree are deletions,
+ * allow the update to delete the entire subtree. */
+ if (working_kind == svn_kind_dir)
+ SVN_ERR(node_has_local_mods(&modified, &all_edits_are_deletes,
+ TRUE, eb->db, moved_to_abspath,
+ eb->cancel_func, eb->cancel_baton,
+ scratch_pool));
+ else
+ SVN_ERR(svn_wc__internal_file_modified_p(&modified, eb->db,
+ moved_to_abspath,
+ FALSE, scratch_pool));
+ if (modified && !all_edits_are_deletes)
+ reason = svn_wc_conflict_reason_moved_away_and_edited;
+ }
break;
case svn_wc__db_status_incomplete:
@@ -1551,7 +1616,7 @@ check_tree_conflict(svn_wc_conflict_desc
* 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,
+ SVN_ERR(node_has_local_mods(&modified, &all_mods_are_deletes, FALSE,
eb->db, local_abspath,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
@@ -1592,6 +1657,7 @@ check_tree_conflict(svn_wc_conflict_desc
if (reason == svn_wc_conflict_reason_edited
|| reason == svn_wc_conflict_reason_deleted
|| reason == svn_wc_conflict_reason_moved_away
+ || reason == svn_wc_conflict_reason_moved_away_and_edited
|| reason == svn_wc_conflict_reason_replaced)
/* When the node existed before (it was locally deleted, replaced or
* edited), then 'update' cannot add it "again". So it can only send
@@ -1706,6 +1772,7 @@ delete_entry(const char *path,
const char *base = svn_relpath_basename(path, NULL);
const char *local_abspath;
const char *repos_relpath;
+ const char *moved_to_abspath = NULL;
svn_kind_t kind, base_kind;
svn_boolean_t conflicted;
svn_boolean_t have_base;
@@ -1805,6 +1872,13 @@ delete_entry(const char *path,
return SVN_NO_ERROR;
}
+ /* Has the to-be-deleted node been moved away? */
+ if (status == svn_wc__db_status_deleted)
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, &moved_to_abspath, NULL,
+ NULL, eb->db, local_abspath,
+ pool, pool));
+
+
/* Is this path the victim of a newly-discovered tree conflict? If so,
* remember it and notify the client. Then (if it was existing and
* modified), re-schedule the node to be added back again, as a (modified)
@@ -1817,7 +1891,8 @@ delete_entry(const char *path,
SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
status, kind, TRUE,
svn_wc_conflict_action_delete, svn_node_none,
- repos_relpath, NULL, pb->pool, scratch_pool));
+ repos_relpath, moved_to_abspath,
+ pb->pool, scratch_pool));
}
if (tree_conflict != NULL)
@@ -1856,6 +1931,8 @@ delete_entry(const char *path,
}
else if (tree_conflict->reason == svn_wc_conflict_reason_deleted
|| tree_conflict->reason == svn_wc_conflict_reason_moved_away
+ || tree_conflict->reason ==
+ svn_wc_conflict_reason_moved_away_and_edited
|| tree_conflict->reason == svn_wc_conflict_reason_replaced)
{
/* The item does not exist locally because it was already shadowed.
@@ -1867,6 +1944,23 @@ delete_entry(const char *path,
else
SVN_ERR_MALFUNCTION(); /* other reasons are not expected here */
}
+ else if (moved_to_abspath)
+ {
+ /* No tree conflict was flagged, and the node was moved-away.
+ * Automatically merge the incoming deletion with the local move
+ * by deleting the node from the moved-away subtree. */
+ /* ### This should probably use a work queue. */
+ SVN_ERR(svn_wc__db_op_delete(eb->db, moved_to_abspath, NULL,
+ NULL, NULL, /* notify below */
+ eb->cancel_func, eb->cancel_baton,
+ scratch_pool));
+ if (kind == svn_kind_dir)
+ SVN_ERR(svn_io_remove_dir2(moved_to_abspath, TRUE,
+ eb->cancel_func, eb->cancel_baton,
+ scratch_pool));
+ else
+ SVN_ERR(svn_io_remove_file2(moved_to_abspath, TRUE, scratch_pool));
+ }
/* Issue a wq operation to delete the BASE_NODE data and to delete actual
nodes based on that from disk, but leave any WORKING_NODEs on disk.
@@ -1917,7 +2011,8 @@ delete_entry(const char *path,
else
node_kind = svn_node_file;
- do_notification(eb, local_abspath, node_kind, action, scratch_pool);
+ do_notification(eb, moved_to_abspath ? moved_to_abspath : local_abspath,
+ node_kind, action, scratch_pool);
}
svn_pool_destroy(scratch_pool);
@@ -2216,8 +2311,8 @@ add_directory(const char *path,
pool));
/* Make sure there is a real directory at LOCAL_ABSPATH, unless we are just
- updating the DB */
- if (!db->shadowed)
+ updating the DB or the parent was moved away. */
+ if (!db->shadowed && !pb->moved_to_abspath)
SVN_ERR(svn_wc__ensure_directory(db->local_abspath, pool));
if (!db->shadowed && status == svn_wc__db_status_added)
@@ -2245,6 +2340,16 @@ add_directory(const char *path,
do_notification(eb, db->local_abspath, svn_node_dir,
svn_wc_notify_tree_conflict, pool);
}
+ else if (wc_kind == svn_kind_unknown &&
+ versioned_locally_and_present == FALSE &&
+ pb->moved_to_abspath)
+ {
+ /* The parent directory of the directory we're adding was moved.
+ * Add the new directory at the new location. */
+ db->moved_to_abspath = svn_dirent_join(pb->moved_to_abspath,
+ db->name, db->pool);
+ db->moved_to_op_root_abspath = pb->moved_to_op_root_abspath;
+ }
@@ -2266,7 +2371,9 @@ add_directory(const char *path,
db->already_notified = TRUE;
- do_notification(eb, db->local_abspath, svn_node_dir, action, pool);
+ do_notification(eb, db->moved_to_abspath ? db->moved_to_abspath
+ : db->local_abspath,
+ svn_node_dir, action, pool);
}
return SVN_NO_ERROR;
@@ -2287,6 +2394,7 @@ open_directory(const char *path,
svn_wc_conflict_description2_t *tree_conflict = NULL;
svn_wc__db_status_t status, base_status;
svn_kind_t wc_kind;
+ svn_error_t *err;
SVN_ERR(make_dir_baton(&db, path, eb, pb, FALSE, pool));
*child_baton = db;
@@ -2361,13 +2469,34 @@ open_directory(const char *path,
/* Is this path a fresh tree conflict victim? If so, skip the tree
with one notification. */
+ /* Check if this directory was moved away. */
+ err = svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ eb->db, db->local_abspath, pool, pool);
+ if (err)
+ {
+ if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ svn_error_clear(err);
+ else
+ return svn_error_trace(err);
+ }
+ else if (status == svn_wc__db_status_deleted)
+ SVN_ERR(svn_wc__db_scan_deletion(NULL, &db->moved_to_abspath, NULL,
+ &db->moved_to_op_root_abspath,
+ eb->db, db->local_abspath,
+ db->pool, pool));
+
/* Check for conflicts only when we haven't already recorded
* 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,
svn_wc_conflict_action_edit, svn_node_dir,
- db->new_relpath, NULL, db->pool, pool));
+ db->new_relpath, db->moved_to_abspath,
+ db->pool, pool));
/* Remember the roots of any locally deleted trees. */
if (tree_conflict != NULL)
@@ -2377,6 +2506,8 @@ open_directory(const char *path,
SVN_ERR_ASSERT(
tree_conflict->reason == svn_wc_conflict_reason_deleted ||
tree_conflict->reason == svn_wc_conflict_reason_moved_away ||
+ tree_conflict->reason ==
+ svn_wc_conflict_reason_moved_away_and_edited ||
tree_conflict->reason == svn_wc_conflict_reason_replaced);
/* Continue updating BASE */
@@ -2804,6 +2935,41 @@ close_directory(void *dir_baton,
new_actual_props,
all_work_items,
scratch_pool));
+
+ if (db->moved_to_abspath)
+ {
+ /* Perform another in-DB move of the directory to sync meta-data
+ * of the moved-away node with the new BASE node. */
+ apr_array_header_t *children = NULL;
+ apr_hash_t *children_hash = apr_hash_get(eb->dir_dirents,
+ db->new_relpath,
+ APR_HASH_KEY_STRING);
+ /* The op-root of the move needs to retain its moved-here flag.
+ * Its children are normal copied children. */
+ svn_boolean_t is_move = (strcmp(db->moved_to_op_root_abspath,
+ db->moved_to_abspath) == 0);
+
+ /* Add the new directory as a copy and create it on disk. */
+ if (children_hash)
+ SVN_ERR(svn_hash_keys(&children, children_hash, scratch_pool));
+ SVN_ERR(svn_wc__db_op_copy_dir(eb->db, db->moved_to_abspath,
+ new_actual_props ? new_actual_props
+ : actual_props,
+ db->changed_rev,
+ db->changed_date,
+ db->changed_author,
+ db->new_relpath,
+ eb->repos_root,
+ eb->repos_uuid,
+ *eb->target_revision,
+ children,
+ is_move,
+ db->ambient_depth,
+ NULL /* conflict */,
+ NULL, /* no work, just modify DB */
+ scratch_pool));
+ SVN_ERR(svn_wc__ensure_directory(db->moved_to_abspath, pool));
+ }
}
/* Process all of the queued work items for this directory. */
@@ -3256,6 +3422,15 @@ add_file(const char *path,
do_notification(eb, fb->local_abspath, svn_node_file,
svn_wc_notify_tree_conflict, scratch_pool);
}
+ else if (wc_kind == svn_kind_unknown &&
+ versioned_locally_and_present == FALSE &&
+ pb->moved_to_abspath)
+ {
+ /* The parent directory of the file we're adding was moved.
+ * Add the new file at the new location. */
+ fb->moved_to_abspath = svn_dirent_join(pb->moved_to_abspath,
+ fb->name, fb->pool);
+ }
svn_pool_destroy(scratch_pool);
@@ -3377,7 +3552,9 @@ open_file(const char *path,
/* Other modifications wouldn't be a tree conflict */
SVN_ERR_ASSERT(
tree_conflict->reason == svn_wc_conflict_reason_deleted ||
- tree_conflict->reason == svn_wc_conflict_reason_moved_away||
+ tree_conflict->reason == svn_wc_conflict_reason_moved_away ||
+ tree_conflict->reason ==
+ svn_wc_conflict_reason_moved_away_and_edited ||
tree_conflict->reason == svn_wc_conflict_reason_replaced);
/* Continue updating BASE */
@@ -4085,28 +4262,28 @@ close_file(void *file_baton,
if (!fb->shadowed
&& (! fb->adding_file || fb->add_existed))
{
- svn_boolean_t local_is_link = FALSE;
- svn_boolean_t incoming_is_link = FALSE;
+ svn_boolean_t local_is_link;
+ svn_boolean_t incoming_is_link;
+ int i;
local_is_link = apr_hash_get(local_actual_props,
SVN_PROP_SPECIAL,
APR_HASH_KEY_STRING) != NULL;
- {
- int i;
+ incoming_is_link = local_is_link;
- for (i = 0; i < regular_prop_changes->nelts; ++i)
- {
- const svn_prop_t *prop = &APR_ARRAY_IDX(regular_prop_changes, i,
- svn_prop_t);
-
- if (strcmp(prop->name, SVN_PROP_SPECIAL) == 0)
- {
- incoming_is_link = TRUE;
- }
- }
- }
+ /* Does an incoming propchange affect symlink-ness? */
+ for (i = 0; i < regular_prop_changes->nelts; ++i)
+ {
+ const svn_prop_t *prop = &APR_ARRAY_IDX(regular_prop_changes, i,
+ svn_prop_t);
+ if (strcmp(prop->name, SVN_PROP_SPECIAL) == 0)
+ {
+ incoming_is_link = (prop->value != NULL);
+ break;
+ }
+ }
if (local_is_link != incoming_is_link)
{
@@ -4116,15 +4293,12 @@ close_file(void *file_baton,
fb->obstruction_found = TRUE;
fb->add_existed = FALSE;
- /* ### Performance: We should just create the conflict here, without
- ### verifying again */
- SVN_ERR(check_tree_conflict(&tree_conflict, eb, fb->local_abspath,
- svn_wc__db_status_added,
- svn_kind_file, TRUE,
- svn_wc_conflict_action_add,
- svn_node_file, fb->new_relpath, NULL,
- scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(tree_conflict != NULL);
+ SVN_ERR(create_tree_conflict(&tree_conflict, eb,
+ fb->local_abspath,
+ svn_wc_conflict_reason_added,
+ svn_wc_conflict_action_add,
+ svn_node_file, fb->new_relpath,
+ scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_op_set_tree_conflict(eb->db,
fb->local_abspath,
tree_conflict,
@@ -4545,63 +4719,6 @@ close_edit(void *edit_baton,
/*** Returning editors. ***/
-struct fetch_baton
-{
- svn_wc__db_t *db;
- const char *target_abspath;
-};
-
-static svn_error_t *
-fetch_props_func(apr_hash_t **props,
- void *baton,
- const char *path,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct fetch_baton *fpb = baton;
- const char *local_abspath = svn_dirent_join(fpb->target_abspath, path,
- scratch_pool);
- svn_error_t *err;
-
- err = svn_wc__db_read_props(props, fpb->db, local_abspath,
- result_pool, scratch_pool);
-
- /* If the path doesn't exist, just return an empty set of props. */
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- {
- svn_error_clear(err);
- *props = apr_hash_make(result_pool);
- }
- else if (err)
- return svn_error_trace(err);
-
- return SVN_NO_ERROR;
-}
-
-static svn_error_t *
-fetch_kind_func(svn_node_kind_t *kind,
- void *baton,
- const char *path,
- apr_pool_t *scratch_pool)
-{
- struct fetch_baton *fpb = baton;
- const char *local_abspath = svn_dirent_join(fpb->target_abspath, path,
- scratch_pool);
- svn_kind_t db_kind;
-
- SVN_ERR(svn_wc__db_read_kind(&db_kind, fpb->db, local_abspath, FALSE,
- scratch_pool));
-
- if (db_kind == svn_kind_dir)
- *kind = svn_node_dir;
- else if (db_kind == svn_kind_file)
- *kind = svn_node_file;
- else
- *kind = svn_node_none;
-
- return SVN_NO_ERROR;
-}
-
/* Helper for the three public editor-supplying functions. */
static svn_error_t *
make_editor(svn_revnum_t *target_revision,
@@ -4639,7 +4756,9 @@ make_editor(svn_revnum_t *target_revisio
svn_delta_editor_t *tree_editor = svn_delta_default_editor(edit_pool);
const svn_delta_editor_t *inner_editor;
const char *repos_root, *repos_uuid;
- struct fetch_baton *fpb;
+ struct svn_wc__shim_fetch_baton_t *sfb;
+ svn_delta_shim_callbacks_t *shim_callbacks =
+ svn_delta_shim_callbacks_default(edit_pool);
/* An unknown depth can't be sticky. */
if (depth == svn_depth_unknown)
@@ -4867,12 +4986,20 @@ make_editor(svn_revnum_t *target_revisio
edit_baton,
result_pool));
- fpb = apr_palloc(result_pool, sizeof(*fpb));
- fpb->db = db;
- fpb->target_abspath = eb->target_abspath;
+ sfb = apr_palloc(result_pool, sizeof(*sfb));
+ sfb->db = db;
+ sfb->base_abspath = eb->target_abspath;
+ sfb->fetch_base = TRUE;
+
+ shim_callbacks->fetch_kind_func = svn_wc__fetch_kind_func;
+ shim_callbacks->fetch_kind_baton = sfb;
+ shim_callbacks->fetch_props_func = svn_wc__fetch_props_func;
+ shim_callbacks->fetch_props_baton = sfb;
+ shim_callbacks->fetch_base_func = svn_wc__fetch_base_func;
+ shim_callbacks->fetch_base_baton = sfb;
+
SVN_ERR(svn_editor__insert_shims(editor, edit_baton, *editor, *edit_baton,
- fetch_props_func, fpb, fetch_kind_func, fpb,
- result_pool, scratch_pool));
+ shim_callbacks, result_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -5397,14 +5524,14 @@ svn_wc_add_repos_file4(svn_wc_context_t
dir_abspath,
pool, pool));
- if (!svn_uri__is_ancestor(original_root_url, copyfrom_url))
+ original_repos_relpath =
+ svn_uri_skip_ancestor(original_root_url, copyfrom_url, pool);
+
+ if (!original_repos_relpath)
return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
_("Copyfrom-url '%s' has different repository"
" root than '%s'"),
copyfrom_url, original_root_url);
-
- original_repos_relpath =
- svn_uri_skip_ancestor(original_root_url, copyfrom_url, pool);
}
else
{
Modified: subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/upgrade.c Mon Dec 19 18:49:34 2011
@@ -614,8 +614,7 @@ ensure_repos_info(svn_wc_entry_t *entry,
for (hi = apr_hash_first(scratch_pool, repos_cache);
hi; hi = apr_hash_next(hi))
{
- if (svn_uri__is_child(svn__apr_hash_index_key(hi), entry->url,
- scratch_pool))
+ if (svn_uri__is_ancestor(svn__apr_hash_index_key(hi), entry->url))
{
if (!entry->repos)
entry->repos = svn__apr_hash_index_key(hi);
@@ -1404,6 +1403,7 @@ upgrade_to_wcng(void **dir_baton,
svn_wc_entry_t *this_dir;
const char *old_wcroot_abspath, *dir_relpath;
apr_hash_t *text_bases_info;
+ svn_error_t *err;
/* Don't try to mess with the WC if there are old log files left. */
@@ -1475,11 +1475,18 @@ upgrade_to_wcng(void **dir_baton,
data->sdb, scratch_pool, scratch_pool));
/***** ENTRIES - WRITE *****/
- SVN_ERR(svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb,
- data->repos_id, data->wc_id,
- dir_abspath, data->root_abspath,
- entries, text_bases_info,
- result_pool, scratch_pool));
+ err = svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb,
+ data->repos_id, data->wc_id,
+ dir_abspath, data->root_abspath,
+ entries, text_bases_info,
+ result_pool, scratch_pool);
+ if (err && err->apr_err == SVN_ERR_WC_CORRUPT)
+ return svn_error_quick_wrap(err,
+ _("This working copy is corrupt and "
+ "cannot be upgraded. Please check out "
+ "a new working copy."));
+ else
+ SVN_ERR(err);
/***** WC PROPS *****/
/* If we don't know precisely where the wcprops are, ignore them. */
Modified: subversion/branches/fs-py/subversion/libsvn_wc/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/util.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/util.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/util.c Mon Dec 19 18:49:34 2011
@@ -150,8 +150,8 @@ svn_wc_dup_notify(const svn_wc_notify_t
}
svn_error_t *
-svn_wc_external_item_create(const svn_wc_external_item2_t **item,
- apr_pool_t *pool)
+svn_wc_external_item2_create(svn_wc_external_item2_t **item,
+ apr_pool_t *pool)
{
*item = apr_pcalloc(pool, sizeof(svn_wc_external_item2_t));
return SVN_NO_ERROR;
@@ -533,3 +533,94 @@ svn_wc__status2_from_3(svn_wc_status2_t
return SVN_NO_ERROR;
}
+
+
+svn_error_t *
+svn_wc__fetch_kind_func(svn_kind_t *kind,
+ void *baton,
+ const char *path,
+ apr_pool_t *scratch_pool)
+{
+ struct svn_wc__shim_fetch_baton_t *sfb = baton;
+ const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
+ scratch_pool);
+
+ SVN_ERR(svn_wc__db_read_kind(kind, sfb->db, local_abspath, FALSE,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__fetch_props_func(apr_hash_t **props,
+ void *baton,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct svn_wc__shim_fetch_baton_t *sfb = baton;
+ const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
+ scratch_pool);
+ svn_error_t *err;
+
+ if (sfb->fetch_base)
+ err = svn_wc__db_base_get_props(props, sfb->db, local_abspath, result_pool,
+ scratch_pool);
+ else
+ err = svn_wc__db_read_props(props, sfb->db, local_abspath,
+ result_pool, scratch_pool);
+
+ /* If the path doesn't exist, just return an empty set of props. */
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ *props = apr_hash_make(result_pool);
+ }
+ else if (err)
+ return svn_error_trace(err);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_wc__fetch_base_func(const char **filename,
+ void *baton,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ struct svn_wc__shim_fetch_baton_t *sfb = baton;
+ svn_stream_t *contents;
+ svn_stream_t *file_stream;
+ const char *tmp_filename;
+ const svn_checksum_t *checksum;
+ svn_error_t *err;
+ const char *local_abspath = svn_dirent_join(sfb->base_abspath, path,
+ scratch_pool);
+
+ 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);
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ *filename = NULL;
+ return SVN_NO_ERROR;
+ }
+ else if (err)
+ return svn_error_trace(err);
+ SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, sfb->db, local_abspath,
+ checksum, scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool));
+
+ *filename = apr_pstrdup(result_pool, tmp_filename);
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc-metadata.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc-metadata.sql?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc-metadata.sql (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc-metadata.sql Mon Dec 19 18:49:34 2011
@@ -383,8 +383,9 @@ CREATE TABLE NODES (
perhaps add a column called "moved_from". */
/* Boolean value, specifying if this node was moved here (rather than just
- copied). The source of the move is implied by a different node with
- a moved_to column pointing at this node. */
+ copied). This is set on all the nodes in the moved tree. The source of
+ the move is implied by a different node with a moved_to column pointing
+ at the root node of the moved tree. */
moved_here INTEGER,
/* If the underlying node was moved away (rather than just deleted), this
Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc-queries.sql Mon Dec 19 18:49:34 2011
@@ -956,6 +956,40 @@ SELECT presence, kind, def_local_relpath
FROM externals WHERE wc_id = ?1 AND local_relpath = ?2
LIMIT 1
+/* Select all committable externals, i.e. only unpegged ones on the same
+ * repository as the target path ?2, that are defined by WC ?1 to
+ * live below the target path. It does not matter which ancestor has the
+ * svn:externals definition, only the local path at which the external is
+ * supposed to be checked out is queried.
+ * Arguments:
+ * ?1: wc_id.
+ * ?2: the target path, local relpath inside ?1.
+ * ?3: boolean, if 1 return immediate children of ?2 only.
+ *
+ * ### NOTE: This statement deliberately removes file externals that live
+ * inside an unversioned dir, because commit still breaks on those.
+ * Once that's been fixed, the conditions below "--->8---" become obsolete. */
+-- STMT_SELECT_COMMITTABLE_EXTERNALS_BELOW
+SELECT local_relpath, kind, repos_id, def_repos_relpath, repository.root
+FROM externals
+LEFT OUTER JOIN repository ON repository.id = externals.repos_id
+WHERE wc_id = ?1
+ AND def_revision IS NULL
+ AND repos_id = (SELECT repos_id FROM nodes
+ WHERE nodes.local_relpath = ?2)
+ AND ( ((NOT ?3)
+ AND (?2 = ''
+ /* Want only the cildren of e.local_relpath;
+ * externals can't have a local_relpath = ''. */
+ OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2)))
+ OR
+ ((?3)
+ AND parent_relpath = ?2) )
+ /* ------>8----- */
+ AND (EXISTS (SELECT 1 FROM nodes
+ WHERE nodes.wc_id = externals.wc_id
+ AND nodes.local_relpath = externals.parent_relpath))
+
-- STMT_SELECT_EXTERNALS_DEFINED
SELECT local_relpath, def_local_relpath
FROM externals
@@ -1193,21 +1227,18 @@ DROP TABLE IF EXISTS delete_list;
CREATE TEMPORARY TABLE delete_list (
/* ### we should put the wc_id in here in case a delete spans multiple
### working copies. queries, etc will need to be adjusted. */
- local_relpath TEXT PRIMARY KEY NOT NULL
+ local_relpath TEXT PRIMARY KEY NOT NULL UNIQUE
)
/* This matches the selection in STMT_INSERT_DELETE_FROM_NODE_RECURSIVE */
-- STMT_INSERT_DELETE_LIST
INSERT INTO delete_list(local_relpath)
-SELECT local_relpath FROM nodes n
+SELECT local_relpath FROM nodes_current
WHERE wc_id = ?1
AND (local_relpath = ?2
OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
AND op_depth >= ?3
AND presence NOT IN ('base-deleted', 'not-present', 'excluded', 'absent')
- AND op_depth = (SELECT MAX(op_depth) FROM nodes s
- WHERE s.wc_id = n.wc_id
- AND s.local_relpath = n.local_relpath)
-- STMT_SELECT_DELETE_LIST
SELECT local_relpath FROM delete_list
Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc.h
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc.h?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc.h (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc.h Mon Dec 19 18:49:34 2011
@@ -149,7 +149,7 @@ extern "C" {
* The bump to 29 renamed the pristine files from '<SHA1>' to '<SHA1>.svn-base'
* and introduced the EXTERNALS store. Bumped in r1129286.
*
- * == 1.7.x shipped with format ???
+ * == 1.7.x shipped with format 29
*
* Please document any further format changes here.
*/
@@ -350,10 +350,8 @@ svn_wc__prop_array_to_hash(const apr_arr
*
* If EXACT_COMPARISON is FALSE, translate LOCAL_ABSPATH's EOL
* style and keywords to repository-normal form according to its properties,
- * and compare the result with the text base. If COMPARE_TEXTBASES is
- * TRUE, translate the text base's EOL style and keywords to working-copy
- * form according to LOCAL_ABSPATH's properties, and compare the
- * result with LOCAL_ABSPATH. Usually, EXACT_COMPARISON should be FALSE.
+ * and compare the result with the text base.
+ * Usually, EXACT_COMPARISON should be FALSE.
*
* If LOCAL_ABSPATH does not exist, consider it unmodified. If it exists
* but is not under revision control (not even scheduled for
@@ -726,6 +724,38 @@ svn_wc__perform_file_merge(svn_skel_t **
apr_pool_t *scratch_pool);
+/* Couple of random helpers for the Ev2 shims.
+ ### These will eventually be obsoleted and removed. */
+struct svn_wc__shim_fetch_baton_t
+{
+ svn_wc__db_t *db;
+ const char *base_abspath;
+ svn_boolean_t fetch_base;
+};
+
+/* Using a BATON of struct shim_fetch_baton, return KIND for PATH. */
+svn_error_t *
+svn_wc__fetch_kind_func(svn_kind_t *kind,
+ void *baton,
+ const char *path,
+ apr_pool_t *scratch_pool);
+
+/* Using a BATON of struct shim_fetch_baton, return PROPS for PATH. */
+svn_error_t *
+svn_wc__fetch_props_func(apr_hash_t **props,
+ void *baton,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
+/* Using a BATON of struct shim_fetch_baton, return a delta base for PATH. */
+svn_error_t *
+svn_wc__fetch_base_func(const char **filename,
+ void *baton,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c?rev=1220893&r1=1220892&r2=1220893&view=diff
==============================================================================
--- subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/fs-py/subversion/libsvn_wc/wc_db.c Mon Dec 19 18:49:34 2011
@@ -842,6 +842,15 @@ insert_base_node(void *baton,
moved_to_relpath /* 21 */));
if (pibb->kind == svn_kind_file)
{
+ if (!pibb->checksum
+ && pibb->status != svn_wc__db_status_not_present
+ && pibb->status != svn_wc__db_status_excluded
+ && pibb->status != svn_wc__db_status_server_excluded)
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, svn_sqlite__reset(stmt),
+ _("The file '%s' has no checksum."),
+ path_for_error_message(wcroot, local_relpath,
+ scratch_pool));
+
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, pibb->checksum,
scratch_pool));
@@ -3059,6 +3068,64 @@ svn_wc__db_external_read(svn_wc__db_stat
}
svn_error_t *
+svn_wc__db_committable_externals_below(apr_array_header_t **externals,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_boolean_t immediates_only,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ svn_sqlite__stmt_t *stmt;
+ const char *local_relpath;
+ svn_boolean_t have_row;
+ svn_wc__committable_external_info_t *info;
+ svn_kind_t db_kind;
+ apr_array_header_t *result = NULL;
+
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ 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(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_SELECT_COMMITTABLE_EXTERNALS_BELOW));
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "isi", wcroot->wc_id, local_relpath,
+ (apr_int64_t)(immediates_only ? 1 : 0)));
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ result = apr_array_make(result_pool, 0,
+ sizeof(svn_wc__committable_external_info_t *));
+
+ while (have_row)
+ {
+ info = apr_palloc(result_pool, sizeof(*info));
+
+ local_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+ info->local_abspath = svn_dirent_join(wcroot->abspath, local_relpath,
+ result_pool);
+
+ db_kind = svn_sqlite__column_token(stmt, 1, kind_map);
+ SVN_ERR_ASSERT(db_kind == svn_kind_file || db_kind == svn_kind_dir);
+ info->kind = db_kind;
+
+ info->repos_relpath = svn_sqlite__column_text(stmt, 3, result_pool);
+ info->repos_root_url = svn_sqlite__column_text(stmt, 4, result_pool);
+
+ APR_ARRAY_PUSH(result, svn_wc__committable_external_info_t *) = info;
+
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ }
+
+ *externals = result;
+ return svn_error_trace(svn_sqlite__reset(stmt));
+}
+
+svn_error_t *
svn_wc__db_externals_defined_below(apr_hash_t **externals,
svn_wc__db_t *db,
const char *local_abspath,
@@ -3525,6 +3592,9 @@ db_op_copy(svn_wc__db_wcroot_t *src_wcro
src_relpath,
scratch_pool));
default:
+ /* Perhaps we should allow incomplete to incomplete? We can't
+ avoid incomplete working nodes as one step in copying a
+ directory is to add incomplete children. */
return svn_error_createf(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, NULL,
_("Cannot handle status of '%s'"),
path_for_error_message(src_wcroot,
@@ -3711,6 +3781,7 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
apr_int64_t repos_id,
const char *repos_relpath,
svn_revnum_t revision,
+ svn_boolean_t is_move,
apr_pool_t *scratch_pool)
{
const apr_array_header_t *children;
@@ -3828,13 +3899,15 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
SVN_ERR(svn_sqlite__get_statement(&stmt, src_wcroot->sdb,
STMT_INSERT_WORKING_NODE_COPY_FROM_BASE));
+ /* Perhaps we should avoid setting moved_here to 0 and leave it
+ null instead? */
SVN_ERR(svn_sqlite__bindf(stmt, "issisti",
src_wcroot->wc_id, src_relpath,
dst_relpath,
dst_op_depth,
svn_relpath_dirname(dst_relpath, iterpool),
presence_map, dst_presence,
- (apr_int64_t)0));
+ (apr_int64_t)(is_move ? 1 : 0)));
if (src_op_depth > 0)
SVN_ERR(svn_sqlite__bind_int64(stmt, 8, src_op_depth));
@@ -3895,7 +3968,7 @@ db_op_copy_shadowed_layer(svn_wc__db_wcr
src_wcroot, child_src_relpath, src_op_depth,
dst_wcroot, child_dst_relpath, dst_op_depth,
del_op_depth,
- repos_id, child_repos_relpath, revision,
+ repos_id, child_repos_relpath, revision, is_move,
scratch_pool));
}
@@ -3970,7 +4043,7 @@ op_copy_shadowed_layer_txn(void * baton,
ocb->src_wcroot, ocb->src_relpath, src_op_depth,
ocb->dst_wcroot, ocb->dst_relpath, dst_op_depth,
del_op_depth,
- repos_id, repos_relpath, revision,
+ repos_id, repos_relpath, revision, ocb->is_move,
scratch_pool));
return SVN_NO_ERROR;
@@ -3980,6 +4053,7 @@ svn_error_t *
svn_wc__db_op_copy_shadowed_layer(svn_wc__db_t *db,
const char *src_abspath,
const char *dst_abspath,
+ svn_boolean_t is_move,
apr_pool_t *scratch_pool)
{
struct op_copy_baton ocb = {0};
@@ -3999,6 +4073,7 @@ svn_wc__db_op_copy_shadowed_layer(svn_wc
scratch_pool, scratch_pool));
VERIFY_USABLE_WCROOT(ocb.dst_wcroot);
+ ocb.is_move = is_move;
ocb.work_items = NULL;
/* Call with the sdb in src_wcroot. It might call itself again to
@@ -4178,6 +4253,7 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
const char *original_uuid,
svn_revnum_t original_revision,
const apr_array_header_t *children,
+ svn_boolean_t is_move,
svn_depth_t depth,
const svn_skel_t *conflict,
const svn_skel_t *work_items,
@@ -4209,7 +4285,7 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
iwb.changed_rev = changed_rev;
iwb.changed_date = changed_date;
iwb.changed_author = changed_author;
- iwb.moved_here = FALSE;
+ iwb.moved_here = is_move;
if (original_root_url != NULL)
{
@@ -6222,10 +6298,10 @@ struct op_delete_baton_t {
};
static svn_error_t *
-op_delete_txn(void *baton,
- svn_wc__db_wcroot_t *wcroot,
- const char *local_relpath,
- apr_pool_t *scratch_pool)
+delete_node(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
{
struct op_delete_baton_t *b = baton;
svn_wc__db_status_t status;
@@ -6236,8 +6312,6 @@ op_delete_txn(void *baton,
svn_boolean_t refetch_depth = FALSE;
svn_kind_t kind;
- SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
-
SVN_ERR(read_info(&status,
&kind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -6403,6 +6477,33 @@ op_delete_txn(void *baton,
}
select_depth = relpath_depth(local_relpath);
+
+ /* When deleting a moved-here op-root, clear moved-to data at the
+ * pre-move location, transforming the move into a normal delete.
+ * This way, deleting the copied half of a move has the same effect
+ * as reverting it. */
+ if (status == svn_wc__db_status_added ||
+ status == svn_wc__db_status_moved_here)
+ {
+ const char *moved_from_relpath;
+ const char *moved_from_op_root_relpath;
+
+ SVN_ERR(scan_addition(&status, NULL, NULL, NULL, NULL, NULL, NULL,
+ &moved_from_relpath,
+ &moved_from_op_root_relpath,
+ wcroot, local_relpath,
+ scratch_pool, scratch_pool));
+ if (status == svn_wc__db_status_moved_here &&
+ moved_from_relpath && moved_from_op_root_relpath &&
+ strcmp(moved_from_relpath, moved_from_op_root_relpath) == 0)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+ STMT_CLEAR_MOVED_TO_RELPATH));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id,
+ moved_from_op_root_relpath));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+ }
}
else
{
@@ -6472,6 +6573,51 @@ op_delete_txn(void *baton,
return SVN_NO_ERROR;
}
+static svn_error_t *
+op_delete_txn(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+
+ SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
+ SVN_ERR(delete_node(baton, wcroot, local_relpath, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+
+struct op_delete_many_baton_t {
+ apr_array_header_t *rel_targets;
+} op_delete_many_baton_t;
+
+static svn_error_t *
+op_delete_many_txn(void *baton,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *local_relpath,
+ apr_pool_t *scratch_pool)
+{
+ struct op_delete_many_baton_t *odmb = baton;
+ int i;
+ apr_pool_t *iterpool;
+
+ SVN_ERR(svn_sqlite__exec_statements(wcroot->sdb, STMT_CREATE_DELETE_LIST));
+ iterpool = svn_pool_create(scratch_pool);
+ for (i = 0; i < odmb->rel_targets->nelts; i++)
+ {
+ const char *target_relpath = APR_ARRAY_IDX(odmb->rel_targets, i,
+ const char *);
+ struct op_delete_baton_t odb;
+
+ svn_pool_clear(iterpool);
+ odb.delete_depth = relpath_depth(target_relpath);
+ odb.moved_to_relpath = NULL;
+ SVN_ERR(delete_node(&odb, wcroot, target_relpath, iterpool));
+ }
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
do_delete_notify(void *baton,
@@ -6498,9 +6644,6 @@ do_delete_notify(void *baton,
svn_pool_clear(iterpool);
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
notify_relpath = svn_sqlite__column_text(stmt, 0, NULL);
notify_abspath = svn_dirent_join(wcroot->abspath,
notify_relpath,
@@ -6516,7 +6659,15 @@ do_delete_notify(void *baton,
}
svn_pool_destroy(iterpool);
- return svn_error_trace(svn_sqlite__reset(stmt));
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ /* We only allow cancellation after notification for all deleted nodes
+ * has happened. The nodes are already deleted so we should notify for
+ * all of them. */
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ return SVN_NO_ERROR;
}
@@ -6582,6 +6733,67 @@ svn_wc__db_op_delete(svn_wc__db_t *db,
}
+svn_error_t *
+svn_wc__db_op_delete_many(svn_wc__db_t *db,
+ apr_array_header_t *targets,
+ 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;
+ const char *local_relpath;
+ struct op_delete_many_baton_t odmb;
+ int i;
+ apr_pool_t *iterpool;
+
+ odmb.rel_targets = apr_array_make(scratch_pool, targets->nelts,
+ sizeof(const char *));
+ iterpool = svn_pool_create(scratch_pool);
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
+ db,
+ APR_ARRAY_IDX(targets, 0,
+ const char *),
+ scratch_pool, iterpool));
+ VERIFY_USABLE_WCROOT(wcroot);
+ for (i = 0; i < targets->nelts; i++)
+ {
+ const char *local_abspath = APR_ARRAY_IDX(targets, i, const char*);
+ svn_wc__db_wcroot_t *target_wcroot;
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&target_wcroot,
+ &local_relpath, db,
+ APR_ARRAY_IDX(targets, i,
+ const char *),
+ scratch_pool, iterpool));
+ VERIFY_USABLE_WCROOT(target_wcroot);
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+ /* Assert that all targets are within the same working copy. */
+ SVN_ERR_ASSERT(wcroot->wc_id == target_wcroot->wc_id);
+
+ APR_ARRAY_PUSH(odmb.rel_targets, const char *) = local_relpath;
+ SVN_ERR(flush_entries(target_wcroot, local_abspath, svn_depth_infinity,
+ iterpool));
+
+ }
+ svn_pool_destroy(iterpool);
+
+ /* Perform the deletion operation (transactionally), perform any
+ notifications necessary, and then clean out our temporary tables. */
+ return svn_error_trace(with_finalization(wcroot, wcroot->abspath,
+ op_delete_many_txn, &odmb,
+ do_delete_notify, NULL,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ STMT_FINALIZE_DELETE,
+ scratch_pool));
+}
+
+
/* Like svn_wc__db_read_info(), but taking WCROOT+LOCAL_RELPATH instead of
DB+LOCAL_ABSPATH, and outputting repos ids instead of URL+UUID. */
static svn_error_t *
@@ -6728,18 +6940,10 @@ read_info(svn_wc__db_status_t *status,
}
else
{
- svn_error_t *err2;
- err2 = svn_sqlite__column_checksum(checksum, stmt_info, 6,
- result_pool);
- if (err2 != NULL)
- err = svn_error_compose_create(
- err,
- svn_error_createf(
- err->apr_err, err2,
- _("The node '%s' has a corrupt checksum value."),
- path_for_error_message(wcroot, local_relpath,
- scratch_pool)));
+ err = svn_error_compose_create(
+ err, svn_sqlite__column_checksum(checksum, stmt_info, 6,
+ result_pool));
}
}
if (recorded_size)
@@ -6922,6 +7126,12 @@ read_info(svn_wc__db_status_t *status,
if (stmt_act != NULL)
err = svn_error_compose_create(err, svn_sqlite__reset(stmt_act));
+ if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
+ err = svn_error_quick_wrap(err,
+ apr_psprintf(scratch_pool,
+ "Error reading node '%s'",
+ local_relpath));
+
SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt_info)));
return SVN_NO_ERROR;
@@ -7186,9 +7396,7 @@ read_children_info(void *baton,
child_item->info.moved_here = svn_sqlite__column_boolean(stmt, 20);
}
- err = svn_sqlite__step(&have_row, stmt);
- if (err)
- SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
@@ -7242,9 +7450,7 @@ read_children_info(void *baton,
apr_hash_set(conflicts, apr_pstrdup(result_pool, name),
APR_HASH_KEY_STRING, "");
- err = svn_sqlite__step(&have_row, stmt);
- if (err)
- SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
@@ -7479,9 +7685,7 @@ svn_wc__db_read_children_walker_info(apr
apr_hash_set(*nodes, apr_pstrdup(result_pool, name),
APR_HASH_KEY_STRING, child);
- err = svn_sqlite__step(&have_row, stmt);
- if (err)
- SVN_ERR(svn_error_compose_create(err, svn_sqlite__reset(stmt)));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
SVN_ERR(svn_sqlite__reset(stmt));
@@ -8541,6 +8745,7 @@ commit_node(void *baton,
apr_int64_t repos_id;
const char *repos_relpath;
apr_int64_t op_depth;
+ svn_wc__db_status_t old_presence;
/* If we are adding a file or directory, then we need to get
repository information from the parent node since "this node" does
@@ -8603,6 +8808,8 @@ commit_node(void *baton,
if (cb->keep_changelist && have_act)
changelist = svn_sqlite__column_text(stmt_act, 1, scratch_pool);
+ old_presence = svn_sqlite__column_token(stmt_info, 3, presence_map);
+
/* ### other stuff? */
SVN_ERR(svn_sqlite__reset(stmt_info));
@@ -8658,8 +8865,10 @@ commit_node(void *baton,
else
parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
- /* ### other presences? or reserve that for separate functions? */
- new_presence = svn_wc__db_status_normal;
+ /* Preserve any incomplete status */
+ new_presence = (old_presence == svn_wc__db_status_incomplete
+ ? svn_wc__db_status_incomplete
+ : svn_wc__db_status_normal);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
STMT_APPLY_CHANGES_TO_BASE_NODE));
@@ -9639,6 +9848,7 @@ scan_addition_txn(void *baton,
{
SVN_ERR_ASSERT(*sab->status == svn_wc__db_status_added
|| *sab->status == svn_wc__db_status_copied
+ || *sab->status == svn_wc__db_status_incomplete
|| *sab->status == svn_wc__db_status_moved_here);
if (*sab->status == svn_wc__db_status_added)
{
@@ -9892,8 +10102,8 @@ scan_deletion_txn(void *baton,
local_relpath,
scratch_pool));
- /* ### incomplete not handled */
SVN_ERR_ASSERT(work_presence == svn_wc__db_status_normal
+ || work_presence == svn_wc__db_status_incomplete
|| work_presence == svn_wc__db_status_not_present
|| work_presence == svn_wc__db_status_base_deleted);
@@ -9958,9 +10168,6 @@ scan_deletion_txn(void *baton,
else
{
const char *moved_child_relpath;
- svn_wc__db_status_t moved_child_status;
- svn_boolean_t found_child;
- svn_error_t *err;
/* The CURRENT_RELPATH is the op_root of the delete-half of
* the move. LOCAL_RELPATH is a child that was moved along.
@@ -9973,65 +10180,19 @@ scan_deletion_txn(void *baton,
moved_child_relpath,
scratch_pool);
- /* Figure out what happened to the child after it was moved
- * along. Maybe the child was moved-away further, either by
- * itself, or along with some intermediate parent node.
- *
- * If the child was deleted instead of moved-away,
- * the resulting MOVED_TO_RELPATH is NULL. */
- err = read_info(&moved_child_status, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, wcroot,
- moved_to_relpath, scratch_pool, scratch_pool);
- if (err)
- {
- if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
- {
- /* Tolerate missing children. A likely cause is that
- * the moved-to information in BASE is incorrect.
- * Just treat this as a normal deletion. */
- svn_error_clear(err);
- moved_to_relpath = NULL;
- moved_to_op_root_relpath = NULL;
- found_child = FALSE;
- }
- else
- return svn_error_compose_create(err,
- svn_sqlite__reset(stmt));
- }
- else
- found_child = TRUE;
-
- if (found_child &&
- moved_child_status == svn_wc__db_status_deleted)
- {
- err = scan_deletion(NULL, &moved_to_relpath, NULL,
- NULL, wcroot, moved_to_relpath,
- scratch_pool, scratch_pool);
- if (err)
- return svn_error_compose_create(err,
- svn_sqlite__reset(stmt));
- }
if (sd_baton->moved_to_relpath)
*sd_baton->moved_to_relpath = moved_to_relpath ?
apr_pstrdup(sd_baton->result_pool, moved_to_relpath) : NULL;
}
- /* CURRENT_RELPATH is the op_root of the delete-half of the move,
- * so it's the BASE_DEL_RELPATH. */
- if (sd_baton->base_del_relpath)
- *sd_baton->base_del_relpath =
- apr_pstrdup(sd_baton->result_pool, current_relpath);
-
if (sd_baton->moved_to_op_root_relpath)
*sd_baton->moved_to_op_root_relpath = moved_to_op_root_relpath ?
apr_pstrdup(sd_baton->result_pool, moved_to_op_root_relpath)
: NULL;
- /* If all other out parameters are irrelevant, stop scanning.
- * Happens to be only WORK_DEL_RELPATH. */
- if (sd_baton->work_del_relpath == NULL)
+ /* If all other out parameters are irrelevant, stop scanning. */
+ if (sd_baton->work_del_relpath == NULL
+ && sd_baton->base_del_relpath == NULL)
break;
found_moved_to = TRUE;
@@ -11334,7 +11495,7 @@ svn_wc__db_wclock_obtain(svn_wc__db_t *d
svn_wc__db_wclock_t* lock = &APR_ARRAY_IDX(wcroot->owned_locks,
i, svn_wc__db_wclock_t);
- if (svn_relpath__is_ancestor(lock->local_relpath, local_relpath)
+ if (svn_relpath_skip_ancestor(lock->local_relpath, local_relpath)
&& (lock->levels == -1
|| (lock->levels + relpath_depth(lock->local_relpath))
>= depth))
@@ -11399,7 +11560,7 @@ is_wclocked(void *baton,
{
const char *relpath = svn_sqlite__column_text(stmt, 0, NULL);
- if (svn_relpath__is_ancestor(relpath, dir_relpath))
+ if (svn_relpath_skip_ancestor(relpath, dir_relpath))
{
/* Any row here means there can be no locks closer to root
that extend past here. */
@@ -11534,7 +11695,7 @@ wclock_owns_lock(svn_boolean_t *own_lock
svn_wc__db_wclock_t *lock = &APR_ARRAY_IDX(owned_locks, i,
svn_wc__db_wclock_t);
- if (svn_relpath__is_ancestor(lock->local_relpath, local_relpath)
+ if (svn_relpath_skip_ancestor(lock->local_relpath, local_relpath)
&& (lock->levels == -1
|| ((relpath_depth(lock->local_relpath) + lock->levels)
>= lock_level)))
@@ -11590,6 +11751,9 @@ end_directory_update(void *baton,
NULL, NULL, NULL, NULL, NULL, NULL,
wcroot, local_relpath, scratch_pool, scratch_pool));
+ if (base_status == svn_wc__db_status_normal)
+ return SVN_NO_ERROR;
+
SVN_ERR_ASSERT(base_status == svn_wc__db_status_incomplete);
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -12136,8 +12300,8 @@ svn_wc__db_get_not_present_descendants(c
const char *found_relpath = svn_sqlite__column_text(stmt, 0, NULL);
APR_ARRAY_PUSH(paths, const char *)
- = svn_relpath__is_child(local_relpath, found_relpath,
- result_pool);
+ = apr_pstrdup(result_pool, svn_relpath_skip_ancestor(
+ local_relpath, found_relpath));
SVN_ERR(svn_sqlite__step(&have_row, stmt));
}
@@ -12226,8 +12390,8 @@ svn_wc__db_min_max_revisions(svn_revnum_
}
-/* Like svn_wc__db_is_sparse_checkout,
- * but accepts a WCROOT/LOCAL_RELPATH pair. */
+/* Set *IS_SPARSE_CHECKOUT TRUE if LOCAL_RELPATH or any of the nodes
+ * within LOCAL_RELPATH is sparse, FALSE otherwise. */
static svn_error_t *
is_sparse_checkout_internal(svn_boolean_t *is_sparse_checkout,
svn_wc__db_wcroot_t *wcroot,
@@ -12251,28 +12415,6 @@ is_sparse_checkout_internal(svn_boolean_
}
-svn_error_t *
-svn_wc__db_is_sparse_checkout(svn_boolean_t *is_sparse_checkout,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_wcroot_t *wcroot;
- const char *local_relpath;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath,
- db, local_abspath,
- scratch_pool, scratch_pool));
- VERIFY_USABLE_WCROOT(wcroot);
-
- return svn_error_trace(is_sparse_checkout_internal(is_sparse_checkout,
- wcroot, local_relpath,
- scratch_pool));
-}
-
-
/* Like svn_wc__db_has_switched_subtrees(),
* but accepts a WCROOT/LOCAL_RELPATH pair. */
static svn_error_t *