aboutsummaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_wc
diff options
context:
space:
mode:
authorPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
committerPeter Wemm <peter@FreeBSD.org>2015-10-12 08:54:49 +0000
commitdc5d469d6574e9fb03bdd793658bb371315b306a (patch)
tree013c2e6845398e5a9ca4901dcc077769c7520e1d /subversion/libsvn_wc
parent58218291fa73a17020ef0447398e9e8a78f9e8c7 (diff)
downloadsrc-dc5d469d6574e9fb03bdd793658bb371315b306a.tar.gz
src-dc5d469d6574e9fb03bdd793658bb371315b306a.zip
Vendor import of subversion-1.9.2vendor/subversion/subversion-1.9.2
Notes
Notes: svn path=/vendor/subversion/dist/; revision=289177 svn path=/vendor/subversion/subversion-1.9.2/; revision=289178; tag=vendor/subversion/subversion-1.9.2
Diffstat (limited to 'subversion/libsvn_wc')
-rw-r--r--subversion/libsvn_wc/adm_crawler.c68
-rw-r--r--subversion/libsvn_wc/adm_files.c47
-rw-r--r--subversion/libsvn_wc/adm_files.h24
-rw-r--r--subversion/libsvn_wc/adm_ops.c461
-rw-r--r--subversion/libsvn_wc/cleanup.c82
-rw-r--r--subversion/libsvn_wc/conflicts.c2022
-rw-r--r--subversion/libsvn_wc/conflicts.h3
-rw-r--r--subversion/libsvn_wc/copy.c182
-rw-r--r--subversion/libsvn_wc/crop.c186
-rw-r--r--subversion/libsvn_wc/delete.c6
-rw-r--r--subversion/libsvn_wc/deprecated.c302
-rw-r--r--subversion/libsvn_wc/diff.h4
-rw-r--r--subversion/libsvn_wc/diff_editor.c163
-rw-r--r--subversion/libsvn_wc/diff_local.c160
-rw-r--r--subversion/libsvn_wc/entries.c536
-rw-r--r--subversion/libsvn_wc/externals.c118
-rw-r--r--subversion/libsvn_wc/info.c163
-rw-r--r--subversion/libsvn_wc/libsvn_wc.pc.in12
-rw-r--r--subversion/libsvn_wc/lock.c12
-rw-r--r--subversion/libsvn_wc/merge.c42
-rw-r--r--subversion/libsvn_wc/node.c473
-rw-r--r--subversion/libsvn_wc/old-and-busted.c4
-rw-r--r--subversion/libsvn_wc/props.c281
-rw-r--r--subversion/libsvn_wc/props.h8
-rw-r--r--subversion/libsvn_wc/questions.c195
-rw-r--r--subversion/libsvn_wc/relocate.c2
-rw-r--r--subversion/libsvn_wc/revert.c385
-rw-r--r--subversion/libsvn_wc/revision_status.c8
-rw-r--r--subversion/libsvn_wc/status.c476
-rw-r--r--subversion/libsvn_wc/token-map.h11
-rw-r--r--subversion/libsvn_wc/translate.c42
-rw-r--r--subversion/libsvn_wc/tree_conflicts.c37
-rw-r--r--subversion/libsvn_wc/update_editor.c1144
-rw-r--r--subversion/libsvn_wc/upgrade.c323
-rw-r--r--subversion/libsvn_wc/util.c212
-rw-r--r--subversion/libsvn_wc/wc-checks.h177
-rw-r--r--subversion/libsvn_wc/wc-checks.sql214
-rw-r--r--subversion/libsvn_wc/wc-metadata.h2
-rw-r--r--subversion/libsvn_wc/wc-metadata.sql14
-rw-r--r--subversion/libsvn_wc/wc-queries.h1960
-rw-r--r--subversion/libsvn_wc/wc-queries.sql461
-rw-r--r--subversion/libsvn_wc/wc.h84
-rw-r--r--subversion/libsvn_wc/wc_db.c4634
-rw-r--r--subversion/libsvn_wc/wc_db.h446
-rw-r--r--subversion/libsvn_wc/wc_db_pristine.c213
-rw-r--r--subversion/libsvn_wc/wc_db_private.h229
-rw-r--r--subversion/libsvn_wc/wc_db_update_move.c2828
-rw-r--r--subversion/libsvn_wc/wc_db_util.c66
-rw-r--r--subversion/libsvn_wc/wc_db_wcroot.c84
-rw-r--r--subversion/libsvn_wc/workqueue.c93
-rw-r--r--subversion/libsvn_wc/workqueue.h22
51 files changed, 11023 insertions, 8698 deletions
diff --git a/subversion/libsvn_wc/adm_crawler.c b/subversion/libsvn_wc/adm_crawler.c
index e5935a274eab..ebdc75e105f4 100644
--- a/subversion/libsvn_wc/adm_crawler.c
+++ b/subversion/libsvn_wc/adm_crawler.c
@@ -69,6 +69,8 @@ restore_file(svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t use_commit_times,
svn_boolean_t mark_resolved_text_conflict,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_skel_t *work_item;
@@ -86,12 +88,14 @@ restore_file(svn_wc__db_t *db,
/* Run the work item immediately. */
SVN_ERR(svn_wc__wq_run(db, local_abspath,
- NULL, NULL, /* ### nice to have cancel_func/baton */
+ cancel_func, cancel_baton,
scratch_pool));
/* Remove any text conflict */
if (mark_resolved_text_conflict)
- SVN_ERR(svn_wc__mark_resolved_text_conflict(db, local_abspath, scratch_pool));
+ SVN_ERR(svn_wc__mark_resolved_text_conflict(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -102,6 +106,7 @@ svn_wc_restore(svn_wc_context_t *wc_ctx,
svn_boolean_t use_commit_times,
apr_pool_t *scratch_pool)
{
+ /* ### If ever revved: Add cancel func. */
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_node_kind_t disk_kind;
@@ -138,6 +143,7 @@ svn_wc_restore(svn_wc_context_t *wc_ctx,
if (kind == svn_node_file || kind == svn_node_symlink)
SVN_ERR(restore_file(wc_ctx->db, local_abspath, use_commit_times,
FALSE /*mark_resolved_text_conflict*/,
+ NULL, NULL /* cancel func, baton */,
scratch_pool));
else
SVN_ERR(svn_io_dir_make(local_abspath, APR_OS_DEFAULT, scratch_pool));
@@ -145,7 +151,7 @@ svn_wc_restore(svn_wc_context_t *wc_ctx,
return SVN_NO_ERROR;
}
-/* Try to restore LOCAL_ABSPATH of node type KIND and if successfull,
+/* Try to restore LOCAL_ABSPATH of node type KIND and if successful,
notify that the node is restored. Use DB for accessing the working copy.
If USE_COMMIT_TIMES is set, then set working file's timestamp to
last-commit-time.
@@ -156,7 +162,10 @@ static svn_error_t *
restore_node(svn_wc__db_t *db,
const char *local_abspath,
svn_node_kind_t kind,
+ svn_boolean_t mark_resolved_text_conflict,
svn_boolean_t use_commit_times,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
@@ -165,7 +174,8 @@ restore_node(svn_wc__db_t *db,
{
/* Recreate file from text-base; mark any text conflict as resolved */
SVN_ERR(restore_file(db, local_abspath, use_commit_times,
- TRUE /*mark_resolved_text_conflict*/,
+ mark_resolved_text_conflict,
+ cancel_func, cancel_baton,
scratch_pool));
}
else if (kind == svn_node_dir)
@@ -293,11 +303,11 @@ report_revisions_and_depths(svn_wc__db_t *db,
hi != NULL;
hi = apr_hash_next(hi))
{
- const char *child = svn__apr_hash_index_key(hi);
+ const char *child = apr_hash_this_key(hi);
const char *this_report_relpath;
const char *this_abspath;
svn_boolean_t this_switched = FALSE;
- struct svn_wc__db_base_info_t *ths = svn__apr_hash_index_val(hi);
+ struct svn_wc__db_base_info_t *ths = apr_hash_this_val(hi);
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
@@ -375,12 +385,13 @@ report_revisions_and_depths(svn_wc__db_t *db,
svn_wc__db_status_t wrk_status;
svn_node_kind_t wrk_kind;
const svn_checksum_t *checksum;
+ svn_boolean_t conflicted;
SVN_ERR(svn_wc__db_read_info(&wrk_status, &wrk_kind, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
&checksum, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, &conflicted,
NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
db, this_abspath, iterpool, iterpool));
if ((wrk_status == svn_wc__db_status_normal
@@ -399,8 +410,9 @@ report_revisions_and_depths(svn_wc__db_t *db,
if (dirent_kind == svn_node_none)
{
SVN_ERR(restore_node(db, this_abspath, wrk_kind,
- use_commit_times, notify_func,
- notify_baton, iterpool));
+ conflicted, use_commit_times,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton, iterpool));
}
}
}
@@ -708,12 +720,13 @@ svn_wc_crawl_revisions5(svn_wc_context_t *wc_ctx,
svn_wc__db_status_t wrk_status;
svn_node_kind_t wrk_kind;
const svn_checksum_t *checksum;
+ svn_boolean_t conflicted;
err = svn_wc__db_read_info(&wrk_status, &wrk_kind, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, &checksum, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL,
+ NULL, &conflicted, NULL, NULL, NULL, NULL,
+ NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool);
@@ -733,7 +746,8 @@ svn_wc_crawl_revisions5(svn_wc_context_t *wc_ctx,
&& (wrk_kind == svn_node_dir || checksum))
{
SVN_ERR(restore_node(wc_ctx->db, local_abspath,
- wrk_kind, use_commit_times,
+ wrk_kind, conflicted, use_commit_times,
+ cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
}
@@ -877,7 +891,7 @@ read_handler_copy(void *baton, char *buffer, apr_size_t *len)
{
struct copying_stream_baton *btn = baton;
- SVN_ERR(svn_stream_read(btn->source, buffer, len));
+ SVN_ERR(svn_stream_read_full(btn->source, buffer, len));
return svn_stream_write(btn->target, buffer, len);
}
@@ -910,7 +924,8 @@ copying_stream(svn_stream_t *source,
baton->target = target;
stream = svn_stream_create(baton, pool);
- svn_stream_set_read(stream, read_handler_copy);
+ svn_stream_set_read2(stream, NULL /* only full read support */,
+ read_handler_copy);
svn_stream_set_close(stream, close_handler_copy);
return stream;
@@ -999,8 +1014,9 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile,
svn_checksum_t *verify_checksum; /* calc'd MD5 of BASE_STREAM */
svn_checksum_t *local_md5_checksum; /* calc'd MD5 of LOCAL_STREAM */
svn_checksum_t *local_sha1_checksum; /* calc'd SHA1 of LOCAL_STREAM */
- const char *new_pristine_tmp_abspath;
+ svn_wc__db_install_data_t *install_data = NULL;
svn_error_t *err;
+ svn_error_t *err2;
svn_stream_t *base_stream; /* delta source */
svn_stream_t *local_stream; /* delta target: LOCAL_ABSPATH transl. to NF */
@@ -1037,11 +1053,11 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile,
{
svn_stream_t *new_pristine_stream;
- SVN_ERR(svn_wc__open_writable_base(&new_pristine_stream,
- &new_pristine_tmp_abspath,
- NULL, &local_sha1_checksum,
- db, local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_pristine_prepare_install(&new_pristine_stream,
+ &install_data,
+ &local_sha1_checksum, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
local_stream = copying_stream(local_stream, new_pristine_stream,
scratch_pool);
}
@@ -1097,7 +1113,15 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile,
scratch_pool, scratch_pool);
/* Close the two streams to force writing the digest */
- err = svn_error_compose_create(err, svn_stream_close(base_stream));
+ err2 = svn_stream_close(base_stream);
+ if (err2)
+ {
+ /* Set verify_checksum to NULL if svn_stream_close() returns error
+ because checksum will be uninitialized in this case. */
+ verify_checksum = NULL;
+ err = svn_error_compose_create(err, err2);
+ }
+
err = svn_error_compose_create(err, svn_stream_close(local_stream));
/* If we have an error, it may be caused by a corrupt text base,
@@ -1145,7 +1169,7 @@ svn_wc__internal_transmit_text_deltas(const char **tempfile,
result_pool);
if (new_text_base_sha1_checksum)
{
- SVN_ERR(svn_wc__db_pristine_install(db, new_pristine_tmp_abspath,
+ SVN_ERR(svn_wc__db_pristine_install(install_data,
local_sha1_checksum,
local_md5_checksum,
scratch_pool));
diff --git a/subversion/libsvn_wc/adm_files.c b/subversion/libsvn_wc/adm_files.c
index 11ad277d92d3..67a1357d4c9a 100644
--- a/subversion/libsvn_wc/adm_files.c
+++ b/subversion/libsvn_wc/adm_files.c
@@ -117,7 +117,7 @@ svn_wc__adm_child(const char *path,
path,
adm_dir_name,
child,
- NULL);
+ SVN_VA_NULL);
}
@@ -295,38 +295,6 @@ svn_wc__open_adm_stream(svn_stream_t **stream,
}
-svn_error_t *
-svn_wc__open_writable_base(svn_stream_t **stream,
- const char **temp_base_abspath,
- svn_checksum_t **md5_checksum,
- svn_checksum_t **sha1_checksum,
- svn_wc__db_t *db,
- const char *wri_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const char *temp_dir_abspath;
- SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
-
- SVN_ERR(svn_wc__db_pristine_get_tempdir(&temp_dir_abspath, db, wri_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_stream_open_unique(stream,
- temp_base_abspath,
- temp_dir_abspath,
- svn_io_file_del_none,
- result_pool, scratch_pool));
- if (md5_checksum)
- *stream = svn_stream_checksummed2(*stream, NULL, md5_checksum,
- svn_checksum_md5, FALSE, result_pool);
- if (sha1_checksum)
- *stream = svn_stream_checksummed2(*stream, NULL, sha1_checksum,
- svn_checksum_sha1, FALSE, result_pool);
-
- return SVN_NO_ERROR;
-}
-
-
-
/*** Checking for and creating administrative subdirs. ***/
@@ -464,11 +432,14 @@ svn_wc__internal_ensure_adm(svn_wc__db_t *db,
db, local_abspath,
scratch_pool, scratch_pool));
else
- SVN_ERR(svn_wc__db_scan_base_repos(&db_repos_relpath,
- &db_repos_root_url,
- &db_repos_uuid,
- db, local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL,
+ &db_repos_relpath,
+ &db_repos_root_url,
+ &db_repos_uuid, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
}
/* The caller gives us a URL which should match the entry. However,
diff --git a/subversion/libsvn_wc/adm_files.h b/subversion/libsvn_wc/adm_files.h
index 37121499b2a1..8c94f74f22d5 100644
--- a/subversion/libsvn_wc/adm_files.h
+++ b/subversion/libsvn_wc/adm_files.h
@@ -112,30 +112,6 @@ svn_error_t *svn_wc__open_adm_stream(svn_stream_t **stream,
apr_pool_t *scratch_pool);
-/* Open a writable stream to a temporary (normal or revert) text base,
- associated with the versioned file LOCAL_ABSPATH in DB. Set *STREAM to
- the opened stream and *TEMP_BASE_ABSPATH to the path to the temporary
- file. The temporary file will have an arbitrary unique name, in contrast
- to the deterministic name that svn_wc__text_base_deterministic_tmp_path()
- returns.
-
- Arrange that, on stream closure, *MD5_CHECKSUM and *SHA1_CHECKSUM will be
- set to the MD-5 and SHA-1 checksums respectively of that file.
- MD5_CHECKSUM and/or SHA1_CHECKSUM may be NULL if not wanted.
-
- Allocate the new stream, path and checksums in RESULT_POOL.
- */
-svn_error_t *
-svn_wc__open_writable_base(svn_stream_t **stream,
- const char **temp_base_abspath,
- svn_checksum_t **md5_checksum,
- svn_checksum_t **sha1_checksum,
- svn_wc__db_t *db,
- const char *wri_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
-
/* Blow away the admistrative directory associated with DIR_ABSPATH.
For single-db this doesn't perform actual work unless the wcroot is passed.
*/
diff --git a/subversion/libsvn_wc/adm_ops.c b/subversion/libsvn_wc/adm_ops.c
index a0f806140937..3ccd2e7afc15 100644
--- a/subversion/libsvn_wc/adm_ops.c
+++ b/subversion/libsvn_wc/adm_ops.c
@@ -36,6 +36,7 @@
#include <apr_time.h>
#include <apr_errno.h>
+#include "svn_private_config.h"
#include "svn_types.h"
#include "svn_pools.h"
#include "svn_string.h"
@@ -53,32 +54,32 @@
#include "conflicts.h"
#include "workqueue.h"
-#include "svn_private_config.h"
-#include "private/svn_subr_private.h"
#include "private/svn_dep_compat.h"
+#include "private/svn_sorts_private.h"
+#include "private/svn_subr_private.h"
struct svn_wc_committed_queue_t
{
/* The pool in which ->queue is allocated. */
apr_pool_t *pool;
- /* Mapping (const char *) local_abspath to (committed_queue_item_t *). */
- apr_hash_t *queue;
- /* Is any item in the queue marked as 'recursive'? */
- svn_boolean_t have_recursive;
+ /* Mapping (const char *) wcroot_abspath to svn_wc__db_commit_queue_t * */
+ apr_hash_t *wc_queues;
};
typedef struct committed_queue_item_t
{
const char *local_abspath;
- svn_boolean_t recurse;
- svn_boolean_t no_unlock;
- svn_boolean_t keep_changelist;
+ svn_boolean_t recurse; /* Use legacy recursion */
+ svn_boolean_t committed; /* Process the node as committed */
+ svn_boolean_t remove_lock; /* Remove existing lock on node */
+ svn_boolean_t remove_changelist; /* Remove changelist on node */
- /* The pristine text checksum. */
- const svn_checksum_t *sha1_checksum;
+ /* The pristine text checksum. NULL if the old value should be kept
+ and for directories */
+ const svn_checksum_t *new_sha1_checksum;
- apr_hash_t *new_dav_cache;
+ apr_hash_t *new_dav_cache; /* New DAV cache for the node */
} committed_queue_item_t;
@@ -88,245 +89,6 @@ svn_wc__get_committed_queue_pool(const struct svn_wc_committed_queue_t *queue)
return queue->pool;
}
-
-
-/*** Finishing updates and commits. ***/
-
-/* Queue work items that will finish a commit of the file or directory
- * LOCAL_ABSPATH in DB:
- * - queue the removal of any "revert-base" props and text files;
- * - queue an update of the DB entry for this node
- *
- * ### The Pristine Store equivalent should be:
- * - remember the old BASE_NODE and WORKING_NODE pristine text c'sums;
- * - queue an update of the DB entry for this node (incl. updating the
- * BASE_NODE c'sum and setting the WORKING_NODE c'sum to NULL);
- * - queue deletion of the old pristine texts by the remembered checksums.
- *
- * CHECKSUM is the checksum of the new text base for LOCAL_ABSPATH, and must
- * be provided if there is one, else NULL.
- *
- * STATUS, KIND, PROP_MODS and OLD_CHECKSUM are the current in-db values of
- * the node LOCAL_ABSPATH.
- */
-static svn_error_t *
-process_committed_leaf(svn_wc__db_t *db,
- const char *local_abspath,
- svn_boolean_t via_recurse,
- svn_wc__db_status_t status,
- svn_node_kind_t kind,
- svn_boolean_t prop_mods,
- const svn_checksum_t *old_checksum,
- svn_revnum_t new_revnum,
- apr_time_t new_changed_date,
- const char *new_changed_author,
- apr_hash_t *new_dav_cache,
- svn_boolean_t no_unlock,
- svn_boolean_t keep_changelist,
- const svn_checksum_t *checksum,
- apr_pool_t *scratch_pool)
-{
- svn_revnum_t new_changed_rev = new_revnum;
- svn_skel_t *work_item = NULL;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- {
- const char *adm_abspath;
-
- if (kind == svn_node_dir)
- adm_abspath = local_abspath;
- else
- adm_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
- SVN_ERR(svn_wc__write_check(db, adm_abspath, scratch_pool));
- }
-
- if (status == svn_wc__db_status_deleted)
- {
- return svn_error_trace(
- svn_wc__db_base_remove(
- db, local_abspath,
- FALSE /* keep_as_working */,
- FALSE /* queue_deletes */,
- TRUE /* remove_locks */,
- (! via_recurse)
- ? new_revnum : SVN_INVALID_REVNUM,
- NULL, NULL,
- scratch_pool));
- }
- else if (status == svn_wc__db_status_not_present)
- {
- /* We are committing the leaf of a copy operation.
- We leave the not-present marker to allow pulling in excluded
- children of a copy.
-
- The next update will remove the not-present marker. */
-
- return SVN_NO_ERROR;
- }
-
- SVN_ERR_ASSERT(status == svn_wc__db_status_normal
- || status == svn_wc__db_status_incomplete
- || status == svn_wc__db_status_added);
-
- if (kind != svn_node_dir)
- {
- /* If we sent a delta (meaning: post-copy modification),
- then this file will appear in the queue and so we should have
- its checksum already. */
- if (checksum == NULL)
- {
- /* It was copied and not modified. We must have a text
- base for it. And the node should have a checksum. */
- SVN_ERR_ASSERT(old_checksum != NULL);
-
- checksum = old_checksum;
-
- /* Is the node completely unmodified and are we recursing? */
- if (via_recurse && !prop_mods)
- {
- /* If a copied node itself is not modified, but the op_root of
- the copy is committed we have to make sure that changed_rev,
- changed_date and changed_author don't change or the working
- copy used for committing will show different last modified
- information then a clean checkout of exactly the same
- revisions. (Issue #3676) */
-
- SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL,
- NULL, &new_changed_rev,
- &new_changed_date,
- &new_changed_author, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
- }
- }
-
- SVN_ERR(svn_wc__wq_build_file_commit(&work_item,
- db, local_abspath,
- prop_mods,
- scratch_pool, scratch_pool));
- }
-
- /* The new text base will be found in the pristine store by its checksum. */
- SVN_ERR(svn_wc__db_global_commit(db, local_abspath,
- new_revnum, new_changed_rev,
- new_changed_date, new_changed_author,
- checksum,
- NULL /* new_children */,
- new_dav_cache,
- keep_changelist,
- no_unlock,
- work_item,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
-svn_wc__process_committed_internal(svn_wc__db_t *db,
- const char *local_abspath,
- svn_boolean_t recurse,
- svn_boolean_t top_of_recurse,
- svn_revnum_t new_revnum,
- apr_time_t new_date,
- const char *rev_author,
- apr_hash_t *new_dav_cache,
- svn_boolean_t no_unlock,
- svn_boolean_t keep_changelist,
- const svn_checksum_t *sha1_checksum,
- const svn_wc_committed_queue_t *queue,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_status_t status;
- svn_node_kind_t kind;
- const svn_checksum_t *old_checksum;
- svn_boolean_t prop_mods;
-
- SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, &old_checksum, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, &prop_mods, NULL, NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- /* NOTE: be wary of making crazy semantic changes in this function, since
- svn_wc_process_committed4() calls this. */
-
- SVN_ERR(process_committed_leaf(db, local_abspath, !top_of_recurse,
- status, kind, prop_mods, old_checksum,
- new_revnum, new_date, rev_author,
- new_dav_cache,
- no_unlock, keep_changelist,
- sha1_checksum,
- scratch_pool));
-
- /* Only check for recursion on nodes that have children */
- if (kind != svn_node_file
- || status == svn_wc__db_status_not_present
- || status == svn_wc__db_status_excluded
- || status == svn_wc__db_status_server_excluded
- /* Node deleted -> then no longer a directory */
- || status == svn_wc__db_status_deleted)
- {
- return SVN_NO_ERROR;
- }
-
- if (recurse)
- {
- const apr_array_header_t *children;
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- int i;
-
- /* Read PATH's entries; this is the absolute path. */
- SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath,
- scratch_pool, iterpool));
-
- /* Recursively loop over all children. */
- for (i = 0; i < children->nelts; i++)
- {
- const char *name = APR_ARRAY_IDX(children, i, const char *);
- const char *this_abspath;
- const committed_queue_item_t *cqi;
-
- svn_pool_clear(iterpool);
-
- this_abspath = svn_dirent_join(local_abspath, name, iterpool);
-
- sha1_checksum = NULL;
- cqi = svn_hash_gets(queue->queue, this_abspath);
-
- if (cqi != NULL)
- sha1_checksum = cqi->sha1_checksum;
-
- /* Recurse. Pass NULL for NEW_DAV_CACHE, because the
- ones present in the current call are only applicable to
- this one committed item. */
- SVN_ERR(svn_wc__process_committed_internal(
- db, this_abspath,
- TRUE /* recurse */,
- FALSE /* top_of_recurse */,
- new_revnum, new_date,
- rev_author,
- NULL /* new_dav_cache */,
- TRUE /* no_unlock */,
- keep_changelist,
- sha1_checksum,
- queue,
- iterpool));
- }
-
- svn_pool_destroy(iterpool);
- }
-
- return SVN_NO_ERROR;
-}
-
-
apr_hash_t *
svn_wc__prop_array_to_hash(const apr_array_header_t *props,
apr_pool_t *result_pool)
@@ -357,76 +119,56 @@ svn_wc_committed_queue_create(apr_pool_t *pool)
q = apr_palloc(pool, sizeof(*q));
q->pool = pool;
- q->queue = apr_hash_make(pool);
- q->have_recursive = FALSE;
+ q->wc_queues = apr_hash_make(pool);
return q;
}
svn_error_t *
-svn_wc_queue_committed3(svn_wc_committed_queue_t *queue,
+svn_wc_queue_committed4(svn_wc_committed_queue_t *queue,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t recurse,
+ svn_boolean_t is_committed,
const apr_array_header_t *wcprop_changes,
svn_boolean_t remove_lock,
svn_boolean_t remove_changelist,
const svn_checksum_t *sha1_checksum,
apr_pool_t *scratch_pool)
{
- committed_queue_item_t *cqi;
+ const char *wcroot_abspath;
+ svn_wc__db_commit_queue_t *db_queue;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- queue->have_recursive |= recurse;
-
/* Use the same pool as the one QUEUE was allocated in,
to prevent lifetime issues. Intermediate operations
should use SCRATCH_POOL. */
- /* Add to the array with paths and options */
- cqi = apr_palloc(queue->pool, sizeof(*cqi));
- cqi->local_abspath = local_abspath;
- cqi->recurse = recurse;
- cqi->no_unlock = !remove_lock;
- cqi->keep_changelist = !remove_changelist;
- cqi->sha1_checksum = sha1_checksum;
- cqi->new_dav_cache = svn_wc__prop_array_to_hash(wcprop_changes, queue->pool);
-
- svn_hash_sets(queue->queue, local_abspath, cqi);
-
- return SVN_NO_ERROR;
-}
-
+ SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
-/* Return TRUE if any item of QUEUE is a parent of ITEM and will be
- processed recursively, return FALSE otherwise.
-
- The algorithmic complexity of this search implementation is O(queue
- length), but it's quite quick.
-*/
-static svn_boolean_t
-have_recursive_parent(apr_hash_t *queue,
- const committed_queue_item_t *item,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
- const char *local_abspath = item->local_abspath;
-
- for (hi = apr_hash_first(scratch_pool, queue); hi; hi = apr_hash_next(hi))
+ db_queue = svn_hash_gets(queue->wc_queues, wcroot_abspath);
+ if (! db_queue)
{
- const committed_queue_item_t *qi = svn__apr_hash_index_val(hi);
+ wcroot_abspath = apr_pstrdup(queue->pool, wcroot_abspath);
- if (qi == item)
- continue;
+ SVN_ERR(svn_wc__db_create_commit_queue(&db_queue,
+ wc_ctx->db, wcroot_abspath,
+ queue->pool, scratch_pool));
- if (qi->recurse && svn_dirent_is_child(qi->local_abspath, local_abspath,
- NULL))
- return TRUE;
+ svn_hash_sets(queue->wc_queues, wcroot_abspath, db_queue);
}
- return FALSE;
+ return svn_error_trace(
+ svn_wc__db_commit_queue_add(db_queue, local_abspath, recurse,
+ is_committed, remove_lock,
+ remove_changelist, sha1_checksum,
+ svn_wc__prop_array_to_hash(wcprop_changes,
+ queue->pool),
+ queue->pool, scratch_pool));
}
@@ -440,75 +182,44 @@ svn_wc_process_committed_queue2(svn_wc_committed_queue_t *queue,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- apr_array_header_t *sorted_queue;
+ apr_array_header_t *wcs;
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
apr_time_t new_date;
- apr_hash_t *run_wqs = apr_hash_make(scratch_pool);
- apr_hash_index_t *hi;
if (rev_date)
SVN_ERR(svn_time_from_cstring(&new_date, rev_date, iterpool));
else
new_date = 0;
- /* Process the queued items in order of their paths. (The requirement is
- * probably just that a directory must be processed before its children.) */
- sorted_queue = svn_sort__hash(queue->queue, svn_sort_compare_items_as_paths,
- scratch_pool);
- for (i = 0; i < sorted_queue->nelts; i++)
+ /* Process the wc's in order of their paths. */
+ wcs = svn_sort__hash(queue->wc_queues, svn_sort_compare_items_as_paths,
+ scratch_pool);
+ for (i = 0; i < wcs->nelts; i++)
{
const svn_sort__item_t *sort_item
- = &APR_ARRAY_IDX(sorted_queue, i, svn_sort__item_t);
- const committed_queue_item_t *cqi = sort_item->value;
- const char *wcroot_abspath;
+ = &APR_ARRAY_IDX(wcs, i, svn_sort__item_t);
+ svn_wc__db_commit_queue_t *db_queue = sort_item->value;
svn_pool_clear(iterpool);
- /* Skip this item if it is a child of a recursive item, because it has
- been (or will be) accounted for when that recursive item was (or
- will be) processed. */
- if (queue->have_recursive && have_recursive_parent(queue->queue, cqi,
- iterpool))
- continue;
-
- SVN_ERR(svn_wc__process_committed_internal(
- wc_ctx->db, cqi->local_abspath,
- cqi->recurse,
- TRUE /* top_of_recurse */,
- new_revnum, new_date, rev_author,
- cqi->new_dav_cache,
- cqi->no_unlock,
- cqi->keep_changelist,
- cqi->sha1_checksum, queue,
- iterpool));
-
- /* Don't run the wq now, but remember that we must call it for this
- working copy */
- SVN_ERR(svn_wc__db_get_wcroot(&wcroot_abspath,
- wc_ctx->db, cqi->local_abspath,
- iterpool, iterpool));
-
- if (! svn_hash_gets(run_wqs, wcroot_abspath))
- {
- wcroot_abspath = apr_pstrdup(scratch_pool, wcroot_abspath);
- svn_hash_sets(run_wqs, wcroot_abspath, wcroot_abspath);
- }
+ SVN_ERR(svn_wc__db_process_commit_queue(wc_ctx->db, db_queue,
+ new_revnum, new_date, rev_author,
+ iterpool));
}
/* Make sure nothing happens if this function is called again. */
- apr_hash_clear(queue->queue);
+ apr_hash_clear(queue->wc_queues);
/* Ok; everything is committed now. Now we can start calling callbacks */
-
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- for (hi = apr_hash_first(scratch_pool, run_wqs);
- hi;
- hi = apr_hash_next(hi))
+ for (i = 0; i < wcs->nelts; i++)
{
- const char *wcroot_abspath = svn__apr_hash_index_key(hi);
+ const svn_sort__item_t *sort_item
+ = &APR_ARRAY_IDX(wcs, i, svn_sort__item_t);
+ const char *wcroot_abspath = sort_item->key;
svn_pool_clear(iterpool);
@@ -631,10 +342,12 @@ check_can_add_to_parent(const char **repos_root_url,
db, parent_abspath,
result_pool, scratch_pool));
else
- SVN_ERR(svn_wc__db_scan_base_repos(NULL,
- repos_root_url, repos_uuid,
- db, parent_abspath,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
+ repos_root_url, repos_uuid, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ db, parent_abspath,
+ result_pool, scratch_pool));
}
return SVN_NO_ERROR;
@@ -887,11 +600,13 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
const char *repos_relpath, *inner_repos_root_url, *inner_repos_uuid;
const char *inner_url;
- SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath,
- &inner_repos_root_url,
- &inner_repos_uuid,
- db, local_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, &repos_relpath,
+ &inner_repos_root_url,
+ &inner_repos_uuid, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
if (strcmp(inner_repos_uuid, repos_uuid)
|| strcmp(repos_root_url, inner_repos_root_url))
@@ -993,9 +708,10 @@ svn_wc_add4(svn_wc_context_t *wc_ctx,
svn_error_t *
-svn_wc_add_from_disk2(svn_wc_context_t *wc_ctx,
+svn_wc_add_from_disk3(svn_wc_context_t *wc_ctx,
const char *local_abspath,
const apr_hash_t *props,
+ svn_boolean_t skip_checks,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
apr_pool_t *scratch_pool)
@@ -1014,7 +730,7 @@ svn_wc_add_from_disk2(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_wc__canonicalize_props(
&new_props,
- local_abspath, kind, props, FALSE /* skip_some_checks */,
+ local_abspath, kind, props, skip_checks,
scratch_pool, scratch_pool));
props = new_props;
}
@@ -1177,10 +893,9 @@ svn_wc_add_lock2(svn_wc_context_t *wc_ctx,
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- /* ### Enable after fixing callers */
- /*SVN_ERR(svn_wc__write_check(wc_ctx->db,
+ SVN_ERR(svn_wc__write_check(wc_ctx->db,
svn_dirent_dirname(local_abspath, scratch_pool),
- scratch_pool));*/
+ scratch_pool));
db_lock.token = lock->token;
db_lock.owner = lock->owner;
@@ -1227,16 +942,20 @@ svn_wc_remove_lock2(svn_wc_context_t *wc_ctx,
apr_pool_t *scratch_pool)
{
svn_error_t *err;
- const svn_string_t *needs_lock;
+ svn_skel_t *work_item;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- /* ### Enable after fixing callers */
- /*SVN_ERR(svn_wc__write_check(wc_ctx->db,
+ SVN_ERR(svn_wc__write_check(wc_ctx->db,
svn_dirent_dirname(local_abspath, scratch_pool),
- scratch_pool));*/
+ scratch_pool));
- err = svn_wc__db_lock_remove(wc_ctx->db, local_abspath, scratch_pool);
+ SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ err = svn_wc__db_lock_remove(wc_ctx->db, local_abspath, work_item,
+ scratch_pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
@@ -1250,24 +969,9 @@ svn_wc_remove_lock2(svn_wc_context_t *wc_ctx,
scratch_pool));
}
- /* if svn:needs-lock is present, then make the file read-only. */
- err = svn_wc__internal_propget(&needs_lock, wc_ctx->db, local_abspath,
- SVN_PROP_NEEDS_LOCK, scratch_pool,
- scratch_pool);
- if (err)
- {
- if (err->apr_err != SVN_ERR_WC_PATH_UNEXPECTED_STATUS)
- return svn_error_trace(err);
-
- svn_error_clear(err);
- return SVN_NO_ERROR; /* Node is shadowed and/or deleted,
- so we shouldn't apply its lock */
- }
-
- if (needs_lock)
- SVN_ERR(svn_io_set_file_read_only(local_abspath, FALSE, scratch_pool));
-
- return SVN_NO_ERROR;
+ return svn_error_trace(svn_wc__wq_run(wc_ctx->db, local_abspath,
+ NULL, NULL /* cancel*/,
+ scratch_pool));
}
@@ -1321,9 +1025,8 @@ get_node_changelist(const char *local_abspath,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
b->db, local_abspath,
scratch_pool, scratch_pool));
-
- if (svn_wc__internal_changelist_match(b->db, local_abspath, b->clhash,
- scratch_pool))
+ if (!b->clhash
+ || (changelist && svn_hash_gets(b->clhash, changelist) != NULL))
SVN_ERR(b->callback_func(b->callback_baton, local_abspath,
changelist, scratch_pool));
diff --git a/subversion/libsvn_wc/cleanup.c b/subversion/libsvn_wc/cleanup.c
index afe73718d0c7..491ca932adc8 100644
--- a/subversion/libsvn_wc/cleanup.c
+++ b/subversion/libsvn_wc/cleanup.c
@@ -81,6 +81,9 @@ status_dummy_callback(void *baton,
static svn_error_t *
cleanup_internal(svn_wc__db_t *db,
const char *dir_abspath,
+ svn_boolean_t break_locks,
+ svn_boolean_t fix_recorded_timestamps,
+ svn_boolean_t vacuum_pristines,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
@@ -98,7 +101,7 @@ cleanup_internal(svn_wc__db_t *db,
scratch_pool, scratch_pool));
if (lock_abspath)
dir_abspath = lock_abspath;
- SVN_ERR(svn_wc__db_wclock_obtain(db, dir_abspath, -1, TRUE, scratch_pool));
+ SVN_ERR(svn_wc__db_wclock_obtain(db, dir_abspath, -1, break_locks, scratch_pool));
/* Run our changes before the subdirectories. We may not have to recurse
if we blow away a subdir. */
@@ -117,7 +120,7 @@ cleanup_internal(svn_wc__db_t *db,
svn_wc__check_wcroot() as that function, will just return true
once we start sharing databases with externals.
*/
- if (is_wcroot)
+ if (is_wcroot && vacuum_pristines)
{
/* Cleanup the tmp area of the admin subdir, if running the log has not
removed it! The logs have been run, so anything left here has no hope
@@ -128,17 +131,20 @@ cleanup_internal(svn_wc__db_t *db,
SVN_ERR(svn_wc__db_pristine_cleanup(db, dir_abspath, scratch_pool));
}
- /* Instead of implementing a separate repair step here, use the standard
- status walker's optimized implementation, which performs repairs when
- there is a lock. */
- SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
- FALSE /* get_all */,
- FALSE /* no_ignore */,
- FALSE /* ignore_text_mods */,
- NULL /* ignore patterns */,
- status_dummy_callback, NULL,
- cancel_func, cancel_baton,
- scratch_pool));
+ if (fix_recorded_timestamps)
+ {
+ /* Instead of implementing a separate repair step here, use the standard
+ status walker's optimized implementation, which performs repairs when
+ there is a lock. */
+ SVN_ERR(svn_wc__internal_walk_status(db, dir_abspath, svn_depth_infinity,
+ FALSE /* get_all */,
+ FALSE /* no_ignore */,
+ FALSE /* ignore_text_mods */,
+ NULL /* ignore patterns */,
+ status_dummy_callback, NULL,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ }
/* All done, toss the lock */
SVN_ERR(svn_wc__db_wclock_release(db, dir_abspath, scratch_pool));
@@ -146,39 +152,59 @@ cleanup_internal(svn_wc__db_t *db,
return SVN_NO_ERROR;
}
-
-/* ### possibly eliminate the WC_CTX parameter? callers really shouldn't
- ### be doing anything *but* running a cleanup, and we need a special
- ### DB anyway. ... *shrug* ... consider later. */
svn_error_t *
-svn_wc_cleanup3(svn_wc_context_t *wc_ctx,
+svn_wc_cleanup4(svn_wc_context_t *wc_ctx,
const char *local_abspath,
+ svn_boolean_t break_locks,
+ svn_boolean_t fix_recorded_timestamps,
+ svn_boolean_t clear_dav_cache,
+ svn_boolean_t vacuum_pristines,
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_t *db;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+ SVN_ERR_ASSERT(wc_ctx != NULL);
- /* We need a DB that allows a non-empty work queue (though it *will*
- auto-upgrade). We'll handle everything manually. */
- SVN_ERR(svn_wc__db_open(&db,
- NULL /* ### config */, FALSE, FALSE,
- scratch_pool, scratch_pool));
+ if (break_locks)
+ {
+ /* We'll handle everything manually. */
- SVN_ERR(cleanup_internal(db, local_abspath, cancel_func, cancel_baton,
+ /* Close the existing database (if any) to avoid problems with
+ exclusive database usage */
+ SVN_ERR(svn_wc__db_drop_root(wc_ctx->db, local_abspath,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__db_open(&db,
+ NULL /* ### config */, FALSE, FALSE,
+ scratch_pool, scratch_pool));
+ }
+ else
+ db = wc_ctx->db;
+
+ SVN_ERR(cleanup_internal(db, local_abspath,
+ break_locks,
+ fix_recorded_timestamps,
+ vacuum_pristines,
+ cancel_func, cancel_baton,
scratch_pool));
/* The DAV cache suffers from flakiness from time to time, and the
pre-1.7 prescribed workarounds aren't as user-friendly in WC-NG. */
- SVN_ERR(svn_wc__db_base_clear_dav_cache_recursive(db, local_abspath,
- scratch_pool));
+ if (clear_dav_cache)
+ SVN_ERR(svn_wc__db_base_clear_dav_cache_recursive(db, local_abspath,
+ scratch_pool));
- SVN_ERR(svn_wc__db_vacuum(db, local_abspath, scratch_pool));
+ if (vacuum_pristines)
+ SVN_ERR(svn_wc__db_vacuum(db, local_abspath, scratch_pool));
/* We're done with this DB, so proactively close it. */
- SVN_ERR(svn_wc__db_close(db));
+ if (break_locks)
+ SVN_ERR(svn_wc__db_close(db));
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_wc/conflicts.c b/subversion/libsvn_wc/conflicts.c
index 8bd54105a500..ae0b348c354c 100644
--- a/subversion/libsvn_wc/conflicts.c
+++ b/subversion/libsvn_wc/conflicts.c
@@ -477,8 +477,7 @@ svn_wc__conflict_skel_add_prop_conflict(svn_skel_t *conflict_skel,
hi;
hi = apr_hash_next(hi))
{
- svn_skel__prepend_str(apr_pstrdup(result_pool,
- svn__apr_hash_index_key(hi)),
+ svn_skel__prepend_str(apr_pstrdup(result_pool, apr_hash_this_key(hi)),
conflict_names,
result_pool);
}
@@ -509,7 +508,7 @@ svn_wc__conflict_skel_add_prop_conflict(svn_skel_t *conflict_skel,
}
/* A map for svn_wc_conflict_reason_t values. */
-static const svn_token_map_t local_change_map[] =
+static const svn_token_map_t reason_map[] =
{
{ "edited", svn_wc_conflict_reason_edited },
{ "obstructed", svn_wc_conflict_reason_obstructed },
@@ -523,7 +522,7 @@ static const svn_token_map_t local_change_map[] =
{ NULL }
};
-static const svn_token_map_t incoming_change_map[] =
+static const svn_token_map_t action_map[] =
{
{ "edited", svn_wc_conflict_action_edit },
{ "added", svn_wc_conflict_action_add },
@@ -536,8 +535,8 @@ svn_error_t *
svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel,
svn_wc__db_t *db,
const char *wri_abspath,
- svn_wc_conflict_reason_t local_change,
- svn_wc_conflict_action_t incoming_change,
+ svn_wc_conflict_reason_t reason,
+ svn_wc_conflict_action_t action,
const char *move_src_op_root_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
@@ -550,12 +549,12 @@ svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel,
SVN_ERR_ASSERT(!tree_conflict); /* ### Use proper error? */
- SVN_ERR_ASSERT(local_change == svn_wc_conflict_reason_moved_away
+ SVN_ERR_ASSERT(reason == svn_wc_conflict_reason_moved_away
|| !move_src_op_root_abspath); /* ### Use proper error? */
tree_conflict = svn_skel__make_empty_list(result_pool);
- if (local_change == svn_wc_conflict_reason_moved_away
+ if (reason == svn_wc_conflict_reason_moved_away
&& move_src_op_root_abspath)
{
const char *move_src_op_root_relpath;
@@ -569,13 +568,11 @@ svn_wc__conflict_skel_add_tree_conflict(svn_skel_t *conflict_skel,
result_pool);
}
- svn_skel__prepend_str(
- svn_token__to_word(incoming_change_map, incoming_change),
- tree_conflict, result_pool);
+ svn_skel__prepend_str(svn_token__to_word(action_map, action),
+ tree_conflict, result_pool);
- svn_skel__prepend_str(
- svn_token__to_word(local_change_map, local_change),
- tree_conflict, result_pool);
+ svn_skel__prepend_str(svn_token__to_word(reason_map, reason),
+ tree_conflict, result_pool);
/* Tree conflicts have no marker files */
markers = svn_skel__make_empty_list(result_pool);
@@ -931,8 +928,8 @@ svn_wc__conflict_read_prop_conflict(const char **marker_abspath,
}
svn_error_t *
-svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change,
- svn_wc_conflict_action_t *incoming_change,
+svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *reason,
+ svn_wc_conflict_action_t *action,
const char **move_src_op_root_abspath,
svn_wc__db_t *db,
const char *wri_abspath,
@@ -957,28 +954,28 @@ svn_wc__conflict_read_tree_conflict(svn_wc_conflict_reason_t *local_change,
c = c->next; /* Skip markers */
{
- int value = svn_token__from_mem(local_change_map, c->data, c->len);
+ int value = svn_token__from_mem(reason_map, c->data, c->len);
- if (local_change)
+ if (reason)
{
if (value != SVN_TOKEN_UNKNOWN)
- *local_change = value;
+ *reason = value;
else
- *local_change = svn_wc_conflict_reason_edited;
+ *reason = svn_wc_conflict_reason_edited;
}
is_moved_away = (value == svn_wc_conflict_reason_moved_away);
}
c = c->next;
- if (incoming_change)
+ if (action)
{
- int value = svn_token__from_mem(incoming_change_map, c->data, c->len);
+ int value = svn_token__from_mem(action_map, c->data, c->len);
if (value != SVN_TOKEN_UNKNOWN)
- *incoming_change = value;
+ *action = value;
else
- *incoming_change = svn_wc_conflict_action_edit;
+ *action = svn_wc_conflict_action_edit;
}
c = c->next;
@@ -1050,69 +1047,8 @@ svn_wc__conflict_read_markers(const apr_array_header_t **markers,
/* --------------------------------------------------------------------
*/
-/* Helper for svn_wc__conflict_create_markers */
-static svn_skel_t *
-prop_conflict_skel_new(apr_pool_t *result_pool)
-{
- svn_skel_t *operation = svn_skel__make_empty_list(result_pool);
- svn_skel_t *result = svn_skel__make_empty_list(result_pool);
-
- svn_skel__prepend(operation, result);
- return result;
-}
-
-
-/* Helper for prop_conflict_skel_add */
-static void
-prepend_prop_value(const svn_string_t *value,
- svn_skel_t *skel,
- apr_pool_t *result_pool)
-{
- svn_skel_t *value_skel = svn_skel__make_empty_list(result_pool);
-
- if (value != NULL)
- {
- const void *dup = apr_pmemdup(result_pool, value->data, value->len);
-
- svn_skel__prepend(svn_skel__mem_atom(dup, value->len, result_pool),
- value_skel);
- }
-
- svn_skel__prepend(value_skel, skel);
-}
-/* Helper for svn_wc__conflict_create_markers */
-static svn_error_t *
-prop_conflict_skel_add(
- svn_skel_t *skel,
- const char *prop_name,
- const svn_string_t *original_value,
- const svn_string_t *mine_value,
- const svn_string_t *incoming_value,
- const svn_string_t *incoming_base_value,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_skel_t *prop_skel = svn_skel__make_empty_list(result_pool);
-
- /* ### check that OPERATION has been filled in. */
-
- /* See notes/wc-ng/conflict-storage */
- prepend_prop_value(incoming_base_value, prop_skel, result_pool);
- prepend_prop_value(incoming_value, prop_skel, result_pool);
- prepend_prop_value(mine_value, prop_skel, result_pool);
- prepend_prop_value(original_value, prop_skel, result_pool);
- svn_skel__prepend_str(apr_pstrdup(result_pool, prop_name), prop_skel,
- result_pool);
- svn_skel__prepend_str(SVN_WC__CONFLICT_KIND_PROP, prop_skel, result_pool);
-
- /* Now we append PROP_SKEL to the end of the provided conflict SKEL. */
- svn_skel__append(skel, prop_skel);
-
- return SVN_NO_ERROR;
-}
-
svn_error_t *
svn_wc__conflict_create_markers(svn_skel_t **work_items,
svn_wc__db_t *db,
@@ -1141,10 +1077,8 @@ svn_wc__conflict_create_markers(svn_skel_t **work_items,
/* Ok, currently we have to do a few things for property conflicts:
- Create a marker file
- - Create a WQ item that sets the marker name
- - Create a WQ item that fills the marker with the expected data
-
- This can be simplified once we really store conflict_skel in wc.db */
+ - Store the name in the conflict_skel
+ - Create a WQ item that fills the marker with the expected data */
SVN_ERR(svn_io_check_path(local_abspath, &kind, scratch_pool));
@@ -1176,65 +1110,9 @@ svn_wc__conflict_create_markers(svn_skel_t **work_items,
svn_skel__prepend_str(marker_relpath, prop_conflict->children->next,
result_pool);
}
-
- /* Store the data in the WQ item in the same format used as 1.7.
- Once we store the data in DB it is easier to just read it back
- from the workqueue */
- {
- svn_skel_t *prop_data;
- apr_hash_index_t *hi;
- apr_hash_t *old_props;
- apr_hash_t *mine_props;
- apr_hash_t *their_original_props;
- apr_hash_t *their_props;
- apr_hash_t *conflicted_props;
-
- SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
- &mine_props,
- &their_original_props,
- &their_props,
- &conflicted_props,
- db, local_abspath,
- conflict_skel,
- scratch_pool,
- scratch_pool));
-
- if (operation == svn_wc_operation_merge)
- SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
- scratch_pool, scratch_pool));
- else
- old_props = their_original_props;
-
- prop_data = prop_conflict_skel_new(result_pool);
-
- for (hi = apr_hash_first(scratch_pool, conflicted_props);
- hi;
- hi = apr_hash_next(hi))
- {
- const char *propname = svn__apr_hash_index_key(hi);
-
- SVN_ERR(prop_conflict_skel_add(
- prop_data, propname,
- old_props
- ? svn_hash_gets(old_props, propname)
- : NULL,
- mine_props
- ? svn_hash_gets(mine_props, propname)
- : NULL,
- their_props
- ? svn_hash_gets(their_props, propname)
- : NULL,
- their_original_props
- ? svn_hash_gets(their_original_props, propname)
- : NULL,
- result_pool, scratch_pool));
- }
-
- SVN_ERR(svn_wc__wq_build_prej_install(work_items,
- db, local_abspath,
- prop_data,
- scratch_pool, scratch_pool));
- }
+ SVN_ERR(svn_wc__wq_build_prej_install(work_items,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
}
return SVN_NO_ERROR;
@@ -1264,6 +1142,7 @@ static svn_error_t *
generate_propconflict(svn_boolean_t *conflict_remains,
svn_wc__db_t *db,
const char *local_abspath,
+ svn_node_kind_t kind,
svn_wc_operation_t operation,
const svn_wc_conflict_version_t *left_version,
const svn_wc_conflict_version_t *right_version,
@@ -1274,29 +1153,18 @@ generate_propconflict(svn_boolean_t *conflict_remains,
const svn_string_t *incoming_new_val,
svn_wc_conflict_resolver_func2_t conflict_func,
void *conflict_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
svn_wc_conflict_result_t *result = NULL;
svn_wc_conflict_description2_t *cdesc;
const char *dirpath = svn_dirent_dirname(local_abspath, scratch_pool);
- svn_node_kind_t kind;
const svn_string_t *new_value = NULL;
- SVN_ERR(svn_wc__db_read_kind(&kind, db, local_abspath,
- FALSE /* allow_missing */,
- FALSE /* show_deleted */,
- FALSE /* show_hidden */,
- scratch_pool));
-
- if (kind == svn_node_none)
- return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
- _("The node '%s' was not found."),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
-
cdesc = svn_wc_conflict_description_create_prop2(
local_abspath,
- (kind == svn_node_dir) ? svn_node_dir : svn_node_file,
+ kind,
propname, scratch_pool);
cdesc->operation = operation;
@@ -1313,6 +1181,7 @@ generate_propconflict(svn_boolean_t *conflict_remains,
svn_io_file_del_on_pool_cleanup,
scratch_pool));
cdesc->my_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+ cdesc->prop_value_working = working_val;
}
if (incoming_new_val)
@@ -1323,7 +1192,11 @@ generate_propconflict(svn_boolean_t *conflict_remains,
incoming_new_val->len,
svn_io_file_del_on_pool_cleanup,
scratch_pool));
- cdesc->their_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ cdesc->merged_file = svn_dirent_join(dirpath, file_name, scratch_pool);
+ cdesc->prop_value_incoming_new = incoming_new_val;
}
if (!base_val && !incoming_old_val)
@@ -1332,7 +1205,6 @@ generate_propconflict(svn_boolean_t *conflict_remains,
base_file stay NULL as-is. Both agents are attempting to add a
new property. */
}
-
else if ((base_val && !incoming_old_val)
|| (!base_val && incoming_old_val))
{
@@ -1354,7 +1226,6 @@ generate_propconflict(svn_boolean_t *conflict_remains,
scratch_pool));
cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
}
-
else /* base and old are both non-NULL */
{
const svn_string_t *conflict_base_val;
@@ -1391,6 +1262,9 @@ generate_propconflict(svn_boolean_t *conflict_remains,
svn_io_file_del_on_pool_cleanup, scratch_pool));
cdesc->base_abspath = svn_dirent_join(dirpath, file_name, scratch_pool);
+ cdesc->prop_value_base = base_val;
+ cdesc->prop_value_incoming_old = incoming_old_val;
+
if (working_val && incoming_new_val)
{
svn_stream_t *mergestream;
@@ -1398,17 +1272,22 @@ generate_propconflict(svn_boolean_t *conflict_remains,
svn_diff_file_options_t *options =
svn_diff_file_options_create(scratch_pool);
- SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->merged_file,
+ SVN_ERR(svn_stream_open_unique(&mergestream, &cdesc->prop_reject_abspath,
NULL, svn_io_file_del_on_pool_cleanup,
scratch_pool, scratch_pool));
SVN_ERR(svn_diff_mem_string_diff3(&diff, conflict_base_val,
working_val,
incoming_new_val, options, scratch_pool));
- SVN_ERR(svn_diff_mem_string_output_merge2
- (mergestream, diff, conflict_base_val, working_val,
+ SVN_ERR(svn_diff_mem_string_output_merge3(mergestream, diff,
+ conflict_base_val, working_val,
incoming_new_val, NULL, NULL, NULL, NULL,
- svn_diff_conflict_display_modified_latest, scratch_pool));
+ svn_diff_conflict_display_modified_latest,
+ cancel_func, cancel_baton, scratch_pool));
SVN_ERR(svn_stream_close(mergestream));
+
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ cdesc->their_abspath = cdesc->prop_reject_abspath;
}
}
@@ -1427,10 +1306,8 @@ generate_propconflict(svn_boolean_t *conflict_remains,
cdesc->reason = svn_wc_conflict_reason_edited;
/* Invoke the interactive conflict callback. */
- {
- SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
- scratch_pool));
- }
+ SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
+ scratch_pool));
if (result == NULL)
{
*conflict_remains = TRUE;
@@ -1476,18 +1353,24 @@ generate_propconflict(svn_boolean_t *conflict_remains,
{
svn_stringbuf_t *merged_stringbuf;
- if (!cdesc->merged_file && !result->merged_file)
+ if (!cdesc->merged_file
+ && (!result->merged_file && !result->merged_value))
return svn_error_create
(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
NULL, _("Conflict callback violated API:"
" returned no merged file"));
- SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
- result->merged_file ?
- result->merged_file :
- cdesc->merged_file,
- scratch_pool));
- new_value = svn_stringbuf__morph_into_string(merged_stringbuf);
+ if (result->merged_value)
+ new_value = result->merged_value;
+ else
+ {
+ SVN_ERR(svn_stringbuf_from_file2(&merged_stringbuf,
+ result->merged_file ?
+ result->merged_file :
+ cdesc->merged_file,
+ scratch_pool));
+ new_value = svn_stringbuf__morph_into_string(merged_stringbuf);
+ }
*conflict_remains = FALSE;
break;
}
@@ -1513,172 +1396,113 @@ generate_propconflict(svn_boolean_t *conflict_remains,
return SVN_NO_ERROR;
}
-/* Resolve the text conflict on DB/LOCAL_ABSPATH in the manner specified
- * by CHOICE.
+/* Perform a 3-way merge in which conflicts are expected, showing the
+ * conflicts in the way specified by STYLE, and using MERGE_OPTIONS.
*
- * Set *WORK_ITEMS to new work items that will make the on-disk changes
- * needed to complete the resolution (but not to mark it as resolved).
- * Set *IS_RESOLVED to true if the conflicts are resolved; otherwise
- * (which is only if CHOICE is 'postpone') to false.
+ * The three input files are LEFT_ABSPATH (the base), DETRANSLATED_TARGET
+ * and RIGHT_ABSPATH. The output is stored in a new temporary file,
+ * whose name is put into *CHOSEN_ABSPATH.
*
- * LEFT_ABSPATH, RIGHT_ABSPATH, and DETRANSLATED_TARGET are the
- * input files to the 3-way merge that will be performed if CHOICE is
- * 'theirs-conflict' or 'mine-conflict'. LEFT_ABSPATH is also the file
- * that will be used if CHOICE is 'base', and RIGHT_ABSPATH if CHOICE is
- * 'theirs-full'. MERGED_ABSPATH will be used if CHOICE is 'merged'.
+ * The output file will be deleted according to DELETE_WHEN. If
+ * DELETE_WHEN is 'on pool cleanup', it refers to RESULT_POOL.
*
- * DETRANSLATED_TARGET is the detranslated version of 'mine' (see
- * detranslate_wc_file() above). MERGE_OPTIONS are passed to the
- * diff3 implementation in case a 3-way merge has to be carried out.
+ * DB and WRI_ABSPATH are used to choose a directory for the output file.
+ *
+ * Allocate *CHOSEN_ABSPATH in RESULT_POOL. Use SCRATCH_POOL for temporary
+ * allocations.
*/
static svn_error_t *
-eval_text_conflict_func_result(svn_skel_t **work_items,
- svn_boolean_t *is_resolved,
+merge_showing_conflicts(const char **chosen_abspath,
+ svn_wc__db_t *db,
+ const char *wri_abspath,
+ svn_diff_conflict_display_style_t style,
+ const apr_array_header_t *merge_options,
+ const char *left_abspath,
+ const char *detranslated_target,
+ const char *right_abspath,
+ svn_io_file_del_t delete_when,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *temp_dir;
+ svn_stream_t *chosen_stream;
+ svn_diff_t *diff;
+ svn_diff_file_options_t *diff3_options;
+
+ diff3_options = svn_diff_file_options_create(scratch_pool);
+ if (merge_options)
+ SVN_ERR(svn_diff_file_options_parse(diff3_options,
+ merge_options,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
+ wri_abspath,
+ scratch_pool, scratch_pool));
+ /* We need to open the stream in RESULT_POOL because that controls the
+ * lifetime of the file if DELETE_WHEN is 'on pool cleanup'. (We also
+ * want to allocate CHOSEN_ABSPATH in RESULT_POOL, but we don't care
+ * about the stream itself.) */
+ SVN_ERR(svn_stream_open_unique(&chosen_stream, chosen_abspath,
+ temp_dir, delete_when,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_diff_file_diff3_2(&diff,
+ left_abspath,
+ detranslated_target, right_abspath,
+ diff3_options, scratch_pool));
+ SVN_ERR(svn_diff_file_output_merge3(chosen_stream, diff,
+ left_abspath,
+ detranslated_target,
+ right_abspath,
+ NULL, NULL, NULL, NULL, /* markers */
+ style, cancel_func, cancel_baton,
+ scratch_pool));
+ SVN_ERR(svn_stream_close(chosen_stream));
+
+ return SVN_NO_ERROR;
+}
+
+/* Prepare to delete an artifact file at ARTIFACT_FILE_ABSPATH in the
+ * working copy at DB/WRI_ABSPATH.
+ *
+ * Set *WORK_ITEMS to a new work item that, when run, will delete the
+ * artifact file; or to NULL if there is no file to delete.
+ *
+ * Set *FILE_FOUND to TRUE if the artifact file is found on disk and its
+ * node kind is 'file'; otherwise do not change *FILE_FOUND. FILE_FOUND
+ * may be NULL if not required.
+ */
+static svn_error_t *
+remove_artifact_file_if_exists(svn_skel_t **work_items,
+ svn_boolean_t *file_found,
svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_conflict_choice_t choice,
- const apr_array_header_t *merge_options,
- const char *left_abspath,
- const char *right_abspath,
- const char *merged_abspath,
- const char *detranslated_target,
+ const char *wri_abspath,
+ const char *artifact_file_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- const char *install_from_abspath = NULL;
- svn_boolean_t remove_source = FALSE;
-
*work_items = NULL;
-
- switch (choice)
+ if (artifact_file_abspath)
{
- /* If the callback wants to use one of the fulltexts
- to resolve the conflict, so be it.*/
- case svn_wc_conflict_choose_base:
- {
- install_from_abspath = left_abspath;
- *is_resolved = TRUE;
- break;
- }
- case svn_wc_conflict_choose_theirs_full:
- {
- install_from_abspath = right_abspath;
- *is_resolved = TRUE;
- break;
- }
- case svn_wc_conflict_choose_mine_full:
- {
- install_from_abspath = detranslated_target;
- *is_resolved = TRUE;
- break;
- }
- case svn_wc_conflict_choose_theirs_conflict:
- case svn_wc_conflict_choose_mine_conflict:
- {
- const char *chosen_abspath;
- const char *temp_dir;
- svn_stream_t *chosen_stream;
- svn_diff_t *diff;
- svn_diff_conflict_display_style_t style;
- svn_diff_file_options_t *diff3_options;
-
- diff3_options = svn_diff_file_options_create(scratch_pool);
-
- if (merge_options)
- SVN_ERR(svn_diff_file_options_parse(diff3_options,
- merge_options,
- scratch_pool));
-
- style = choice == svn_wc_conflict_choose_theirs_conflict
- ? svn_diff_conflict_display_latest
- : svn_diff_conflict_display_modified;
-
- SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
- local_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_stream_open_unique(&chosen_stream, &chosen_abspath,
- temp_dir, svn_io_file_del_none,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_diff_file_diff3_2(&diff,
- left_abspath,
- detranslated_target, right_abspath,
- diff3_options, scratch_pool));
- SVN_ERR(svn_diff_file_output_merge2(chosen_stream, diff,
- left_abspath,
- detranslated_target,
- right_abspath,
- /* markers ignored */
- NULL, NULL,
- NULL, NULL,
- style,
- scratch_pool));
- SVN_ERR(svn_stream_close(chosen_stream));
-
- install_from_abspath = chosen_abspath;
- remove_source = TRUE;
- *is_resolved = TRUE;
- break;
- }
+ svn_node_kind_t node_kind;
- /* For the case of 3-way file merging, we don't
- really distinguish between these return values;
- if the callback claims to have "generally
- resolved" the situation, we still interpret
- that as "OK, we'll assume the merged version is
- good to use". */
- case svn_wc_conflict_choose_merged:
- {
- install_from_abspath = merged_abspath;
- *is_resolved = TRUE;
- break;
- }
- case svn_wc_conflict_choose_postpone:
- default:
+ SVN_ERR(svn_io_check_path(artifact_file_abspath, &node_kind,
+ scratch_pool));
+ if (node_kind == svn_node_file)
{
- /* Assume conflict remains. */
- *is_resolved = FALSE;
- return SVN_NO_ERROR;
+ SVN_ERR(svn_wc__wq_build_file_remove(work_items,
+ db, wri_abspath,
+ artifact_file_abspath,
+ result_pool, scratch_pool));
+ if (file_found)
+ *file_found = TRUE;
}
}
- if (install_from_abspath == NULL)
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("Conflict on '%s' could not be resolved "
- "because the chosen version of the file "
- "is not available."),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
-
- {
- svn_skel_t *work_item;
-
- SVN_ERR(svn_wc__wq_build_file_install(&work_item,
- db, local_abspath,
- install_from_abspath,
- FALSE /* use_commit_times */,
- FALSE /* record_fileinfo */,
- result_pool, scratch_pool));
- *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
-
- SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item, db, local_abspath,
- result_pool, scratch_pool));
- *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
-
- if (remove_source)
- {
- SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
- db, local_abspath,
- install_from_abspath,
- result_pool, scratch_pool));
- *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
- }
- }
-
return SVN_NO_ERROR;
}
-
/* Create a new file in the same directory as LOCAL_ABSPATH, with the
same basename as LOCAL_ABSPATH, with a ".edited" extension, and set
*WORK_ITEM to a new work item that will copy and translate from the file
@@ -1721,154 +1545,294 @@ save_merge_result(svn_skel_t **work_item,
}
-/* Call the conflict resolver callback for a text conflict, and resolve
- * the conflict if it tells us to do so.
- *
- * Assume that there is a text conflict on the path DB/LOCAL_ABSPATH.
+
+/* Resolve the text conflict in CONFLICT, which is currently recorded
+ * on DB/LOCAL_ABSPATH in the manner specified by CHOICE.
*
- * Call CONFLICT_FUNC with CONFLICT_BATON to find out whether and how
- * it wants to resolve the conflict. Pass it a conflict description
- * containing OPERATION, LEFT/RIGHT_ABSPATH, LEFT/RIGHT_VERSION,
- * RESULT_TARGET and DETRANSLATED_TARGET.
+ * Set *WORK_ITEMS to new work items that will make the on-disk changes
+ * needed to complete the resolution (but not to mark it as resolved).
*
- * If the callback returns a resolution other than 'postpone', then
- * perform that requested resolution and prepare to mark the conflict
- * as resolved.
+ * Set *FOUND_ARTIFACT to true if conflict markers are removed; otherwise
+ * (which is only if CHOICE is 'postpone') to false.
*
- * Return *WORK_ITEMS that will do the on-disk work required to complete
- * the resolution (but not to mark the conflict as resolved), and set
- * *WAS_RESOLVED to true, if it was resolved. Set *WORK_ITEMS to NULL
- * and *WAS_RESOLVED to FALSE otherwise.
+ * CHOICE, MERGED_FILE and SAVE_MERGED are typically values provided by
+ * the conflict resolver.
*
- * RESULT_TARGET is the path to the merged file produced by the internal
- * or external 3-way merge, which may contain conflict markers, in
- * repository normal form. DETRANSLATED_TARGET is the 'mine' version of
- * the file, also in RNF.
+ * MERGE_OPTIONS allows customizing the diff handling when using
+ * per hunk conflict resolving.
*/
static svn_error_t *
-resolve_text_conflict(svn_skel_t **work_items,
- svn_boolean_t *was_resolved,
- svn_wc__db_t *db,
- const char *local_abspath,
- const apr_array_header_t *merge_options,
- svn_wc_operation_t operation,
- const char *left_abspath,
- const char *right_abspath,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- const char *result_target,
- const char *detranslated_target,
- svn_wc_conflict_resolver_func2_t conflict_func,
- void *conflict_baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+build_text_conflict_resolve_items(svn_skel_t **work_items,
+ svn_boolean_t *found_artifact,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_skel_t *conflict,
+ svn_wc_conflict_choice_t choice,
+ const char *merged_file,
+ svn_boolean_t save_merged,
+ const apr_array_header_t *merge_options,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_wc_conflict_result_t *result;
+ const char *mine_abspath;
+ const char *their_old_abspath;
+ const char *their_abspath;
svn_skel_t *work_item;
- svn_wc_conflict_description2_t *cdesc;
- apr_hash_t *props;
- const char *mime_type;
+ const char *install_from_abspath = NULL;
+ svn_boolean_t remove_source = FALSE;
*work_items = NULL;
- *was_resolved = FALSE;
-
- /* Give the conflict resolution callback a chance to clean
- up the conflicts before we mark the file 'conflicted' */
-
- SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
- scratch_pool, scratch_pool));
-
- cdesc = svn_wc_conflict_description_create_text2(local_abspath,
- scratch_pool);
- mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
- cdesc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
- cdesc->mime_type = mime_type;
- cdesc->base_abspath = left_abspath;
- cdesc->their_abspath = right_abspath;
- cdesc->my_abspath = detranslated_target;
- cdesc->merged_file = result_target;
- cdesc->operation = operation;
- cdesc->src_left_version = left_version;
- cdesc->src_right_version = right_version;
- SVN_ERR(conflict_func(&result, cdesc, conflict_baton, scratch_pool,
- scratch_pool));
- if (result == NULL)
- return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
- _("Conflict callback violated API:"
- " returned no results"));
+ if (found_artifact)
+ *found_artifact = FALSE;
+
+ SVN_ERR(svn_wc__conflict_read_text_conflict(&mine_abspath,
+ &their_old_abspath,
+ &their_abspath,
+ db, local_abspath,
+ conflict,
+ scratch_pool, scratch_pool));
- if (result->save_merged)
+ if (save_merged)
+ SVN_ERR(save_merge_result(work_items,
+ db, local_abspath,
+ merged_file
+ ? merged_file
+ : local_abspath,
+ result_pool, scratch_pool));
+
+ if (choice == svn_wc_conflict_choose_postpone)
+ return SVN_NO_ERROR;
+
+ switch (choice)
{
- SVN_ERR(save_merge_result(work_items,
- db, local_abspath,
- /* Look for callback's own
- merged-file first: */
- result->merged_file
- ? result->merged_file
- : result_target,
- result_pool, scratch_pool));
+ /* If the callback wants to use one of the fulltexts
+ to resolve the conflict, so be it.*/
+ case svn_wc_conflict_choose_base:
+ {
+ install_from_abspath = their_old_abspath;
+ break;
+ }
+ case svn_wc_conflict_choose_theirs_full:
+ {
+ install_from_abspath = their_abspath;
+ break;
+ }
+ case svn_wc_conflict_choose_mine_full:
+ {
+ install_from_abspath = mine_abspath;
+ break;
+ }
+ case svn_wc_conflict_choose_theirs_conflict:
+ case svn_wc_conflict_choose_mine_conflict:
+ {
+ svn_diff_conflict_display_style_t style
+ = choice == svn_wc_conflict_choose_theirs_conflict
+ ? svn_diff_conflict_display_latest
+ : svn_diff_conflict_display_modified;
+
+ SVN_ERR(merge_showing_conflicts(&install_from_abspath,
+ db, local_abspath,
+ style, merge_options,
+ their_old_abspath,
+ mine_abspath,
+ their_abspath,
+ /* ### why not same as other caller? */
+ svn_io_file_del_none,
+ cancel_func, cancel_baton,
+ scratch_pool, scratch_pool));
+ remove_source = TRUE;
+ break;
+ }
+
+ /* For the case of 3-way file merging, we don't
+ really distinguish between these return values;
+ if the callback claims to have "generally
+ resolved" the situation, we still interpret
+ that as "OK, we'll assume the merged version is
+ good to use". */
+ case svn_wc_conflict_choose_merged:
+ {
+ install_from_abspath = merged_file
+ ? merged_file
+ : local_abspath;
+ break;
+ }
+ case svn_wc_conflict_choose_postpone:
+ {
+ /* Assume conflict remains. */
+ return SVN_NO_ERROR;
+ }
+ default:
+ SVN_ERR_ASSERT(choice == svn_wc_conflict_choose_postpone);
}
- if (result->choice != svn_wc_conflict_choose_postpone)
+ if (install_from_abspath == NULL)
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("Conflict on '%s' could not be resolved "
+ "because the chosen version of the file "
+ "is not available."),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+
+ /* ### It would be nice if we could somehow pass RECORD_FILEINFO
+ as true in some easy cases. */
+ SVN_ERR(svn_wc__wq_build_file_install(&work_item,
+ db, local_abspath,
+ install_from_abspath,
+ FALSE /* use_commit_times */,
+ FALSE /* record_fileinfo */,
+ result_pool, scratch_pool));
+ *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+ if (remove_source)
{
- SVN_ERR(eval_text_conflict_func_result(&work_item,
- was_resolved,
- db, local_abspath,
- result->choice,
- merge_options,
- left_abspath,
- right_abspath,
- /* ### Sure this is an abspath? */
- result->merged_file
- ? result->merged_file
- : result_target,
- detranslated_target,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_item,
+ db, local_abspath,
+ install_from_abspath,
+ result_pool, scratch_pool));
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
}
- else
- *was_resolved = FALSE;
+
+ SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
+ db, local_abspath,
+ their_old_abspath,
+ result_pool, scratch_pool));
+ *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+ SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
+ db, local_abspath,
+ their_abspath,
+ result_pool, scratch_pool));
+ *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
+
+ SVN_ERR(remove_artifact_file_if_exists(&work_item, found_artifact,
+ db, local_abspath,
+ mine_abspath,
+ result_pool, scratch_pool));
+ *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
return SVN_NO_ERROR;
}
+/* Set *DESC to a new description of the text conflict in
+ * CONFLICT_SKEL. If there is no text conflict in CONFLICT_SKEL, return
+ * an error.
+ *
+ * Use OPERATION and shallow copies of LEFT_VERSION and RIGHT_VERSION,
+ * rather than reading them from CONFLICT_SKEL. Use IS_BINARY and
+ * MIME_TYPE for the corresponding fields of *DESC.
+ *
+ * Allocate results in RESULT_POOL. SCRATCH_POOL is used for temporary
+ * allocations. */
static svn_error_t *
-setup_tree_conflict_desc(svn_wc_conflict_description2_t **desc,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_operation_t operation,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- svn_wc_conflict_reason_t local_change,
- svn_wc_conflict_action_t incoming_change,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+read_text_conflict_desc(svn_wc_conflict_description2_t **desc,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_skel_t *conflict_skel,
+ const char *mime_type,
+ svn_wc_operation_t operation,
+ const svn_wc_conflict_version_t *left_version,
+ const svn_wc_conflict_version_t *right_version,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_node_kind_t tc_kind;
+ *desc = svn_wc_conflict_description_create_text2(local_abspath, result_pool);
+ (*desc)->mime_type = mime_type;
+ (*desc)->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
+ (*desc)->operation = operation;
+ (*desc)->src_left_version = left_version;
+ (*desc)->src_right_version = right_version;
+
+ SVN_ERR(svn_wc__conflict_read_text_conflict(&(*desc)->my_abspath,
+ &(*desc)->base_abspath,
+ &(*desc)->their_abspath,
+ db, local_abspath,
+ conflict_skel,
+ result_pool, scratch_pool));
+ (*desc)->merged_file = apr_pstrdup(result_pool, local_abspath);
+
+ return SVN_NO_ERROR;
+}
- if (left_version)
- tc_kind = left_version->node_kind;
- else if (right_version)
- tc_kind = right_version->node_kind;
+/* Set *CONFLICT_DESC to a new description of the tree conflict in
+ * CONFLICT_SKEL. If there is no tree conflict in CONFLICT_SKEL, return
+ * an error.
+ *
+ * Use OPERATION and shallow copies of LEFT_VERSION and RIGHT_VERSION,
+ * rather than reading them from CONFLICT_SKEL.
+ *
+ * Allocate results in RESULT_POOL. SCRATCH_POOL is used for temporary
+ * allocations. */
+static svn_error_t *
+read_tree_conflict_desc(svn_wc_conflict_description2_t **desc,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_node_kind_t node_kind,
+ const svn_skel_t *conflict_skel,
+ svn_wc_operation_t operation,
+ const svn_wc_conflict_version_t *left_version,
+ const svn_wc_conflict_version_t *right_version,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_node_kind_t local_kind;
+ svn_wc_conflict_reason_t reason;
+ svn_wc_conflict_action_t action;
+
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(
+ &reason, &action, NULL,
+ db, local_abspath, conflict_skel, scratch_pool, scratch_pool));
+
+ if (reason == svn_wc_conflict_reason_missing)
+ local_kind = svn_node_none;
+ else if (reason == svn_wc_conflict_reason_unversioned ||
+ reason == svn_wc_conflict_reason_obstructed)
+ SVN_ERR(svn_io_check_path(local_abspath, &local_kind, scratch_pool));
+ else if (action == svn_wc_conflict_action_delete
+ && left_version
+ && (operation == svn_wc_operation_update
+ ||operation == svn_wc_operation_switch)
+ && (reason == svn_wc_conflict_reason_deleted
+ || reason == svn_wc_conflict_reason_moved_away))
+ {
+ /* We have nothing locally to take the kind from */
+ local_kind = left_version->node_kind;
+ }
else
- tc_kind = svn_node_file; /* Avoid assertion */
+ local_kind = node_kind;
- *desc = svn_wc_conflict_description_create_tree2(local_abspath, tc_kind,
+ *desc = svn_wc_conflict_description_create_tree2(local_abspath, local_kind,
operation,
left_version, right_version,
result_pool);
- (*desc)->reason = local_change;
- (*desc)->action = incoming_change;
+ (*desc)->reason = reason;
+ (*desc)->action = action;
return SVN_NO_ERROR;
}
+/* Forward definition */
+static svn_error_t *
+resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ const svn_skel_t *conflict,
+ svn_wc_conflict_choice_t conflict_choice,
+ apr_hash_t *resolve_later,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool);
svn_error_t *
svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
const char *local_abspath,
+ svn_node_kind_t kind,
const svn_skel_t *conflict_skel,
const apr_array_header_t *merge_options,
svn_wc_conflict_resolver_func2_t resolver_func,
@@ -1936,7 +1900,7 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
hi;
hi = apr_hash_next(hi))
{
- const char *propname = svn__apr_hash_index_key(hi);
+ const char *propname = apr_hash_this_key(hi);
svn_boolean_t conflict_remains = TRUE;
svn_pool_clear(iterpool);
@@ -1945,7 +1909,7 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
SVN_ERR(cancel_func(cancel_baton));
SVN_ERR(generate_propconflict(&conflict_remains,
- db, local_abspath,
+ db, local_abspath, kind,
operation,
left_version,
right_version,
@@ -1963,6 +1927,7 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
? svn_hash_gets(their_props, propname)
: NULL,
resolver_func, resolver_baton,
+ cancel_func, cancel_baton,
iterpool));
if (conflict_remains)
@@ -1974,75 +1939,96 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
SVN_ERR(svn_wc__mark_resolved_prop_conflicts(db, local_abspath,
scratch_pool));
}
+ svn_pool_destroy(iterpool);
}
if (text_conflicted)
{
- const char *mine_abspath;
- const char *their_original_abspath;
- const char *their_abspath;
svn_skel_t *work_items;
svn_boolean_t was_resolved;
+ svn_wc_conflict_description2_t *desc;
+ apr_hash_t *props;
+ svn_wc_conflict_result_t *result;
- SVN_ERR(svn_wc__conflict_read_text_conflict(&mine_abspath,
- &their_original_abspath,
- &their_abspath,
- db, local_abspath,
- conflict_skel,
- scratch_pool, scratch_pool));
-
- SVN_ERR(resolve_text_conflict(&work_items, &was_resolved,
- db, local_abspath,
- merge_options,
- operation,
- their_original_abspath, their_abspath,
- left_version, right_version,
- local_abspath, mine_abspath,
- resolver_func, resolver_baton,
+ SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
scratch_pool, scratch_pool));
- if (was_resolved)
+ SVN_ERR(read_text_conflict_desc(&desc,
+ db, local_abspath, conflict_skel,
+ svn_prop_get_value(props,
+ SVN_PROP_MIME_TYPE),
+ operation, left_version, right_version,
+ scratch_pool, scratch_pool));
+
+
+ work_items = NULL;
+ was_resolved = FALSE;
+
+ /* Give the conflict resolution callback a chance to clean
+ up the conflicts before we mark the file 'conflicted' */
+
+ SVN_ERR(resolver_func(&result, desc, resolver_baton, scratch_pool,
+ scratch_pool));
+ if (result == NULL)
+ return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("Conflict callback violated API:"
+ " returned no results"));
+
+ SVN_ERR(build_text_conflict_resolve_items(&work_items, &was_resolved,
+ db, local_abspath,
+ conflict_skel, result->choice,
+ result->merged_file,
+ result->save_merged,
+ merge_options,
+ cancel_func, cancel_baton,
+ scratch_pool, scratch_pool));
+
+ if (result->choice != svn_wc_conflict_choose_postpone)
{
- if (work_items)
- {
- SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_items,
- scratch_pool));
- SVN_ERR(svn_wc__wq_run(db, local_abspath,
- cancel_func, cancel_baton,
- scratch_pool));
- }
- SVN_ERR(svn_wc__mark_resolved_text_conflict(db, local_abspath,
- scratch_pool));
+ SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
+ TRUE, FALSE, FALSE,
+ work_items, scratch_pool));
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
}
}
if (tree_conflicted)
{
- svn_wc_conflict_reason_t local_change;
- svn_wc_conflict_action_t incoming_change;
svn_wc_conflict_result_t *result;
svn_wc_conflict_description2_t *desc;
+ svn_boolean_t resolved;
+ svn_node_kind_t node_kind;
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
- &incoming_change,
- NULL,
- db, local_abspath,
- conflict_skel,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_kind(&node_kind, db, local_abspath, TRUE,
+ TRUE, FALSE, scratch_pool));
- SVN_ERR(setup_tree_conflict_desc(&desc,
- db, local_abspath,
- operation, left_version, right_version,
- local_change, incoming_change,
- scratch_pool, scratch_pool));
+ SVN_ERR(read_tree_conflict_desc(&desc,
+ db, local_abspath, node_kind,
+ conflict_skel,
+ operation, left_version, right_version,
+ scratch_pool, scratch_pool));
/* Tell the resolver func about this conflict. */
SVN_ERR(resolver_func(&result, desc, resolver_baton, scratch_pool,
scratch_pool));
- /* Ignore the result. We cannot apply it here since this code runs
- * during an update or merge operation. Tree conflicts are always
- * postponed and resolved after the operation has completed. */
+ if (result == NULL)
+ return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
+ _("Conflict callback violated API:"
+ " returned no results"));
+
+ /* Pass retry hash to avoid erroring out on cases where update
+ can continue safely. ### Need notify handling */
+ if (result->choice != svn_wc_conflict_choose_postpone)
+ SVN_ERR(resolve_tree_conflict_on_node(&resolved,
+ db, local_abspath, conflict_skel,
+ result->choice,
+ apr_hash_make(scratch_pool),
+ NULL, NULL, /* ### notify */
+ cancel_func, cancel_baton,
+ scratch_pool));
}
return SVN_NO_ERROR;
@@ -2050,7 +2036,8 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
/* Read all property conflicts contained in CONFLICT_SKEL into
* individual conflict descriptions, and append those descriptions
- * to the CONFLICTS array.
+ * to the CONFLICTS array. If there is no property conflict in
+ * CONFLICT_SKEL, return an error.
*
* If NOT create_tempfiles, always create a legacy property conflict
* descriptor.
@@ -2061,27 +2048,36 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
* Allocate results in RESULT_POOL. SCRATCH_POOL is used for temporary
* allocations. */
static svn_error_t *
-read_prop_conflicts(apr_array_header_t *conflicts,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_skel_t *conflict_skel,
- svn_boolean_t create_tempfiles,
- svn_node_kind_t node_kind,
- svn_wc_operation_t operation,
- const svn_wc_conflict_version_t *left_version,
- const svn_wc_conflict_version_t *right_version,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+read_prop_conflict_descs(apr_array_header_t *conflicts,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_skel_t *conflict_skel,
+ svn_boolean_t create_tempfiles,
+ svn_node_kind_t node_kind,
+ svn_wc_operation_t operation,
+ const svn_wc_conflict_version_t *left_version,
+ const svn_wc_conflict_version_t *right_version,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const char *prop_reject_file;
+ const char *prop_reject_abspath;
+ apr_hash_t *base_props;
apr_hash_t *my_props;
apr_hash_t *their_old_props;
apr_hash_t *their_props;
apr_hash_t *conflicted_props;
apr_hash_index_t *hi;
apr_pool_t *iterpool;
+ svn_boolean_t prop_conflicted;
- SVN_ERR(svn_wc__conflict_read_prop_conflict(&prop_reject_file,
+ SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, &prop_conflicted,
+ NULL, db, local_abspath, conflict_skel,
+ scratch_pool, scratch_pool));
+
+ if (!prop_conflicted)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_wc__conflict_read_prop_conflict(&prop_reject_abspath,
&my_props,
&their_old_props,
&their_props,
@@ -2090,7 +2086,9 @@ read_prop_conflicts(apr_array_header_t *conflicts,
conflict_skel,
scratch_pool, scratch_pool));
- if ((! create_tempfiles) || apr_hash_count(conflicted_props) == 0)
+ prop_reject_abspath = apr_pstrdup(result_pool, prop_reject_abspath);
+
+ if (apr_hash_count(conflicted_props) == 0)
{
/* Legacy prop conflict with only a .reject file. */
svn_wc_conflict_description2_t *desc;
@@ -2099,26 +2097,31 @@ read_prop_conflicts(apr_array_header_t *conflicts,
node_kind,
"", result_pool);
- /* ### This should be changed. The prej file should be stored
- * ### separately from the other files. We need to rev the
- * ### conflict description struct for this. */
- desc->their_abspath = apr_pstrdup(result_pool, prop_reject_file);
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ desc->prop_reject_abspath = prop_reject_abspath; /* in result_pool */
+ desc->their_abspath = desc->prop_reject_abspath;
desc->operation = operation;
desc->src_left_version = left_version;
desc->src_right_version = right_version;
- APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t*) = desc;
+ APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t *) = desc;
return SVN_NO_ERROR;
}
+ if (operation == svn_wc_operation_merge)
+ SVN_ERR(svn_wc__db_read_pristine_props(&base_props, db, local_abspath,
+ result_pool, scratch_pool));
+ else
+ base_props = NULL;
iterpool = svn_pool_create(scratch_pool);
for (hi = apr_hash_first(scratch_pool, conflicted_props);
hi;
hi = apr_hash_next(hi))
{
- const char *propname = svn__apr_hash_index_key(hi);
+ const char *propname = apr_hash_this_key(hi);
svn_string_t *old_value;
svn_string_t *my_value;
svn_string_t *their_value;
@@ -2126,10 +2129,10 @@ read_prop_conflicts(apr_array_header_t *conflicts,
svn_pool_clear(iterpool);
- desc = svn_wc_conflict_description_create_prop2(local_abspath,
- node_kind,
- propname,
- result_pool);
+ desc = svn_wc_conflict_description_create_prop2(local_abspath,
+ node_kind,
+ propname,
+ result_pool);
desc->operation = operation;
desc->src_left_version = left_version;
@@ -2157,26 +2160,30 @@ read_prop_conflicts(apr_array_header_t *conflicts,
else
desc->reason = svn_wc_conflict_reason_edited;
- /* ### This should be changed. The prej file should be stored
- * ### separately from the other files. We need to rev the
- * ### conflict description struct for this. */
- desc->their_abspath = apr_pstrdup(result_pool, prop_reject_file);
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ desc->prop_reject_abspath = prop_reject_abspath; /* in result_pool */
+ desc->their_abspath = desc->prop_reject_abspath;
+
+ desc->prop_value_base = base_props ? svn_hash_gets(base_props, propname)
+ : desc->prop_value_incoming_old;
- /* ### This should be changed. The conflict description for
- * ### props should contain these values as svn_string_t,
- * ### rather than in temporary files. We need to rev the
- * ### conflict description struct for this. */
if (my_value)
{
svn_stream_t *s;
apr_size_t len;
- SVN_ERR(svn_stream_open_unique(&s, &desc->my_abspath, NULL,
- svn_io_file_del_on_pool_cleanup,
- result_pool, iterpool));
- len = my_value->len;
- SVN_ERR(svn_stream_write(s, my_value->data, &len));
- SVN_ERR(svn_stream_close(s));
+ if (create_tempfiles)
+ {
+ SVN_ERR(svn_stream_open_unique(&s, &desc->my_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ result_pool, iterpool));
+ len = my_value->len;
+ SVN_ERR(svn_stream_write(s, my_value->data, &len));
+ SVN_ERR(svn_stream_close(s));
+ }
+
+ desc->prop_value_working = svn_string_dup(my_value, result_pool);
}
if (their_value)
@@ -2184,15 +2191,19 @@ read_prop_conflicts(apr_array_header_t *conflicts,
svn_stream_t *s;
apr_size_t len;
- /* ### Currently, their_abspath is used for the prop reject file.
- * ### Put their value into merged instead...
- * ### We need to rev the conflict description struct to fix this. */
- SVN_ERR(svn_stream_open_unique(&s, &desc->merged_file, NULL,
- svn_io_file_del_on_pool_cleanup,
- result_pool, iterpool));
- len = their_value->len;
- SVN_ERR(svn_stream_write(s, their_value->data, &len));
- SVN_ERR(svn_stream_close(s));
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ if (create_tempfiles)
+ {
+ SVN_ERR(svn_stream_open_unique(&s, &desc->merged_file, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ result_pool, iterpool));
+ len = their_value->len;
+ SVN_ERR(svn_stream_write(s, their_value->data, &len));
+ SVN_ERR(svn_stream_close(s));
+ }
+
+ desc->prop_value_incoming_new = svn_string_dup(their_value, result_pool);
}
if (old_value)
@@ -2200,15 +2211,20 @@ read_prop_conflicts(apr_array_header_t *conflicts,
svn_stream_t *s;
apr_size_t len;
- SVN_ERR(svn_stream_open_unique(&s, &desc->base_abspath, NULL,
- svn_io_file_del_on_pool_cleanup,
- result_pool, iterpool));
- len = old_value->len;
- SVN_ERR(svn_stream_write(s, old_value->data, &len));
- SVN_ERR(svn_stream_close(s));
+ if (create_tempfiles)
+ {
+ SVN_ERR(svn_stream_open_unique(&s, &desc->base_abspath, NULL,
+ svn_io_file_del_on_pool_cleanup,
+ result_pool, iterpool));
+ len = old_value->len;
+ SVN_ERR(svn_stream_write(s, old_value->data, &len));
+ SVN_ERR(svn_stream_close(s));
+ }
+
+ desc->prop_value_incoming_old = svn_string_dup(old_value, result_pool);
}
- APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t*) = desc;
+ APR_ARRAY_PUSH(conflicts, svn_wc_conflict_description2_t *) = desc;
}
svn_pool_destroy(iterpool);
@@ -2217,13 +2233,15 @@ read_prop_conflicts(apr_array_header_t *conflicts,
svn_error_t *
svn_wc__read_conflicts(const apr_array_header_t **conflicts,
+ svn_skel_t **conflict_skel,
svn_wc__db_t *db,
const char *local_abspath,
svn_boolean_t create_tempfiles,
+ svn_boolean_t only_tree_conflict,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_skel_t *conflict_skel;
+ svn_skel_t *the_conflict_skel;
apr_array_header_t *cflcts;
svn_boolean_t prop_conflicted;
svn_boolean_t text_conflicted;
@@ -2232,90 +2250,71 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
const apr_array_header_t *locations;
const svn_wc_conflict_version_t *left_version = NULL;
const svn_wc_conflict_version_t *right_version = NULL;
-
- SVN_ERR(svn_wc__db_read_conflict(&conflict_skel, db, local_abspath,
- scratch_pool, scratch_pool));
+ svn_node_kind_t node_kind;
+ apr_hash_t *props;
if (!conflict_skel)
+ conflict_skel = &the_conflict_skel;
+
+ SVN_ERR(svn_wc__db_read_conflict(conflict_skel, &node_kind, &props,
+ db, local_abspath,
+ (conflict_skel == &the_conflict_skel)
+ ? scratch_pool
+ : result_pool,
+ scratch_pool));
+
+ if (!*conflict_skel)
{
/* Some callers expect not NULL */
*conflicts = apr_array_make(result_pool, 0,
- sizeof(svn_wc_conflict_description2_t*));;
+ sizeof(svn_wc_conflict_description2_t *));
return SVN_NO_ERROR;
}
SVN_ERR(svn_wc__conflict_read_info(&operation, &locations, &text_conflicted,
&prop_conflicted, &tree_conflicted,
- db, local_abspath, conflict_skel,
+ db, local_abspath, *conflict_skel,
result_pool, scratch_pool));
cflcts = apr_array_make(result_pool, 4,
- sizeof(svn_wc_conflict_description2_t*));
+ sizeof(svn_wc_conflict_description2_t *));
if (locations && locations->nelts > 0)
left_version = APR_ARRAY_IDX(locations, 0, const svn_wc_conflict_version_t *);
if (locations && locations->nelts > 1)
right_version = APR_ARRAY_IDX(locations, 1, const svn_wc_conflict_version_t *);
- if (prop_conflicted)
+ if (prop_conflicted && !only_tree_conflict)
{
- svn_node_kind_t node_kind
- = left_version ? left_version->node_kind : svn_node_unknown;
-
- SVN_ERR(read_prop_conflicts(cflcts, db, local_abspath, conflict_skel,
- create_tempfiles, node_kind,
- operation, left_version, right_version,
- result_pool, scratch_pool));
+ SVN_ERR(read_prop_conflict_descs(cflcts,
+ db, local_abspath, *conflict_skel,
+ create_tempfiles, node_kind,
+ operation, left_version, right_version,
+ result_pool, scratch_pool));
}
- if (text_conflicted)
+ if (text_conflicted && !only_tree_conflict)
{
- apr_hash_t *props;
- const char *mime_type;
svn_wc_conflict_description2_t *desc;
- desc = svn_wc_conflict_description_create_text2(local_abspath,
- result_pool);
-
- desc->operation = operation;
- desc->src_left_version = left_version;
- desc->src_right_version = right_version;
-
- SVN_ERR(svn_wc__db_read_props(&props, db, local_abspath,
- scratch_pool, scratch_pool));
- mime_type = svn_prop_get_value(props, SVN_PROP_MIME_TYPE);
- desc->is_binary = mime_type ? svn_mime_type_is_binary(mime_type) : FALSE;
- desc->mime_type = mime_type;
-
- SVN_ERR(svn_wc__conflict_read_text_conflict(&desc->my_abspath,
- &desc->base_abspath,
- &desc->their_abspath,
- db, local_abspath,
- conflict_skel,
- result_pool, scratch_pool));
-
- desc->merged_file = apr_pstrdup(result_pool, local_abspath);
- APR_ARRAY_PUSH(cflcts, svn_wc_conflict_description2_t*) = desc;
+ SVN_ERR(read_text_conflict_desc(&desc,
+ db, local_abspath, *conflict_skel,
+ svn_prop_get_value(props,
+ SVN_PROP_MIME_TYPE),
+ operation, left_version, right_version,
+ result_pool, scratch_pool));
+ APR_ARRAY_PUSH(cflcts, svn_wc_conflict_description2_t *) = desc;
}
if (tree_conflicted)
{
- svn_wc_conflict_reason_t local_change;
- svn_wc_conflict_action_t incoming_change;
svn_wc_conflict_description2_t *desc;
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&local_change,
- &incoming_change,
- NULL,
- db, local_abspath,
- conflict_skel,
- scratch_pool, scratch_pool));
-
- SVN_ERR(setup_tree_conflict_desc(&desc,
- db, local_abspath,
- operation, left_version, right_version,
- local_change, incoming_change,
- result_pool, scratch_pool));
+ SVN_ERR(read_tree_conflict_desc(&desc,
+ db, local_abspath, node_kind,
+ *conflict_skel,
+ operation, left_version, right_version,
+ result_pool, scratch_pool));
APR_ARRAY_PUSH(cflcts, const svn_wc_conflict_description2_t *) = desc;
}
@@ -2327,206 +2326,6 @@ svn_wc__read_conflicts(const apr_array_header_t **conflicts,
/*** Resolving a conflict automatically ***/
-/* Prepare to delete an artifact file at ARTIFACT_FILE_ABSPATH in the
- * working copy at DB/WRI_ABSPATH.
- *
- * Set *WORK_ITEMS to a new work item that, when run, will delete the
- * artifact file; or to NULL if there is no file to delete.
- *
- * Set *FILE_FOUND to TRUE if the artifact file is found on disk and its
- * node kind is 'file'; otherwise do not change *FILE_FOUND. FILE_FOUND
- * may be NULL if not required.
- */
-static svn_error_t *
-remove_artifact_file_if_exists(svn_skel_t **work_items,
- svn_boolean_t *file_found,
- svn_wc__db_t *db,
- const char *wri_abspath,
- const char *artifact_file_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- *work_items = NULL;
- if (artifact_file_abspath)
- {
- svn_node_kind_t node_kind;
-
- SVN_ERR(svn_io_check_path(artifact_file_abspath, &node_kind,
- scratch_pool));
- if (node_kind == svn_node_file)
- {
- SVN_ERR(svn_wc__wq_build_file_remove(work_items,
- db, wri_abspath,
- artifact_file_abspath,
- result_pool, scratch_pool));
- if (file_found)
- *file_found = TRUE;
- }
- }
-
- return SVN_NO_ERROR;
-}
-
-/*
- * Resolve the text conflict found in DB/LOCAL_ABSPATH according
- * to CONFLICT_CHOICE.
- *
- * It is not an error if there is no text conflict. If a text conflict
- * existed and was resolved, set *DID_RESOLVE to TRUE, else set it to FALSE.
- *
- * Note: When there are no conflict markers to remove there is no existing
- * text conflict; just a database containing old information, which we should
- * remove to avoid checking all the time. Resolving a text conflict by
- * removing all the marker files is a fully supported scenario since
- * Subversion 1.0.
- */
-static svn_error_t *
-resolve_text_conflict_on_node(svn_boolean_t *did_resolve,
- svn_wc__db_t *db,
- const char *local_abspath,
- svn_wc_conflict_choice_t conflict_choice,
- const char *merged_file,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
-{
- const char *conflict_old = NULL;
- const char *conflict_new = NULL;
- const char *conflict_working = NULL;
- const char *auto_resolve_src;
- svn_skel_t *work_item;
- svn_skel_t *work_items = NULL;
- svn_skel_t *conflicts;
- svn_wc_operation_t operation;
- svn_boolean_t text_conflicted;
-
- *did_resolve = FALSE;
-
- SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
- scratch_pool, scratch_pool));
- if (!conflicts)
- return SVN_NO_ERROR;
-
- SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, &text_conflicted,
- NULL, NULL, db, local_abspath, conflicts,
- scratch_pool, scratch_pool));
- if (!text_conflicted)
- return SVN_NO_ERROR;
-
- SVN_ERR(svn_wc__conflict_read_text_conflict(&conflict_working,
- &conflict_old,
- &conflict_new,
- db, local_abspath, conflicts,
- scratch_pool, scratch_pool));
-
- /* Handle automatic conflict resolution before the temporary files are
- * deleted, if necessary. */
- switch (conflict_choice)
- {
- case svn_wc_conflict_choose_base:
- auto_resolve_src = conflict_old;
- break;
- case svn_wc_conflict_choose_mine_full:
- auto_resolve_src = conflict_working;
- break;
- case svn_wc_conflict_choose_theirs_full:
- auto_resolve_src = conflict_new;
- break;
- case svn_wc_conflict_choose_merged:
- auto_resolve_src = merged_file;
- break;
- case svn_wc_conflict_choose_theirs_conflict:
- case svn_wc_conflict_choose_mine_conflict:
- {
- if (conflict_old && conflict_working && conflict_new)
- {
- const char *temp_dir;
- svn_stream_t *tmp_stream = NULL;
- svn_diff_t *diff;
- svn_diff_conflict_display_style_t style =
- conflict_choice == svn_wc_conflict_choose_theirs_conflict
- ? svn_diff_conflict_display_latest
- : svn_diff_conflict_display_modified;
-
- SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir, db,
- local_abspath,
- scratch_pool,
- scratch_pool));
- SVN_ERR(svn_stream_open_unique(&tmp_stream,
- &auto_resolve_src,
- temp_dir,
- svn_io_file_del_on_pool_cleanup,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_diff_file_diff3_2(&diff,
- conflict_old,
- conflict_working,
- conflict_new,
- svn_diff_file_options_create(
- scratch_pool),
- scratch_pool));
- SVN_ERR(svn_diff_file_output_merge2(tmp_stream, diff,
- conflict_old,
- conflict_working,
- conflict_new,
- /* markers ignored */
- NULL, NULL, NULL, NULL,
- style,
- scratch_pool));
- SVN_ERR(svn_stream_close(tmp_stream));
- }
- else
- auto_resolve_src = NULL;
- break;
- }
- default:
- return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- _("Invalid 'conflict_result' argument"));
- }
-
- if (auto_resolve_src)
- {
- SVN_ERR(svn_wc__wq_build_file_copy_translated(
- &work_item, db, local_abspath,
- auto_resolve_src, local_abspath, scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
-
- SVN_ERR(svn_wc__wq_build_sync_file_flags(&work_item, db,
- local_abspath,
- scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
- }
-
- /* Legacy behavior: Only report text conflicts as resolved when at least
- one conflict marker file exists.
-
- If not the UI shows the conflict as already resolved
- (and in this case we just remove the in-db conflict) */
-
- SVN_ERR(remove_artifact_file_if_exists(&work_item, did_resolve,
- db, local_abspath, conflict_old,
- scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
-
- SVN_ERR(remove_artifact_file_if_exists(&work_item, did_resolve,
- db, local_abspath, conflict_new,
- scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
-
- SVN_ERR(remove_artifact_file_if_exists(&work_item, did_resolve,
- db, local_abspath, conflict_working,
- scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
-
- SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
- TRUE, FALSE, FALSE,
- work_items, scratch_pool));
- SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
- scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
/*
* Resolve the property conflicts found in DB/LOCAL_ABSPATH according
* to CONFLICT_CHOICE.
@@ -2566,9 +2365,11 @@ static svn_error_t *
resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
svn_wc__db_t *db,
const char *local_abspath,
+ svn_skel_t *conflicts,
const char *conflicted_propname,
svn_wc_conflict_choice_t conflict_choice,
const char *merged_file,
+ const svn_string_t *merged_value,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
@@ -2581,18 +2382,13 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
apr_hash_t *old_props;
apr_hash_t *resolve_from = NULL;
svn_skel_t *work_items = NULL;
- svn_skel_t *conflicts;
svn_wc_operation_t operation;
svn_boolean_t prop_conflicted;
+ apr_hash_t *actual_props;
+ svn_boolean_t resolved_all, resolved_all_prop;
*did_resolve = FALSE;
- SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
- scratch_pool, scratch_pool));
-
- if (!conflicts)
- return SVN_NO_ERROR;
-
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, &prop_conflicted,
NULL, db, local_abspath, conflicts,
scratch_pool, scratch_pool));
@@ -2605,12 +2401,35 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
db, local_abspath, conflicts,
scratch_pool, scratch_pool));
+ if (!conflicted_props)
+ {
+ /* We have a pre 1.8 property conflict. Just mark it resolved */
+
+ SVN_ERR(remove_artifact_file_if_exists(&work_items, did_resolve,
+ db, local_abspath, prop_reject_file,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE, FALSE,
+ work_items, scratch_pool));
+ SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
+ scratch_pool));
+ return SVN_NO_ERROR;
+ }
+
+ if (conflicted_propname[0] != '\0'
+ && !svn_hash_gets(conflicted_props, conflicted_propname))
+ {
+ return SVN_NO_ERROR; /* This property is not conflicted! */
+ }
+
if (operation == svn_wc_operation_merge)
SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
scratch_pool, scratch_pool));
else
old_props = their_old_props;
+ SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
+ scratch_pool, scratch_pool));
+
/* We currently handle *_conflict as *_full as this argument is currently
always applied for all conflicts on a node at the same time. Giving
an error would break some tests that assumed that this would just
@@ -2636,21 +2455,23 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
resolve_from = their_props;
break;
case svn_wc_conflict_choose_merged:
- if (merged_file && conflicted_propname[0] != '\0')
+ if ((merged_file || merged_value) && conflicted_propname[0] != '\0')
{
- apr_hash_t *actual_props;
- svn_stream_t *stream;
- svn_string_t *merged_propval;
+ resolve_from = apr_hash_copy(scratch_pool, actual_props);
- SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
- scratch_pool, scratch_pool));
- resolve_from = actual_props;
+ if (!merged_value)
+ {
+ svn_stream_t *stream;
+ svn_string_t *merged_propval;
- SVN_ERR(svn_stream_open_readonly(&stream, merged_file,
- scratch_pool, scratch_pool));
- SVN_ERR(svn_string_from_stream(&merged_propval, stream,
- scratch_pool, scratch_pool));
- svn_hash_sets(resolve_from, conflicted_propname, merged_propval);
+ SVN_ERR(svn_stream_open_readonly(&stream, merged_file,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_string_from_stream(&merged_propval, stream,
+ scratch_pool, scratch_pool));
+
+ merged_value = merged_propval;
+ }
+ svn_hash_sets(resolve_from, conflicted_propname, merged_value);
}
else
resolve_from = NULL;
@@ -2660,47 +2481,97 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
_("Invalid 'conflict_result' argument"));
}
- if (conflicted_props && apr_hash_count(conflicted_props) && resolve_from)
+
+ if (resolve_from)
{
apr_hash_index_t *hi;
- apr_hash_t *actual_props;
+ apr_hash_t *apply_on_props;
- SVN_ERR(svn_wc__db_read_props(&actual_props, db, local_abspath,
- scratch_pool, scratch_pool));
+ if (conflicted_propname[0] == '\0')
+ {
+ /* Apply to all conflicted properties */
+ apply_on_props = conflicted_props;
+ }
+ else
+ {
+ /* Apply to a single property */
+ apply_on_props = apr_hash_make(scratch_pool);
+ svn_hash_sets(apply_on_props, conflicted_propname, "");
+ }
- for (hi = apr_hash_first(scratch_pool, conflicted_props);
+ /* Apply the selected changes */
+ for (hi = apr_hash_first(scratch_pool, apply_on_props);
hi;
hi = apr_hash_next(hi))
{
- const char *propname = svn__apr_hash_index_key(hi);
+ const char *propname = apr_hash_this_key(hi);
svn_string_t *new_value = NULL;
new_value = svn_hash_gets(resolve_from, propname);
svn_hash_sets(actual_props, propname, new_value);
}
- SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, actual_props,
- FALSE, NULL, NULL,
- scratch_pool));
}
+ /*else the user accepted the properties as-is */
- /* Legacy behavior: Only report property conflicts as resolved when the
- property reject file exists
+ /* This function handles conflicted_propname "" as resolving
+ all property conflicts... Just what we need here */
+ SVN_ERR(svn_wc__conflict_skel_resolve(&resolved_all, conflicts,
+ db, local_abspath,
+ FALSE, conflicted_propname,
+ FALSE,
+ scratch_pool, scratch_pool));
- If not the UI shows the conflict as already resolved
- (and in this case we just remove the in-db conflict) */
+ if (!resolved_all)
+ {
+ /* Are there still property conflicts left? (or only...) */
+ SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, &prop_conflicted,
+ NULL, db, local_abspath, conflicts,
+ scratch_pool, scratch_pool));
- {
- svn_skel_t *work_item;
+ resolved_all_prop = (! prop_conflicted);
+ }
+ else
+ {
+ resolved_all_prop = TRUE;
+ conflicts = NULL;
+ }
+
+ if (resolved_all_prop)
+ {
+ /* Legacy behavior: Only report property conflicts as resolved when the
+ property reject file exists
- SVN_ERR(remove_artifact_file_if_exists(&work_item, did_resolve,
- db, local_abspath, prop_reject_file,
- scratch_pool, scratch_pool));
- work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
- }
+ If not the UI shows the conflict as already resolved
+ (and in this case we just remove the in-db conflict) */
+ SVN_ERR(remove_artifact_file_if_exists(&work_items, did_resolve,
+ db, local_abspath,
+ prop_reject_file,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ /* Create a new prej file, based on the remaining conflicts */
+ SVN_ERR(svn_wc__wq_build_prej_install(&work_items,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+ *did_resolve = TRUE; /* We resolved a property conflict */
+ }
+
+ /* This installs the updated conflict skel */
+ SVN_ERR(svn_wc__db_op_set_props(db, local_abspath, actual_props,
+ FALSE, conflicts, work_items,
+ scratch_pool));
+
+ if (resolved_all)
+ {
+ /* Remove the whole conflict. Should probably be integrated
+ into the op_set_props() call */
+ SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
+ FALSE, TRUE, FALSE,
+ NULL, scratch_pool));
+ }
- SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, TRUE, FALSE,
- work_items, scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
scratch_pool));
@@ -2715,12 +2586,18 @@ resolve_prop_conflict_on_node(svn_boolean_t *did_resolve,
* existed and was resolved, set *DID_RESOLVE to TRUE, else set it to FALSE.
*
* It is not an error if there is no tree conflict.
+ *
+ * If the conflict can't be resolved yet because another tree conflict is
+ * blocking a storage location, store the tree conflict in the RESOLVE_LATER
+ * hash.
*/
static svn_error_t *
resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_wc__db_t *db,
const char *local_abspath,
+ const svn_skel_t *conflicts,
svn_wc_conflict_choice_t conflict_choice,
+ apr_hash_t *resolve_later,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
@@ -2729,24 +2606,20 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
{
svn_wc_conflict_reason_t reason;
svn_wc_conflict_action_t action;
- svn_skel_t *conflicts;
svn_wc_operation_t operation;
svn_boolean_t tree_conflicted;
+ const char *src_op_root_abspath;
*did_resolve = FALSE;
- SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
- scratch_pool, scratch_pool));
- if (!conflicts)
- return SVN_NO_ERROR;
-
SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL,
&tree_conflicted, db, local_abspath,
conflicts, scratch_pool, scratch_pool));
if (!tree_conflicted)
return SVN_NO_ERROR;
- SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action, NULL,
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
+ &src_op_root_abspath,
db, local_abspath,
conflicts,
scratch_pool, scratch_pool));
@@ -2754,6 +2627,7 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
if (operation == svn_wc_operation_update
|| operation == svn_wc_operation_switch)
{
+ svn_error_t *err;
if (reason == svn_wc_conflict_reason_deleted ||
reason == svn_wc_conflict_reason_replaced)
{
@@ -2761,21 +2635,88 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
{
/* Break moves for any children moved out of this directory,
* and leave this directory deleted. */
- SVN_ERR(svn_wc__db_resolve_break_moved_away_children(
- db, local_abspath, notify_func, notify_baton,
- scratch_pool));
+
+ if (action != svn_wc_conflict_action_delete)
+ {
+ SVN_ERR(svn_wc__db_op_break_moved_away(
+ db, local_abspath, src_op_root_abspath, TRUE,
+ notify_func, notify_baton,
+ scratch_pool));
+ *did_resolve = TRUE;
+ return SVN_NO_ERROR; /* Marked resolved by function*/
+ }
+ /* else # The move is/moves are already broken */
+
+
*did_resolve = TRUE;
}
else if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
{
- /* Raised moved-away conflicts on any children moved out of
- * this directory, and leave this directory deleted.
+ svn_skel_t *new_conflicts;
+
+ /* Raise moved-away conflicts on any children moved out of
+ * this directory, and leave this directory as-is.
+ *
* The newly conflicted moved-away children will be updated
* if they are resolved with 'mine_conflict' as well. */
- SVN_ERR(svn_wc__db_resolve_delete_raise_moved_away(
+ err = svn_wc__db_op_raise_moved_away(
db, local_abspath, notify_func, notify_baton,
- scratch_pool));
- *did_resolve = TRUE;
+ scratch_pool);
+
+ if (err)
+ {
+ const char *dup_abspath;
+
+ if (!resolve_later
+ || err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+ local_abspath);
+
+ svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+ return SVN_NO_ERROR; /* Retry after other conflicts */
+ }
+
+ /* We might now have a moved-away on *this* path, let's
+ try to resolve that directly if that is the case */
+ SVN_ERR(svn_wc__db_read_conflict(&new_conflicts, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (new_conflicts)
+ SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, NULL, NULL,
+ &tree_conflicted,
+ db, local_abspath,
+ new_conflicts,
+ scratch_pool,
+ scratch_pool));
+
+ if (!new_conflicts || !tree_conflicted)
+ {
+ /* TC is marked resolved by calling
+ svn_wc__db_resolve_delete_raise_moved_away */
+ *did_resolve = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ SVN_ERR(svn_wc__conflict_read_tree_conflict(&reason, &action,
+ &src_op_root_abspath,
+ db, local_abspath,
+ new_conflicts,
+ scratch_pool,
+ scratch_pool));
+
+ if (reason != svn_wc_conflict_reason_moved_away)
+ {
+ *did_resolve = TRUE;
+ return SVN_NO_ERROR; /* We fixed one, but... */
+ }
+
+ conflicts = new_conflicts;
+ /* Fall through in moved_away handling */
}
else
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
@@ -2786,8 +2727,9 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_dirent_local_style(local_abspath,
scratch_pool));
}
- else if (reason == svn_wc_conflict_reason_moved_away
- && action == svn_wc_conflict_action_edit)
+
+ if (reason == svn_wc_conflict_reason_moved_away
+ && action == svn_wc_conflict_action_edit)
{
/* After updates, we can resolve local moved-away
* vs. any incoming change, either by updating the
@@ -2795,12 +2737,31 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
* move (theirs-conflict). */
if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
{
- SVN_ERR(svn_wc__db_update_moved_away_conflict_victim(
- db, local_abspath,
- notify_func, notify_baton,
+ err = svn_wc__db_update_moved_away_conflict_victim(
+ db, local_abspath, src_op_root_abspath,
+ operation, action, reason,
cancel_func, cancel_baton,
- scratch_pool));
- *did_resolve = TRUE;
+ notify_func, notify_baton,
+ scratch_pool);
+
+ if (err)
+ {
+ const char *dup_abspath;
+
+ if (!resolve_later
+ || err->apr_err != SVN_ERR_WC_OBSTRUCTED_UPDATE)
+ return svn_error_trace(err);
+
+ svn_error_clear(err);
+ dup_abspath = apr_pstrdup(apr_hash_pool_get(resolve_later),
+ local_abspath);
+
+ svn_hash_sets(resolve_later, dup_abspath, dup_abspath);
+
+ return SVN_NO_ERROR; /* Retry after other conflicts */
+ }
+ else
+ *did_resolve = TRUE;
}
else if (conflict_choice == svn_wc_conflict_choose_merged)
{
@@ -2808,14 +2769,12 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
* working copy state instead of updating the move.
* Else the move would be left in an invalid state. */
- /* ### This breaks the move but leaves the conflict
- ### involving the move until
- ### svn_wc__db_op_mark_resolved. */
- SVN_ERR(svn_wc__db_resolve_break_moved_away(db, local_abspath,
- notify_func,
- notify_baton,
- scratch_pool));
+ SVN_ERR(svn_wc__db_op_break_moved_away(db, local_abspath,
+ src_op_root_abspath, TRUE,
+ notify_func, notify_baton,
+ scratch_pool));
*did_resolve = TRUE;
+ return SVN_NO_ERROR; /* Conflict is marked resolved */
}
else
return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
@@ -2826,22 +2785,57 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_dirent_local_style(local_abspath,
scratch_pool));
}
+ else if (reason == svn_wc_conflict_reason_moved_away
+ && action != svn_wc_conflict_action_edit)
+ {
+ /* action added is impossible, because that would imply that
+ something was added, but before that already moved...
+ (which would imply a replace) */
+ SVN_ERR_ASSERT(action == svn_wc_conflict_action_delete
+ || action == svn_wc_conflict_action_replace);
+
+ if (conflict_choice == svn_wc_conflict_choose_merged)
+ {
+ /* Whatever was moved is removed at its original location by the
+ update. That must also remove the recording of the move, so
+ we don't have to do anything here. */
+
+ *did_resolve = TRUE;
+ }
+ else if (conflict_choice == svn_wc_conflict_choose_mine_conflict)
+ {
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+ NULL,
+ _("Tree conflict can only be "
+ "resolved to 'working' state; "
+ "'%s' is no longer moved"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ }
}
- if (! *did_resolve && conflict_choice != svn_wc_conflict_choose_merged)
+ if (! *did_resolve)
{
- /* For other tree conflicts, there is no way to pick
- * theirs-full or mine-full, etc. Throw an error if the
- * user expects us to be smarter than we really are. */
- return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
- NULL,
- _("Tree conflict can only be "
- "resolved to 'working' state; "
- "'%s' not resolved"),
- svn_dirent_local_style(local_abspath,
- scratch_pool));
+ if (conflict_choice != svn_wc_conflict_choose_merged)
+ {
+ /* For other tree conflicts, there is no way to pick
+ * theirs-full or mine-full, etc. Throw an error if the
+ * user expects us to be smarter than we really are. */
+ return svn_error_createf(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE,
+ NULL,
+ _("Tree conflict can only be "
+ "resolved to 'working' state; "
+ "'%s' not resolved"),
+ svn_dirent_local_style(local_abspath,
+ scratch_pool));
+ }
+ else
+ *did_resolve = TRUE;
}
+ SVN_ERR_ASSERT(*did_resolve);
+
SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, FALSE, FALSE, TRUE,
NULL, scratch_pool));
SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
@@ -2852,16 +2846,33 @@ resolve_tree_conflict_on_node(svn_boolean_t *did_resolve,
svn_error_t *
svn_wc__mark_resolved_text_conflict(svn_wc__db_t *db,
const char *local_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_boolean_t ignored_result;
+ svn_skel_t *work_items;
+ svn_skel_t *conflict;
- return svn_error_trace(resolve_text_conflict_on_node(
- &ignored_result,
- db, local_abspath,
- svn_wc_conflict_choose_merged, NULL,
- NULL, NULL,
- scratch_pool));
+ SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (!conflict)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(build_text_conflict_resolve_items(&work_items, NULL,
+ db, local_abspath, conflict,
+ svn_wc_conflict_choose_merged,
+ NULL, FALSE, NULL,
+ cancel_func, cancel_baton,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath, TRUE, FALSE, FALSE,
+ work_items, scratch_pool));
+
+ return svn_error_trace(svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
}
svn_error_t *
@@ -2870,11 +2881,20 @@ svn_wc__mark_resolved_prop_conflicts(svn_wc__db_t *db,
apr_pool_t *scratch_pool)
{
svn_boolean_t ignored_result;
+ svn_skel_t *conflicts;
+
+ SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (!conflicts)
+ return SVN_NO_ERROR;
return svn_error_trace(resolve_prop_conflict_on_node(
&ignored_result,
- db, local_abspath, "",
- svn_wc_conflict_choose_merged, NULL,
+ db, local_abspath, conflicts, "",
+ svn_wc_conflict_choose_merged,
+ NULL, NULL,
NULL, NULL,
scratch_pool));
}
@@ -2894,8 +2914,39 @@ struct conflict_status_walker_baton
void *cancel_baton;
svn_wc_notify_func2_t notify_func;
void *notify_baton;
+ svn_boolean_t resolved_one;
+ apr_hash_t *resolve_later;
};
+/* Implements svn_wc_notify_func2_t to collect new conflicts caused by
+ resolving a tree conflict. */
+static void
+tree_conflict_collector(void *baton,
+ const svn_wc_notify_t *notify,
+ apr_pool_t *pool)
+{
+ struct conflict_status_walker_baton *cswb = baton;
+
+ if (cswb->notify_func)
+ cswb->notify_func(cswb->notify_baton, notify, pool);
+
+ if (cswb->resolve_later
+ && (notify->action == svn_wc_notify_tree_conflict
+ || notify->prop_state == svn_wc_notify_state_conflicted
+ || notify->content_state == svn_wc_notify_state_conflicted))
+ {
+ if (!svn_hash_gets(cswb->resolve_later, notify->path))
+ {
+ const char *dup_path;
+
+ dup_path = apr_pstrdup(apr_hash_pool_get(cswb->resolve_later),
+ notify->path);
+
+ svn_hash_sets(cswb->resolve_later, dup_path, dup_path);
+ }
+ }
+}
+
/* Implements svn_wc_status4_t to walk all conflicts to resolve.
*/
static svn_error_t *
@@ -2911,13 +2962,17 @@ conflict_status_walker(void *baton,
apr_pool_t *iterpool;
int i;
svn_boolean_t resolved = FALSE;
+ svn_skel_t *conflict;
if (!status->conflicted)
return SVN_NO_ERROR;
iterpool = svn_pool_create(scratch_pool);
- SVN_ERR(svn_wc__read_conflicts(&conflicts, db, local_abspath, TRUE,
+ SVN_ERR(svn_wc__read_conflicts(&conflicts, &conflict,
+ db, local_abspath,
+ (cswb->conflict_func != NULL) /* tmp files */,
+ FALSE /* only tree conflicts */,
scratch_pool, iterpool));
for (i = 0; i < conflicts->nelts; i++)
@@ -2925,11 +2980,15 @@ conflict_status_walker(void *baton,
const svn_wc_conflict_description2_t *cd;
svn_boolean_t did_resolve;
svn_wc_conflict_choice_t my_choice = cswb->conflict_choice;
- const char *merged_file = NULL;
+ svn_wc_conflict_result_t *result = NULL;
+ svn_skel_t *work_items;
cd = APR_ARRAY_IDX(conflicts, i, const svn_wc_conflict_description2_t *);
- if ((cd->kind == svn_wc_conflict_kind_property && !cswb->resolve_prop)
+ if ((cd->kind == svn_wc_conflict_kind_property
+ && (!cswb->resolve_prop
+ || (*cswb->resolve_prop != '\0'
+ && strcmp(cswb->resolve_prop, cd->property_name) != 0)))
|| (cd->kind == svn_wc_conflict_kind_text && !cswb->resolve_text)
|| (cd->kind == svn_wc_conflict_kind_tree && !cswb->resolve_tree))
{
@@ -2940,8 +2999,6 @@ conflict_status_walker(void *baton,
if (my_choice == svn_wc_conflict_choose_unspecified)
{
- svn_wc_conflict_result_t *result;
-
if (!cswb->conflict_func)
return svn_error_create(SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, NULL,
_("No conflict-callback and no "
@@ -2951,8 +3008,6 @@ conflict_status_walker(void *baton,
iterpool, iterpool));
my_choice = result->choice;
- merged_file = result->merged_file;
- /* ### Bug: ignores result->save_merged */
}
@@ -2962,54 +3017,57 @@ conflict_status_walker(void *baton,
switch (cd->kind)
{
case svn_wc_conflict_kind_tree:
- if (!cswb->resolve_tree)
- break;
SVN_ERR(resolve_tree_conflict_on_node(&did_resolve,
db,
- local_abspath,
+ local_abspath, conflict,
my_choice,
- cswb->notify_func,
- cswb->notify_baton,
+ cswb->resolve_later,
+ tree_conflict_collector,
+ cswb,
cswb->cancel_func,
cswb->cancel_baton,
iterpool));
- resolved = TRUE;
+ if (did_resolve)
+ resolved = TRUE;
break;
case svn_wc_conflict_kind_text:
- if (!cswb->resolve_text)
- break;
-
- SVN_ERR(resolve_text_conflict_on_node(&did_resolve,
- db,
- local_abspath,
- my_choice,
- merged_file,
- cswb->cancel_func,
- cswb->cancel_baton,
- iterpool));
-
- if (did_resolve)
- resolved = TRUE;
+ SVN_ERR(build_text_conflict_resolve_items(
+ &work_items,
+ &resolved,
+ db, local_abspath, conflict,
+ my_choice,
+ result ? result->merged_file
+ : NULL,
+ result ? result->save_merged
+ : FALSE,
+ NULL /* merge_options */,
+ cswb->cancel_func,
+ cswb->cancel_baton,
+ iterpool, iterpool));
+
+ SVN_ERR(svn_wc__db_op_mark_resolved(db, local_abspath,
+ TRUE, FALSE, FALSE,
+ work_items, iterpool));
+ SVN_ERR(svn_wc__wq_run(db, local_abspath,
+ cswb->cancel_func, cswb->cancel_baton,
+ iterpool));
break;
case svn_wc_conflict_kind_property:
- if (!cswb->resolve_prop)
- break;
-
- if (*cswb->resolve_prop != '\0' &&
- strcmp(cswb->resolve_prop, cd->property_name) != 0)
- {
- break; /* This is not the property we want to resolve. */
- }
-
SVN_ERR(resolve_prop_conflict_on_node(&did_resolve,
db,
local_abspath,
+ conflict,
cd->property_name,
my_choice,
- merged_file,
+ result
+ ? result->merged_file
+ : NULL,
+ result
+ ? result->merged_value
+ : NULL,
cswb->cancel_func,
cswb->cancel_baton,
iterpool));
@@ -3032,6 +3090,9 @@ conflict_status_walker(void *baton,
iterpool),
iterpool);
+ if (resolved)
+ cswb->resolved_one = TRUE;
+
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
@@ -3056,13 +3117,8 @@ svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx,
svn_node_kind_t kind;
svn_boolean_t conflicted;
struct conflict_status_walker_baton cswb;
-
- /* ### the underlying code does NOT support resolving individual
- ### properties. bail out if the caller tries it. */
- if (resolve_prop != NULL && *resolve_prop != '\0')
- return svn_error_create(SVN_ERR_INCORRECT_PARAMS, NULL,
- U_("Resolving a single property is not (yet) "
- "supported."));
+ apr_pool_t *iterpool = NULL;
+ svn_error_t *err;
/* ### Just a versioned check? */
/* Conflicted is set to allow invoking on actual only nodes */
@@ -3095,6 +3151,11 @@ svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx,
cswb.notify_func = notify_func;
cswb.notify_baton = notify_baton;
+ cswb.resolved_one = FALSE;
+ cswb.resolve_later = (depth != svn_depth_empty)
+ ? apr_hash_make(scratch_pool)
+ : NULL;
+
if (notify_func)
notify_func(notify_baton,
svn_wc_create_notify(local_abspath,
@@ -3102,16 +3163,103 @@ svn_wc__resolve_conflicts(svn_wc_context_t *wc_ctx,
scratch_pool),
scratch_pool);
- SVN_ERR(svn_wc_walk_status(wc_ctx,
- local_abspath,
- depth,
- FALSE /* get_all */,
- FALSE /* no_ignore */,
- TRUE /* ignore_text_mods */,
- NULL /* ignore_patterns */,
- conflict_status_walker, &cswb,
- cancel_func, cancel_baton,
- scratch_pool));
+ err = svn_wc_walk_status(wc_ctx,
+ local_abspath,
+ depth,
+ FALSE /* get_all */,
+ FALSE /* no_ignore */,
+ TRUE /* ignore_text_mods */,
+ NULL /* ignore_patterns */,
+ conflict_status_walker, &cswb,
+ cancel_func, cancel_baton,
+ scratch_pool);
+
+ /* If we got new tree conflicts (or delayed conflicts) during the initial
+ walk, we now walk them one by one as closure. */
+ while (!err && cswb.resolve_later && apr_hash_count(cswb.resolve_later))
+ {
+ apr_hash_index_t *hi;
+ svn_wc_status3_t *status = NULL;
+ const char *tc_abspath = NULL;
+
+ if (iterpool)
+ svn_pool_clear(iterpool);
+ else
+ iterpool = svn_pool_create(scratch_pool);
+
+ hi = apr_hash_first(scratch_pool, cswb.resolve_later);
+ cswb.resolve_later = apr_hash_make(scratch_pool);
+ cswb.resolved_one = FALSE;
+
+ for (; hi && !err; hi = apr_hash_next(hi))
+ {
+ const char *relpath;
+ svn_pool_clear(iterpool);
+
+ tc_abspath = apr_hash_this_key(hi);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+
+ relpath = svn_dirent_skip_ancestor(local_abspath,
+ tc_abspath);
+
+ if (!relpath
+ || (depth >= svn_depth_empty
+ && depth < svn_depth_infinity
+ && strchr(relpath, '/')))
+ {
+ continue;
+ }
+
+ SVN_ERR(svn_wc_status3(&status, wc_ctx, tc_abspath,
+ iterpool, iterpool));
+
+ if (depth == svn_depth_files
+ && status->kind == svn_node_dir)
+ continue;
+
+ err = svn_error_trace(conflict_status_walker(&cswb, tc_abspath,
+ status, scratch_pool));
+ }
+
+ /* None of the remaining conflicts got resolved, and non did provide
+ an error...
+
+ We can fix that if we disable the 'resolve_later' option...
+ */
+ if (!cswb.resolved_one && !err && tc_abspath
+ && apr_hash_count(cswb.resolve_later))
+ {
+ /* Run the last resolve operation again. We still have status
+ and tc_abspath for that one. */
+
+ cswb.resolve_later = NULL; /* Produce proper error! */
+
+ /* Recreate the error */
+ err = svn_error_trace(conflict_status_walker(&cswb, tc_abspath,
+ status, scratch_pool));
+
+ SVN_ERR_ASSERT(err != NULL);
+
+ err = svn_error_createf(
+ SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
+ _("Unable to resolve pending conflict on '%s'"),
+ svn_dirent_local_style(tc_abspath, scratch_pool));
+ break;
+ }
+ }
+
+ if (iterpool)
+ svn_pool_destroy(iterpool);
+
+ if (err && err->apr_err != SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE)
+ err = svn_error_createf(
+ SVN_ERR_WC_CONFLICT_RESOLVER_FAILURE, err,
+ _("Unable to resolve conflicts on '%s'"),
+ svn_dirent_local_style(local_abspath, scratch_pool));
+
+ SVN_ERR(err);
if (notify_func)
notify_func(notify_baton,
@@ -3155,7 +3303,7 @@ svn_wc_create_conflict_result(svn_wc_conflict_choice_t choice,
{
svn_wc_conflict_result_t *result = apr_pcalloc(pool, sizeof(*result));
result->choice = choice;
- result->merged_file = merged_file;
+ result->merged_file = apr_pstrdup(pool, merged_file);
result->save_merged = FALSE;
/* If we add more fields to svn_wc_conflict_result_t, add them here. */
diff --git a/subversion/libsvn_wc/conflicts.h b/subversion/libsvn_wc/conflicts.h
index 839e8a0d4eb0..0a9324b89a61 100644
--- a/subversion/libsvn_wc/conflicts.h
+++ b/subversion/libsvn_wc/conflicts.h
@@ -419,6 +419,7 @@ svn_wc__conflict_create_markers(svn_skel_t **work_item,
svn_error_t *
svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
const char *local_abspath,
+ svn_node_kind_t kind,
const svn_skel_t *conflict_skel,
const apr_array_header_t *merge_options,
svn_wc_conflict_resolver_func2_t resolver_func,
@@ -432,6 +433,8 @@ svn_wc__conflict_invoke_resolver(svn_wc__db_t *db,
svn_error_t *
svn_wc__mark_resolved_text_conflict(svn_wc__db_t *db,
const char *local_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool);
/* Mark as resolved any prop conflicts on the node at DB/LOCAL_ABSPATH. */
diff --git a/subversion/libsvn_wc/copy.c b/subversion/libsvn_wc/copy.c
index 1e7d7cf08b76..30a0db58cc6a 100644
--- a/subversion/libsvn_wc/copy.c
+++ b/subversion/libsvn_wc/copy.c
@@ -42,6 +42,7 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
+/* #define RECORD_MIXED_MOVE */
/*** Code. ***/
@@ -50,7 +51,14 @@
TMPDIR_ABSPATH and return the absolute path of the copy in
*DST_ABSPATH. Return the node kind of SRC_ABSPATH in *KIND. If
SRC_ABSPATH doesn't exist then set *DST_ABSPATH to NULL to indicate
- that no copy was made. */
+ that no copy was made.
+
+ If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
+ RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of
+ SRC_ABSPATH, and RECORDED_TIME the recorded size or 0.
+
+ These values will be used to avoid unneeded work.
+ */
static svn_error_t *
copy_to_tmpdir(svn_skel_t **work_item,
svn_node_kind_t *kind,
@@ -60,6 +68,9 @@ copy_to_tmpdir(svn_skel_t **work_item,
const char *tmpdir_abspath,
svn_boolean_t file_copy,
svn_boolean_t unversioned,
+ const svn_io_dirent2_t *dirent,
+ svn_filesize_t recorded_size,
+ apr_time_t recorded_time,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
@@ -74,8 +85,14 @@ copy_to_tmpdir(svn_skel_t **work_item,
*work_item = NULL;
- SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special,
- scratch_pool));
+ if (dirent)
+ {
+ *kind = dirent->kind;
+ is_special = dirent->special;
+ }
+ else
+ SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special,
+ scratch_pool));
if (*kind == svn_node_none)
{
return SVN_NO_ERROR;
@@ -104,9 +121,21 @@ copy_to_tmpdir(svn_skel_t **work_item,
the timestamp might match, than to examine the
destination later as the destination timestamp will
never match. */
- SVN_ERR(svn_wc__internal_file_modified_p(&modified,
- db, src_abspath,
- FALSE, scratch_pool));
+
+ if (dirent
+ && dirent->kind == svn_node_file
+ && recorded_size != SVN_INVALID_FILESIZE
+ && recorded_size == dirent->filesize
+ && recorded_time == dirent->mtime)
+ {
+ modified = FALSE; /* Recorded matches on-disk. Easy out */
+ }
+ else
+ {
+ SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, src_abspath,
+ FALSE, scratch_pool));
+ }
+
if (!modified)
{
/* Why create a temp copy if we can just reinstall from pristine? */
@@ -117,6 +146,15 @@ copy_to_tmpdir(svn_skel_t **work_item,
return SVN_NO_ERROR;
}
}
+ else if (*kind == svn_node_dir && !file_copy)
+ {
+ /* Just build a new direcory from the workqueue */
+ SVN_ERR(svn_wc__wq_build_dir_install(work_item,
+ db, dst_abspath,
+ result_pool, scratch_pool));
+
+ return SVN_NO_ERROR;
+ }
/* Set DST_TMP_ABSPATH to a temporary unique path. If *KIND is file, leave
a file there and then overwrite it; otherwise leave no node on disk at
@@ -172,7 +210,14 @@ copy_to_tmpdir(svn_skel_t **work_item,
versioned file itself.
This also works for versioned symlinks that are stored in the db as
- svn_node_file with svn:special set. */
+ svn_node_file with svn:special set.
+
+ If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
+ RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of
+ SRC_ABSPATH, and RECORDED_TIME the recorded size or 0.
+
+ These values will be used to avoid unneeded work.
+*/
static svn_error_t *
copy_versioned_file(svn_wc__db_t *db,
const char *src_abspath,
@@ -182,6 +227,9 @@ copy_versioned_file(svn_wc__db_t *db,
svn_boolean_t metadata_only,
svn_boolean_t conflicted,
svn_boolean_t is_move,
+ const svn_io_dirent2_t *dirent,
+ svn_filesize_t recorded_size,
+ apr_time_t recorded_time,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -210,8 +258,9 @@ copy_versioned_file(svn_wc__db_t *db,
svn_error_t *err;
/* Is there a text conflict at the source path? */
- SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
+ db, src_abspath,
+ scratch_pool, scratch_pool));
err = svn_wc__conflict_read_text_conflict(&conflict_working, NULL, NULL,
db, src_abspath, conflict,
@@ -248,6 +297,7 @@ copy_versioned_file(svn_wc__db_t *db,
dst_abspath, tmpdir_abspath,
TRUE /* file_copy */,
handle_as_unversioned /* unversioned */,
+ dirent, recorded_size, recorded_time,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
}
@@ -265,10 +315,6 @@ copy_versioned_file(svn_wc__db_t *db,
scratch_pool);
notify->kind = svn_node_file;
- /* When we notify that we performed a copy, make sure we already did */
- if (work_items != NULL)
- SVN_ERR(svn_wc__wq_run(db, dst_abspath,
- cancel_func, cancel_baton, scratch_pool));
(*notify_func)(notify_baton, notify, scratch_pool);
}
return SVN_NO_ERROR;
@@ -282,6 +328,8 @@ copy_versioned_file(svn_wc__db_t *db,
data in addition to copying the directory.
WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root)
+
+ If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH.
*/
static svn_error_t *
copy_versioned_dir(svn_wc__db_t *db,
@@ -291,6 +339,7 @@ copy_versioned_dir(svn_wc__db_t *db,
const char *tmpdir_abspath,
svn_boolean_t metadata_only,
svn_boolean_t is_move,
+ const svn_io_dirent2_t *dirent,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -314,6 +363,7 @@ copy_versioned_dir(svn_wc__db_t *db,
tmpdir_abspath,
FALSE /* file_copy */,
FALSE /* unversioned */,
+ dirent, SVN_INVALID_FILESIZE, 0,
cancel_func, cancel_baton,
scratch_pool, scratch_pool));
}
@@ -353,6 +403,7 @@ copy_versioned_dir(svn_wc__db_t *db,
SVN_ERR(svn_wc__db_read_children_info(&versioned_children,
&conflicted_children,
db, src_abspath,
+ FALSE /* base_tree_only */,
scratch_pool, iterpool));
for (hi = apr_hash_first(scratch_pool, versioned_children);
hi;
@@ -366,8 +417,8 @@ copy_versioned_dir(svn_wc__db_t *db,
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- child_name = svn__apr_hash_index_key(hi);
- info = svn__apr_hash_index_val(hi);
+ child_name = apr_hash_this_key(hi);
+ info = apr_hash_this_val(hi);
child_src_abspath = svn_dirent_join(src_abspath, child_name, iterpool);
child_dst_abspath = svn_dirent_join(dst_abspath, child_name, iterpool);
@@ -394,6 +445,12 @@ copy_versioned_dir(svn_wc__db_t *db,
tmpdir_abspath,
metadata_only, info->conflicted,
is_move,
+ disk_children
+ ? svn_hash_gets(disk_children,
+ child_name)
+ : NULL,
+ info->recorded_size,
+ info->recorded_time,
cancel_func, cancel_baton,
NULL, NULL,
iterpool));
@@ -403,6 +460,10 @@ copy_versioned_dir(svn_wc__db_t *db,
child_src_abspath, child_dst_abspath,
dst_op_root_abspath, tmpdir_abspath,
metadata_only, is_move,
+ disk_children
+ ? svn_hash_gets(disk_children,
+ child_name)
+ : NULL,
cancel_func, cancel_baton, NULL, NULL,
iterpool));
else
@@ -421,7 +482,7 @@ copy_versioned_dir(svn_wc__db_t *db,
child_dst_abspath, dst_op_root_abspath,
is_move, NULL, iterpool));
- /* Don't recurse on children while all we do is creating not-present
+ /* Don't recurse on children when all we do is creating not-present
children */
}
else if (info->status == svn_wc__db_status_incomplete)
@@ -467,7 +528,7 @@ copy_versioned_dir(svn_wc__db_t *db,
for (hi = apr_hash_first(scratch_pool, disk_children); hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
+ const char *name = apr_hash_this_key(hi);
const char *unver_src_abspath, *unver_dst_abspath;
svn_skel_t *work_item;
@@ -488,6 +549,7 @@ copy_versioned_dir(svn_wc__db_t *db,
SVN_ERR(copy_to_tmpdir(&work_item, NULL, db, unver_src_abspath,
unver_dst_abspath, tmpdir_abspath,
TRUE /* recursive */, TRUE /* unversioned */,
+ NULL, SVN_INVALID_FILESIZE, 0,
cancel_func, cancel_baton,
scratch_pool, iterpool));
@@ -507,10 +569,10 @@ copy_versioned_dir(svn_wc__db_t *db,
* The additional parameter IS_MOVE indicates whether this is a copy or
* a move operation.
*
- * If MOVE_DEGRADED_TO_COPY is not NULL and a move had to be degraded
- * to a copy, then set *MOVE_DEGRADED_TO_COPY. */
+ * If RECORD_MOVE_ON_DELETE is not NULL and a move had to be degraded
+ * to a copy, then set *RECORD_MOVE_ON_DELETE to FALSE. */
static svn_error_t *
-copy_or_move(svn_boolean_t *move_degraded_to_copy,
+copy_or_move(svn_boolean_t *record_move_on_delete,
svn_wc_context_t *wc_ctx,
const char *src_abspath,
const char *dst_abspath,
@@ -533,6 +595,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
svn_boolean_t within_one_wc;
svn_wc__db_status_t src_status;
svn_error_t *err;
+ svn_filesize_t recorded_size;
+ apr_time_t recorded_time;
SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
@@ -550,7 +614,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
err = svn_wc__db_read_info(&src_status, &src_db_kind, NULL,
&src_repos_relpath, &src_repos_root_url,
&src_repos_uuid, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ &recorded_size, &recorded_time,
NULL, &conflicted, NULL, NULL, NULL, NULL,
NULL, NULL,
db, src_abspath, scratch_pool, scratch_pool);
@@ -643,10 +708,13 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
scratch_pool, scratch_pool));
else
/* If not added, the node must have a base or we can't copy */
- SVN_ERR(svn_wc__db_scan_base_repos(NULL, &src_repos_root_url,
- &src_repos_uuid,
- db, src_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
+ &src_repos_root_url,
+ &src_repos_uuid, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ db, src_abspath,
+ scratch_pool, scratch_pool));
}
if (!dst_repos_root_url)
@@ -660,10 +728,13 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
scratch_pool, scratch_pool));
else
/* If not added, the node must have a base or we can't copy */
- SVN_ERR(svn_wc__db_scan_base_repos(NULL, &dst_repos_root_url,
- &dst_repos_uuid,
- db, dstdir_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL,
+ &dst_repos_root_url,
+ &dst_repos_uuid, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ db, dstdir_abspath,
+ scratch_pool, scratch_pool));
}
if (strcmp(src_repos_root_url, dst_repos_root_url) != 0
@@ -751,8 +822,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
if (is_move
&& !within_one_wc)
{
- if (move_degraded_to_copy)
- *move_degraded_to_copy = TRUE;
+ if (record_move_on_delete)
+ *record_move_on_delete = FALSE;
is_move = FALSE;
}
@@ -768,6 +839,7 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
err = copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath,
tmpdir_abspath,
metadata_only, conflicted, is_move,
+ NULL, recorded_size, recorded_time,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool);
@@ -795,14 +867,17 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy,
scratch_pool),
min_rev, max_rev);
+#ifndef RECORD_MIXED_MOVE
is_move = FALSE;
- if (move_degraded_to_copy)
- *move_degraded_to_copy = TRUE;
+ if (record_move_on_delete)
+ *record_move_on_delete = FALSE;
+#endif
}
}
err = copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath,
tmpdir_abspath, metadata_only, is_move,
+ NULL /* dirent */,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool);
@@ -871,7 +946,8 @@ remove_node_conflict_markers(svn_wc__db_t *db,
{
svn_skel_t *conflict;
- SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath,
+ SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
+ db, src_abspath,
scratch_pool, scratch_pool));
/* Do we have conflict markers that should be removed? */
@@ -923,6 +999,8 @@ static svn_error_t *
remove_all_conflict_markers(svn_wc__db_t *db,
const char *src_dir_abspath,
const char *dst_dir_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -936,14 +1014,18 @@ remove_all_conflict_markers(svn_wc__db_t *db,
artillery. */
SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db,
src_dir_abspath,
+ FALSE /* base_tree_only */,
scratch_pool, iterpool));
for (hi = apr_hash_first(scratch_pool, nodes);
hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- struct svn_wc__db_info_t *info = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ struct svn_wc__db_info_t *info = apr_hash_this_val(hi);
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
if (info->conflicted)
{
@@ -961,6 +1043,7 @@ remove_all_conflict_markers(svn_wc__db_t *db,
db,
svn_dirent_join(src_dir_abspath, name, iterpool),
svn_dirent_join(dst_dir_abspath, name, iterpool),
+ cancel_func, cancel_baton,
iterpool));
}
}
@@ -982,7 +1065,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
apr_pool_t *scratch_pool)
{
svn_wc__db_t *db = wc_ctx->db;
- svn_boolean_t move_degraded_to_copy = FALSE;
+ svn_boolean_t record_on_delete = TRUE;
svn_node_kind_t kind;
svn_boolean_t conflicted;
@@ -994,7 +1077,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
svn_dirent_dirname(dst_abspath, scratch_pool),
scratch_pool));
- SVN_ERR(copy_or_move(&move_degraded_to_copy,
+ SVN_ERR(copy_or_move(&record_on_delete,
wc_ctx, src_abspath, dst_abspath,
TRUE /* metadata_only */,
TRUE /* is_move */,
@@ -1018,7 +1101,25 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
is still in a valid state. So be careful when switching this over
to the workqueue. */
if (!metadata_only)
- SVN_ERR(svn_io_file_rename(src_abspath, dst_abspath, scratch_pool));
+ {
+ svn_error_t *err;
+
+ err = svn_error_trace(svn_io_file_rename(src_abspath, dst_abspath,
+ scratch_pool));
+
+ /* Let's try if we can keep wc.db consistent even when the move
+ fails. Deleting the target is a wc.db only operation, while
+ going forward (delaying the error) would try to change
+ conflict markers, which might also fail. */
+ if (err)
+ return svn_error_trace(
+ svn_error_compose_create(
+ err,
+ svn_wc__db_op_delete(wc_ctx->db, dst_abspath, NULL, TRUE,
+ NULL, NULL, cancel_func, cancel_baton,
+ NULL, NULL,
+ scratch_pool)));
+ }
SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
@@ -1030,6 +1131,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
if (kind == svn_node_dir)
SVN_ERR(remove_all_conflict_markers(db, src_abspath, dst_abspath,
+ cancel_func, cancel_baton,
scratch_pool));
if (conflicted)
@@ -1045,7 +1147,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx,
}
SVN_ERR(svn_wc__db_op_delete(db, src_abspath,
- move_degraded_to_copy ? NULL : dst_abspath,
+ record_on_delete ? dst_abspath : NULL,
TRUE /* delete_dir_externals */,
NULL /* conflict */, NULL /* work_items */,
cancel_func, cancel_baton,
diff --git a/subversion/libsvn_wc/crop.c b/subversion/libsvn_wc/crop.c
index a8d5ce2571ad..3a46b42d4be2 100644
--- a/subversion/libsvn_wc/crop.c
+++ b/subversion/libsvn_wc/crop.c
@@ -53,7 +53,7 @@ crop_children(svn_wc__db_t *db,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
const apr_array_header_t *children;
apr_pool_t *iterpool;
@@ -65,7 +65,7 @@ crop_children(svn_wc__db_t *db,
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- iterpool = svn_pool_create(pool);
+ iterpool = svn_pool_create(scratch_pool);
if (dir_depth == svn_depth_unknown)
dir_depth = svn_depth_infinity;
@@ -76,8 +76,8 @@ crop_children(svn_wc__db_t *db,
iterpool));
/* Looping over current directory's SVN entries: */
- SVN_ERR(svn_wc__db_read_children(&children, db, local_abspath, pool,
- iterpool));
+ SVN_ERR(svn_wc__db_base_get_children(&children, db, local_abspath,
+ scratch_pool, iterpool));
for (i = 0; i < children->nelts; i++)
{
@@ -86,6 +86,8 @@ crop_children(svn_wc__db_t *db,
svn_wc__db_status_t child_status;
svn_node_kind_t kind;
svn_depth_t child_depth;
+ svn_boolean_t have_work;
+ svn_depth_t remove_below;
svn_pool_clear(iterpool);
@@ -96,86 +98,80 @@ crop_children(svn_wc__db_t *db,
NULL,NULL, NULL, NULL, &child_depth,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, &have_work,
db, child_abspath, iterpool, iterpool));
- if (child_status == svn_wc__db_status_server_excluded ||
- child_status == svn_wc__db_status_excluded ||
- child_status == svn_wc__db_status_not_present)
+ if (have_work)
+ {
+ svn_boolean_t modified, all_deletes;
+
+ if (child_status != svn_wc__db_status_deleted)
+ continue; /* Leave local additions alone */
+
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_deletes,
+ db, child_abspath, FALSE,
+ cancel_func, cancel_baton,
+ iterpool));
+
+ if (modified && !all_deletes)
+ continue; /* Something interesting is still there */
+ }
+
+ remove_below = (kind == svn_node_dir)
+ ? svn_depth_immediates
+ : svn_depth_files;
+
+ if ((child_status == svn_wc__db_status_server_excluded ||
+ child_status == svn_wc__db_status_excluded ||
+ child_status == svn_wc__db_status_not_present))
{
- svn_depth_t remove_below = (kind == svn_node_dir)
- ? svn_depth_immediates
- : svn_depth_files;
if (new_depth < remove_below)
SVN_ERR(svn_wc__db_base_remove(db, child_abspath,
FALSE /* keep_as_working */,
- FALSE /* queue_deletes */,
- FALSE /* remove_locks */,
+ FALSE, FALSE,
SVN_INVALID_REVNUM,
NULL, NULL, iterpool));
- continue;
+ continue; /* No recurse */
}
- else if (kind == svn_node_file)
+
+ if (new_depth < remove_below)
{
- if (new_depth == svn_depth_empty)
- SVN_ERR(svn_wc__db_op_remove_node(NULL,
- db, child_abspath,
- TRUE /* destroy */,
- FALSE /* destroy_changes */,
- SVN_INVALID_REVNUM,
- svn_wc__db_status_not_present,
- svn_node_none,
- NULL, NULL,
+ svn_boolean_t modified, all_deletes;
+
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_deletes,
+ db, child_abspath, FALSE,
cancel_func, cancel_baton,
iterpool));
- else
- continue;
- }
- else if (kind == svn_node_dir)
- {
- if (new_depth < svn_depth_immediates)
- {
- SVN_ERR(svn_wc__db_op_remove_node(NULL,
- db, child_abspath,
- TRUE /* destroy */,
- FALSE /* destroy_changes */,
- SVN_INVALID_REVNUM,
- svn_wc__db_status_not_present,
- svn_node_none,
- NULL, NULL,
- cancel_func, cancel_baton,
- iterpool));
- }
- else
+ if (!modified || all_deletes)
{
- SVN_ERR(crop_children(db,
- child_abspath,
- child_depth,
- svn_depth_empty,
- notify_func,
- notify_baton,
- cancel_func,
- cancel_baton,
- iterpool));
- continue;
+ SVN_ERR(svn_wc__db_base_remove(db, child_abspath,
+ FALSE, FALSE, FALSE,
+ SVN_INVALID_REVNUM,
+ NULL, NULL, iterpool));
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify(child_abspath,
+ svn_wc_notify_delete,
+ iterpool);
+ (*notify_func)(notify_baton, notify, iterpool);
+ }
+
+ continue; /* No recurse */
}
- }
- else
- {
- return svn_error_createf
- (SVN_ERR_NODE_UNKNOWN_KIND, NULL, _("Unknown node kind for '%s'"),
- svn_dirent_local_style(child_abspath, iterpool));
+
+ /* Fall through: recurse:*/
}
- if (notify_func)
+ if (kind == svn_node_dir)
{
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(child_abspath,
- svn_wc_notify_delete,
- iterpool);
- (*notify_func)(notify_baton, notify, iterpool);
+ SVN_ERR(crop_children(db, child_abspath,
+ child_depth, svn_depth_empty,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ iterpool));
}
}
@@ -197,6 +193,8 @@ svn_wc_exclude(svn_wc_context_t *wc_ctx,
svn_wc__db_status_t status;
svn_node_kind_t kind;
svn_revnum_t revision;
+ svn_depth_t depth;
+ svn_boolean_t modified, all_deletes;
const char *repos_relpath, *repos_root, *repos_uuid;
SVN_ERR(svn_wc__db_is_switched(&is_root, &is_switched, NULL,
@@ -221,7 +219,7 @@ svn_wc_exclude(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_wc__db_read_info(&status, &kind, &revision, &repos_relpath,
&repos_root, &repos_uuid, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ &depth, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
wc_ctx->db, local_abspath,
@@ -258,29 +256,41 @@ svn_wc_exclude(svn_wc_context_t *wc_ctx,
break; /* Ok to exclude */
}
- /* Remove all working copy data below local_abspath */
- SVN_ERR(svn_wc__db_op_remove_node(NULL,
- wc_ctx->db, local_abspath,
- TRUE /* destroy */,
- FALSE /* destroy_changes */,
- revision,
- svn_wc__db_status_excluded,
- kind,
- NULL, NULL,
- cancel_func, cancel_baton,
- scratch_pool));
-
- SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
- cancel_func, cancel_baton,
- scratch_pool));
-
- if (notify_func)
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_deletes,
+ wc_ctx->db, local_abspath, FALSE,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
+ if (!modified || all_deletes)
+ {
+ /* Remove all working copy data below local_abspath */
+ SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath,
+ FALSE /* keep_working */,
+ FALSE, TRUE,
+ revision,
+ NULL, NULL,
+ scratch_pool));
+
+ SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify(local_abspath,
+ svn_wc_notify_exclude,
+ scratch_pool);
+ notify_func(notify_baton, notify, scratch_pool);
+ }
+ }
+ else
{
- svn_wc_notify_t *notify;
- notify = svn_wc_create_notify(local_abspath,
- svn_wc_notify_exclude,
- scratch_pool);
- notify_func(notify_baton, notify, scratch_pool);
+ /* Do the next best thing: retry below this path */
+ SVN_ERR(crop_children(wc_ctx->db, local_abspath, depth, svn_depth_empty,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ scratch_pool));
}
return SVN_NO_ERROR;
diff --git a/subversion/libsvn_wc/delete.c b/subversion/libsvn_wc/delete.c
index 37c8af08198c..82ae9382d6dc 100644
--- a/subversion/libsvn_wc/delete.c
+++ b/subversion/libsvn_wc/delete.c
@@ -135,7 +135,8 @@ create_delete_wq_items(svn_skel_t **work_items,
const apr_array_header_t *markers;
int i;
- SVN_ERR(svn_wc__db_read_conflict(&conflict, db, local_abspath,
+ SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL,
+ db, local_abspath,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_markers(&markers, db, local_abspath,
@@ -431,9 +432,6 @@ svn_wc__internal_remove_from_revision_control(svn_wc__db_t *db,
db, local_abspath,
destroy_wf /* destroy_wc */,
destroy_wf /* destroy_changes */,
- SVN_INVALID_REVNUM,
- svn_wc__db_status_not_present,
- svn_node_none,
NULL, NULL,
cancel_func, cancel_baton,
scratch_pool));
diff --git a/subversion/libsvn_wc/deprecated.c b/subversion/libsvn_wc/deprecated.c
index 79cdb3030cbc..e6db56887660 100644
--- a/subversion/libsvn_wc/deprecated.c
+++ b/subversion/libsvn_wc/deprecated.c
@@ -127,7 +127,7 @@ gather_traversal_info(svn_wc_context_t *wc_ctx,
hi;
hi = apr_hash_next(hi))
{
- const char *node_abspath = svn__apr_hash_index_key(hi);
+ const char *node_abspath = apr_hash_this_key(hi);
const char *relpath;
relpath = svn_dirent_join(path,
@@ -137,11 +137,11 @@ gather_traversal_info(svn_wc_context_t *wc_ctx,
if (gather_as_old)
svn_hash_sets(traversal_info->externals_old, relpath,
- svn__apr_hash_index_val(hi));
+ apr_hash_this_val(hi));
if (gather_as_new)
svn_hash_sets(traversal_info->externals_new, relpath,
- svn__apr_hash_index_val(hi));
+ apr_hash_this_val(hi));
svn_hash_sets(traversal_info->depths, relpath,
svn_hash_gets(ambient_depths, node_abspath));
@@ -652,6 +652,24 @@ svn_wc_get_pristine_contents(svn_stream_t **contents,
return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}
+svn_error_t *
+svn_wc_queue_committed3(svn_wc_committed_queue_t *queue,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_boolean_t recurse,
+ const apr_array_header_t *wcprop_changes,
+ svn_boolean_t remove_lock,
+ svn_boolean_t remove_changelist,
+ const svn_checksum_t *sha1_checksum,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc_queue_committed4(queue, wc_ctx, local_abspath,
+ recurse, TRUE /* is_committed */,
+ wcprop_changes, remove_lock,
+ remove_changelist, sha1_checksum,
+ scratch_pool));
+}
svn_error_t *
svn_wc_queue_committed2(svn_wc_committed_queue_t *queue,
@@ -668,7 +686,9 @@ svn_wc_queue_committed2(svn_wc_committed_queue_t *queue,
const char *local_abspath;
const svn_checksum_t *sha1_checksum = NULL;
- SVN_ERR(svn_wc_context_create(&wc_ctx, NULL, scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL,
+ svn_wc__adm_get_db(adm_access),
+ scratch_pool));
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, scratch_pool));
if (md5_checksum != NULL)
@@ -759,15 +779,11 @@ svn_wc_process_committed4(const char *path,
const char *local_abspath;
const svn_checksum_t *md5_checksum;
const svn_checksum_t *sha1_checksum = NULL;
- apr_time_t new_date;
- apr_hash_t *wcprop_changes_hash;
+ svn_wc_context_t *wc_ctx;
+ svn_wc_committed_queue_t *queue;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
-
- if (rev_date)
- SVN_ERR(svn_time_from_cstring(&new_date, rev_date, pool));
- else
- new_date = 0;
+ SVN_ERR(svn_wc__context_create_with_db(&wc_ctx, NULL, db, pool));
if (digest)
md5_checksum = svn_checksum__from_digest_md5(digest, pool);
@@ -790,15 +806,20 @@ svn_wc_process_committed4(const char *path,
SVN_ERR(err);
}
- wcprop_changes_hash = svn_wc__prop_array_to_hash(wcprop_changes, pool);
- SVN_ERR(svn_wc__process_committed_internal(db, local_abspath, recurse, TRUE,
- new_revnum, new_date, rev_author,
- wcprop_changes_hash,
- !remove_lock, !remove_changelist,
- sha1_checksum, NULL, pool));
+ queue = svn_wc_committed_queue_create(pool);
+ SVN_ERR(svn_wc_queue_committed3(queue, wc_ctx, local_abspath, recurse,
+ wcprop_changes, remove_lock,
+ remove_changelist,
+ sha1_checksum /* or NULL if not modified
+ or directory */,
+ pool));
+
+ SVN_ERR(svn_wc_process_committed_queue2(queue, wc_ctx,
+ new_revnum, rev_date, rev_author,
+ NULL, NULL /* cancel */,
+ pool));
- /* Run the log file(s) we just created. */
- return svn_error_trace(svn_wc__wq_run(db, local_abspath, NULL, NULL, pool));
+ return svn_error_trace(svn_wc_context_destroy(wc_ctx));
}
@@ -925,6 +946,19 @@ svn_wc_delete(const char *path,
}
svn_error_t *
+svn_wc_add_from_disk2(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ const apr_hash_t *props,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ SVN_ERR(svn_wc_add_from_disk3(wc_ctx, local_abspath, props, FALSE,
+ notify_func, notify_baton, scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_wc_add_from_disk(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_wc_notify_func2_t notify_func,
@@ -1025,6 +1059,30 @@ svn_wc_add(const char *path,
compat_call_notify_func, &nb, pool);
}
+/*** From revert.c ***/
+svn_error_t *
+svn_wc_revert4(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_depth_t depth,
+ svn_boolean_t use_commit_times,
+ const apr_array_header_t *changelist_filter,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_wc_notify_func2_t notify_func,
+ void *notify_baton,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(svn_wc_revert5(wc_ctx, local_abspath,
+ depth,
+ use_commit_times,
+ changelist_filter,
+ FALSE /* clear_changelists */,
+ FALSE /* metadata_only */,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
+}
+
svn_error_t *
svn_wc_revert3(const char *path,
svn_wc_adm_access_t *parent_access,
@@ -1966,16 +2024,37 @@ svn_wc_get_diff_editor6(const svn_delta_editor_t **editor,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ const svn_diff_tree_processor_t *diff_processor;
+
+ /* --git implies --show-copies-as-adds */
+ if (use_git_diff_format)
+ show_copies_as_adds = TRUE;
+
+ /* --show-copies-as-adds implies --notice-ancestry */
+ if (show_copies_as_adds)
+ ignore_ancestry = FALSE;
+
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
+ callbacks, callback_baton, TRUE,
+ result_pool, scratch_pool));
+
+ if (reverse_order)
+ diff_processor = svn_diff__tree_processor_reverse_create(
+ diff_processor, NULL, result_pool);
+
+ if (! show_copies_as_adds)
+ diff_processor = svn_diff__tree_processor_copy_as_changed_create(
+ diff_processor, result_pool);
+
return svn_error_trace(
svn_wc__get_diff_editor(editor, edit_baton,
wc_ctx,
anchor_abspath, target,
depth,
- ignore_ancestry, show_copies_as_adds,
use_git_diff_format, use_text_base,
reverse_order, server_performs_filtering,
changelist_filter,
- callbacks, callback_baton,
+ diff_processor,
cancel_func, cancel_baton,
result_pool, scratch_pool));
}
@@ -2633,6 +2712,146 @@ svn_wc_props_modified_p(svn_boolean_t *modified_p,
}
+svn_error_t *
+svn_wc__status2_from_3(svn_wc_status2_t **status,
+ const svn_wc_status3_t *old_status,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const svn_wc_entry_t *entry = NULL;
+
+ if (old_status == NULL)
+ {
+ *status = NULL;
+ return SVN_NO_ERROR;
+ }
+
+ *status = apr_pcalloc(result_pool, sizeof(**status));
+
+ if (old_status->versioned)
+ {
+ svn_error_t *err;
+ err= svn_wc__get_entry(&entry, wc_ctx->db, local_abspath, FALSE,
+ svn_node_unknown, result_pool, scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND)
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+ }
+
+ (*status)->entry = entry;
+ (*status)->copied = old_status->copied;
+ (*status)->repos_lock = svn_lock_dup(old_status->repos_lock, result_pool);
+
+ if (old_status->repos_relpath)
+ (*status)->url = svn_path_url_add_component2(old_status->repos_root_url,
+ old_status->repos_relpath,
+ result_pool);
+ (*status)->ood_last_cmt_rev = old_status->ood_changed_rev;
+ (*status)->ood_last_cmt_date = old_status->ood_changed_date;
+ (*status)->ood_kind = old_status->ood_kind;
+ (*status)->ood_last_cmt_author = old_status->ood_changed_author;
+
+ if (old_status->conflicted)
+ {
+ const svn_wc_conflict_description2_t *tree_conflict2;
+ SVN_ERR(svn_wc__get_tree_conflict(&tree_conflict2, wc_ctx, local_abspath,
+ scratch_pool, scratch_pool));
+ (*status)->tree_conflict = svn_wc__cd2_to_cd(tree_conflict2, result_pool);
+ }
+
+ (*status)->switched = old_status->switched;
+
+ (*status)->text_status = old_status->node_status;
+ (*status)->prop_status = old_status->prop_status;
+
+ (*status)->repos_text_status = old_status->repos_node_status;
+ (*status)->repos_prop_status = old_status->repos_prop_status;
+
+ /* Some values might be inherited from properties */
+ if (old_status->node_status == svn_wc_status_modified
+ || old_status->node_status == svn_wc_status_conflicted)
+ (*status)->text_status = old_status->text_status;
+
+ /* (Currently a no-op, but just make sure it is ok) */
+ if (old_status->repos_node_status == svn_wc_status_modified
+ || old_status->repos_node_status == svn_wc_status_conflicted)
+ (*status)->repos_text_status = old_status->repos_text_status;
+
+ if (old_status->node_status == svn_wc_status_added)
+ (*status)->prop_status = svn_wc_status_none; /* No separate info */
+
+ /* Find pristine_text_status value */
+ switch (old_status->text_status)
+ {
+ case svn_wc_status_none:
+ case svn_wc_status_normal:
+ case svn_wc_status_modified:
+ (*status)->pristine_text_status = old_status->text_status;
+ break;
+ case svn_wc_status_conflicted:
+ default:
+ /* ### Fetch compare data, or fall back to the documented
+ not retrieved behavior? */
+ (*status)->pristine_text_status = svn_wc_status_none;
+ break;
+ }
+
+ /* Find pristine_prop_status value */
+ switch (old_status->prop_status)
+ {
+ case svn_wc_status_none:
+ case svn_wc_status_normal:
+ case svn_wc_status_modified:
+ if (old_status->node_status != svn_wc_status_added
+ && old_status->node_status != svn_wc_status_deleted
+ && old_status->node_status != svn_wc_status_replaced)
+ {
+ (*status)->pristine_prop_status = old_status->prop_status;
+ }
+ else
+ (*status)->pristine_prop_status = svn_wc_status_none;
+ break;
+ case svn_wc_status_conflicted:
+ default:
+ /* ### Fetch compare data, or fall back to the documented
+ not retrieved behavior? */
+ (*status)->pristine_prop_status = svn_wc_status_none;
+ break;
+ }
+
+ if (old_status->versioned
+ && old_status->conflicted
+ && old_status->node_status != svn_wc_status_obstructed
+ && (old_status->kind == svn_node_file
+ || old_status->node_status != svn_wc_status_missing))
+ {
+ svn_boolean_t text_conflict_p, prop_conflict_p;
+
+ /* The entry says there was a conflict, but the user might have
+ marked it as resolved by deleting the artifact files, so check
+ for that. */
+ SVN_ERR(svn_wc__internal_conflicted_p(&text_conflict_p,
+ &prop_conflict_p,
+ NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool));
+
+ if (text_conflict_p)
+ (*status)->text_status = svn_wc_status_conflicted;
+
+ if (prop_conflict_p)
+ (*status)->prop_status = svn_wc_status_conflicted;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+
/*** From status.c ***/
struct status4_wrapper_baton
@@ -2698,9 +2917,9 @@ svn_wc_get_status_editor5(const svn_delta_editor_t **editor,
wc_ctx,
anchor_abspath,
target_basename,
- depth,
- get_all, no_ignore,
- depth_as_sticky,
+ depth, get_all,
+ TRUE, /* check_working_copy */
+ no_ignore, depth_as_sticky,
server_performs_filtering,
ignore_patterns,
status_func, status_baton,
@@ -4044,7 +4263,26 @@ svn_wc_relocate(const char *path,
}
-/*** From log.c ***/
+/*** From log.c / cleanup.c ***/
+
+svn_error_t *
+svn_wc_cleanup3(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ return svn_error_trace(
+ svn_wc_cleanup4(wc_ctx,
+ local_abspath,
+ TRUE /* break_locks */,
+ TRUE /* fix_recorded_timestamps */,
+ TRUE /* clear_dav_cache */,
+ TRUE /* clean_pristines */,
+ cancel_func, cancel_baton,
+ NULL, NULL /* notify */,
+ scratch_pool));
+}
svn_error_t *
svn_wc_cleanup2(const char *path,
@@ -4570,13 +4808,11 @@ svn_wc_read_kind(svn_node_kind_t *kind,
TRUE /* show_deleted */,
show_hidden,
scratch_pool));
+}
- /*if (db_kind == svn_node_dir)
- *kind = svn_node_dir;
- else if (db_kind == svn_node_file || db_kind == svn_node_symlink)
- *kind = svn_node_file;
- else
- *kind = svn_node_none;*/
-
- return SVN_NO_ERROR;
+svn_wc_conflict_description2_t *
+svn_wc__conflict_description2_dup(const svn_wc_conflict_description2_t *conflict,
+ apr_pool_t *pool)
+{
+ return svn_wc_conflict_description2_dup(conflict, pool);
}
diff --git a/subversion/libsvn_wc/diff.h b/subversion/libsvn_wc/diff.h
index 3ddada67d5d4..2df88e16a3e3 100644
--- a/subversion/libsvn_wc/diff.h
+++ b/subversion/libsvn_wc/diff.h
@@ -39,7 +39,7 @@ extern "C" {
#endif /* __cplusplus */
/* A function to diff locally added and locally copied files.
-
+
Reports the file LOCAL_ABSPATH as ADDED file with relpath RELPATH to
PROCESSOR with as parent baton PROCESSOR_PARENT_BATON.
@@ -60,7 +60,7 @@ svn_wc__diff_local_only_file(svn_wc__db_t *db,
apr_pool_t *scratch_pool);
/* A function to diff locally added and locally copied directories.
-
+
Reports the directory LOCAL_ABSPATH and everything below it (limited by
DEPTH) as added with relpath RELPATH to PROCESSOR with as parent baton
PROCESSOR_PARENT_BATON.
diff --git a/subversion/libsvn_wc/diff_editor.c b/subversion/libsvn_wc/diff_editor.c
index c9078ed7de23..fc059a5d4dea 100644
--- a/subversion/libsvn_wc/diff_editor.c
+++ b/subversion/libsvn_wc/diff_editor.c
@@ -64,10 +64,11 @@
#include "svn_hash.h"
#include "svn_sorts.h"
-#include "private/svn_subr_private.h"
-#include "private/svn_wc_private.h"
#include "private/svn_diff_tree.h"
#include "private/svn_editor.h"
+#include "private/svn_sorts_private.h"
+#include "private/svn_subr_private.h"
+#include "private/svn_wc_private.h"
#include "wc.h"
#include "props.h"
@@ -241,10 +242,9 @@ make_edit_baton(struct edit_baton_t **edit_baton,
svn_wc__db_t *db,
const char *anchor_abspath,
const char *target,
- const svn_diff_tree_processor_t *processor,
+ const svn_diff_tree_processor_t *diff_processor,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
- svn_boolean_t show_copies_as_adds,
svn_boolean_t use_text_base,
svn_boolean_t reverse_order,
svn_cancel_func_t cancel_func,
@@ -255,22 +255,11 @@ make_edit_baton(struct edit_baton_t **edit_baton,
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
- if (reverse_order)
- processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
-
- /* --show-copies-as-adds implies --notice-ancestry */
- if (show_copies_as_adds)
- ignore_ancestry = FALSE;
-
- if (! show_copies_as_adds)
- processor = svn_diff__tree_processor_copy_as_changed_create(processor,
- pool);
-
eb = apr_pcalloc(pool, sizeof(*eb));
eb->db = db;
eb->anchor_abspath = apr_pstrdup(pool, anchor_abspath);
eb->target = apr_pstrdup(pool, target);
- eb->processor = processor;
+ eb->processor = diff_processor;
eb->depth = depth;
eb->ignore_ancestry = ignore_ancestry;
eb->local_before_remote = reverse_order;
@@ -566,6 +555,7 @@ ensure_local_info(struct dir_baton_t *db,
SVN_ERR(svn_wc__db_read_children_info(&db->local_info, &conflicts,
db->eb->db, db->local_abspath,
+ FALSE /* base_tree_only */,
db->pool, scratch_pool));
return SVN_NO_ERROR;
@@ -655,6 +645,7 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
db, local_abspath,
+ FALSE /* base_tree_only */,
scratch_pool, iterpool));
children = svn_sort__hash(nodes, svn_sort_compare_items_lexically,
@@ -703,6 +694,9 @@ walk_local_nodes_diff(struct edit_baton_t *eb,
if (!info->have_base)
{
local_only = TRUE; /* Only report additions */
+
+ if (info->status == svn_wc__db_status_deleted)
+ continue; /* Nothing added (deleted copy) */
}
else if (info->status == svn_wc__db_status_normal)
{
@@ -1042,9 +1036,6 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
svn_boolean_t skip_children = FALSE;
svn_diff_source_t *right_src = svn_diff__source_create(SVN_INVALID_REVNUM,
scratch_pool);
- svn_depth_t depth_below_here = depth;
- apr_hash_t *nodes;
- apr_hash_t *conflicts;
SVN_ERR(svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
@@ -1098,70 +1089,82 @@ svn_wc__diff_local_only_dir(svn_wc__db_t *db,
processor_parent_baton,
processor,
scratch_pool, iterpool));
- /* ### skip_children is not used */
-
- SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, local_abspath,
- scratch_pool, iterpool));
-
- if (depth_below_here == svn_depth_immediates)
- depth_below_here = svn_depth_empty;
- children = svn_sort__hash(nodes, svn_sort_compare_items_lexically,
- scratch_pool);
-
- for (i = 0; i < children->nelts; i++)
+ if ((depth > svn_depth_empty || depth == svn_depth_unknown)
+ && ! skip_children)
{
- svn_sort__item_t *item = &APR_ARRAY_IDX(children, i, svn_sort__item_t);
- const char *name = item->key;
- struct svn_wc__db_info_t *info = item->value;
- const char *child_abspath;
- const char *child_relpath;
+ svn_depth_t depth_below_here = depth;
+ apr_hash_t *nodes;
+ apr_hash_t *conflicts;
- svn_pool_clear(iterpool);
+ if (depth_below_here == svn_depth_immediates)
+ depth_below_here = svn_depth_empty;
+
+ SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
+ db, local_abspath,
+ FALSE /* base_tree_only */,
+ scratch_pool, iterpool));
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
- child_abspath = svn_dirent_join(local_abspath, name, iterpool);
+ children = svn_sort__hash(nodes, svn_sort_compare_items_lexically,
+ scratch_pool);
- if (NOT_PRESENT(info->status))
+ for (i = 0; i < children->nelts; i++)
{
- continue;
- }
+ svn_sort__item_t *item = &APR_ARRAY_IDX(children, i, svn_sort__item_t);
+ const char *name = item->key;
+ struct svn_wc__db_info_t *info = item->value;
+ const char *child_abspath;
+ const char *child_relpath;
- /* If comparing against WORKING, skip entries that are
- schedule-deleted - they don't really exist. */
- if (!diff_pristine && info->status == svn_wc__db_status_deleted)
- continue;
+ svn_pool_clear(iterpool);
- child_relpath = svn_relpath_join(relpath, name, iterpool);
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- switch (info->kind)
- {
- case svn_node_file:
- case svn_node_symlink:
- SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
- child_relpath,
- processor, pdb,
- diff_pristine,
- cancel_func, cancel_baton,
- scratch_pool));
- break;
+ child_abspath = svn_dirent_join(local_abspath, name, iterpool);
- case svn_node_dir:
- if (depth > svn_depth_files || depth == svn_depth_unknown)
+ if (NOT_PRESENT(info->status))
{
- SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
- child_relpath, depth_below_here,
- processor, pdb,
- diff_pristine,
- cancel_func, cancel_baton,
- iterpool));
+ continue;
}
- break;
- default:
- break;
+ /* If comparing against WORKING, skip entries that are
+ schedule-deleted - they don't really exist. */
+ if (!diff_pristine && info->status == svn_wc__db_status_deleted)
+ continue;
+
+ child_relpath = svn_relpath_join(relpath, name, iterpool);
+
+ switch (info->kind)
+ {
+ case svn_node_file:
+ case svn_node_symlink:
+ SVN_ERR(svn_wc__diff_local_only_file(db, child_abspath,
+ child_relpath,
+ processor, pdb,
+ diff_pristine,
+ cancel_func, cancel_baton,
+ scratch_pool));
+ break;
+
+ case svn_node_dir:
+ if (depth > svn_depth_files || depth == svn_depth_unknown)
+ {
+ SVN_ERR(svn_wc__diff_local_only_dir(db, child_abspath,
+ child_relpath,
+ depth_below_here,
+ processor, pdb,
+ diff_pristine,
+ cancel_func,
+ cancel_baton,
+ iterpool));
+ }
+ break;
+
+ default:
+ break;
+ }
}
}
@@ -2193,7 +2196,7 @@ change_file_prop(void *file_baton,
propchange = apr_array_push(fb->propchanges);
propchange->name = apr_pstrdup(fb->pool, name);
- propchange->value = value ? svn_string_dup(value, fb->pool) : NULL;
+ propchange->value = svn_string_dup(value, fb->pool);
return SVN_NO_ERROR;
}
@@ -2218,7 +2221,7 @@ change_dir_prop(void *dir_baton,
propchange = apr_array_push(db->propchanges);
propchange->name = apr_pstrdup(db->pool, name);
- propchange->value = value ? svn_string_dup(value, db->pool) : NULL;
+ propchange->value = svn_string_dup(value, db->pool);
return SVN_NO_ERROR;
}
@@ -2257,14 +2260,11 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
const char *target,
svn_depth_t depth,
svn_boolean_t ignore_ancestry,
- svn_boolean_t show_copies_as_adds,
- svn_boolean_t use_git_diff_format,
svn_boolean_t use_text_base,
svn_boolean_t reverse_order,
svn_boolean_t server_performs_filtering,
const apr_array_header_t *changelist_filter,
- const svn_wc_diff_callbacks4_t *callbacks,
- void *callback_baton,
+ const svn_diff_tree_processor_t *diff_processor,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *result_pool,
@@ -2277,18 +2277,9 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
struct svn_wc__shim_fetch_baton_t *sfb;
svn_delta_shim_callbacks_t *shim_callbacks =
svn_delta_shim_callbacks_default(result_pool);
- const svn_diff_tree_processor_t *diff_processor;
SVN_ERR_ASSERT(svn_dirent_is_absolute(anchor_abspath));
- /* --git implies --show-copies-as-adds */
- if (use_git_diff_format)
- show_copies_as_adds = TRUE;
-
- SVN_ERR(svn_wc__wrap_diff_callbacks(&diff_processor,
- callbacks, callback_baton, TRUE,
- result_pool, scratch_pool));
-
/* Apply changelist filtering to the output */
if (changelist_filter && changelist_filter->nelts)
{
@@ -2305,7 +2296,7 @@ svn_wc__get_diff_editor(const svn_delta_editor_t **editor,
wc_ctx->db,
anchor_abspath, target,
diff_processor,
- depth, ignore_ancestry, show_copies_as_adds,
+ depth, ignore_ancestry,
use_text_base, reverse_order,
cancel_func, cancel_baton,
result_pool));
@@ -2458,8 +2449,8 @@ wrap_dir_opened(void **new_dir_baton,
/* svn_diff_tree_processor_t function */
static svn_error_t *
wrap_dir_added(const char *relpath,
- const svn_diff_source_t *right_source,
const svn_diff_source_t *copyfrom_source,
+ const svn_diff_source_t *right_source,
/*const*/ apr_hash_t *copyfrom_props,
/*const*/ apr_hash_t *right_props,
void *dir_baton,
diff --git a/subversion/libsvn_wc/diff_local.c b/subversion/libsvn_wc/diff_local.c
index 22b498ffdb29..e1cb3294b4ba 100644
--- a/subversion/libsvn_wc/diff_local.c
+++ b/subversion/libsvn_wc/diff_local.c
@@ -1,6 +1,6 @@
/*
- * diff_pristine.c -- A simple diff walker which compares local files against
- * their pristine versions.
+ * diff_local.c -- A simple diff walker which compares local files against
+ * their pristine versions.
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -41,8 +41,8 @@
#include "private/svn_diff_tree.h"
#include "wc.h"
+#include "wc_db.h"
#include "props.h"
-#include "translate.h"
#include "diff.h"
#include "svn_private_config.h"
@@ -89,9 +89,6 @@ struct diff_baton
/* Should this diff ignore node ancestry? */
svn_boolean_t ignore_ancestry;
- /* Should this diff not compare copied files with their source? */
- svn_boolean_t show_copies_as_adds;
-
/* Cancel function/baton */
svn_cancel_func_t cancel_func;
void *cancel_baton;
@@ -119,17 +116,17 @@ ensure_state(struct diff_baton *eb,
if (! relpath)
return SVN_NO_ERROR;
- /* Don't recurse on the anchor, as that might loop infinately because
+ /* Don't recurse on the anchor, as that might loop infinitely because
svn_dirent_dirname("/",...) -> "/"
svn_dirent_dirname("C:/",...) -> "C:/" (Windows) */
if (*relpath)
SVN_ERR(ensure_state(eb,
- svn_dirent_dirname(local_abspath,scratch_pool),
+ svn_dirent_dirname(local_abspath, scratch_pool),
FALSE,
scratch_pool));
}
else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
- SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath,scratch_pool),
+ SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath, scratch_pool),
FALSE,
scratch_pool));
else
@@ -421,23 +418,22 @@ diff_status_callback(void *baton,
/* Public Interface */
svn_error_t *
-svn_wc_diff6(svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- const svn_wc_diff_callbacks4_t *callbacks,
- void *callback_baton,
- svn_depth_t depth,
- svn_boolean_t ignore_ancestry,
- svn_boolean_t show_copies_as_adds,
- svn_boolean_t use_git_diff_format,
- const apr_array_header_t *changelist_filter,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *scratch_pool)
+svn_wc__diff7(const char **root_relpath,
+ svn_boolean_t *root_is_dir,
+ svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ const apr_array_header_t *changelist_filter,
+ const svn_diff_tree_processor_t *diff_processor,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
struct diff_baton eb = { 0 };
svn_node_kind_t kind;
svn_boolean_t get_all;
- const svn_diff_tree_processor_t *processor;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
SVN_ERR(svn_wc__db_read_kind(&kind, wc_ctx->db, local_abspath,
@@ -446,30 +442,27 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
FALSE /* show_hidden */,
scratch_pool));
- if (kind == svn_node_dir)
- eb.anchor_abspath = local_abspath;
- else
- eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
-
- SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
- callbacks, callback_baton, TRUE,
- scratch_pool, scratch_pool));
-
- if (use_git_diff_format)
- show_copies_as_adds = TRUE;
- if (show_copies_as_adds)
- ignore_ancestry = FALSE;
+ eb.anchor_abspath = local_abspath;
+ if (root_relpath)
+ {
+ svn_boolean_t is_wcroot;
+ SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot,
+ wc_ctx->db, local_abspath, scratch_pool));
- /*
- if (reverse_order)
- processor = svn_diff__tree_processor_reverse_create(processor, NULL, pool);
- */
+ if (!is_wcroot)
+ eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
+ }
+ else if (kind != svn_node_dir)
+ eb.anchor_abspath = svn_dirent_dirname(local_abspath, scratch_pool);
- if (! show_copies_as_adds && !use_git_diff_format)
- processor = svn_diff__tree_processor_copy_as_changed_create(processor,
- scratch_pool);
+ if (root_relpath)
+ *root_relpath = apr_pstrdup(result_pool,
+ svn_dirent_skip_ancestor(eb.anchor_abspath,
+ local_abspath));
+ if (root_is_dir)
+ *root_is_dir = (kind == svn_node_dir);
/* Apply changelist filtering to the output */
if (changelist_filter && changelist_filter->nelts)
@@ -477,19 +470,18 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
apr_hash_t *changelist_hash;
SVN_ERR(svn_hash_from_cstring_keys(&changelist_hash, changelist_filter,
- scratch_pool));
- processor = svn_wc__changelist_filter_tree_processor_create(
- processor, wc_ctx, local_abspath,
- changelist_hash, scratch_pool);
+ result_pool));
+ diff_processor = svn_wc__changelist_filter_tree_processor_create(
+ diff_processor, wc_ctx, local_abspath,
+ changelist_hash, result_pool);
}
eb.db = wc_ctx->db;
- eb.processor = processor;
+ eb.processor = diff_processor;
eb.ignore_ancestry = ignore_ancestry;
- eb.show_copies_as_adds = show_copies_as_adds;
eb.pool = scratch_pool;
- if (show_copies_as_adds || use_git_diff_format || !ignore_ancestry)
+ if (ignore_ancestry)
get_all = TRUE; /* We need unmodified descendants of copies */
else
get_all = FALSE;
@@ -512,22 +504,22 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
if (!ns->skip)
{
if (ns->propchanges)
- SVN_ERR(processor->dir_changed(ns->relpath,
- ns->left_src,
- ns->right_src,
- ns->left_props,
- ns->right_props,
- ns->propchanges,
- ns->baton,
- processor,
- ns->pool));
+ SVN_ERR(diff_processor->dir_changed(ns->relpath,
+ ns->left_src,
+ ns->right_src,
+ ns->left_props,
+ ns->right_props,
+ ns->propchanges,
+ ns->baton,
+ diff_processor,
+ ns->pool));
else
- SVN_ERR(processor->dir_closed(ns->relpath,
- ns->left_src,
- ns->right_src,
- ns->baton,
- processor,
- ns->pool));
+ SVN_ERR(diff_processor->dir_closed(ns->relpath,
+ ns->left_src,
+ ns->right_src,
+ ns->baton,
+ diff_processor,
+ ns->pool));
}
eb.cur = ns->parent;
svn_pool_clear(ns->pool);
@@ -535,3 +527,43 @@ svn_wc_diff6(svn_wc_context_t *wc_ctx,
return SVN_NO_ERROR;
}
+
+svn_error_t *
+svn_wc_diff6(svn_wc_context_t *wc_ctx,
+ const char *local_abspath,
+ const svn_wc_diff_callbacks4_t *callbacks,
+ void *callback_baton,
+ svn_depth_t depth,
+ svn_boolean_t ignore_ancestry,
+ svn_boolean_t show_copies_as_adds,
+ svn_boolean_t use_git_diff_format,
+ const apr_array_header_t *changelist_filter,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ const svn_diff_tree_processor_t *processor;
+
+ SVN_ERR(svn_wc__wrap_diff_callbacks(&processor,
+ callbacks, callback_baton, TRUE,
+ scratch_pool, scratch_pool));
+
+ if (use_git_diff_format)
+ show_copies_as_adds = TRUE;
+ if (show_copies_as_adds)
+ ignore_ancestry = FALSE;
+
+ if (! show_copies_as_adds && !use_git_diff_format)
+ processor = svn_diff__tree_processor_copy_as_changed_create(processor,
+ scratch_pool);
+
+ return svn_error_trace(svn_wc__diff7(NULL, NULL,
+ wc_ctx, local_abspath,
+ depth,
+ ignore_ancestry,
+ changelist_filter,
+ processor,
+ cancel_func, cancel_baton,
+ scratch_pool, scratch_pool));
+}
+
diff --git a/subversion/libsvn_wc/entries.c b/subversion/libsvn_wc/entries.c
index 24dae50c0ca8..1be6a8bec870 100644
--- a/subversion/libsvn_wc/entries.c
+++ b/subversion/libsvn_wc/entries.c
@@ -45,9 +45,14 @@
#include "wc_db.h"
#include "wc-queries.h" /* for STMT_* */
+#define SVN_WC__I_AM_WC_DB
+
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
#include "private/svn_sqlite.h"
+#include "token-map.h"
+
+#include "wc_db_private.h"
#define MAYBE_ALLOC(x,p) ((x) ? (x) : apr_pcalloc((p), sizeof(*(x))))
@@ -213,6 +218,8 @@ get_info_for_deleted(svn_wc_entry_t *entry,
svn_wc__db_lock_t **lock,
svn_wc__db_t *db,
const char *entry_abspath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *entry_relpath,
const svn_wc_entry_t *parent_entry,
svn_boolean_t have_base,
svn_boolean_t have_more_work,
@@ -221,12 +228,13 @@ get_info_for_deleted(svn_wc_entry_t *entry,
{
if (have_base && !have_more_work)
{
+ apr_int64_t repos_id;
/* This is the delete of a BASE node */
- SVN_ERR(svn_wc__db_base_get_info(NULL, kind,
+ SVN_ERR(svn_wc__db_base_get_info_internal(
+ NULL, kind,
&entry->revision,
repos_relpath,
- &entry->repos,
- &entry->uuid,
+ &repos_id,
&entry->cmt_rev,
&entry->cmt_date,
&entry->cmt_author,
@@ -236,16 +244,18 @@ get_info_for_deleted(svn_wc_entry_t *entry,
lock,
&entry->has_props, NULL,
NULL,
- db,
- entry_abspath,
+ wcroot, entry_relpath,
result_pool,
scratch_pool));
+ SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid,
+ wcroot, repos_id, result_pool));
}
else
{
- const char *work_del_abspath;
+ const char *work_del_relpath;
const char *parent_repos_relpath;
- const char *parent_abspath;
+ const char *parent_relpath;
+ apr_int64_t repos_id;
/* This is a deleted child of a copy/move-here,
so we need to scan up the WORKING tree to find the root of
@@ -265,30 +275,33 @@ get_info_for_deleted(svn_wc_entry_t *entry,
scratch_pool));
/* working_size and text_time unavailable */
- SVN_ERR(svn_wc__db_scan_deletion(NULL,
+ SVN_ERR(svn_wc__db_scan_deletion_internal(
NULL,
- &work_del_abspath, NULL,
- db, entry_abspath,
+ NULL,
+ &work_del_relpath, NULL,
+ wcroot, entry_relpath,
scratch_pool, scratch_pool));
- SVN_ERR_ASSERT(work_del_abspath != NULL);
- parent_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool);
+ SVN_ERR_ASSERT(work_del_relpath != NULL);
+ parent_relpath = svn_relpath_dirname(work_del_relpath, scratch_pool);
/* The parent directory of the delete root must be added, so we
can find the required information there */
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
+ SVN_ERR(svn_wc__db_scan_addition_internal(
+ NULL, NULL,
&parent_repos_relpath,
- &entry->repos,
- &entry->uuid,
- NULL, NULL, NULL, NULL,
- db, parent_abspath,
+ &repos_id,
+ NULL, NULL, NULL,
+ wcroot, parent_relpath,
result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid,
+ wcroot, repos_id, result_pool));
/* Now glue it all together */
*repos_relpath = svn_relpath_join(parent_repos_relpath,
- svn_dirent_is_child(parent_abspath,
- entry_abspath,
- NULL),
+ svn_relpath_skip_ancestor(
+ parent_relpath,
+ entry_relpath),
result_pool);
@@ -297,11 +310,12 @@ get_info_for_deleted(svn_wc_entry_t *entry,
if (have_base)
{
svn_wc__db_status_t status;
- SVN_ERR(svn_wc__db_base_get_info(&status, NULL, &entry->revision,
+ SVN_ERR(svn_wc__db_base_get_info_internal(
+ &status, NULL, &entry->revision,
NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, lock, NULL, NULL,
+ NULL, NULL, lock, NULL, NULL,
NULL,
- db, entry_abspath,
+ wcroot, entry_relpath,
result_pool, scratch_pool));
if (status == svn_wc__db_status_not_present)
@@ -346,7 +360,7 @@ write_tree_conflicts(const char **conflict_data,
{
svn_skel_t *c_skel;
- SVN_ERR(svn_wc__serialize_conflict(&c_skel, svn__apr_hash_index_val(hi),
+ SVN_ERR(svn_wc__serialize_conflict(&c_skel, apr_hash_this_val(hi),
pool, pool));
svn_skel__prepend(c_skel, skel);
}
@@ -369,12 +383,17 @@ write_tree_conflicts(const char **conflict_data,
If this node is "this dir", then PARENT_ENTRY should be NULL. Otherwise,
it should refer to the entry for the child's parent directory.
+ ### All database read operations should really use wcroot, dir_relpath,
+ as that restores obstruction compatibility with <= 1.6.0
+ but that has been the case since the introduction of WC-NG in 1.7.0
+
Temporary allocations are made in SCRATCH_POOL. */
static svn_error_t *
read_one_entry(const svn_wc_entry_t **new_entry,
svn_wc__db_t *db,
- apr_int64_t wc_id,
const char *dir_abspath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *dir_relpath,
const char *name,
const svn_wc_entry_t *parent_entry,
apr_pool_t *result_pool,
@@ -387,24 +406,28 @@ read_one_entry(const svn_wc_entry_t **new_entry,
const svn_checksum_t *checksum;
svn_filesize_t translated_size;
svn_wc_entry_t *entry = alloc_entry(result_pool);
+ const char *entry_relpath;
const char *entry_abspath;
+ apr_int64_t repos_id;
+ apr_int64_t original_repos_id;
const char *original_repos_relpath;
const char *original_root_url;
svn_boolean_t conflicted;
svn_boolean_t have_base;
svn_boolean_t have_more_work;
+ svn_boolean_t op_root;
- entry->name = name;
+ entry->name = apr_pstrdup(result_pool, name);
+ entry_relpath = svn_relpath_join(dir_relpath, entry->name, scratch_pool);
entry_abspath = svn_dirent_join(dir_abspath, entry->name, scratch_pool);
- SVN_ERR(svn_wc__db_read_info(
+ SVN_ERR(svn_wc__db_read_info_internal(
&status,
&kind,
&entry->revision,
&repos_relpath,
- &entry->repos,
- &entry->uuid,
+ &repos_id,
&entry->cmt_rev,
&entry->cmt_date,
&entry->cmt_author,
@@ -412,24 +435,27 @@ read_one_entry(const svn_wc_entry_t **new_entry,
&checksum,
NULL,
&original_repos_relpath,
- &original_root_url,
- NULL,
+ &original_repos_id,
&entry->copyfrom_rev,
&lock,
&translated_size,
&entry->text_time,
&entry->changelist,
&conflicted,
- NULL /* op_root */,
+ &op_root,
&entry->has_props /* have_props */,
&entry->has_prop_mods /* props_mod */,
&have_base,
&have_more_work,
NULL /* have_work */,
- db,
- entry_abspath,
- result_pool,
- scratch_pool));
+ wcroot, entry_relpath,
+ result_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid,
+ wcroot, repos_id, result_pool));
+ SVN_ERR(svn_wc__db_fetch_repos_info(&original_root_url, NULL,
+ wcroot, original_repos_id,
+ result_pool));
if (entry->has_prop_mods)
entry->has_props = TRUE;
@@ -457,9 +483,10 @@ read_one_entry(const svn_wc_entry_t **new_entry,
child_abspath = svn_dirent_join(dir_abspath, child_name,
scratch_pool);
- SVN_ERR(svn_wc__read_conflicts(&child_conflicts,
+ SVN_ERR(svn_wc__read_conflicts(&child_conflicts, NULL,
db, child_abspath,
FALSE /* create tempfiles */,
+ TRUE /* tree_conflicts_only */,
scratch_pool, scratch_pool));
for (j = 0; j < child_conflicts->nelts; j++)
@@ -493,13 +520,15 @@ read_one_entry(const svn_wc_entry_t **new_entry,
/* Grab inherited repository information, if necessary. */
if (repos_relpath == NULL)
{
- SVN_ERR(svn_wc__db_scan_base_repos(&repos_relpath,
- &entry->repos,
- &entry->uuid,
- db,
- entry_abspath,
- result_pool,
- scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info_internal(
+ NULL, NULL, NULL, &repos_relpath,
+ &repos_id, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL,
+ wcroot, entry_relpath,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid,
+ wcroot, repos_id, result_pool));
}
entry->incomplete = (status == svn_wc__db_status_incomplete);
@@ -519,13 +548,14 @@ read_one_entry(const svn_wc_entry_t **new_entry,
entry->copied = FALSE;
else
{
- const char *work_del_abspath;
- SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
- &work_del_abspath, NULL,
- db, entry_abspath,
+ const char *work_del_relpath;
+ SVN_ERR(svn_wc__db_scan_deletion_internal(
+ NULL, NULL,
+ &work_del_relpath, NULL,
+ wcroot, entry_relpath,
scratch_pool, scratch_pool));
- if (work_del_abspath)
+ if (work_del_relpath)
entry->copied = TRUE;
}
@@ -563,13 +593,14 @@ read_one_entry(const svn_wc_entry_t **new_entry,
/* ENTRY->REVISION is overloaded. When a node is schedule-add
or -replace, then REVISION refers to the BASE node's revision
that is being overwritten. We need to fetch it now. */
- SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL,
+ SVN_ERR(svn_wc__db_base_get_info_internal(
+ &base_status, NULL,
&entry->revision,
NULL, NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, entry_abspath,
+ NULL, NULL, NULL,
+ wcroot, entry_relpath,
scratch_pool,
scratch_pool));
@@ -603,18 +634,27 @@ read_one_entry(const svn_wc_entry_t **new_entry,
have important data. Set up stuff to kill that idea off,
and finish up this entry. */
{
- SVN_ERR(svn_wc__db_scan_addition(&work_status,
- &op_root_abspath,
+ const char *op_root_relpath;
+ SVN_ERR(svn_wc__db_scan_addition_internal(
+ &work_status,
+ &op_root_relpath,
&repos_relpath,
- &entry->repos,
- &entry->uuid,
+ &repos_id,
&scanned_original_relpath,
- NULL, NULL, /* original_root|uuid */
+ NULL /* original_repos_id */,
&original_revision,
- db,
- entry_abspath,
+ wcroot, entry_relpath,
result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_fetch_repos_info(&entry->repos, &entry->uuid,
+ wcroot, repos_id, result_pool));
+
+ if (!op_root_relpath)
+ op_root_abspath = NULL;
+ else
+ op_root_abspath = svn_dirent_join(wcroot->abspath, op_root_relpath,
+ scratch_pool);
+
/* In wc.db we want to keep the valid revision of the not-present
BASE_REV, but when we used entries we set the revision to 0
when adding a new node over a not present base node. */
@@ -633,7 +673,7 @@ read_one_entry(const svn_wc_entry_t **new_entry,
/* ### scan_addition may need to be updated to avoid returning
### status_copied in this case. */
}
- /* For backwards-compatiblity purposes we treat moves just like
+ /* For backwards-compatibility purposes we treat moves just like
* regular copies. */
else if (work_status == svn_wc__db_status_copied ||
work_status == svn_wc__db_status_moved_here)
@@ -675,10 +715,12 @@ read_one_entry(const svn_wc_entry_t **new_entry,
mixed-revision situation. */
if (!is_copied_child)
{
- const char *parent_abspath;
+ const char *parent_relpath;
svn_error_t *err;
const char *parent_repos_relpath;
const char *parent_root_url;
+ apr_int64_t parent_repos_id;
+ const char *op_root_relpath;
/* When we insert entries into the database, we will
construct additional copyfrom records for mixed-revision
@@ -705,15 +747,16 @@ read_one_entry(const svn_wc_entry_t **new_entry,
Note that the parent could be added/copied/moved-here.
There is no way for it to be deleted/moved-away and
have *this* node appear as copied. */
- parent_abspath = svn_dirent_dirname(entry_abspath,
- scratch_pool);
- err = svn_wc__db_scan_addition(NULL,
- &op_root_abspath,
- NULL, NULL, NULL,
- &parent_repos_relpath,
- &parent_root_url,
+ parent_relpath = svn_relpath_dirname(entry_relpath,
+ scratch_pool);
+ err = svn_wc__db_scan_addition_internal(
+ NULL,
+ &op_root_relpath,
NULL, NULL,
- db, parent_abspath,
+ &parent_repos_relpath,
+ &parent_repos_id,
+ NULL,
+ wcroot, parent_relpath,
scratch_pool,
scratch_pool);
if (err)
@@ -721,10 +764,24 @@ read_one_entry(const svn_wc_entry_t **new_entry,
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
svn_error_clear(err);
+ op_root_abspath = NULL;
+ parent_repos_relpath = NULL;
+ parent_root_url = NULL;
+ }
+ else
+ {
+ SVN_ERR(svn_wc__db_fetch_repos_info(&parent_root_url, NULL,
+ wcroot, parent_repos_id,
+ scratch_pool));
+ op_root_abspath = svn_dirent_join(wcroot->abspath,
+ op_root_relpath,
+ scratch_pool);
}
- else if (parent_root_url != NULL
+
+ if (parent_root_url != NULL
&& strcmp(original_root_url, parent_root_url) == 0)
{
+
const char *relpath_to_entry = svn_dirent_is_child(
op_root_abspath, entry_abspath, NULL);
const char *entry_repos_relpath = svn_relpath_join(
@@ -827,6 +884,7 @@ read_one_entry(const svn_wc_entry_t **new_entry,
&checksum,
&lock,
db, entry_abspath,
+ wcroot, entry_relpath,
parent_entry,
have_base, have_more_work,
result_pool, scratch_pool));
@@ -869,7 +927,7 @@ read_one_entry(const svn_wc_entry_t **new_entry,
/* We got a SHA-1, get the corresponding MD-5. */
if (checksum->kind != svn_checksum_md5)
SVN_ERR(svn_wc__db_pristine_get_md5(&checksum, db,
- entry_abspath, checksum,
+ dir_abspath, checksum,
scratch_pool, scratch_pool));
SVN_ERR_ASSERT(checksum->kind == svn_checksum_md5);
@@ -881,8 +939,9 @@ read_one_entry(const svn_wc_entry_t **new_entry,
svn_skel_t *conflict;
svn_boolean_t text_conflicted;
svn_boolean_t prop_conflicted;
- SVN_ERR(svn_wc__db_read_conflict(&conflict, db, entry_abspath,
- scratch_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_conflict_internal(&conflict, NULL, NULL,
+ wcroot, entry_relpath,
+ scratch_pool, scratch_pool));
SVN_ERR(svn_wc__conflict_read_info(NULL, NULL, &text_conflicted,
&prop_conflicted, NULL,
@@ -955,7 +1014,9 @@ read_one_entry(const svn_wc_entry_t **new_entry,
static svn_error_t *
read_entries_new(apr_hash_t **result_entries,
svn_wc__db_t *db,
- const char *local_abspath,
+ const char *dir_abspath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *dir_relpath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -964,11 +1025,12 @@ read_entries_new(apr_hash_t **result_entries,
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
const svn_wc_entry_t *parent_entry;
- apr_int64_t wc_id = 1; /* ### hacky. should remove. */
entries = apr_hash_make(result_pool);
- SVN_ERR(read_one_entry(&parent_entry, db, wc_id, local_abspath,
+ SVN_ERR(read_one_entry(&parent_entry,
+ db, dir_abspath,
+ wcroot, dir_relpath,
"" /* name */,
NULL /* parent_entry */,
result_pool, iterpool));
@@ -977,8 +1039,8 @@ read_entries_new(apr_hash_t **result_entries,
/* Use result_pool so that the child names (used by reference, rather
than copied) appear in result_pool. */
SVN_ERR(svn_wc__db_read_children(&children, db,
- local_abspath,
- result_pool, iterpool));
+ dir_abspath,
+ scratch_pool, iterpool));
for (i = children->nelts; i--; )
{
const char *name = APR_ARRAY_IDX(children, i, const char *);
@@ -987,7 +1049,9 @@ read_entries_new(apr_hash_t **result_entries,
svn_pool_clear(iterpool);
SVN_ERR(read_one_entry(&entry,
- db, wc_id, local_abspath, name, parent_entry,
+ db, dir_abspath,
+ wcroot, dir_relpath,
+ name, parent_entry,
result_pool, iterpool));
svn_hash_sets(entries, entry->name, entry);
}
@@ -1000,28 +1064,20 @@ read_entries_new(apr_hash_t **result_entries,
}
-/* Read a pair of entries from wc_db in the directory DIR_ABSPATH. Return
- the directory's entry in *PARENT_ENTRY and NAME's entry in *ENTRY. The
- two returned pointers will be the same if NAME=="" ("this dir").
-
- The parent entry must exist.
-
- The requested entry MAY exist. If it does not, then NULL will be returned.
-
- The resulting entries are allocated in RESULT_POOL, and all temporary
- allocations are made in SCRATCH_POOL. */
static svn_error_t *
-read_entry_pair(const svn_wc_entry_t **parent_entry,
- const svn_wc_entry_t **entry,
- svn_wc__db_t *db,
- const char *dir_abspath,
- const char *name,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+read_entry_pair_txn(const svn_wc_entry_t **parent_entry,
+ const svn_wc_entry_t **entry,
+ svn_wc__db_t *db,
+ const char *dir_abspath,
+ svn_wc__db_wcroot_t *wcroot,
+ const char *dir_relpath,
+ const char *name,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_int64_t wc_id = 1; /* ### hacky. should remove. */
-
- SVN_ERR(read_one_entry(parent_entry, db, wc_id, dir_abspath,
+ SVN_ERR(read_one_entry(parent_entry,
+ db, dir_abspath,
+ wcroot, dir_relpath,
"" /* name */,
NULL /* parent_entry */,
result_pool, scratch_pool));
@@ -1073,7 +1129,9 @@ read_entry_pair(const svn_wc_entry_t **parent_entry,
svn_error_t *err;
err = read_one_entry(entry,
- db, wc_id, dir_abspath, name, *parent_entry,
+ db, dir_abspath,
+ wcroot, dir_relpath,
+ name, *parent_entry,
result_pool, scratch_pool);
if (err)
{
@@ -1096,28 +1154,76 @@ read_entry_pair(const svn_wc_entry_t **parent_entry,
return SVN_NO_ERROR;
}
+/* Read a pair of entries from wc_db in the directory DIR_ABSPATH. Return
+ the directory's entry in *PARENT_ENTRY and NAME's entry in *ENTRY. The
+ two returned pointers will be the same if NAME=="" ("this dir").
+
+ The parent entry must exist.
+
+ The requested entry MAY exist. If it does not, then NULL will be returned.
+
+ The resulting entries are allocated in RESULT_POOL, and all temporary
+ allocations are made in SCRATCH_POOL. */
+static svn_error_t *
+read_entry_pair(const svn_wc_entry_t **parent_entry,
+ const svn_wc_entry_t **entry,
+ svn_wc__db_t *db,
+ const char *dir_abspath,
+ const char *name,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *dir_relpath;
+
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath,
+ db, dir_abspath,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ SVN_WC__DB_WITH_TXN(read_entry_pair_txn(parent_entry, entry,
+ db, dir_abspath,
+ wcroot, dir_relpath,
+ name,
+ result_pool, scratch_pool),
+ wcroot);
+
+ return SVN_NO_ERROR;
+}
/* */
static svn_error_t *
read_entries(apr_hash_t **entries,
svn_wc__db_t *db,
- const char *wcroot_abspath,
+ const char *dir_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *dir_relpath;
int wc_format;
- SVN_ERR(svn_wc__db_temp_get_format(&wc_format, db, wcroot_abspath,
+ SVN_ERR(svn_wc__db_temp_get_format(&wc_format, db, dir_abspath,
scratch_pool));
if (wc_format < SVN_WC__WC_NG_VERSION)
return svn_error_trace(svn_wc__read_entries_old(entries,
- wcroot_abspath,
+ dir_abspath,
result_pool,
scratch_pool));
- return svn_error_trace(read_entries_new(entries, db, wcroot_abspath,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &dir_relpath,
+ db, dir_abspath,
+ scratch_pool, scratch_pool));
+ VERIFY_USABLE_WCROOT(wcroot);
+
+ SVN_WC__DB_WITH_TXN(read_entries_new(entries,
+ db, dir_abspath,
+ wcroot, dir_relpath,
+ result_pool, scratch_pool),
+ wcroot);
+
+ return SVN_NO_ERROR;
}
@@ -1342,7 +1448,7 @@ prune_deleted(apr_hash_t **entries_pruned,
svn_boolean_t hidden;
SVN_ERR(svn_wc__entry_is_hidden(&hidden,
- svn__apr_hash_index_val(hi)));
+ apr_hash_this_val(hi)));
if (hidden)
break;
}
@@ -1360,8 +1466,8 @@ prune_deleted(apr_hash_t **entries_pruned,
hi;
hi = apr_hash_next(hi))
{
- const void *key = svn__apr_hash_index_key(hi);
- const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi);
+ const void *key = apr_hash_this_key(hi);
+ const svn_wc_entry_t *entry = apr_hash_this_val(hi);
svn_boolean_t hidden;
SVN_ERR(svn_wc__entry_is_hidden(&hidden, entry));
@@ -1372,25 +1478,6 @@ prune_deleted(apr_hash_t **entries_pruned,
return SVN_NO_ERROR;
}
-struct entries_read_baton_t
-{
- apr_hash_t **new_entries;
- svn_wc__db_t *db;
- const char *local_abspath;
- apr_pool_t *result_pool;
-};
-
-static svn_error_t *
-entries_read_txn(void *baton, svn_sqlite__db_t *db, apr_pool_t *scratch_pool)
-{
- struct entries_read_baton_t *erb = baton;
-
- SVN_ERR(read_entries(erb->new_entries, erb->db, erb->local_abspath,
- erb->result_pool, scratch_pool));
-
- return NULL;
-}
-
svn_error_t *
svn_wc__entries_read_internal(apr_hash_t **entries,
svn_wc_adm_access_t *adm_access,
@@ -1405,21 +1492,9 @@ svn_wc__entries_read_internal(apr_hash_t **entries,
svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
const char *local_abspath = svn_wc__adm_access_abspath(adm_access);
apr_pool_t *result_pool = svn_wc__adm_access_pool_internal(adm_access);
- svn_sqlite__db_t *sdb;
- struct entries_read_baton_t erb;
-
- /* ### Use the borrow DB api to handle all calls in a single read
- ### transaction. This api is used extensively in our test suite
- ### via the entries-read application. */
- SVN_ERR(svn_wc__db_temp_borrow_sdb(&sdb, db, local_abspath, pool));
-
- erb.db = db;
- erb.local_abspath = local_abspath;
- erb.new_entries = &new_entries;
- erb.result_pool = result_pool;
-
- SVN_ERR(svn_sqlite__with_lock(sdb, entries_read_txn, &erb, pool));
+ SVN_ERR(read_entries(&new_entries, db, local_abspath,
+ result_pool, pool));
svn_wc__adm_access_set_entries(adm_access, new_entries);
}
@@ -1452,23 +1527,31 @@ insert_node(svn_sqlite__db_t *sdb,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
+ svn_boolean_t present = (node->presence == svn_wc__db_status_normal
+ || node->presence == svn_wc__db_status_incomplete);
SVN_ERR_ASSERT(node->op_depth > 0 || node->repos_relpath);
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
- SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnnnsnrisnnni",
+ SVN_ERR(svn_sqlite__bindf(stmt, "isdsnnnnsn",
node->wc_id,
node->local_relpath,
node->op_depth,
node->parent_relpath,
/* Setting depth for files? */
- svn_depth_to_word(node->depth),
- node->changed_rev,
- node->changed_date,
- node->changed_author,
- node->recorded_time));
+ (node->kind == svn_node_dir && present)
+ ? svn_depth_to_word(node->depth)
+ : NULL));
- if (node->repos_relpath)
+ if (present && node->repos_relpath)
+ {
+ SVN_ERR(svn_sqlite__bind_revnum(stmt, 11, node->changed_rev));
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 12, node->changed_date));
+ SVN_ERR(svn_sqlite__bind_text(stmt, 13, node->changed_author));
+ }
+
+ if (node->repos_relpath
+ && node->presence != svn_wc__db_status_base_deleted)
{
SVN_ERR(svn_sqlite__bind_int64(stmt, 5,
node->repos_id));
@@ -1477,26 +1560,14 @@ insert_node(svn_sqlite__db_t *sdb,
SVN_ERR(svn_sqlite__bind_revnum(stmt, 7, node->revision));
}
- if (node->presence == svn_wc__db_status_normal)
- SVN_ERR(svn_sqlite__bind_text(stmt, 8, "normal"));
- else if (node->presence == svn_wc__db_status_not_present)
- SVN_ERR(svn_sqlite__bind_text(stmt, 8, "not-present"));
- else if (node->presence == svn_wc__db_status_base_deleted)
- SVN_ERR(svn_sqlite__bind_text(stmt, 8, "base-deleted"));
- else if (node->presence == svn_wc__db_status_incomplete)
- 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, "server-excluded"));
+ SVN_ERR(svn_sqlite__bind_token(stmt, 8, presence_map, node->presence));
if (node->kind == svn_node_none)
SVN_ERR(svn_sqlite__bind_text(stmt, 10, "unknown"));
else
- SVN_ERR(svn_sqlite__bind_text(stmt, 10,
- svn_node_kind_to_word(node->kind)));
+ SVN_ERR(svn_sqlite__bind_token(stmt, 10, kind_map, node->kind));
- if (node->kind == svn_node_file)
+ if (node->kind == svn_node_file && present)
{
if (!node->checksum
&& node->op_depth == 0
@@ -1510,19 +1581,25 @@ insert_node(svn_sqlite__db_t *sdb,
SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, node->checksum,
scratch_pool));
+
+ if (node->repos_relpath)
+ {
+ if (node->recorded_size != SVN_INVALID_FILESIZE)
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->recorded_size));
+
+ SVN_ERR(svn_sqlite__bind_int64(stmt, 17, node->recorded_time));
+ }
}
- if (node->properties) /* ### Never set, props done later */
+ /* ### Never set, props done later */
+ if (node->properties && present && node->repos_relpath)
SVN_ERR(svn_sqlite__bind_properties(stmt, 15, node->properties,
scratch_pool));
- if (node->recorded_size != SVN_INVALID_FILESIZE)
- SVN_ERR(svn_sqlite__bind_int64(stmt, 16, node->recorded_size));
-
if (node->file_external)
SVN_ERR(svn_sqlite__bind_int(stmt, 20, 1));
- if (node->inherited_props)
+ if (node->inherited_props && present)
SVN_ERR(svn_sqlite__bind_iprops(stmt, 23, node->inherited_props,
scratch_pool));
@@ -1801,6 +1878,10 @@ write_entry(struct write_baton **entry_node,
if (entry->copied)
{
+ db_node_t *work = parent_node->work
+ ? parent_node->work
+ : parent_node->below_work;
+
if (entry->copyfrom_url)
{
working_node->repos_id = repos_id;
@@ -1810,20 +1891,37 @@ write_entry(struct write_baton **entry_node,
working_node->revision = entry->copyfrom_rev;
working_node->op_depth
= svn_wc__db_op_depth_for_upgrade(local_relpath);
+
+ if (work && work->repos_relpath
+ && work->repos_id == repos_id
+ && work->revision == entry->copyfrom_rev)
+ {
+ const char *name;
+
+ name = svn_relpath_skip_ancestor(work->repos_relpath,
+ working_node->repos_relpath);
+
+ if (name
+ && !strcmp(name, svn_relpath_basename(local_relpath, NULL)))
+ {
+ working_node->op_depth = work->op_depth;
+ }
+ }
}
- else if (parent_node->work && parent_node->work->repos_relpath)
+ else if (work && work->repos_relpath)
{
working_node->repos_id = repos_id;
working_node->repos_relpath
- = svn_relpath_join(parent_node->work->repos_relpath,
+ = svn_relpath_join(work->repos_relpath,
svn_relpath_basename(local_relpath, NULL),
result_pool);
- working_node->revision = parent_node->work->revision;
- working_node->op_depth = parent_node->work->op_depth;
+ working_node->revision = work->revision;
+ working_node->op_depth = work->op_depth;
}
else if (parent_node->below_work
&& parent_node->below_work->repos_relpath)
{
+ /* Parent deleted, this not-present or similar */
working_node->repos_id = repos_id;
working_node->repos_relpath
= svn_relpath_join(parent_node->below_work->repos_relpath,
@@ -1837,6 +1935,29 @@ write_entry(struct write_baton **entry_node,
_("No copyfrom URL for '%s'"),
svn_dirent_local_style(local_relpath,
scratch_pool));
+
+ if (work && work->op_depth != working_node->op_depth
+ && work->repos_relpath
+ && work->repos_id == working_node->repos_id
+ && work->presence == svn_wc__db_status_normal
+ && !below_working_node)
+ {
+ /* Introduce a not-present node! */
+ below_working_node = MAYBE_ALLOC(below_working_node, scratch_pool);
+
+ below_working_node->wc_id = wc_id;
+ below_working_node->op_depth = work->op_depth;
+ below_working_node->local_relpath = local_relpath;
+ below_working_node->parent_relpath = parent_relpath;
+
+ below_working_node->presence = svn_wc__db_status_not_present;
+ below_working_node->repos_id = repos_id;
+ below_working_node->repos_relpath = working_node->local_relpath;
+
+ SVN_ERR(insert_node(sdb, below_working_node, scratch_pool));
+
+ below_working_node = NULL; /* Don't write a present intermediate! */
+ }
}
if (entry->conflict_old)
@@ -1892,7 +2013,7 @@ write_entry(struct write_baton **entry_node,
scratch_pool);
tree_conflicts = apr_hash_make(result_pool);
skel = skel->children;
- while(skel)
+ while (skel)
{
svn_wc_conflict_description2_t *conflict;
svn_skel_t *new_skel;
@@ -1909,11 +2030,6 @@ write_entry(struct write_baton **entry_node,
WRITE_ENTRY_ASSERT(conflict->kind == svn_wc_conflict_kind_tree);
- /* Fix dubious data stored by old clients, local adds don't have
- a repository URL. */
- if (conflict->reason == svn_wc_conflict_reason_added)
- conflict->src_left_version = NULL;
-
SVN_ERR(svn_wc__serialize_conflict(&new_skel, conflict,
scratch_pool, scratch_pool));
@@ -2295,6 +2411,11 @@ write_entry(struct write_baton **entry_node,
{
working_node->op_depth = parent_node->work->op_depth;
}
+ else if (working_node->presence == svn_wc__db_status_excluded
+ && parent_node->work)
+ {
+ working_node->op_depth = parent_node->work->op_depth;
+ }
else if (!entry->copied)
{
working_node->op_depth
@@ -2358,9 +2479,9 @@ write_actual_only_entries(apr_hash_t *tree_conflicts,
actual_node = MAYBE_ALLOC(actual_node, scratch_pool);
actual_node->wc_id = wc_id;
- actual_node->local_relpath = svn__apr_hash_index_key(hi);
+ actual_node->local_relpath = apr_hash_this_key(hi);
actual_node->parent_relpath = parent_relpath;
- actual_node->tree_conflict_data = svn__apr_hash_index_val(hi);
+ actual_node->tree_conflict_data = apr_hash_this_val(hi);
SVN_ERR(insert_actual_node(sdb, db, wri_abspath, actual_node,
scratch_pool));
@@ -2418,8 +2539,8 @@ svn_wc__write_upgraded_entries(void **dir_baton,
for (hi = apr_hash_first(scratch_pool, entries); hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- const svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ const svn_wc_entry_t *this_entry = apr_hash_this_val(hi);
const char *child_abspath, *child_relpath;
svn_wc__text_base_info_t *text_base_info
= svn_hash_gets(text_bases_info, name);
@@ -2573,8 +2694,8 @@ walker_helper(const char *dirpath,
/* Loop over each of the other entries. */
for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- const svn_wc_entry_t *current_entry = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ const svn_wc_entry_t *current_entry = apr_hash_this_val(hi);
const char *entrypath;
const char *entry_abspath;
svn_boolean_t hidden;
@@ -2661,11 +2782,11 @@ svn_wc_walk_entries3(const char *path,
svn_wc__db_t *db = svn_wc__adm_get_db(adm_access);
svn_error_t *err;
svn_node_kind_t kind;
- svn_depth_t depth;
+ svn_wc__db_status_t status;
SVN_ERR(svn_dirent_get_absolute(&local_abspath, path, pool));
- err = svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, &depth, NULL, NULL,
+ err = svn_wc__db_read_info(&status, &kind, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL,
@@ -2684,7 +2805,9 @@ svn_wc_walk_entries3(const char *path,
walk_baton, pool);
}
- if (kind == svn_node_file || depth == svn_depth_exclude)
+ if (kind == svn_node_file
+ || status == svn_wc__db_status_excluded
+ || status == svn_wc__db_status_server_excluded)
{
const svn_wc_entry_t *entry;
@@ -2693,27 +2816,24 @@ svn_wc_walk_entries3(const char *path,
### we should not call handle_error for an error the *callback*
### gave us. let it deal with the problem before returning. */
- if (!show_hidden)
+ if (!show_hidden
+ && (status == svn_wc__db_status_not_present
+ || status == svn_wc__db_status_excluded
+ || status == svn_wc__db_status_server_excluded))
{
- svn_boolean_t hidden;
- SVN_ERR(svn_wc__db_node_hidden(&hidden, db, local_abspath, pool));
-
- if (hidden)
- {
- /* The fool asked to walk a "hidden" node. Report the node as
- unversioned.
-
- ### this is incorrect behavior. see depth_test 36. the walk
- ### API will be revamped to avoid entry structures. we should
- ### be able to solve the problem with the new API. (since we
- ### shouldn't return a hidden entry here) */
- return walk_callbacks->handle_error(
- path, svn_error_createf(
- SVN_ERR_UNVERSIONED_RESOURCE, NULL,
- _("'%s' is not under version control"),
- svn_dirent_local_style(local_abspath, pool)),
- walk_baton, pool);
- }
+ /* The fool asked to walk a "hidden" node. Report the node as
+ unversioned.
+
+ ### this is incorrect behavior. see depth_test 36. the walk
+ ### API will be revamped to avoid entry structures. we should
+ ### be able to solve the problem with the new API. (since we
+ ### shouldn't return a hidden entry here) */
+ return walk_callbacks->handle_error(
+ path, svn_error_createf(
+ SVN_ERR_UNVERSIONED_RESOURCE, NULL,
+ _("'%s' is not under version control"),
+ svn_dirent_local_style(local_abspath, pool)),
+ walk_baton, pool);
}
SVN_ERR(svn_wc__get_entry(&entry, db, local_abspath, FALSE,
diff --git a/subversion/libsvn_wc/externals.c b/subversion/libsvn_wc/externals.c
index 98395b87cc12..4cbd4f0e4b26 100644
--- a/subversion/libsvn_wc/externals.c
+++ b/subversion/libsvn_wc/externals.c
@@ -68,6 +68,7 @@
* the revision if the revision is found. Set REV_IDX to the index in
* LINE_PARTS where the revision specification starts. Remove from
* LINE_PARTS the element(s) that specify the revision.
+ * Set REV_STR to the element that specifies the revision.
* PARENT_DIRECTORY_DISPLAY and LINE are given to return a nice error
* string.
*
@@ -76,6 +77,7 @@
*/
static svn_error_t *
find_and_remove_externals_revision(int *rev_idx,
+ const char **rev_str,
const char **line_parts,
int num_line_parts,
svn_wc_external_item2_t *item,
@@ -137,6 +139,8 @@ find_and_remove_externals_revision(int *rev_idx,
line_parts[j] = line_parts[j+shift_count];
line_parts[num_line_parts-shift_count] = NULL;
+ *rev_str = apr_psprintf(pool, "-r%s", digits_ptr);
+
/* Found the revision, so leave the function immediately, do
* not continue looking for additional revisions. */
return SVN_NO_ERROR;
@@ -158,23 +162,29 @@ find_and_remove_externals_revision(int *rev_idx,
}
svn_error_t *
-svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
- const char *parent_directory,
+svn_wc__parse_externals_description(apr_array_header_t **externals_p,
+ apr_array_header_t **parser_infos_p,
+ const char *defining_directory,
const char *desc,
svn_boolean_t canonicalize_url,
apr_pool_t *pool)
{
int i;
apr_array_header_t *externals = NULL;
+ apr_array_header_t *parser_infos = NULL;
apr_array_header_t *lines = svn_cstring_split(desc, "\n\r", TRUE, pool);
- const char *parent_directory_display = svn_path_is_url(parent_directory) ?
- parent_directory : svn_dirent_local_style(parent_directory, pool);
+ const char *defining_directory_display = svn_path_is_url(defining_directory) ?
+ defining_directory : svn_dirent_local_style(defining_directory, pool);
/* If an error occurs halfway through parsing, *externals_p should stay
* untouched. So, store the list in a local var first. */
if (externals_p)
externals = apr_array_make(pool, 1, sizeof(svn_wc_external_item2_t *));
+ if (parser_infos_p)
+ parser_infos =
+ apr_array_make(pool, 1, sizeof(svn_wc__externals_parser_info_t *));
+
for (i = 0; i < lines->nelts; i++)
{
const char *line = APR_ARRAY_IDX(lines, i, const char *);
@@ -186,10 +196,12 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
const char *token1;
svn_boolean_t token0_is_url;
svn_boolean_t token1_is_url;
+ svn_wc__externals_parser_info_t *info = NULL;
/* Index into line_parts where the revision specification
started. */
int rev_idx = -1;
+ const char *rev_str = NULL;
if ((! line) || (line[0] == '#'))
continue;
@@ -209,6 +221,9 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
item->revision.kind = svn_opt_revision_unspecified;
item->peg_revision.kind = svn_opt_revision_unspecified;
+ if (parser_infos)
+ info = apr_pcalloc(pool, sizeof(*info));
+
/*
* There are six different formats of externals:
*
@@ -231,7 +246,7 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
(SVN_ERR_CLIENT_INVALID_EXTERNALS_DESCRIPTION, NULL,
_("Error parsing %s property on '%s': '%s'"),
SVN_PROP_EXTERNALS,
- parent_directory_display,
+ defining_directory_display,
line);
/* To make it easy to check for the forms, find and remove -r N
@@ -240,9 +255,10 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
set item->revision to the parsed revision. */
/* ### ugh. stupid cast. */
SVN_ERR(find_and_remove_externals_revision(&rev_idx,
+ &rev_str,
(const char **)line_parts,
num_line_parts, item,
- parent_directory_display,
+ defining_directory_display,
line, pool));
token0 = line_parts[0];
@@ -258,7 +274,7 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
"cannot use two absolute URLs ('%s' and '%s') in an external; "
"one must be a path where an absolute or relative URL is "
"checked out to"),
- SVN_PROP_EXTERNALS, parent_directory_display, token0, token1);
+ SVN_PROP_EXTERNALS, defining_directory_display, token0, token1);
if (0 == rev_idx && token1_is_url)
return svn_error_createf
@@ -266,7 +282,7 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
_("Invalid %s property on '%s': "
"cannot use a URL '%s' as the target directory for an external "
"definition"),
- SVN_PROP_EXTERNALS, parent_directory_display, token1);
+ SVN_PROP_EXTERNALS, defining_directory_display, token1);
if (1 == rev_idx && token0_is_url)
return svn_error_createf
@@ -274,9 +290,9 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
_("Invalid %s property on '%s': "
"cannot use a URL '%s' as the target directory for an external "
"definition"),
- SVN_PROP_EXTERNALS, parent_directory_display, token0);
+ SVN_PROP_EXTERNALS, defining_directory_display, token0);
- /* The appearence of -r N or -rN forces the type of external.
+ /* The appearance of -r N or -rN forces the type of external.
If -r is at the beginning of the line or the first token is
an absolute URL or if the second token is not an absolute
URL, then the URL supports peg revisions. */
@@ -290,12 +306,34 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
SVN_ERR(svn_opt_parse_path(&item->peg_revision, &item->url,
token0, pool));
item->target_dir = token1;
+
+ if (info)
+ {
+ info->format = svn_wc__external_description_format_2;
+
+ if (rev_str)
+ info->rev_str = apr_pstrdup(pool, rev_str);
+
+ if (item->peg_revision.kind != svn_opt_revision_unspecified)
+ info->peg_rev_str = strrchr(token0, '@');
+ }
}
else
{
item->target_dir = token0;
item->url = token1;
item->peg_revision = item->revision;
+
+ if (info)
+ {
+ info->format = svn_wc__external_description_format_1;
+
+ if (rev_str)
+ {
+ info->rev_str = apr_pstrdup(pool, rev_str);
+ info->peg_rev_str = info->rev_str;
+ }
+ }
}
SVN_ERR(svn_opt_resolve_revisions(&item->peg_revision,
@@ -316,7 +354,7 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
_("Invalid %s property on '%s': "
"target '%s' is an absolute path or involves '..'"),
SVN_PROP_EXTERNALS,
- parent_directory_display,
+ defining_directory_display,
item->target_dir);
if (canonicalize_url)
@@ -333,15 +371,34 @@ svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
if (externals)
APR_ARRAY_PUSH(externals, svn_wc_external_item2_t *) = item;
+ if (parser_infos)
+ APR_ARRAY_PUSH(parser_infos, svn_wc__externals_parser_info_t *) = info;
}
if (externals_p)
*externals_p = externals;
+ if (parser_infos_p)
+ *parser_infos_p = parser_infos;
return SVN_NO_ERROR;
}
svn_error_t *
+svn_wc_parse_externals_description3(apr_array_header_t **externals_p,
+ const char *defining_directory,
+ const char *desc,
+ svn_boolean_t canonicalize_url,
+ apr_pool_t *pool)
+{
+ return svn_error_trace(svn_wc__parse_externals_description(externals_p,
+ NULL,
+ defining_directory,
+ desc,
+ canonicalize_url,
+ pool));
+}
+
+svn_error_t *
svn_wc__externals_find_target_dups(apr_array_header_t **duplicate_targets,
apr_array_header_t *externals,
apr_pool_t *pool,
@@ -418,8 +475,6 @@ struct edit_baton
/* Introducing a new file external */
svn_boolean_t added;
- svn_wc_conflict_resolver_func2_t conflict_func;
- void *conflict_baton;
svn_cancel_func_t cancel_func;
void *cancel_baton;
svn_wc_notify_func2_t notify_func;
@@ -432,7 +487,7 @@ struct edit_baton
const svn_checksum_t *original_checksum;
/* What we are installing now */
- const char *new_pristine_abspath;
+ svn_wc__db_install_data_t *install_data;
svn_checksum_t *new_sha1_checksum;
svn_checksum_t *new_md5_checksum;
@@ -581,11 +636,12 @@ apply_textdelta(void *file_baton,
else
src_stream = svn_stream_empty(pool);
- SVN_ERR(svn_wc__open_writable_base(&dest_stream, &eb->new_pristine_abspath,
- &eb->new_md5_checksum,
- &eb->new_sha1_checksum,
- eb->db, eb->wri_abspath,
- eb->pool, pool));
+ SVN_ERR(svn_wc__db_pristine_prepare_install(&dest_stream,
+ &eb->install_data,
+ &eb->new_sha1_checksum,
+ &eb->new_md5_checksum,
+ eb->db, eb->wri_abspath,
+ eb->pool, pool));
svn_txdelta_apply(src_stream, dest_stream, NULL, eb->local_abspath, pool,
handler, handler_baton);
@@ -605,7 +661,7 @@ change_file_prop(void *file_baton,
propchange = apr_array_push(eb->propchanges);
propchange->name = apr_pstrdup(eb->pool, name);
- propchange->value = value ? svn_string_dup(value, eb->pool) : NULL;
+ propchange->value = svn_string_dup(value, eb->pool);
return SVN_NO_ERROR;
}
@@ -658,11 +714,11 @@ close_file(void *file_baton,
behavior to the pristine store. */
if (eb->new_sha1_checksum)
{
- SVN_ERR(svn_wc__db_pristine_install(eb->db, eb->new_pristine_abspath,
+ SVN_ERR(svn_wc__db_pristine_install(eb->install_data,
eb->new_sha1_checksum,
eb->new_md5_checksum, pool));
- eb->new_pristine_abspath = NULL;
+ eb->install_data = NULL;
}
/* Merge the changes */
@@ -767,7 +823,6 @@ close_file(void *file_baton,
{
svn_node_kind_t disk_kind;
svn_boolean_t install_pristine = FALSE;
- const char *install_from = NULL;
SVN_ERR(svn_io_check_path(eb->local_abspath, &disk_kind, pool));
@@ -832,7 +887,7 @@ close_file(void *file_baton,
{
SVN_ERR(svn_wc__wq_build_file_install(&work_item, eb->db,
eb->local_abspath,
- install_from,
+ NULL,
eb->use_commit_times, TRUE,
pool, pool));
@@ -971,6 +1026,7 @@ close_edit(void *edit_baton,
apr_hash_make(pool)
/* exclude_relpaths */,
wcroot_iprops,
+ TRUE /* empty update */,
eb->notify_func,
eb->notify_baton,
pool));
@@ -997,8 +1053,6 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor,
const char *recorded_url,
const svn_opt_revision_t *recorded_peg_rev,
const svn_opt_revision_t *recorded_rev,
- svn_wc_conflict_resolver_func2_t conflict_func,
- void *conflict_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -1050,8 +1104,6 @@ svn_wc__get_file_external_editor(const svn_delta_editor_t **editor,
else
eb->recorded_revision = SVN_INVALID_REVNUM; /* Not fixed/HEAD */
- eb->conflict_func = conflict_func;
- eb->conflict_baton = conflict_baton;
eb->cancel_func = cancel_func;
eb->cancel_baton = cancel_baton;
eb->notify_func = notify_func;
@@ -1421,10 +1473,8 @@ svn_wc__external_remove(svn_wc_context_t *wc_ctx,
else
{
SVN_ERR(svn_wc__db_base_remove(wc_ctx->db, local_abspath,
- FALSE /* keep_as_working */,
- TRUE /* queue_deletes */,
- FALSE /* remove_locks */,
- SVN_INVALID_REVNUM,
+ FALSE, TRUE, FALSE,
+ 0,
NULL, NULL, scratch_pool));
SVN_ERR(svn_wc__wq_run(wc_ctx->db, local_abspath,
cancel_func, cancel_baton,
@@ -1567,7 +1617,7 @@ svn_wc__resolve_relative_external_url(const char **resolved_url,
apr_pstrndup(scratch_pool, url, num_leading_slashes),
svn_relpath_canonicalize(url + num_leading_slashes,
scratch_pool),
- (char*)NULL);
+ SVN_VA_NULL);
}
else
{
@@ -1674,7 +1724,7 @@ svn_wc__resolve_relative_external_url(const char **resolved_url,
SVN_ERR(uri_scheme(&scheme, repos_root_url, scratch_pool));
*resolved_url = svn_uri_canonicalize(apr_pstrcat(scratch_pool, scheme,
- ":", url, (char *)NULL),
+ ":", url, SVN_VA_NULL),
result_pool);
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_wc/info.c b/subversion/libsvn_wc/info.c
index dc80ee72d27e..78e5d7f7a22e 100644
--- a/subversion/libsvn_wc/info.c
+++ b/subversion/libsvn_wc/info.c
@@ -52,7 +52,7 @@ svn_wc_info_dup(const svn_wc_info_t *info,
for (i = 0; i < info->conflicts->nelts; i++)
{
APR_ARRAY_PUSH(new_conflicts, svn_wc_conflict_description2_t *)
- = svn_wc__conflict_description2_dup(
+ = svn_wc_conflict_description2_dup(
APR_ARRAY_IDX(info->conflicts, i,
const svn_wc_conflict_description2_t *),
pool);
@@ -141,7 +141,6 @@ build_info_for_node(svn_wc__info2_t **info,
{
/* Root or child of copy */
tmpinfo->rev = original_revision;
- repos_relpath = original_repos_relpath;
if (op_root)
{
@@ -167,34 +166,6 @@ build_info_for_node(svn_wc__info2_t **info,
}
}
}
- else if (op_root)
- {
- /* Local addition */
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
- &tmpinfo->repos_root_URL,
- &tmpinfo->repos_UUID,
- NULL, NULL, NULL, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
-
- if (have_base)
- SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, &tmpinfo->rev, NULL,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
- }
- else
- {
- /* Child of copy. ### Not WC-NG like */
- SVN_ERR(svn_wc__internal_get_origin(NULL, &tmpinfo->rev,
- &repos_relpath,
- &tmpinfo->repos_root_URL,
- &tmpinfo->repos_UUID, NULL,
- db, local_abspath, TRUE,
- result_pool, scratch_pool));
- }
/* ### We should be able to avoid both these calls with the information
from read_info() in most cases */
@@ -222,14 +193,20 @@ build_info_for_node(svn_wc__info2_t **info,
else
wc_info->schedule = svn_wc_schedule_add;
}
- SVN_ERR(svn_wc__db_read_url(&tmpinfo->URL, db, local_abspath,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
+ &tmpinfo->repos_root_URL,
+ &tmpinfo->repos_UUID,
+ db, local_abspath,
+ result_pool, scratch_pool));
+
+ tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
+ repos_relpath, result_pool);
}
else if (status == svn_wc__db_status_deleted)
{
- const char *work_del_abspath;
+ svn_wc__db_status_t w_status;
- SVN_ERR(svn_wc__db_read_pristine_info(NULL, NULL,
+ SVN_ERR(svn_wc__db_read_pristine_info(&w_status, &tmpinfo->kind,
&tmpinfo->last_changed_rev,
&tmpinfo->last_changed_date,
&tmpinfo->last_changed_author,
@@ -239,51 +216,32 @@ build_info_for_node(svn_wc__info2_t **info,
db, local_abspath,
result_pool, scratch_pool));
+ if (w_status == svn_wc__db_status_deleted)
+ {
+ /* We have a working not-present status. We don't know anything
+ about this node, but it *is visible* in STATUS.
+
+ Let's tell that it is excluded */
+
+ wc_info->depth = svn_depth_exclude;
+ tmpinfo->kind = svn_node_unknown;
+ }
+
/* And now fetch the url and revision of what will be deleted */
SVN_ERR(svn_wc__db_scan_deletion(NULL, &wc_info->moved_to_abspath,
- &work_del_abspath, NULL,
+ NULL, NULL,
db, local_abspath,
scratch_pool, scratch_pool));
- if (work_del_abspath != NULL)
- {
- /* This is a deletion within a copied subtree. Get the copied-from
- * revision. */
- const char *added_abspath = svn_dirent_dirname(work_del_abspath,
- scratch_pool);
-
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, &repos_relpath,
- &tmpinfo->repos_root_URL,
- &tmpinfo->repos_UUID,
- NULL, NULL, NULL,
- &tmpinfo->rev,
- db, added_abspath,
- result_pool, scratch_pool));
-
- tmpinfo->URL = svn_path_url_add_component2(
- tmpinfo->repos_root_URL,
- svn_relpath_join(repos_relpath,
- svn_dirent_skip_ancestor(added_abspath,
- local_abspath),
- scratch_pool),
- result_pool);
- }
- else
- {
- SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, &tmpinfo->rev,
- &repos_relpath,
- &tmpinfo->repos_root_URL,
- &tmpinfo->repos_UUID, NULL, NULL,
- NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
-
- tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
- repos_relpath,
- result_pool);
- }
+
+ SVN_ERR(svn_wc__db_read_repos_info(&tmpinfo->rev, &repos_relpath,
+ &tmpinfo->repos_root_URL,
+ &tmpinfo->repos_UUID,
+ db, local_abspath,
+ result_pool, scratch_pool));
wc_info->schedule = svn_wc_schedule_delete;
+ tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
+ repos_relpath, result_pool);
}
else if (status == svn_wc__db_status_not_present
|| status == svn_wc__db_status_server_excluded)
@@ -291,6 +249,21 @@ build_info_for_node(svn_wc__info2_t **info,
*info = NULL;
return SVN_NO_ERROR;
}
+ else if (status == svn_wc__db_status_excluded && !repos_relpath)
+ {
+ /* We have a WORKING exclude. Avoid segfault on no repos info */
+
+ SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
+ &tmpinfo->repos_root_URL,
+ &tmpinfo->repos_UUID,
+ db, local_abspath,
+ result_pool, scratch_pool));
+
+ wc_info->schedule = svn_wc_schedule_normal;
+ tmpinfo->URL = svn_path_url_add_component2(tmpinfo->repos_root_URL,
+ repos_relpath, result_pool);
+ tmpinfo->wc_info->depth = svn_depth_exclude;
+ }
else
{
/* Just a BASE node. We have all the info we need */
@@ -298,10 +271,10 @@ build_info_for_node(svn_wc__info2_t **info,
repos_relpath,
result_pool);
wc_info->schedule = svn_wc_schedule_normal;
- }
- if (status == svn_wc__db_status_excluded)
- tmpinfo->wc_info->depth = svn_depth_exclude;
+ if (status == svn_wc__db_status_excluded)
+ wc_info->depth = svn_depth_exclude;
+ }
/* A default */
tmpinfo->size = SVN_INVALID_FILESIZE;
@@ -310,9 +283,10 @@ build_info_for_node(svn_wc__info2_t **info,
local_abspath, result_pool, scratch_pool));
if (conflicted)
- SVN_ERR(svn_wc__read_conflicts(&wc_info->conflicts, db,
- local_abspath,
- TRUE /* ### create tempfiles */,
+ SVN_ERR(svn_wc__read_conflicts(&wc_info->conflicts, NULL,
+ db, local_abspath,
+ FALSE /* create tempfiles */,
+ FALSE /* only tree conflicts */,
result_pool, scratch_pool));
else
wc_info->conflicts = NULL;
@@ -373,7 +347,7 @@ struct found_entry_baton
svn_boolean_t actual_only;
svn_boolean_t first;
/* The set of tree conflicts that have been found but not (yet) visited by
- * the tree walker. Map of abspath -> svn_wc_conflict_description2_t. */
+ * the tree walker. Map of abspath -> empty string. */
apr_hash_t *tree_conflicts;
apr_pool_t *pool;
};
@@ -533,9 +507,10 @@ svn_wc__get_info(svn_wc_context_t *wc_ctx,
for (hi = apr_hash_first(scratch_pool, fe_baton.tree_conflicts); hi;
hi = apr_hash_next(hi))
{
- const char *this_abspath = svn__apr_hash_index_key(hi);
+ const char *this_abspath = apr_hash_this_key(hi);
const svn_wc_conflict_description2_t *tree_conflict;
svn_wc__info2_t *info;
+ const apr_array_header_t *conflicts;
svn_pool_clear(iterpool);
@@ -543,35 +518,35 @@ svn_wc__get_info(svn_wc_context_t *wc_ctx,
if (!repos_root_url)
{
- SVN_ERR(svn_wc__internal_get_repos_info(NULL, NULL,
- &repos_root_url,
- &repos_uuid,
- wc_ctx->db,
- svn_dirent_dirname(
+ SVN_ERR(svn_wc__db_read_repos_info(NULL, NULL,
+ &repos_root_url,
+ &repos_uuid,
+ wc_ctx->db,
+ svn_dirent_dirname(
this_abspath,
iterpool),
- scratch_pool,
- iterpool));
+ scratch_pool, iterpool));
}
info->repos_root_URL = repos_root_url;
info->repos_UUID = repos_uuid;
- SVN_ERR(svn_wc__read_conflicts(&info->wc_info->conflicts,
+ SVN_ERR(svn_wc__read_conflicts(&conflicts, NULL,
wc_ctx->db, this_abspath,
- TRUE /* ### create tempfiles */,
+ FALSE /* create tempfiles */,
+ FALSE /* only tree conflicts */,
iterpool, iterpool));
-
- if (! info->wc_info->conflicts || ! info->wc_info->conflicts->nelts)
+ if (! conflicts || ! conflicts->nelts)
continue;
- tree_conflict = APR_ARRAY_IDX(info->wc_info->conflicts, 0,
- svn_wc_conflict_description2_t *);
+ tree_conflict = APR_ARRAY_IDX(conflicts, 0,
+ const svn_wc_conflict_description2_t *);
if (!depth_includes(local_abspath, depth, tree_conflict->local_abspath,
tree_conflict->node_kind, iterpool))
continue;
+ info->wc_info->conflicts = conflicts;
SVN_ERR(receiver(receiver_baton, this_abspath, info, iterpool));
}
svn_pool_destroy(iterpool);
diff --git a/subversion/libsvn_wc/libsvn_wc.pc.in b/subversion/libsvn_wc/libsvn_wc.pc.in
new file mode 100644
index 000000000000..f44387e7472b
--- /dev/null
+++ b/subversion/libsvn_wc/libsvn_wc.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libsvn_wc
+Description: Subversion Working Copy Library
+Version: @PACKAGE_VERSION@
+Requires: apr-util-@SVN_APR_MAJOR_VERSION@ apr-@SVN_APR_MAJOR_VERSION@
+Requires.private: libsvn_delta libsvn_diff libsvn_subr
+Libs: -L${libdir} -lsvn_wc
+Cflags: -I${includedir}
diff --git a/subversion/libsvn_wc/lock.c b/subversion/libsvn_wc/lock.c
index 36fbb0eeb199..2392c3fe4e8c 100644
--- a/subversion/libsvn_wc/lock.c
+++ b/subversion/libsvn_wc/lock.c
@@ -1211,7 +1211,7 @@ open_anchor(svn_wc_adm_access_t **anchor_access,
if (disjoint)
{
/* Switched or disjoint, so drop P_ACCESS. Don't close any
- descendents, or we might blast the child. */
+ descendants, or we might blast the child. */
err = close_single(p_access, FALSE /* preserve_lock */, pool);
if (err)
{
@@ -1308,13 +1308,13 @@ do_close(svn_wc_adm_access_t *adm_access,
/* Gather all the opened access batons from the DB. */
opened = svn_wc__db_temp_get_all_access(adm_access->db, scratch_pool);
- /* Close any that are descendents of this baton. */
+ /* Close any that are descendants of this baton. */
for (hi = apr_hash_first(scratch_pool, opened);
hi;
hi = apr_hash_next(hi))
{
- const char *abspath = svn__apr_hash_index_key(hi);
- svn_wc_adm_access_t *child = svn__apr_hash_index_val(hi);
+ const char *abspath = apr_hash_this_key(hi);
+ svn_wc_adm_access_t *child = apr_hash_this_val(hi);
const char *path = child->path;
if (IS_MISSING(child))
@@ -1630,7 +1630,7 @@ svn_wc__acquire_write_lock_for_resolve(const char **lock_root_abspath,
scratch_pool, scratch_pool));
/* It's possible for the required lock path to be an ancestor
- of, a descendent of, or equal to, the obtained lock path. If
+ of, a descendant of, or equal to, the obtained lock path. If
it's an ancestor we have to try again, otherwise the obtained
lock will do. */
child = svn_dirent_skip_ancestor(required_abspath, obtained_abspath);
@@ -1643,7 +1643,7 @@ svn_wc__acquire_write_lock_for_resolve(const char **lock_root_abspath,
}
else
{
- /* required should be a descendent of, or equal to, obtained */
+ /* required should be a descendant of, or equal to, obtained */
SVN_ERR_ASSERT(!strcmp(required_abspath, obtained_abspath)
|| svn_dirent_skip_ancestor(obtained_abspath,
required_abspath));
diff --git a/subversion/libsvn_wc/merge.c b/subversion/libsvn_wc/merge.c
index 7cff3e4bd225..85ec63221c23 100644
--- a/subversion/libsvn_wc/merge.c
+++ b/subversion/libsvn_wc/merge.c
@@ -26,10 +26,11 @@
#include "svn_dirent_uri.h"
#include "svn_path.h"
#include "svn_pools.h"
+#include "svn_props.h"
#include "wc.h"
-#include "adm_files.h"
#include "conflicts.h"
+#include "props.h"
#include "translate.h"
#include "workqueue.h"
@@ -179,7 +180,7 @@ detranslate_wc_file(const char **detranslated_abspath,
= prop ? (prop->value ? prop->value->data : NULL) : old_mime_value;
old_is_binary = old_mime_value && svn_mime_type_is_binary(old_mime_value);
- new_is_binary = new_mime_value && svn_mime_type_is_binary(new_mime_value);;
+ new_is_binary = new_mime_value && svn_mime_type_is_binary(new_mime_value);
}
/* See what translations we want to do */
@@ -391,6 +392,8 @@ do_text_merge(svn_boolean_t *contains_conflicts,
const char *target_label,
const char *left_label,
const char *right_label,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *pool)
{
svn_diff_t *diff;
@@ -415,13 +418,14 @@ do_text_merge(svn_boolean_t *contains_conflicts,
ostream = svn_stream_from_aprfile2(result_f, TRUE, pool);
- SVN_ERR(svn_diff_file_output_merge2(ostream, diff,
+ SVN_ERR(svn_diff_file_output_merge3(ostream, diff,
left, detranslated_target, right,
left_marker,
target_marker,
right_marker,
"=======", /* separator */
- svn_diff_conflict_display_modified_latest,
+ svn_diff_conflict_display_modified_original_latest,
+ cancel_func, cancel_baton,
pool));
SVN_ERR(svn_stream_close(ostream));
@@ -725,16 +729,20 @@ merge_file_trivial(svn_skel_t **work_items,
{
svn_stream_t *tmp_src;
svn_stream_t *tmp_dst;
+ const char *tmp_dir;
SVN_ERR(svn_stream_open_readonly(&tmp_src, right_abspath,
scratch_pool,
scratch_pool));
- SVN_ERR(svn_wc__open_writable_base(&tmp_dst, &right_abspath,
- NULL, NULL,
- db, target_abspath,
- scratch_pool,
- scratch_pool));
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir, db,
+ target_abspath,
+ scratch_pool,
+ scratch_pool));
+
+ SVN_ERR(svn_stream_open_unique(&tmp_dst, &right_abspath,
+ tmp_dir, svn_io_file_del_none,
+ scratch_pool, scratch_pool));
SVN_ERR(svn_stream_copy3(tmp_src, tmp_dst,
cancel_func, cancel_baton,
@@ -866,15 +874,17 @@ merge_text_file(svn_skel_t **work_items,
target_label,
left_label,
right_label,
+ cancel_func, cancel_baton,
pool));
SVN_ERR(svn_io_file_close(result_f, pool));
/* Determine the MERGE_OUTCOME, and record any conflict. */
- if (contains_conflicts && ! dry_run)
+ if (contains_conflicts)
{
*merge_outcome = svn_wc_merge_conflict;
- if (*merge_outcome == svn_wc_merge_conflict)
+
+ if (! dry_run)
{
const char *left_copy, *right_copy, *target_copy;
@@ -902,12 +912,7 @@ merge_text_file(svn_skel_t **work_items,
result_pool,
scratch_pool));
}
-
- if (*merge_outcome == svn_wc_merge_merged)
- goto done;
}
- else if (contains_conflicts && dry_run)
- *merge_outcome = svn_wc_merge_conflict;
else
{
svn_boolean_t same, special;
@@ -941,7 +946,6 @@ merge_text_file(svn_skel_t **work_items,
*work_items = svn_wc__wq_merge(*work_items, work_item, result_pool);
}
-done:
/* Remove the tempfile after use */
SVN_ERR(svn_wc__wq_build_file_remove(&work_item, mt->db, mt->local_abspath,
result_target,
@@ -1226,6 +1230,7 @@ svn_wc_merge5(enum svn_wc_merge_outcome_t *merge_content_outcome,
apr_hash_t *pristine_props = NULL;
apr_hash_t *old_actual_props;
apr_hash_t *new_actual_props = NULL;
+ svn_node_kind_t kind;
SVN_ERR_ASSERT(svn_dirent_is_absolute(left_abspath));
SVN_ERR_ASSERT(svn_dirent_is_absolute(right_abspath));
@@ -1238,7 +1243,6 @@ svn_wc_merge5(enum svn_wc_merge_outcome_t *merge_content_outcome,
/* Sanity check: the merge target must be a file under revision control */
{
svn_wc__db_status_t status;
- svn_node_kind_t kind;
svn_boolean_t had_props;
svn_boolean_t props_mod;
svn_boolean_t conflicted;
@@ -1401,7 +1405,7 @@ svn_wc_merge5(enum svn_wc_merge_outcome_t *merge_content_outcome,
svn_boolean_t text_conflicted, prop_conflicted;
SVN_ERR(svn_wc__conflict_invoke_resolver(
- wc_ctx->db, target_abspath,
+ wc_ctx->db, target_abspath, kind,
conflict_skel, merge_options,
conflict_func, conflict_baton,
cancel_func, cancel_baton,
diff --git a/subversion/libsvn_wc/node.c b/subversion/libsvn_wc/node.c
index a1d6b02f5083..560a899ea043 100644
--- a/subversion/libsvn_wc/node.c
+++ b/subversion/libsvn_wc/node.c
@@ -54,18 +54,14 @@
/* Set *CHILDREN_ABSPATHS to a new array of the full paths formed by joining
- * each name in REL_CHILDREN onto DIR_ABSPATH. If SHOW_HIDDEN is false then
- * omit any paths that are reported as 'hidden' by svn_wc__db_node_hidden().
+ * each name in REL_CHILDREN onto DIR_ABSPATH.
*
* Allocate the output array and its elements in RESULT_POOL. */
-static svn_error_t *
-filter_and_make_absolute(const apr_array_header_t **children_abspaths,
- svn_wc_context_t *wc_ctx,
- const char *dir_abspath,
- const apr_array_header_t *rel_children,
- svn_boolean_t show_hidden,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+static void
+make_absolute(const apr_array_header_t **children_abspaths,
+ const char *dir_abspath,
+ const apr_array_header_t *rel_children,
+ apr_pool_t *result_pool)
{
apr_array_header_t *children;
int i;
@@ -74,29 +70,13 @@ filter_and_make_absolute(const apr_array_header_t **children_abspaths,
sizeof(const char *));
for (i = 0; i < rel_children->nelts; i++)
{
- const char *child_abspath = svn_dirent_join(dir_abspath,
- APR_ARRAY_IDX(rel_children,
- i,
- const char *),
- result_pool);
-
- /* Don't add hidden nodes to *CHILDREN if we don't want them. */
- if (!show_hidden)
- {
- svn_boolean_t child_is_hidden;
-
- SVN_ERR(svn_wc__db_node_hidden(&child_is_hidden, wc_ctx->db,
- child_abspath, scratch_pool));
- if (child_is_hidden)
- continue;
- }
-
- APR_ARRAY_PUSH(children, const char *) = child_abspath;
+ const char *name = APR_ARRAY_IDX(rel_children, i, const char *);
+ APR_ARRAY_PUSH(children, const char *) =
+ svn_dirent_join(dir_abspath, name,
+ result_pool);
}
*children_abspaths = children;
-
- return SVN_NO_ERROR;
}
@@ -104,139 +84,36 @@ svn_error_t *
svn_wc__node_get_children_of_working_node(const apr_array_header_t **children,
svn_wc_context_t *wc_ctx,
const char *dir_abspath,
- svn_boolean_t show_hidden,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- const apr_array_header_t *rel_children;
+ const apr_array_header_t *child_names;
- SVN_ERR(svn_wc__db_read_children_of_working_node(&rel_children,
+ SVN_ERR(svn_wc__db_read_children_of_working_node(&child_names,
wc_ctx->db, dir_abspath,
scratch_pool, scratch_pool));
- SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
- rel_children, show_hidden,
- result_pool, scratch_pool));
+ make_absolute(children, dir_abspath, child_names, result_pool);
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_wc__node_get_children(const apr_array_header_t **children,
- svn_wc_context_t *wc_ctx,
- const char *dir_abspath,
- svn_boolean_t show_hidden,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const apr_array_header_t *rel_children;
-
- SVN_ERR(svn_wc__db_read_children(&rel_children, wc_ctx->db, dir_abspath,
- scratch_pool, scratch_pool));
- SVN_ERR(filter_and_make_absolute(children, wc_ctx, dir_abspath,
- rel_children, show_hidden,
- result_pool, scratch_pool));
- return SVN_NO_ERROR;
-}
-
svn_error_t *
-svn_wc__internal_get_repos_info(svn_revnum_t *revision,
- const char **repos_relpath,
- const char **repos_root_url,
- const char **repos_uuid,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+svn_wc__node_get_not_present_children(const apr_array_header_t **children,
+ svn_wc_context_t *wc_ctx,
+ const char *dir_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- svn_wc__db_status_t status;
- svn_boolean_t have_work;
-
- SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
- repos_root_url, repos_uuid,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, &have_work,
- db, local_abspath,
- result_pool, scratch_pool));
-
- if ((repos_relpath ? *repos_relpath != NULL : TRUE)
- && (repos_root_url ? *repos_root_url != NULL: TRUE)
- && (repos_uuid ? *repos_uuid != NULL : TRUE))
- return SVN_NO_ERROR; /* We got the requested information */
-
- if (!have_work) /* not-present, (server-)excluded? */
- {
- return SVN_NO_ERROR; /* Can't fetch more */
- }
-
- if (status == svn_wc__db_status_deleted)
- {
- const char *base_del_abspath, *wrk_del_abspath;
-
- SVN_ERR(svn_wc__db_scan_deletion(&base_del_abspath, NULL,
- &wrk_del_abspath, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- if (base_del_abspath)
- {
- SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, repos_relpath,
- repos_root_url, repos_uuid, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL,
- db, base_del_abspath,
- result_pool, scratch_pool));
-
- /* If we have a repos_relpath, it is of the op-root */
- if (repos_relpath)
- *repos_relpath = svn_relpath_join(*repos_relpath,
- svn_dirent_skip_ancestor(base_del_abspath,
- local_abspath),
- result_pool);
- /* We keep revision as SVN_INVALID_REVNUM */
- }
- else if (wrk_del_abspath)
- {
- const char *op_root_abspath = NULL;
-
- SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
- ? &op_root_abspath : NULL,
- repos_relpath, repos_root_url,
- repos_uuid, NULL, NULL, NULL, NULL,
- db, svn_dirent_dirname(
- wrk_del_abspath,
- scratch_pool),
- result_pool, scratch_pool));
-
- /* If we have a repos_relpath, it is of the op-root */
- if (repos_relpath)
- *repos_relpath = svn_relpath_join(
- *repos_relpath,
- svn_dirent_skip_ancestor(op_root_abspath,
- local_abspath),
- result_pool);
- }
- }
- else /* added, or WORKING incomplete */
- {
- const char *op_root_abspath = NULL;
-
- /* We have an addition. scan_addition() will find the intended
- repository location by scanning up the tree. */
- SVN_ERR(svn_wc__db_scan_addition(NULL, repos_relpath
- ? &op_root_abspath : NULL,
- repos_relpath, repos_root_url,
- repos_uuid, NULL, NULL, NULL, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
- }
+ const apr_array_header_t *child_names;
- SVN_ERR_ASSERT(repos_root_url == NULL || *repos_root_url != NULL);
- SVN_ERR_ASSERT(repos_uuid == NULL || *repos_uuid != NULL);
+ SVN_ERR(svn_wc__db_base_read_not_present_children(
+ &child_names,
+ wc_ctx->db, dir_abspath,
+ scratch_pool, scratch_pool));
+ make_absolute(children, dir_abspath, child_names, result_pool);
return SVN_NO_ERROR;
}
+
svn_error_t *
svn_wc__node_get_repos_info(svn_revnum_t *revision,
const char **repos_relpath,
@@ -248,12 +125,12 @@ svn_wc__node_get_repos_info(svn_revnum_t *revision,
apr_pool_t *scratch_pool)
{
return svn_error_trace(
- svn_wc__internal_get_repos_info(revision,
- repos_relpath,
- repos_root_url,
- repos_uuid,
- wc_ctx->db, local_abspath,
- result_pool, scratch_pool));
+ svn_wc__db_read_repos_info(revision,
+ repos_relpath,
+ repos_root_url,
+ repos_uuid,
+ wc_ctx->db, local_abspath,
+ result_pool, scratch_pool));
}
/* Convert DB_KIND into the appropriate NODE_KIND value.
@@ -323,21 +200,6 @@ svn_wc_read_kind2(svn_node_kind_t *kind,
}
svn_error_t *
-svn_wc__node_get_depth(svn_depth_t *depth,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(
- svn_wc__db_read_info(NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, depth, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL,
- wc_ctx->db, local_abspath, scratch_pool,
- scratch_pool));
-}
-
-svn_error_t *
svn_wc__node_get_changed_info(svn_revnum_t *changed_rev,
apr_time_t *changed_date,
const char **changed_author,
@@ -362,8 +224,18 @@ svn_wc__node_get_url(const char **url,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- return svn_error_trace(svn_wc__db_read_url(url, wc_ctx->db, local_abspath,
- result_pool, scratch_pool));
+ const char *repos_root_url;
+ const char *repos_relpath;
+
+ SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath, &repos_root_url,
+ NULL,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ *url = svn_path_url_add_component2(repos_root_url, repos_relpath,
+ result_pool);
+
+ return SVN_NO_ERROR;
}
/* A recursive node-walker, helper for svn_wc__internal_walk_children().
@@ -388,25 +260,24 @@ walker_helper(svn_wc__db_t *db,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- apr_hash_t *rel_children_info;
- apr_hash_index_t *hi;
apr_pool_t *iterpool;
+ const apr_array_header_t *items;
+ int i;
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
- SVN_ERR(svn_wc__db_read_children_walker_info(&rel_children_info, db,
- dir_abspath, scratch_pool,
- scratch_pool));
+ iterpool = svn_pool_create(scratch_pool);
+ SVN_ERR(svn_wc__db_read_children_walker_info(&items, db,
+ dir_abspath, scratch_pool,
+ iterpool));
- iterpool = svn_pool_create(scratch_pool);
- for (hi = apr_hash_first(scratch_pool, rel_children_info);
- hi;
- hi = apr_hash_next(hi))
+ for (i = 0; i < items->nelts; i++)
{
- const char *child_name = svn__apr_hash_index_key(hi);
- struct svn_wc__db_walker_info_t *wi = svn__apr_hash_index_val(hi);
+ struct svn_wc__db_walker_info_t *wi =
+ APR_ARRAY_IDX(items, i, struct svn_wc__db_walker_info_t *);
+ const char *child_name = wi->name;
svn_node_kind_t child_kind = wi->kind;
svn_wc__db_status_t child_status = wi->status;
const char *child_abspath;
@@ -489,6 +360,7 @@ svn_wc__internal_walk_children(svn_wc__db_t *db,
svn_node_kind_t kind;
svn_wc__db_status_t status;
apr_hash_t *changelist_hash = NULL;
+ const char *changelist = NULL;
SVN_ERR_ASSERT(walk_depth >= svn_depth_empty
&& walk_depth <= svn_depth_infinity);
@@ -501,14 +373,17 @@ svn_wc__internal_walk_children(svn_wc__db_t *db,
SVN_ERR(svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ changelist_hash ? &changelist : NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
db, local_abspath, scratch_pool, scratch_pool));
SVN_ERR(convert_db_kind_to_node_kind(&kind, db_kind, status, show_hidden));
- if (svn_wc__internal_changelist_match(db, local_abspath,
- changelist_hash, scratch_pool))
- SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
+ if (!changelist_hash
+ || (changelist && svn_hash_gets(changelist_hash, changelist)))
+ {
+ SVN_ERR(walk_callback(local_abspath, kind, walk_baton, scratch_pool));
+ }
if (db_kind == svn_node_file
|| status == svn_wc__db_status_not_present
@@ -531,54 +406,6 @@ svn_wc__internal_walk_children(svn_wc__db_t *db,
}
svn_error_t *
-svn_wc__node_is_status_deleted(svn_boolean_t *is_deleted,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_status_t status;
-
- SVN_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,
- wc_ctx->db, local_abspath,
- scratch_pool, scratch_pool));
-
- *is_deleted = (status == svn_wc__db_status_deleted);
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__node_get_deleted_ancestor(const char **deleted_ancestor_abspath,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_status_t status;
-
- *deleted_ancestor_abspath = NULL;
-
- SVN_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,
- wc_ctx->db, local_abspath,
- scratch_pool, scratch_pool));
-
- if (status == svn_wc__db_status_deleted)
- SVN_ERR(svn_wc__db_scan_deletion(deleted_ancestor_abspath, NULL, NULL,
- NULL, wc_ctx->db, local_abspath,
- result_pool, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_wc__node_is_not_present(svn_boolean_t *is_not_present,
svn_boolean_t *is_excluded,
svn_boolean_t *is_server_excluded,
@@ -671,7 +498,6 @@ svn_wc__node_get_base(svn_node_kind_t *kind,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_boolean_t ignore_enoent,
- svn_boolean_t show_hidden,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -691,9 +517,8 @@ svn_wc__node_get_base(svn_node_kind_t *kind,
if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
return svn_error_trace(err);
else if (err
- || (!err && !show_hidden
- && (status != svn_wc__db_status_normal
- && status != svn_wc__db_status_incomplete)))
+ || (status != svn_wc__db_status_normal
+ && status != svn_wc__db_status_incomplete))
{
if (!ignore_enoent)
{
@@ -783,133 +608,6 @@ svn_wc__node_get_pre_ng_status_data(svn_revnum_t *revision,
}
svn_error_t *
-svn_wc__internal_node_get_schedule(svn_wc_schedule_t *schedule,
- svn_boolean_t *copied,
- svn_wc__db_t *db,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_status_t status;
- svn_boolean_t op_root;
- svn_boolean_t have_base;
- svn_boolean_t have_work;
- svn_boolean_t have_more_work;
- const char *copyfrom_relpath;
-
- if (schedule)
- *schedule = svn_wc_schedule_normal;
- if (copied)
- *copied = FALSE;
-
- SVN_ERR(svn_wc__db_read_info(&status, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, &copyfrom_relpath,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &op_root, NULL, NULL,
- &have_base, &have_more_work, &have_work,
- db, local_abspath, scratch_pool, scratch_pool));
-
- switch (status)
- {
- case svn_wc__db_status_not_present:
- case svn_wc__db_status_server_excluded:
- case svn_wc__db_status_excluded:
- /* We used status normal in the entries world. */
- if (schedule)
- *schedule = svn_wc_schedule_normal;
- break;
- case svn_wc__db_status_normal:
- case svn_wc__db_status_incomplete:
- break;
-
- case svn_wc__db_status_deleted:
- {
- if (schedule)
- *schedule = svn_wc_schedule_delete;
-
- if (!copied)
- break;
-
- if (have_more_work || !have_base)
- *copied = TRUE;
- else
- {
- const char *work_del_abspath;
-
- /* Find out details of our deletion. */
- SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL,
- &work_del_abspath, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- if (work_del_abspath)
- *copied = TRUE; /* Working deletion */
- }
- break;
- }
- case svn_wc__db_status_added:
- {
- if (!op_root)
- {
- if (copied)
- *copied = TRUE;
-
- if (schedule)
- *schedule = svn_wc_schedule_normal;
-
- break;
- }
-
- if (copied)
- *copied = (copyfrom_relpath != NULL);
-
- if (schedule)
- *schedule = svn_wc_schedule_add;
- else
- break;
-
- /* Check for replaced */
- if (have_base || have_more_work)
- {
- svn_wc__db_status_t below_working;
- SVN_ERR(svn_wc__db_info_below_working(&have_base, &have_work,
- &below_working,
- db, local_abspath,
- scratch_pool));
-
- /* If the node is not present or deleted (read: not present
- in working), then the node is not a replacement */
- if (below_working != svn_wc__db_status_not_present
- && below_working != svn_wc__db_status_deleted)
- {
- *schedule = svn_wc_schedule_replace;
- break;
- }
- }
- break;
- }
- default:
- SVN_ERR_MALFUNCTION();
- }
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__node_get_schedule(svn_wc_schedule_t *schedule,
- svn_boolean_t *copied,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *scratch_pool)
-{
- return svn_error_trace(
- svn_wc__internal_node_get_schedule(schedule,
- copied,
- wc_ctx->db,
- local_abspath,
- scratch_pool));
-}
-
-svn_error_t *
svn_wc__node_clear_dav_cache_recursive(svn_wc_context_t *wc_ctx,
const char *local_abspath,
apr_pool_t *scratch_pool)
@@ -952,6 +650,7 @@ svn_wc__internal_get_origin(svn_boolean_t *is_copy,
const char **repos_relpath,
const char **repos_root_url,
const char **repos_uuid,
+ svn_depth_t *depth,
const char **copy_root_abspath,
svn_wc__db_t *db,
const char *local_abspath,
@@ -964,20 +663,24 @@ svn_wc__internal_get_origin(svn_boolean_t *is_copy,
const char *original_repos_uuid;
svn_revnum_t original_revision;
svn_wc__db_status_t status;
+ svn_boolean_t have_more_work;
+ svn_boolean_t op_root;
const char *tmp_repos_relpath;
+ if (copy_root_abspath)
+ *copy_root_abspath = NULL;
if (!repos_relpath)
repos_relpath = &tmp_repos_relpath;
SVN_ERR(svn_wc__db_read_info(&status, NULL, revision, repos_relpath,
repos_root_url, repos_uuid, NULL, NULL, NULL,
- NULL, NULL, NULL,
+ depth, NULL, NULL,
&original_repos_relpath,
&original_repos_root_url,
&original_repos_uuid, &original_revision,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, is_copy,
+ NULL, NULL, NULL, NULL, NULL, &op_root, NULL,
+ NULL, NULL, &have_more_work, is_copy,
db, local_abspath, result_pool, scratch_pool));
if (*repos_relpath)
@@ -995,6 +698,7 @@ svn_wc__internal_get_origin(svn_boolean_t *is_copy,
if (original_repos_relpath)
{
+ /* We an have a copy */
*repos_relpath = original_repos_relpath;
if (revision)
*revision = original_revision;
@@ -1005,21 +709,19 @@ svn_wc__internal_get_origin(svn_boolean_t *is_copy,
if (copy_root_abspath == NULL)
return SVN_NO_ERROR;
+ else if (op_root)
+ {
+ *copy_root_abspath = apr_pstrdup(result_pool, local_abspath);
+ return SVN_NO_ERROR;
+ }
}
{
svn_boolean_t scan_working = FALSE;
- if (status == svn_wc__db_status_added)
+ if (status == svn_wc__db_status_added
+ || (status == svn_wc__db_status_deleted && have_more_work))
scan_working = TRUE;
- else if (status == svn_wc__db_status_deleted)
- {
- svn_boolean_t have_base;
- /* Is this a BASE or a WORKING delete? */
- SVN_ERR(svn_wc__db_info_below_working(&have_base, &scan_working,
- &status, db, local_abspath,
- scratch_pool));
- }
if (scan_working)
{
@@ -1079,6 +781,7 @@ svn_wc__node_get_origin(svn_boolean_t *is_copy,
const char **repos_relpath,
const char **repos_root_url,
const char **repos_uuid,
+ svn_depth_t *depth,
const char **copy_root_abspath,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
@@ -1088,7 +791,7 @@ svn_wc__node_get_origin(svn_boolean_t *is_copy,
{
return svn_error_trace(svn_wc__internal_get_origin(is_copy, revision,
repos_relpath, repos_root_url, repos_uuid,
- copy_root_abspath,
+ depth, copy_root_abspath,
wc_ctx->db, local_abspath, scan_deleted,
result_pool, scratch_pool));
}
@@ -1364,16 +1067,22 @@ svn_wc__node_was_moved_away(const char **moved_to_abspath,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_boolean_t is_deleted;
+ svn_wc__db_status_t status;
if (moved_to_abspath)
*moved_to_abspath = NULL;
if (op_root_abspath)
*op_root_abspath = NULL;
- SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, wc_ctx, local_abspath,
- scratch_pool));
- if (is_deleted)
+ SVN_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,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ if (status == svn_wc__db_status_deleted)
SVN_ERR(svn_wc__db_scan_deletion(NULL, moved_to_abspath, NULL,
op_root_abspath, wc_ctx->db,
local_abspath,
diff --git a/subversion/libsvn_wc/old-and-busted.c b/subversion/libsvn_wc/old-and-busted.c
index b87be85550bb..8cd94af2733b 100644
--- a/subversion/libsvn_wc/old-and-busted.c
+++ b/subversion/libsvn_wc/old-and-busted.c
@@ -443,7 +443,7 @@ svn_wc__serialize_file_external(const char **str,
SVN_ERR(opt_revision_to_string(&s1, path, peg_rev, pool));
SVN_ERR(opt_revision_to_string(&s2, path, rev, pool));
- s = apr_pstrcat(pool, s1, ":", s2, ":", path, (char *)NULL);
+ s = apr_pstrcat(pool, s1, ":", s2, ":", path, SVN_VA_NULL);
}
else
s = NULL;
@@ -1154,7 +1154,7 @@ resolve_to_defaults(apr_hash_t *entries,
/* Then use it to fill in missing information in other entries. */
for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
{
- svn_wc_entry_t *this_entry = svn__apr_hash_index_val(hi);
+ svn_wc_entry_t *this_entry = apr_hash_this_val(hi);
if (this_entry == default_entry)
/* THIS_DIR already has all the information it can possibly
diff --git a/subversion/libsvn_wc/props.c b/subversion/libsvn_wc/props.c
index a7b2339b0107..664bcf170664 100644
--- a/subversion/libsvn_wc/props.c
+++ b/subversion/libsvn_wc/props.c
@@ -62,31 +62,6 @@
#include "svn_private_config.h"
-/* Forward declaration. */
-static svn_error_t *
-prop_conflict_from_skel(const svn_string_t **conflict_desc,
- const svn_skel_t *skel,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool);
-
-/* Given a *SINGLE* property conflict in PROP_SKEL, generate a description
- for it, and write it to STREAM, along with a trailing EOL sequence.
-
- See prop_conflict_from_skel() for details on PROP_SKEL. */
-static svn_error_t *
-append_prop_conflict(svn_stream_t *stream,
- const svn_skel_t *prop_skel,
- apr_pool_t *pool)
-{
- /* TODO: someday, perhaps prefix each conflict_description with a
- timestamp or something? */
- const svn_string_t *conflict_desc;
-
- SVN_ERR(prop_conflict_from_skel(&conflict_desc, prop_skel, pool, pool));
-
- return svn_stream_puts(stream, conflict_desc->data);
-}
-
/*---------------------------------------------------------------------*/
/*** Merging propchanges into the working copy ***/
@@ -352,7 +327,8 @@ svn_wc_merge_props3(svn_wc_notify_state_t *state,
{
svn_boolean_t prop_conflicted;
- SVN_ERR(svn_wc__conflict_invoke_resolver(db, local_abspath, conflict_skel,
+ SVN_ERR(svn_wc__conflict_invoke_resolver(db, local_abspath, kind,
+ conflict_skel,
NULL /* merge_options */,
conflict_func, conflict_baton,
cancel_func, cancel_baton,
@@ -531,89 +507,96 @@ maybe_prop_value(const svn_skel_t *skel,
}
-/* Parse a property conflict description from the provided SKEL.
- The result includes a descriptive message (see generate_conflict_message)
- and maybe a diff of property values containing conflict markers.
- The result will be allocated in RESULT_POOL.
-
- Note: SKEL is a single property conflict of the form:
-
- ("prop" ([ORIGINAL]) ([MINE]) ([INCOMING]) ([INCOMING_BASE]))
-
- See notes/wc-ng/conflict-storage for more information. */
+/* Create a property rejection description for the specified property.
+ The result will be allocated in RESULT_POOL. */
static svn_error_t *
-prop_conflict_from_skel(const svn_string_t **conflict_desc,
- const svn_skel_t *skel,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
+prop_conflict_new(const svn_string_t **conflict_desc,
+ const char *propname,
+ const svn_string_t *original,
+ const svn_string_t *mine,
+ const svn_string_t *incoming,
+ const svn_string_t *incoming_base,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- const svn_string_t *original;
- const svn_string_t *mine;
- const svn_string_t *incoming;
- const svn_string_t *incoming_base;
- const char *propname;
svn_diff_t *diff;
svn_diff_file_options_t *diff_opts;
svn_stringbuf_t *buf;
- svn_boolean_t original_is_binary;
+ svn_boolean_t incoming_base_is_binary;
svn_boolean_t mine_is_binary;
svn_boolean_t incoming_is_binary;
- /* Navigate to the property name. */
- skel = skel->children->next;
-
- /* We need to copy these into SCRATCH_POOL in order to nul-terminate
- the values. */
- propname = apr_pstrmemdup(scratch_pool, skel->data, skel->len);
- original = maybe_prop_value(skel->next, scratch_pool);
- mine = maybe_prop_value(skel->next->next, scratch_pool);
- incoming = maybe_prop_value(skel->next->next->next, scratch_pool);
- incoming_base = maybe_prop_value(skel->next->next->next->next, scratch_pool);
-
buf = generate_conflict_message(propname, original, mine, incoming,
incoming_base, scratch_pool);
+ /* Convert deleted or not-yet-added values to empty-string values, for the
+ purposes of diff generation and binary detection. */
if (mine == NULL)
mine = svn_string_create_empty(scratch_pool);
if (incoming == NULL)
incoming = svn_string_create_empty(scratch_pool);
+ if (incoming_base == NULL)
+ incoming_base = svn_string_create_empty(scratch_pool);
- /* Pick a suitable base for the conflict diff.
- * The incoming value is always a change,
- * but the local value might not have changed. */
- if (original == NULL)
- {
- if (incoming_base)
- original = incoming_base;
- else
- original = svn_string_create_empty(scratch_pool);
- }
- else if (incoming_base && svn_string_compare(original, mine))
- original = incoming_base;
+ /* How we render the conflict:
+
+ We have four sides: original, mine, incoming_base, incoming.
+ We render the conflict as a 3-way diff. A diff3 API has three parts,
+ called:
+
+ <<< - original
+ ||| - modified (or "older")
+ === - latest (or "theirs")
+ >>>
+
+ We fill those parts as follows:
+
+ PART FILLED BY SKEL MEMBER USER-FACING ROLE
+ ==== ===================== ================
+ original mine was WORKING tree at conflict creation
+ modified incoming_base left-hand side of merge
+ latest incoming right-hand side of merge
+ (none) original was BASE tree at conflict creation
+
+ An 'update -r rN' is treated like a 'merge -r BASE:rN', i.e., in an
+ 'update' operation skel->original and skel->incoming_base coincide.
+
+ Note that the term "original" is used both in the skel and in diff3
+ with different meanings. Note also that the skel's ORIGINAL value was
+ at some point in the BASE tree, but the BASE tree need not have contained
+ the INCOMING_BASE value.
+
+ Yes, it's confusing. */
/* If any of the property values involved in the diff is binary data,
* do not generate a diff. */
- original_is_binary = svn_io_is_binary_data(original->data, original->len);
+ incoming_base_is_binary = svn_io_is_binary_data(incoming_base->data,
+ incoming_base->len);
mine_is_binary = svn_io_is_binary_data(mine->data, mine->len);
incoming_is_binary = svn_io_is_binary_data(incoming->data, incoming->len);
- if (!(original_is_binary || mine_is_binary || incoming_is_binary))
+ if (!(incoming_base_is_binary || mine_is_binary || incoming_is_binary))
{
diff_opts = svn_diff_file_options_create(scratch_pool);
diff_opts->ignore_space = svn_diff_file_ignore_space_none;
diff_opts->ignore_eol_style = FALSE;
diff_opts->show_c_function = FALSE;
- SVN_ERR(svn_diff_mem_string_diff3(&diff, original, mine, incoming,
+ /* Pass skel member INCOMING_BASE into the formal parameter ORIGINAL.
+ Ignore the skel member ORIGINAL. */
+ SVN_ERR(svn_diff_mem_string_diff3(&diff, incoming_base, mine, incoming,
diff_opts, scratch_pool));
if (svn_diff_contains_conflicts(diff))
{
svn_stream_t *stream;
svn_diff_conflict_display_style_t style;
const char *mine_marker = _("<<<<<<< (local property value)");
- const char *incoming_marker = _(">>>>>>> (incoming property value)");
+ const char *incoming_marker = _(">>>>>>> (incoming 'changed to' value)");
+ const char *incoming_base_marker = _("||||||| (incoming 'changed from' value)");
const char *separator = "=======";
- svn_string_t *original_ascii =
- svn_string_create(svn_utf_cstring_from_utf8_fuzzy(original->data,
+ svn_string_t *incoming_base_ascii =
+ svn_string_create(svn_utf_cstring_from_utf8_fuzzy(incoming_base->data,
scratch_pool),
scratch_pool);
svn_string_t *mine_ascii =
@@ -625,16 +608,18 @@ prop_conflict_from_skel(const svn_string_t **conflict_desc,
scratch_pool),
scratch_pool);
- style = svn_diff_conflict_display_modified_latest;
+ style = svn_diff_conflict_display_modified_original_latest;
stream = svn_stream_from_stringbuf(buf, scratch_pool);
SVN_ERR(svn_stream_skip(stream, buf->len));
- SVN_ERR(svn_diff_mem_string_output_merge2(stream, diff,
- original_ascii,
+ SVN_ERR(svn_diff_mem_string_output_merge3(stream, diff,
+ incoming_base_ascii,
mine_ascii,
incoming_ascii,
- NULL, mine_marker,
+ incoming_base_marker, mine_marker,
incoming_marker, separator,
- style, scratch_pool));
+ style,
+ cancel_func, cancel_baton,
+ scratch_pool));
SVN_ERR(svn_stream_close(stream));
*conflict_desc = svn_string_create_from_buf(buf, result_pool);
@@ -669,6 +654,49 @@ prop_conflict_from_skel(const svn_string_t **conflict_desc,
return SVN_NO_ERROR;
}
+/* Parse a property conflict description from the provided SKEL.
+ The result includes a descriptive message (see generate_conflict_message)
+ and maybe a diff of property values containing conflict markers.
+ The result will be allocated in RESULT_POOL.
+
+ Note: SKEL is a single property conflict of the form:
+
+ ("prop" ([ORIGINAL]) ([MINE]) ([INCOMING]) ([INCOMING_BASE]))
+
+ Note: This is not the same format as the property conflicts we store in
+ wc.db since 1.8. This is the legacy format used in the Workqueue in 1.7-1.8 */
+static svn_error_t *
+prop_conflict_from_skel(const svn_string_t **conflict_desc,
+ const svn_skel_t *skel,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const svn_string_t *original;
+ const svn_string_t *mine;
+ const svn_string_t *incoming;
+ const svn_string_t *incoming_base;
+ const char *propname;
+
+ /* Navigate to the property name. */
+ skel = skel->children->next;
+
+ /* We need to copy these into SCRATCH_POOL in order to nul-terminate
+ the values. */
+ propname = apr_pstrmemdup(scratch_pool, skel->data, skel->len);
+ original = maybe_prop_value(skel->next, scratch_pool);
+ mine = maybe_prop_value(skel->next->next, scratch_pool);
+ incoming = maybe_prop_value(skel->next->next->next, scratch_pool);
+ incoming_base = maybe_prop_value(skel->next->next->next->next, scratch_pool);
+
+ return svn_error_trace(prop_conflict_new(conflict_desc,
+ propname,
+ original, mine,
+ incoming, incoming_base,
+ cancel_func, cancel_baton,
+ result_pool, scratch_pool));
+}
/* Create a property conflict file at PREJFILE based on the property
conflicts in CONFLICT_SKEL. */
@@ -676,7 +704,9 @@ svn_error_t *
svn_wc__create_prejfile(const char **tmp_prejfile_abspath,
svn_wc__db_t *db,
const char *local_abspath,
- const svn_skel_t *conflict_skel,
+ const svn_skel_t *prop_conflict_data,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -694,11 +724,88 @@ svn_wc__create_prejfile(const char **tmp_prejfile_abspath,
tempdir_abspath, svn_io_file_del_none,
scratch_pool, iterpool));
- for (scan = conflict_skel->children->next; scan != NULL; scan = scan->next)
+ if (prop_conflict_data)
{
- svn_pool_clear(iterpool);
+ for (scan = prop_conflict_data->children->next;
+ scan != NULL; scan = scan->next)
+ {
+ const svn_string_t *conflict_desc;
+
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(prop_conflict_from_skel(&conflict_desc, scan,
+ cancel_func, cancel_baton,
+ iterpool, iterpool));
- SVN_ERR(append_prop_conflict(stream, scan, iterpool));
+ SVN_ERR(svn_stream_puts(stream, conflict_desc->data));
+ }
+ }
+ else
+ {
+ svn_wc_operation_t operation;
+ apr_hash_index_t *hi;
+ apr_hash_t *old_props;
+ apr_hash_t *mine_props;
+ apr_hash_t *their_original_props;
+ apr_hash_t *their_props;
+ apr_hash_t *conflicted_props;
+ svn_skel_t *conflicts;
+
+ SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__conflict_read_info(&operation, NULL, NULL, NULL, NULL,
+ db, local_abspath,
+ conflicts,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_wc__conflict_read_prop_conflict(NULL,
+ &mine_props,
+ &their_original_props,
+ &their_props,
+ &conflicted_props,
+ db, local_abspath,
+ conflicts,
+ scratch_pool,
+ scratch_pool));
+
+ if (operation == svn_wc_operation_merge)
+ SVN_ERR(svn_wc__db_read_pristine_props(&old_props, db, local_abspath,
+ scratch_pool, scratch_pool));
+ else
+ old_props = their_original_props;
+
+ /* ### TODO: Sort conflicts? */
+ for (hi = apr_hash_first(scratch_pool, conflicted_props);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const svn_string_t *conflict_desc;
+ const char *propname = apr_hash_this_key(hi);
+ const svn_string_t *old_value;
+ const svn_string_t *mine_value;
+ const svn_string_t *their_value;
+ const svn_string_t *their_original_value;
+
+ svn_pool_clear(iterpool);
+
+ old_value = old_props ? svn_hash_gets(old_props, propname) : NULL;
+ mine_value = mine_props ? svn_hash_gets(mine_props, propname) : NULL;
+ their_value = their_props ? svn_hash_gets(their_props, propname)
+ : NULL;
+ their_original_value = their_original_props
+ ? svn_hash_gets(their_original_props, propname)
+ : NULL;
+
+ SVN_ERR(prop_conflict_new(&conflict_desc,
+ propname, old_value, mine_value,
+ their_value, their_original_value,
+ cancel_func, cancel_baton,
+ iterpool, iterpool));
+
+ SVN_ERR(svn_stream_puts(stream, conflict_desc->data));
+ }
}
SVN_ERR(svn_stream_close(stream));
@@ -1167,7 +1274,7 @@ svn_wc__merge_props(svn_skel_t **conflict_skel,
svn_pool_clear(iterpool);
- to_val = to_val ? svn_string_dup(to_val, result_pool) : NULL;
+ to_val = svn_string_dup(to_val, result_pool);
svn_hash_sets(their_props, propname, to_val);
@@ -2030,8 +2137,8 @@ svn_wc__canonicalize_props(apr_hash_t **prepared_props,
for (hi = apr_hash_first(scratch_pool, (apr_hash_t *)props); hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- const svn_string_t *value = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ const svn_string_t *value = apr_hash_this_val(hi);
if (strcmp(name, SVN_PROP_MIME_TYPE) == 0)
continue;
diff --git a/subversion/libsvn_wc/props.h b/subversion/libsvn_wc/props.h
index c648e3c42ff9..c33e13e58ec9 100644
--- a/subversion/libsvn_wc/props.h
+++ b/subversion/libsvn_wc/props.h
@@ -139,11 +139,17 @@ svn_wc__get_actual_props(apr_hash_t **props,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
+/* Creates a property reject file at *TMP_PREJFILE_ABSPATH, with
+ either the property conflict data from DB (when PROP_CONFLICT_DATA
+ is NULL) or the information in PROP_CONFLICT_DATA if it isn't.
+ */
svn_error_t *
svn_wc__create_prejfile(const char **tmp_prejfile_abspath,
svn_wc__db_t *db,
const char *local_abspath,
- const svn_skel_t *conflict_skel,
+ const svn_skel_t *prop_conflict_data,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
diff --git a/subversion/libsvn_wc/questions.c b/subversion/libsvn_wc/questions.c
index c2a42b6ad935..08583639b571 100644
--- a/subversion/libsvn_wc/questions.c
+++ b/subversion/libsvn_wc/questions.c
@@ -117,6 +117,7 @@ compare_and_verify(svn_boolean_t *modified_p,
apr_hash_t *keywords;
svn_boolean_t special = FALSE;
svn_boolean_t need_translation;
+ svn_stream_t *v_stream; /* versioned_file */
SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_file_abspath));
@@ -150,22 +151,24 @@ compare_and_verify(svn_boolean_t *modified_p,
/* ### Other checks possible? */
- if (need_translation)
+ /* Reading files is necessary. */
+ if (special && need_translation)
{
- /* Reading files is necessary. */
- svn_stream_t *v_stream; /* versioned_file */
-
- if (special)
- {
- SVN_ERR(svn_subst_read_specialfile(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
- }
- else
+ SVN_ERR(svn_subst_read_specialfile(&v_stream, versioned_file_abspath,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ /* We don't use APR-level buffering because the comparison function
+ * will do its own buffering. */
+ apr_file_t *file;
+ SVN_ERR(svn_io_file_open(&file, versioned_file_abspath, APR_READ,
+ APR_OS_DEFAULT, scratch_pool));
+ v_stream = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+
+ if (need_translation)
{
- SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
-
- if (!exact_comparison && need_translation)
+ if (!exact_comparison)
{
if (eol_style == svn_subst_eol_style_native)
eol_str = SVN_SUBST_NATIVE_EOL_STR;
@@ -183,7 +186,7 @@ compare_and_verify(svn_boolean_t *modified_p,
FALSE /* expand */,
scratch_pool);
}
- else if (need_translation)
+ else
{
/* Wrap base stream to translate into working copy form, and
* arrange to throw an error if its EOL style is inconsistent. */
@@ -193,21 +196,10 @@ compare_and_verify(svn_boolean_t *modified_p,
scratch_pool);
}
}
-
- SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
- scratch_pool));
}
- else
- {
- /* Translation would be a no-op, so compare the original file. */
- svn_stream_t *v_stream; /* versioned_file */
- SVN_ERR(svn_stream_open_readonly(&v_stream, versioned_file_abspath,
- scratch_pool, scratch_pool));
-
- SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
- scratch_pool));
- }
+ SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream,
+ scratch_pool));
*modified_p = (! same);
@@ -377,7 +369,8 @@ internal_conflicted_p(svn_boolean_t *text_conflicted_p,
svn_boolean_t resolved_text = FALSE;
svn_boolean_t resolved_props = FALSE;
- SVN_ERR(svn_wc__db_read_conflict(&conflicts, db, local_abspath,
+ SVN_ERR(svn_wc__db_read_conflict(&conflicts, NULL, NULL,
+ db, local_abspath,
scratch_pool, scratch_pool));
if (!conflicts)
@@ -604,18 +597,150 @@ svn_wc__has_switched_subtrees(svn_boolean_t *is_switched,
}
+/* A baton for use with modcheck_found_entry(). */
+typedef struct modcheck_baton_t {
+ svn_boolean_t ignore_unversioned;
+ svn_boolean_t found_mod; /* whether a modification has been found */
+ svn_boolean_t found_not_delete; /* Found a not-delete modification */
+} modcheck_baton_t;
+
+/* An implementation of svn_wc_status_func4_t. */
+static svn_error_t *
+modcheck_callback(void *baton,
+ const char *local_abspath,
+ const svn_wc_status3_t *status,
+ apr_pool_t *scratch_pool)
+{
+ modcheck_baton_t *mb = baton;
+
+ switch (status->node_status)
+ {
+ case svn_wc_status_normal:
+ case svn_wc_status_ignored:
+ case svn_wc_status_none:
+ case svn_wc_status_external:
+ break;
+
+ case svn_wc_status_incomplete:
+ if ((status->text_status != svn_wc_status_normal
+ && status->text_status != svn_wc_status_none)
+ || (status->prop_status != svn_wc_status_normal
+ && status->prop_status != svn_wc_status_none))
+ {
+ mb->found_mod = TRUE;
+ mb->found_not_delete = TRUE;
+ /* Incomplete, but local modifications */
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+ }
+ break;
+
+ case svn_wc_status_deleted:
+ mb->found_mod = TRUE;
+ if (!mb->ignore_unversioned
+ && status->actual_kind != svn_node_none
+ && status->actual_kind != svn_node_unknown)
+ {
+ /* The delete is obstructed by something unversioned */
+ mb->found_not_delete = TRUE;
+ return svn_error_create(SVN_ERR_CEASE_INVOCATION, NULL, NULL);
+ }
+ break;
+
+ case svn_wc_status_unversioned:
+ if (mb->ignore_unversioned)
+ break;
+ /* else fall through */
+ case svn_wc_status_missing:
+ case svn_wc_status_obstructed:
+ 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);
+
+ default:
+ case svn_wc_status_added:
+ case svn_wc_status_replaced:
+ case svn_wc_status_modified:
+ 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);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+
+/* Set *MODIFIED to true iff there are any local modifications within the
+ * 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. */
+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_boolean_t ignore_unversioned,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ modcheck_baton_t modcheck_baton = { FALSE, FALSE, FALSE };
+ svn_error_t *err;
+
+ if (!all_edits_are_deletes)
+ {
+ SVN_ERR(svn_wc__db_has_db_mods(modified, db, local_abspath,
+ scratch_pool));
+
+ if (*modified)
+ return SVN_NO_ERROR;
+ }
+
+ modcheck_baton.ignore_unversioned = ignore_unversioned;
+
+ /* 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
+ * no local mods in the pieces that aren't present in the WC. */
+
+ err = svn_wc__internal_walk_status(db, local_abspath,
+ svn_depth_infinity,
+ FALSE, FALSE, FALSE, NULL,
+ modcheck_callback, &modcheck_baton,
+ cancel_func, cancel_baton,
+ scratch_pool);
+
+ if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+ svn_error_clear(err);
+ else
+ SVN_ERR(err);
+
+ *modified = modcheck_baton.found_mod;
+ if (all_edits_are_deletes)
+ *all_edits_are_deletes = (modcheck_baton.found_mod
+ && !modcheck_baton.found_not_delete);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_wc__has_local_mods(svn_boolean_t *is_modified,
svn_wc_context_t *wc_ctx,
const char *local_abspath,
+ svn_boolean_t ignore_unversioned,
svn_cancel_func_t cancel_func,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- return svn_error_trace(svn_wc__db_has_local_mods(is_modified,
- wc_ctx->db,
- local_abspath,
- cancel_func,
- cancel_baton,
- scratch_pool));
+ svn_boolean_t modified;
+
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, NULL,
+ wc_ctx->db, local_abspath,
+ ignore_unversioned,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
+ *is_modified = modified;
+ return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_wc/relocate.c b/subversion/libsvn_wc/relocate.c
index 4a9df678aaf1..e4b335b5b971 100644
--- a/subversion/libsvn_wc/relocate.c
+++ b/subversion/libsvn_wc/relocate.c
@@ -148,7 +148,7 @@ svn_wc_relocate4(svn_wc_context_t *wc_ctx,
if (old_url_len == from_len)
new_url = to;
else
- new_url = apr_pstrcat(scratch_pool, to, old_url + from_len, (char *)NULL);
+ new_url = apr_pstrcat(scratch_pool, to, old_url + from_len, SVN_VA_NULL);
if (! svn_path_is_url(new_url))
return svn_error_createf(SVN_ERR_WC_INVALID_RELOCATION, NULL,
_("Invalid relocation destination: '%s' "
diff --git a/subversion/libsvn_wc/revert.c b/subversion/libsvn_wc/revert.c
index 5e190e89c403..bba1799864ab 100644
--- a/subversion/libsvn_wc/revert.c
+++ b/subversion/libsvn_wc/revert.c
@@ -46,6 +46,7 @@
#include "svn_private_config.h"
#include "private/svn_io_private.h"
#include "private/svn_wc_private.h"
+#include "private/svn_sorts_private.h"
/* Thoughts on Reversion.
@@ -154,7 +155,7 @@ revert_restore_handle_copied_dirs(svn_boolean_t *removed_self,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- const apr_array_header_t *copied_children;
+ apr_array_header_t *copied_children;
svn_wc__db_revert_list_copied_child_info_t *child_info;
int i;
svn_node_kind_t on_disk;
@@ -198,9 +199,7 @@ revert_restore_handle_copied_dirs(svn_boolean_t *removed_self,
* that still exist on disk (e.g. unversioned files within the copied tree).
* So sort the children list such that longest paths come first and try to
* remove each child directory in order. */
- qsort(copied_children->elts, copied_children->nelts,
- sizeof(svn_wc__db_revert_list_copied_child_info_t *),
- compare_revert_list_copied_children);
+ svn_sort__array(copied_children, compare_revert_list_copied_children);
for (i = 0; i < copied_children->nelts; i++)
{
child_info = APR_ARRAY_IDX(
@@ -247,6 +246,22 @@ revert_restore_handle_copied_dirs(svn_boolean_t *removed_self,
return SVN_NO_ERROR;
}
+/* Forward definition */
+static svn_error_t *
+revert_wc_data(svn_boolean_t *run_wq,
+ svn_boolean_t *notify_required,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_wc__db_status_t status,
+ svn_node_kind_t kind,
+ svn_node_kind_t reverted_kind,
+ svn_filesize_t recorded_size,
+ apr_time_t recorded_time,
+ svn_boolean_t copied_here,
+ svn_boolean_t use_commit_times,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool);
/* Make the working tree under LOCAL_ABSPATH to depth DEPTH match the
versioned tree. This function is called after svn_wc__db_op_revert
@@ -255,56 +270,63 @@ revert_restore_handle_copied_dirs(svn_boolean_t *removed_self,
REVERT_ROOT is true for explicit revert targets and FALSE for targets
reached via recursion.
+
+ Sets *RUN_WQ to TRUE when the caller should (eventually) run the workqueue.
+ (The function sets it to FALSE when it has run the WQ itself)
+
+ If INFO is NULL, LOCAL_ABSPATH doesn't exist in DB. Otherwise INFO
+ specifies the state of LOCAL_ABSPATH in DB.
*/
static svn_error_t *
-revert_restore(svn_wc__db_t *db,
+revert_restore(svn_boolean_t *run_wq,
+ svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
+ svn_boolean_t metadata_only,
svn_boolean_t use_commit_times,
svn_boolean_t revert_root,
+ const struct svn_wc__db_info_t *info,
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_error_t *err;
svn_wc__db_status_t status;
svn_node_kind_t kind;
- svn_node_kind_t on_disk;
svn_boolean_t notify_required;
const apr_array_header_t *conflict_files;
svn_filesize_t recorded_size;
apr_time_t recorded_time;
- apr_finfo_t finfo;
-#ifdef HAVE_SYMLINK
- svn_boolean_t special;
-#endif
svn_boolean_t copied_here;
svn_node_kind_t reverted_kind;
- svn_boolean_t is_wcroot;
-
if (cancel_func)
SVN_ERR(cancel_func(cancel_baton));
- SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath, scratch_pool));
- if (is_wcroot && !revert_root)
+ if (!revert_root)
{
- /* Issue #4162: Obstructing working copy. We can't access the working
- copy data from the parent working copy for this node by just using
- local_abspath */
+ svn_boolean_t is_wcroot;
- if (notify_func)
+ SVN_ERR(svn_wc__db_is_wcroot(&is_wcroot, db, local_abspath, scratch_pool));
+ if (is_wcroot)
{
- svn_wc_notify_t *notify = svn_wc_create_notify(
+ /* Issue #4162: Obstructing working copy. We can't access the working
+ copy data from the parent working copy for this node by just using
+ local_abspath */
+
+ if (notify_func)
+ {
+ svn_wc_notify_t *notify =
+ svn_wc_create_notify(
local_abspath,
svn_wc_notify_update_skip_obstruction,
scratch_pool);
- notify_func(notify_baton, notify, scratch_pool);
- }
+ notify_func(notify_baton, notify, scratch_pool);
+ }
- return SVN_NO_ERROR; /* We don't revert obstructing working copies */
+ return SVN_NO_ERROR; /* We don't revert obstructing working copies */
+ }
}
SVN_ERR(svn_wc__db_revert_list_read(&notify_required,
@@ -313,17 +335,15 @@ revert_restore(svn_wc__db_t *db,
db, local_abspath,
scratch_pool, scratch_pool));
- err = svn_wc__db_read_info(&status, &kind,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- &recorded_size, &recorded_time, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- db, local_abspath, scratch_pool, scratch_pool);
-
- if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ if (info)
+ {
+ status = info->status;
+ kind = info->kind;
+ recorded_size = info->recorded_size;
+ recorded_time = info->recorded_time;
+ }
+ else
{
- svn_error_clear(err);
-
if (!copied_here)
{
if (notify_func && notify_required)
@@ -350,9 +370,116 @@ revert_restore(svn_wc__db_t *db,
recorded_time = 0;
}
}
- else if (err)
- return svn_error_trace(err);
+ if (!metadata_only)
+ {
+ SVN_ERR(revert_wc_data(run_wq,
+ &notify_required,
+ db, local_abspath, status, kind,
+ reverted_kind, recorded_size, recorded_time,
+ copied_here, use_commit_times,
+ cancel_func, cancel_baton, scratch_pool));
+ }
+
+ /* We delete these marker files even though they are not strictly metadata.
+ But for users that use revert as an API with metadata_only, these are. */
+ if (conflict_files)
+ {
+ int i;
+ for (i = 0; i < conflict_files->nelts; i++)
+ {
+ SVN_ERR(remove_conflict_file(&notify_required,
+ APR_ARRAY_IDX(conflict_files, i,
+ const char *),
+ local_abspath, scratch_pool));
+ }
+ }
+
+ if (notify_func && notify_required)
+ notify_func(notify_baton,
+ svn_wc_create_notify(local_abspath, svn_wc_notify_revert,
+ scratch_pool),
+ scratch_pool);
+
+ if (depth == svn_depth_infinity && kind == svn_node_dir)
+ {
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_t *children, *conflicts;
+ apr_hash_index_t *hi;
+
+ SVN_ERR(revert_restore_handle_copied_dirs(NULL, db, local_abspath, FALSE,
+ cancel_func, cancel_baton,
+ iterpool));
+
+ SVN_ERR(svn_wc__db_read_children_info(&children, &conflicts,
+ db, local_abspath, FALSE,
+ scratch_pool, iterpool));
+
+ for (hi = apr_hash_first(scratch_pool, children);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *child_name = apr_hash_this_key(hi);
+ const char *child_abspath;
+
+ svn_pool_clear(iterpool);
+
+ child_abspath = svn_dirent_join(local_abspath, child_name, iterpool);
+
+ SVN_ERR(revert_restore(run_wq,
+ db, child_abspath, depth, metadata_only,
+ use_commit_times, FALSE /* revert root */,
+ apr_hash_this_val(hi),
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ iterpool));
+ }
+
+ /* Run the queue per directory */
+ if (*run_wq)
+ {
+ SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
+ iterpool));
+ *run_wq = FALSE;
+ }
+
+ svn_pool_destroy(iterpool);
+ }
+
+ if (notify_func && (revert_root || kind == svn_node_dir))
+ SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
+ db, local_abspath, scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+/* Perform the in-working copy revert of LOCAL_ABSPATH, to what is stored in DB */
+static svn_error_t *
+revert_wc_data(svn_boolean_t *run_wq,
+ svn_boolean_t *notify_required,
+ svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_wc__db_status_t status,
+ svn_node_kind_t kind,
+ svn_node_kind_t reverted_kind,
+ svn_filesize_t recorded_size,
+ apr_time_t recorded_time,
+ svn_boolean_t copied_here,
+ svn_boolean_t use_commit_times,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_error_t *err;
+ apr_finfo_t finfo;
+ svn_node_kind_t on_disk;
+#ifdef HAVE_SYMLINK
+ svn_boolean_t special;
+#endif
+
+ /* Would be nice to use svn_io_dirent2_t here, but the performance
+ improvement that provides doesn't work, because we need the read
+ only and executable bits later on, in the most likely code path */
err = svn_io_stat(&finfo, local_abspath,
APR_FINFO_TYPE | APR_FINFO_LINK
| APR_FINFO_SIZE | APR_FINFO_MTIME
@@ -478,14 +605,14 @@ revert_restore(svn_wc__db_t *db,
modified = FALSE;
}
else
+ /* Side effect: fixes recorded timestamps */
SVN_ERR(svn_wc__internal_file_modified_p(&modified,
db, local_abspath,
TRUE, scratch_pool));
if (modified)
{
- SVN_ERR(svn_io_remove_file2(local_abspath, FALSE,
- scratch_pool));
+ /* Install will replace the file */
on_disk = svn_node_none;
}
else
@@ -505,14 +632,14 @@ revert_restore(svn_wc__db_t *db,
SVN_ERR(svn_io_set_file_read_only(local_abspath,
FALSE,
scratch_pool));
- notify_required = TRUE;
+ *notify_required = TRUE;
}
else if (!needs_lock_prop && read_only)
{
SVN_ERR(svn_io_set_file_read_write(local_abspath,
FALSE,
scratch_pool));
- notify_required = TRUE;
+ *notify_required = TRUE;
}
}
@@ -533,14 +660,14 @@ revert_restore(svn_wc__db_t *db,
SVN_ERR(svn_io_set_file_executable(local_abspath,
TRUE, FALSE,
scratch_pool));
- notify_required = TRUE;
+ *notify_required = TRUE;
}
else if (!executable_prop && executable)
{
SVN_ERR(svn_io_set_file_executable(local_abspath,
FALSE, FALSE,
scratch_pool));
- notify_required = TRUE;
+ *notify_required = TRUE;
}
}
#endif
@@ -564,90 +691,36 @@ revert_restore(svn_wc__db_t *db,
{
svn_skel_t *work_item;
- /* ### Get the checksum from read_info above and pass in here? */
SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath,
NULL, use_commit_times, TRUE,
scratch_pool, scratch_pool));
SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item,
scratch_pool));
- SVN_ERR(svn_wc__wq_run(db, local_abspath, cancel_func, cancel_baton,
- scratch_pool));
+ *run_wq = TRUE;
}
- notify_required = TRUE;
+ *notify_required = TRUE;
}
- if (conflict_files)
- {
- int i;
- for (i = 0; i < conflict_files->nelts; i++)
- {
- SVN_ERR(remove_conflict_file(&notify_required,
- APR_ARRAY_IDX(conflict_files, i,
- const char *),
- local_abspath, scratch_pool));
- }
- }
-
- if (notify_func && notify_required)
- notify_func(notify_baton,
- svn_wc_create_notify(local_abspath, svn_wc_notify_revert,
- scratch_pool),
- scratch_pool);
-
- if (depth == svn_depth_infinity && kind == svn_node_dir)
- {
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- const apr_array_header_t *children;
- int i;
-
- SVN_ERR(revert_restore_handle_copied_dirs(NULL, db, local_abspath, FALSE,
- cancel_func, cancel_baton,
- iterpool));
-
- SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
- local_abspath,
- scratch_pool,
- iterpool));
- for (i = 0; i < children->nelts; ++i)
- {
- const char *child_abspath;
-
- svn_pool_clear(iterpool);
-
- child_abspath = svn_dirent_join(local_abspath,
- APR_ARRAY_IDX(children, i,
- const char *),
- iterpool);
-
- SVN_ERR(revert_restore(db, child_abspath, depth,
- use_commit_times, FALSE /* revert root */,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- iterpool));
- }
-
- svn_pool_destroy(iterpool);
- }
-
- if (notify_func)
- SVN_ERR(svn_wc__db_revert_list_notify(notify_func, notify_baton,
- db, local_abspath, scratch_pool));
return SVN_NO_ERROR;
}
-
-svn_error_t *
-svn_wc__revert_internal(svn_wc__db_t *db,
- const char *local_abspath,
- svn_depth_t depth,
- svn_boolean_t use_commit_times,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- svn_wc_notify_func2_t notify_func,
- void *notify_baton,
- apr_pool_t *scratch_pool)
+/* Revert tree LOCAL_ABSPATH to depth DEPTH and notify for all reverts. */
+static svn_error_t *
+revert(svn_wc__db_t *db,
+ const char *local_abspath,
+ svn_depth_t depth,
+ svn_boolean_t use_commit_times,
+ svn_boolean_t clear_changelists,
+ svn_boolean_t metadata_only,
+ 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_error_t *err;
+ const struct svn_wc__db_info_t *info = NULL;
+ svn_boolean_t run_queue = FALSE;
SVN_ERR_ASSERT(depth == svn_depth_empty || depth == svn_depth_infinity);
@@ -667,15 +740,37 @@ svn_wc__revert_internal(svn_wc__db_t *db,
SVN_ERR(svn_wc__write_check(db, dir_abspath, scratch_pool));
}
- err = svn_wc__db_op_revert(db, local_abspath, depth,
- scratch_pool, scratch_pool);
+ err = svn_error_trace(
+ svn_wc__db_op_revert(db, local_abspath, depth, clear_changelists,
+ scratch_pool, scratch_pool));
if (!err)
- err = revert_restore(db, local_abspath, depth,
- use_commit_times, TRUE /* revert root */,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- scratch_pool);
+ {
+ err = svn_error_trace(
+ svn_wc__db_read_single_info(&info, db, local_abspath, FALSE,
+ scratch_pool, scratch_pool));
+
+ if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+ {
+ svn_error_clear(err);
+ err = NULL;
+ info = NULL;
+ }
+ }
+
+ if (!err)
+ err = svn_error_trace(
+ revert_restore(&run_queue, db, local_abspath, depth, metadata_only,
+ use_commit_times, TRUE /* revert root */,
+ info, cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
+
+ if (run_queue)
+ err = svn_error_compose_create(err,
+ svn_wc__wq_run(db, local_abspath,
+ cancel_func, cancel_baton,
+ scratch_pool));
err = svn_error_compose_create(err,
svn_wc__db_revert_list_done(db,
@@ -694,6 +789,8 @@ revert_changelist(svn_wc__db_t *db,
svn_depth_t depth,
svn_boolean_t use_commit_times,
apr_hash_t *changelist_hash,
+ svn_boolean_t clear_changelists,
+ svn_boolean_t metadata_only,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -710,11 +807,12 @@ revert_changelist(svn_wc__db_t *db,
/* Revert this node (depth=empty) if it matches one of the changelists. */
if (svn_wc__internal_changelist_match(db, local_abspath, changelist_hash,
scratch_pool))
- SVN_ERR(svn_wc__revert_internal(db, local_abspath,
- svn_depth_empty, use_commit_times,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- scratch_pool));
+ SVN_ERR(revert(db, local_abspath,
+ svn_depth_empty, use_commit_times, clear_changelists,
+ metadata_only,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
if (depth == svn_depth_empty)
return SVN_NO_ERROR;
@@ -746,6 +844,7 @@ revert_changelist(svn_wc__db_t *db,
SVN_ERR(revert_changelist(db, child_abspath, depth,
use_commit_times, changelist_hash,
+ clear_changelists, metadata_only,
cancel_func, cancel_baton,
notify_func, notify_baton,
iterpool));
@@ -770,6 +869,8 @@ revert_partial(svn_wc__db_t *db,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
+ svn_boolean_t clear_changelists,
+ svn_boolean_t metadata_only,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -789,9 +890,10 @@ revert_partial(svn_wc__db_t *db,
/* Revert the root node itself (depth=empty), then move on to the
children. */
- SVN_ERR(svn_wc__revert_internal(db, local_abspath, svn_depth_empty,
- use_commit_times, cancel_func, cancel_baton,
- notify_func, notify_baton, iterpool));
+ SVN_ERR(revert(db, local_abspath, svn_depth_empty,
+ use_commit_times, clear_changelists, metadata_only,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton, iterpool));
SVN_ERR(svn_wc__db_read_children_of_working_node(&children, db,
local_abspath,
@@ -822,11 +924,12 @@ revert_partial(svn_wc__db_t *db,
}
/* Revert just this node (depth=empty). */
- SVN_ERR(svn_wc__revert_internal(db, child_abspath,
- svn_depth_empty, use_commit_times,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- iterpool));
+ SVN_ERR(revert(db, child_abspath,
+ svn_depth_empty, use_commit_times, clear_changelists,
+ metadata_only,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ iterpool));
}
svn_pool_destroy(iterpool);
@@ -836,11 +939,13 @@ revert_partial(svn_wc__db_t *db,
svn_error_t *
-svn_wc_revert4(svn_wc_context_t *wc_ctx,
+svn_wc_revert5(svn_wc_context_t *wc_ctx,
const char *local_abspath,
svn_depth_t depth,
svn_boolean_t use_commit_times,
const apr_array_header_t *changelist_filter,
+ svn_boolean_t clear_changelists,
+ svn_boolean_t metadata_only,
svn_cancel_func_t cancel_func,
void *cancel_baton,
svn_wc_notify_func2_t notify_func,
@@ -856,17 +961,20 @@ svn_wc_revert4(svn_wc_context_t *wc_ctx,
return svn_error_trace(revert_changelist(wc_ctx->db, local_abspath,
depth, use_commit_times,
changelist_hash,
+ clear_changelists,
+ metadata_only,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
}
if (depth == svn_depth_empty || depth == svn_depth_infinity)
- return svn_error_trace(svn_wc__revert_internal(wc_ctx->db, local_abspath,
- depth, use_commit_times,
- cancel_func, cancel_baton,
- notify_func, notify_baton,
- scratch_pool));
+ return svn_error_trace(revert(wc_ctx->db, local_abspath,
+ depth, use_commit_times, clear_changelists,
+ metadata_only,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool));
/* The user may expect svn_depth_files/svn_depth_immediates to work
on copied dirs with one level of children. It doesn't, the user
@@ -877,6 +985,7 @@ svn_wc_revert4(svn_wc_context_t *wc_ctx,
if (depth == svn_depth_files || depth == svn_depth_immediates)
return svn_error_trace(revert_partial(wc_ctx->db, local_abspath,
depth, use_commit_times,
+ clear_changelists, metadata_only,
cancel_func, cancel_baton,
notify_func, notify_baton,
scratch_pool));
diff --git a/subversion/libsvn_wc/revision_status.c b/subversion/libsvn_wc/revision_status.c
index a4b9bea81ea1..c53c45e6a933 100644
--- a/subversion/libsvn_wc/revision_status.c
+++ b/subversion/libsvn_wc/revision_status.c
@@ -60,8 +60,14 @@ svn_wc_revision_status2(svn_wc_revision_status_t **result_p,
&result->modified,
&result->switched,
wc_ctx->db, local_abspath, trail_url,
- committed, cancel_func, cancel_baton,
+ committed,
scratch_pool));
+ if (!result->modified)
+ SVN_ERR(svn_wc__node_has_local_mods(&result->modified, NULL,
+ wc_ctx->db, local_abspath, TRUE,
+ cancel_func, cancel_baton,
+ scratch_pool));
+
return SVN_NO_ERROR;
}
diff --git a/subversion/libsvn_wc/status.c b/subversion/libsvn_wc/status.c
index fa57b0aee5e5..83fd3d4a377b 100644
--- a/subversion/libsvn_wc/status.c
+++ b/subversion/libsvn_wc/status.c
@@ -36,7 +36,6 @@
#include "svn_string.h"
#include "svn_error.h"
#include "svn_dirent_uri.h"
-#include "svn_path.h"
#include "svn_io.h"
#include "svn_config.h"
#include "svn_time.h"
@@ -47,15 +46,33 @@
#include "wc.h"
#include "props.h"
-#include "entries.h"
-#include "translate.h"
-#include "tree_conflicts.h"
+#include "private/svn_sorts_private.h"
#include "private/svn_wc_private.h"
#include "private/svn_fspath.h"
#include "private/svn_editor.h"
+/* The file internal variant of svn_wc_status3_t, with slightly more
+ data.
+
+ Instead of directly creating svn_wc_status3_t instances, we really
+ create instances of this struct with slightly more data for processing
+ by the status walker and status editor.
+
+ svn_wc_status3_dup() allocates space for this struct, but doesn't
+ copy the actual data. The remaining fields are copied by hash_stash(),
+ which is where the status editor stashes information for producing
+ later. */
+typedef struct svn_wc__internal_status_t
+{
+ svn_wc_status3_t s; /* First member; same pointer*/
+
+ svn_boolean_t has_descendants;
+
+ /* Make sure to update hash_stash() when adding values here */
+} svn_wc__internal_status_t;
+
/*** Baton used for walking the local status */
struct walk_status_baton
@@ -70,6 +87,9 @@ struct walk_status_baton
/* Should we ignore text modifications? */
svn_boolean_t ignore_text_mods;
+ /* Scan the working copy for local modifications and missing nodes. */
+ svn_boolean_t check_working_copy;
+
/* Externals info harvested during the status run. */
apr_hash_t *externals;
@@ -92,7 +112,6 @@ struct edit_baton
/* The DB handle for managing the working copy state. */
svn_wc__db_t *db;
- svn_wc_context_t *wc_ctx;
/* The overall depth of this edit (a dir baton may override this).
*
@@ -127,7 +146,7 @@ struct edit_baton
const apr_array_header_t *ignores;
/* Status item for the path represented by the anchor of the edit. */
- svn_wc_status3_t *anchor_status;
+ svn_wc__internal_status_t *anchor_status;
/* Was open_root() called for this edit drive? */
svn_boolean_t root_opened;
@@ -276,63 +295,23 @@ get_repos_root_url_relpath(const char **repos_relpath,
*repos_root_url = apr_pstrdup(result_pool, parent_repos_root_url);
*repos_uuid = apr_pstrdup(result_pool, parent_repos_uuid);
}
- else if (info->status == svn_wc__db_status_added)
- {
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL,
- repos_relpath, repos_root_url,
- repos_uuid, NULL, NULL, NULL, NULL,
- db, local_abspath,
- result_pool, scratch_pool));
- }
- else if (info->status == svn_wc__db_status_deleted
- && !info->have_more_work
- && info->have_base)
+ else
{
- SVN_ERR(svn_wc__db_scan_base_repos(repos_relpath, repos_root_url,
+ SVN_ERR(svn_wc__db_read_repos_info(NULL,
+ repos_relpath, repos_root_url,
repos_uuid,
db, local_abspath,
result_pool, scratch_pool));
}
- else if (info->status == svn_wc__db_status_deleted)
- {
- const char *work_del_abspath;
- const char *add_abspath;
-
- /* Handles working DELETE and the special case where there is just
- svn_wc__db_status_not_present in WORKING */
-
- SVN_ERR(svn_wc__db_scan_deletion(NULL, NULL, &work_del_abspath, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool));
-
- /* The parent of what has been deleted must be added */
- add_abspath = svn_dirent_dirname(work_del_abspath, scratch_pool);
-
- SVN_ERR(svn_wc__db_scan_addition(NULL, NULL, repos_relpath,
- repos_root_url, repos_uuid, NULL,
- NULL, NULL, NULL,
- db, add_abspath,
- result_pool, scratch_pool));
- *repos_relpath = svn_relpath_join(*repos_relpath,
- svn_dirent_skip_ancestor(
- add_abspath,
- local_abspath),
- result_pool);
- }
- else
- {
- *repos_relpath = NULL;
- *repos_root_url = NULL;
- *repos_uuid = NULL;
- }
return SVN_NO_ERROR;
}
static svn_error_t *
-internal_status(svn_wc_status3_t **status,
+internal_status(svn_wc__internal_status_t **status,
svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t check_working_copy,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
@@ -350,12 +329,13 @@ internal_status(svn_wc_status3_t **status,
*STATUS will be set to NULL. If GET_ALL is non-zero, then *STATUS will be
allocated and returned no matter what. If IGNORE_TEXT_MODS is TRUE then
don't check for text mods, assume there are none and set and *STATUS
- returned to reflect that assumption.
+ returned to reflect that assumption. If CHECK_WORKING_COPY is FALSE,
+ do not adjust the result for missing working copy files.
The status struct's repos_lock field will be set to REPOS_LOCK.
*/
static svn_error_t *
-assemble_status(svn_wc_status3_t **status,
+assemble_status(svn_wc__internal_status_t **status,
svn_wc__db_t *db,
const char *local_abspath,
const char *parent_repos_root_url,
@@ -365,18 +345,17 @@ assemble_status(svn_wc_status3_t **status,
const svn_io_dirent2_t *dirent,
svn_boolean_t get_all,
svn_boolean_t ignore_text_mods,
+ svn_boolean_t check_working_copy,
const svn_lock_t *repos_lock,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ svn_wc__internal_status_t *inner_stat;
svn_wc_status3_t *stat;
svn_boolean_t switched_p = FALSE;
svn_boolean_t copied = FALSE;
svn_boolean_t conflicted;
const char *moved_from_abspath = NULL;
- svn_filesize_t filesize = (dirent && (dirent->kind == svn_node_file))
- ? dirent->filesize
- : SVN_INVALID_FILESIZE;
/* Defaults for two main variables. */
enum svn_wc_status_kind node_status = svn_wc_status_normal;
@@ -384,10 +363,6 @@ assemble_status(svn_wc_status3_t **status,
enum svn_wc_status_kind prop_status = svn_wc_status_none;
- if (!info)
- SVN_ERR(svn_wc__db_read_single_info(&info, db, local_abspath,
- result_pool, scratch_pool));
-
if (!info->repos_relpath || !parent_repos_relpath)
switched_p = FALSE;
else
@@ -426,7 +401,7 @@ assemble_status(svn_wc_status3_t **status,
copied = TRUE; /* Working deletion */
}
}
- else
+ else if (check_working_copy)
{
/* Examine whether our target is missing or obstructed. To detect
* obstructions, we have to look at the on-disk status in DIRENT. */
@@ -606,19 +581,21 @@ assemble_status(svn_wc_status3_t **status,
&& prop_status != svn_wc_status_none)
node_status = prop_status;
- /* 5. Easy out: unless we're fetching -every- entry, don't bother
- to allocate a struct for an uninteresting entry. */
+ /* 5. Easy out: unless we're fetching -every- node, don't bother
+ to allocate a struct for an uninteresting node.
+ This filter should match the filter in is_sendable_status() */
if (! get_all)
if (((node_status == svn_wc_status_none)
|| (node_status == svn_wc_status_normal))
&& (! switched_p)
- && (! info->locked )
+ && (! info->locked)
&& (! info->lock)
&& (! repos_lock)
&& (! info->changelist)
- && (! conflicted))
+ && (! conflicted)
+ && (! info->moved_to))
{
*status = NULL;
return SVN_NO_ERROR;
@@ -626,7 +603,9 @@ assemble_status(svn_wc_status3_t **status,
/* 6. Build and return a status structure. */
- stat = apr_pcalloc(result_pool, sizeof(**status));
+ inner_stat = apr_pcalloc(result_pool, sizeof(*inner_stat));
+ stat = &inner_stat->s;
+ inner_stat->has_descendants = info->has_descendants;
switch (info->kind)
{
@@ -642,7 +621,22 @@ assemble_status(svn_wc_status3_t **status,
stat->kind = svn_node_unknown;
}
stat->depth = info->depth;
- stat->filesize = filesize;
+
+ if (dirent)
+ {
+ stat->filesize = (dirent->kind == svn_node_file)
+ ? dirent->filesize
+ : SVN_INVALID_FILESIZE;
+ stat->actual_kind = dirent->special ? svn_node_symlink
+ : dirent->kind;
+ }
+ else
+ {
+ stat->filesize = SVN_INVALID_FILESIZE;
+ stat->actual_kind = ignore_text_mods ? svn_node_unknown
+ : svn_node_none;
+ }
+
stat->node_status = node_status;
stat->text_status = text_status;
stat->prop_status = prop_status;
@@ -700,7 +694,7 @@ assemble_status(svn_wc_status3_t **status,
stat->file_external = info->file_external;
- *status = stat;
+ *status = inner_stat;
return SVN_NO_ERROR;
}
@@ -714,7 +708,7 @@ assemble_status(svn_wc_status3_t **status,
node_status to svn_wc_status_unversioned.
*/
static svn_error_t *
-assemble_unversioned(svn_wc_status3_t **status,
+assemble_unversioned(svn_wc__internal_status_t **status,
svn_wc__db_t *db,
const char *local_abspath,
const svn_io_dirent2_t *dirent,
@@ -723,17 +717,30 @@ assemble_unversioned(svn_wc_status3_t **status,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
+ svn_wc__internal_status_t *inner_status;
svn_wc_status3_t *stat;
/* return a fairly blank structure. */
- stat = apr_pcalloc(result_pool, sizeof(*stat));
+ inner_status = apr_pcalloc(result_pool, sizeof(*inner_status));
+ stat = &inner_status->s;
/*stat->versioned = FALSE;*/
stat->kind = svn_node_unknown; /* not versioned */
stat->depth = svn_depth_unknown;
- stat->filesize = (dirent && dirent->kind == svn_node_file)
- ? dirent->filesize
- : SVN_INVALID_FILESIZE;
+ if (dirent)
+ {
+ stat->actual_kind = dirent->special ? svn_node_symlink
+ : dirent->kind;
+ stat->filesize = (dirent->kind == svn_node_file)
+ ? dirent->filesize
+ : SVN_INVALID_FILESIZE;
+ }
+ else
+ {
+ stat->actual_kind = svn_node_none;
+ stat->filesize = SVN_INVALID_FILESIZE;
+ }
+
stat->node_status = svn_wc_status_none;
stat->text_status = svn_wc_status_none;
stat->prop_status = svn_wc_status_none;
@@ -770,7 +777,7 @@ assemble_unversioned(svn_wc_status3_t **status,
stat->conflicted = tree_conflicted;
stat->changelist = NULL;
- *status = stat;
+ *status = inner_status;
return SVN_NO_ERROR;
}
@@ -791,7 +798,7 @@ send_status_structure(const struct walk_status_baton *wb,
void *status_baton,
apr_pool_t *scratch_pool)
{
- svn_wc_status3_t *statstruct;
+ svn_wc__internal_status_t *statstruct;
const svn_lock_t *repos_lock = NULL;
/* Check for a repository lock. */
@@ -819,12 +826,14 @@ send_status_structure(const struct walk_status_baton *wb,
SVN_ERR(assemble_status(&statstruct, wb->db, local_abspath,
parent_repos_root_url, parent_repos_relpath,
parent_repos_uuid,
- info, dirent, get_all, wb->ignore_text_mods,
+ info, dirent, get_all,
+ wb->ignore_text_mods, wb->check_working_copy,
repos_lock, scratch_pool, scratch_pool));
if (statstruct && status_func)
return svn_error_trace((*status_func)(status_baton, local_abspath,
- statstruct, scratch_pool));
+ &statstruct->s,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -940,7 +949,7 @@ is_external_path(apr_hash_t *externals,
hi;
hi = apr_hash_next(hi))
{
- const char *external_abspath = svn__apr_hash_index_key(hi);
+ const char *external_abspath = apr_hash_this_key(hi);
if (svn_dirent_is_child(local_abspath, external_abspath, NULL))
return TRUE;
@@ -980,7 +989,7 @@ send_unversioned_item(const struct walk_status_baton *wb,
{
svn_boolean_t is_ignored;
svn_boolean_t is_external;
- svn_wc_status3_t *status;
+ svn_wc__internal_status_t *status;
const char *base_name = svn_dirent_basename(local_abspath, NULL);
is_ignored = svn_wc_match_ignore_list(base_name, patterns, scratch_pool);
@@ -992,12 +1001,12 @@ send_unversioned_item(const struct walk_status_baton *wb,
is_external = is_external_path(wb->externals, local_abspath, scratch_pool);
if (is_external)
- status->node_status = svn_wc_status_external;
+ status->s.node_status = svn_wc_status_external;
/* We can have a tree conflict on an unversioned path, i.e. an incoming
* delete on a locally deleted path during an update. Don't ever ignore
* those! */
- if (status->conflicted)
+ if (status->s.conflicted)
is_ignored = FALSE;
/* If we aren't ignoring it, or if it's an externals path, pass this
@@ -1006,7 +1015,7 @@ send_unversioned_item(const struct walk_status_baton *wb,
|| !is_ignored
|| is_external)
return svn_error_trace((*status_func)(status_baton, local_abspath,
- status, scratch_pool));
+ &status->s, scratch_pool));
return SVN_NO_ERROR;
}
@@ -1109,7 +1118,7 @@ one_child_status(const struct walk_status_baton *wb,
/* Descend in subdirectories. */
if (depth == svn_depth_infinity
- && info->kind == svn_node_dir)
+ && info->has_descendants /* is dir, or was dir and tc descendants */)
{
SVN_ERR(get_dir_status(wb, local_abspath, TRUE,
dir_repos_root_url, dir_repos_relpath,
@@ -1132,11 +1141,16 @@ one_child_status(const struct walk_status_baton *wb,
* look up the kinds in the conflict ... just show all. */
if (! conflicted)
{
- /* Selected node, but not found */
- if (dirent == NULL)
- return SVN_NO_ERROR;
+ /* We have a node, but its not visible in the WC. It can be a marker
+ node (not present, (server) excluded), *or* it can be the explictly
+ passed target of the status walk operation that doesn't exist.
- if (depth == svn_depth_files && dirent->kind == svn_node_dir)
+ We only report the node when the caller explicitly as
+ */
+ if (dirent == NULL && strcmp(wb->target_abspath, local_abspath) != 0)
+ return SVN_NO_ERROR; /* Marker node */
+
+ if (depth == svn_depth_files && dirent && dirent->kind == svn_node_dir)
return SVN_NO_ERROR;
if (svn_wc_is_adm_dir(svn_dirent_basename(local_abspath, NULL),
@@ -1228,21 +1242,28 @@ get_dir_status(const struct walk_status_baton *wb,
iterpool = svn_pool_create(scratch_pool);
- err = svn_io_get_dirents3(&dirents, local_abspath, FALSE, scratch_pool,
- iterpool);
- if (err
- && (APR_STATUS_IS_ENOENT(err->apr_err)
- || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
+ if (wb->check_working_copy)
{
- svn_error_clear(err);
- dirents = apr_hash_make(scratch_pool);
+ err = svn_io_get_dirents3(&dirents, local_abspath,
+ wb->ignore_text_mods /* only_check_type*/,
+ scratch_pool, iterpool);
+ if (err
+ && (APR_STATUS_IS_ENOENT(err->apr_err)
+ || SVN__APR_STATUS_IS_ENOTDIR(err->apr_err)))
+ {
+ svn_error_clear(err);
+ dirents = apr_hash_make(scratch_pool);
+ }
+ else
+ SVN_ERR(err);
}
else
- SVN_ERR(err);
+ dirents = apr_hash_make(scratch_pool);
if (!dir_info)
- SVN_ERR(svn_wc__db_read_single_info(&dir_info, wb->db, local_abspath,
- scratch_pool, iterpool));
+ SVN_ERR(svn_wc__db_read_single_info(&dir_info, wb->db, local_abspath,
+ !wb->check_working_copy,
+ scratch_pool, iterpool));
SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
&dir_repos_uuid, dir_info,
@@ -1256,6 +1277,7 @@ get_dir_status(const struct walk_status_baton *wb,
hash are subsequently used. */
SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts,
wb->db, local_abspath,
+ !wb->check_working_copy,
scratch_pool, iterpool));
all_children = apr_hash_overlay(scratch_pool, nodes, dirents);
@@ -1404,6 +1426,7 @@ get_child_status(const struct walk_status_baton *wb,
SVN_ERR(svn_wc__db_read_single_info(&dir_info,
wb->db, parent_abspath,
+ !wb->check_working_copy,
scratch_pool, scratch_pool));
SVN_ERR(get_repos_root_url_relpath(&dir_repos_relpath, &dir_repos_root_url,
@@ -1455,9 +1478,15 @@ hash_stash(void *baton,
{
apr_hash_t *stat_hash = baton;
apr_pool_t *hash_pool = apr_hash_pool_get(stat_hash);
+ void *new_status = svn_wc_dup_status3(status, hash_pool);
+ const svn_wc__internal_status_t *old_status = (const void*)status;
+
+ /* Copy the internal/private data. */
+ svn_wc__internal_status_t *is = new_status;
+ is->has_descendants = old_status->has_descendants;
+
assert(! svn_hash_gets(stat_hash, path));
- svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path),
- svn_wc_dup_status3(status, hash_pool));
+ svn_hash_sets(stat_hash, apr_pstrdup(hash_pool, path), new_status);
return SVN_NO_ERROR;
}
@@ -1497,6 +1526,7 @@ tweak_statushash(void *baton,
void *this_dir_baton,
svn_boolean_t is_dir_baton,
svn_wc__db_t *db,
+ svn_boolean_t check_working_copy,
const char *local_abspath,
enum svn_wc_status_kind repos_node_status,
enum svn_wc_status_kind repos_text_status,
@@ -1521,6 +1551,7 @@ tweak_statushash(void *baton,
/* If not, make it so. */
if (! statstruct)
{
+ svn_wc__internal_status_t *i_stat;
/* If this item isn't being added, then we're most likely
dealing with a non-recursive (or at least partially
non-recursive) working copy. Due to bugs in how the client
@@ -1536,8 +1567,9 @@ tweak_statushash(void *baton,
return SVN_NO_ERROR;
/* Use the public API to get a statstruct, and put it into the hash. */
- SVN_ERR(internal_status(&statstruct, db, local_abspath, pool,
- scratch_pool));
+ SVN_ERR(internal_status(&i_stat, db, local_abspath,
+ check_working_copy, pool, scratch_pool));
+ statstruct = &i_stat->s;
statstruct->repos_lock = repos_lock;
svn_hash_sets(statushash, apr_pstrdup(pool, local_abspath), statstruct);
}
@@ -1576,9 +1608,9 @@ tweak_statushash(void *baton,
statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath);
statstruct->repos_root_url =
- b->edit_baton->anchor_status->repos_root_url;
+ b->edit_baton->anchor_status->s.repos_root_url;
statstruct->repos_uuid =
- b->edit_baton->anchor_status->repos_uuid;
+ b->edit_baton->anchor_status->s.repos_uuid;
}
/* The last committed date, and author for deleted items
@@ -1618,9 +1650,9 @@ tweak_statushash(void *baton,
{
statstruct->repos_relpath = apr_pstrdup(pool, b->repos_relpath);
statstruct->repos_root_url =
- b->edit_baton->anchor_status->repos_root_url;
+ b->edit_baton->anchor_status->s.repos_root_url;
statstruct->repos_uuid =
- b->edit_baton->anchor_status->repos_uuid;
+ b->edit_baton->anchor_status->s.repos_uuid;
}
statstruct->ood_kind = b->ood_kind;
if (b->ood_changed_author)
@@ -1636,7 +1668,7 @@ find_dir_repos_relpath(const struct dir_baton *db, apr_pool_t *pool)
{
/* If we have no name, we're the root, return the anchor URL. */
if (! db->name)
- return db->edit_baton->anchor_status->repos_relpath;
+ return db->edit_baton->anchor_status->s.repos_relpath;
else
{
const char *repos_relpath;
@@ -1668,7 +1700,7 @@ make_dir_baton(void **dir_baton,
struct edit_baton *eb = edit_baton;
struct dir_baton *d;
const char *local_abspath;
- const svn_wc_status3_t *status_in_parent;
+ const svn_wc__internal_status_t *status_in_parent;
apr_pool_t *dir_pool;
if (parent_baton)
@@ -1727,8 +1759,7 @@ make_dir_baton(void **dir_baton,
status_in_parent = eb->anchor_status;
if (status_in_parent
- && status_in_parent->versioned
- && (status_in_parent->kind == svn_node_dir)
+ && (status_in_parent->has_descendants)
&& (! d->excluded)
&& (d->depth == svn_depth_unknown
|| d->depth == svn_depth_infinity
@@ -1740,9 +1771,9 @@ make_dir_baton(void **dir_baton,
const apr_array_header_t *ignores = eb->ignores;
SVN_ERR(get_dir_status(&eb->wb, local_abspath, TRUE,
- status_in_parent->repos_root_url,
+ status_in_parent->s.repos_root_url,
NULL /*parent_repos_relpath*/,
- status_in_parent->repos_uuid,
+ status_in_parent->s.repos_uuid,
NULL,
NULL /* dirent */, ignores,
d->depth == svn_depth_files
@@ -1757,7 +1788,7 @@ make_dir_baton(void **dir_baton,
this_dir_status = svn_hash_gets(d->statii, d->local_abspath);
if (this_dir_status && this_dir_status->versioned
&& (d->depth == svn_depth_unknown
- || d->depth > status_in_parent->depth))
+ || d->depth > status_in_parent->s.depth))
{
d->depth = this_dir_status->depth;
}
@@ -1799,12 +1830,15 @@ make_file_baton(struct dir_baton *parent_dir_baton,
* Return a boolean answer to the question "Is @a status something that
* should be reported?". @a no_ignore and @a get_all are the same as
* svn_wc_get_status_editor4().
+ *
+ * This implementation should match the filter in assemble_status()
*/
static svn_boolean_t
-is_sendable_status(const svn_wc_status3_t *status,
+is_sendable_status(const svn_wc__internal_status_t *i_status,
svn_boolean_t no_ignore,
svn_boolean_t get_all)
{
+ const svn_wc_status3_t *status = &i_status->s;
/* If the repository status was touched at all, it's interesting. */
if (status->repos_node_status != svn_wc_status_none)
return TRUE;
@@ -1830,8 +1864,8 @@ is_sendable_status(const svn_wc_status3_t *status,
return TRUE;
/* If the text, property or tree state is interesting, send it. */
- if ((status->node_status != svn_wc_status_none
- && (status->node_status != svn_wc_status_normal)))
+ if ((status->node_status != svn_wc_status_none)
+ && (status->node_status != svn_wc_status_normal))
return TRUE;
/* If it's switched, send it. */
@@ -1846,6 +1880,9 @@ is_sendable_status(const svn_wc_status3_t *status,
if (status->changelist)
return TRUE;
+ if (status->moved_to_abspath)
+ return TRUE;
+
/* Otherwise, don't send it. */
return FALSE;
}
@@ -1910,15 +1947,15 @@ handle_statii(struct edit_baton *eb,
/* Loop over all the statii still in our hash, handling each one. */
for (hi = apr_hash_first(pool, statii); hi; hi = apr_hash_next(hi))
{
- const char *local_abspath = svn__apr_hash_index_key(hi);
- svn_wc_status3_t *status = svn__apr_hash_index_val(hi);
+ const char *local_abspath = apr_hash_this_key(hi);
+ svn_wc__internal_status_t *status = apr_hash_this_val(hi);
/* Clear the subpool. */
svn_pool_clear(iterpool);
/* Now, handle the status. We don't recurse for svn_depth_immediates
because we already have the subdirectories' statii. */
- if (status->versioned && status->kind == svn_node_dir
+ if (status->has_descendants
&& (depth == svn_depth_unknown
|| depth == svn_depth_infinity))
{
@@ -1934,9 +1971,9 @@ handle_statii(struct edit_baton *eb,
iterpool));
}
if (dir_was_deleted)
- status->repos_node_status = svn_wc_status_deleted;
+ status->s.repos_node_status = svn_wc_status_deleted;
if (is_sendable_status(status, eb->no_ignore, eb->get_all))
- SVN_ERR((eb->status_func)(eb->status_baton, local_abspath, status,
+ SVN_ERR((eb->status_func)(eb->status_baton, local_abspath, &status->s,
iterpool));
}
@@ -1991,7 +2028,7 @@ delete_entry(const char *path,
statushash immediately. No need to wait until close_file or
close_dir, because there's no risk of having to honor the 'added'
flag. We already know this item exists in the working copy. */
- SVN_ERR(tweak_statushash(db, db, TRUE, eb->db,
+ SVN_ERR(tweak_statushash(db, db, TRUE, eb->db, eb->wb.check_working_copy,
local_abspath,
svn_wc_status_deleted, 0, 0, revision, NULL, pool));
@@ -1999,7 +2036,8 @@ delete_entry(const char *path,
is the root node and we're not supposed to report on the root
node). */
if (db->parent_baton && (! *eb->target_basename))
- SVN_ERR(tweak_statushash(db->parent_baton, db, TRUE,eb->db,
+ SVN_ERR(tweak_statushash(db->parent_baton, db, TRUE,
+ eb->db, eb->wb.check_working_copy,
db->local_abspath,
svn_wc_status_modified, svn_wc_status_modified,
0, SVN_INVALID_REVNUM, NULL, pool));
@@ -2123,7 +2161,9 @@ close_directory(void *dir_baton,
{
/* ### When we add directory locking, we need to find a
### directory lock here. */
- SVN_ERR(tweak_statushash(pb, db, TRUE, eb->db, db->local_abspath,
+ SVN_ERR(tweak_statushash(pb, db, TRUE,
+ eb->db, eb->wb.check_working_copy,
+ db->local_abspath,
repos_node_status, repos_text_status,
repos_prop_status, SVN_INVALID_REVNUM, NULL,
scratch_pool));
@@ -2133,17 +2173,17 @@ close_directory(void *dir_baton,
/* We're editing the root dir of the WC. As its repos
status info isn't otherwise set, set it directly to
trigger invocation of the status callback below. */
- eb->anchor_status->repos_node_status = repos_node_status;
- eb->anchor_status->repos_prop_status = repos_prop_status;
- eb->anchor_status->repos_text_status = repos_text_status;
+ eb->anchor_status->s.repos_node_status = repos_node_status;
+ eb->anchor_status->s.repos_prop_status = repos_prop_status;
+ eb->anchor_status->s.repos_text_status = repos_text_status;
/* If the root dir is out of date set the ood info directly too. */
- if (db->ood_changed_rev != eb->anchor_status->revision)
+ if (db->ood_changed_rev != eb->anchor_status->s.revision)
{
- eb->anchor_status->ood_changed_rev = db->ood_changed_rev;
- eb->anchor_status->ood_changed_date = db->ood_changed_date;
- eb->anchor_status->ood_kind = db->ood_kind;
- eb->anchor_status->ood_changed_author =
+ eb->anchor_status->s.ood_changed_rev = db->ood_changed_rev;
+ eb->anchor_status->s.ood_changed_date = db->ood_changed_date;
+ eb->anchor_status->s.ood_kind = db->ood_kind;
+ eb->anchor_status->s.ood_changed_author =
apr_pstrdup(pool, db->ood_changed_author);
}
}
@@ -2154,25 +2194,25 @@ close_directory(void *dir_baton,
if (pb && ! db->excluded)
{
svn_boolean_t was_deleted = FALSE;
- const svn_wc_status3_t *dir_status;
+ svn_wc__internal_status_t *dir_status;
/* See if the directory was deleted or replaced. */
dir_status = svn_hash_gets(pb->statii, db->local_abspath);
if (dir_status &&
- ((dir_status->repos_node_status == svn_wc_status_deleted)
- || (dir_status->repos_node_status == svn_wc_status_replaced)))
+ ((dir_status->s.repos_node_status == svn_wc_status_deleted)
+ || (dir_status->s.repos_node_status == svn_wc_status_replaced)))
was_deleted = TRUE;
/* Now do the status reporting. */
SVN_ERR(handle_statii(eb,
- dir_status ? dir_status->repos_root_url : NULL,
- dir_status ? dir_status->repos_relpath : NULL,
- dir_status ? dir_status->repos_uuid : NULL,
+ dir_status ? dir_status->s.repos_root_url : NULL,
+ dir_status ? dir_status->s.repos_relpath : NULL,
+ dir_status ? dir_status->s.repos_uuid : NULL,
db->statii, was_deleted, db->depth, scratch_pool));
if (dir_status && is_sendable_status(dir_status, eb->no_ignore,
eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath,
- dir_status, scratch_pool));
+ &dir_status->s, scratch_pool));
svn_hash_sets(pb->statii, db->local_abspath, NULL);
}
else if (! pb)
@@ -2181,13 +2221,12 @@ close_directory(void *dir_baton,
target, we should only report the target. */
if (*eb->target_basename)
{
- const svn_wc_status3_t *tgt_status;
+ const svn_wc__internal_status_t *tgt_status;
tgt_status = svn_hash_gets(db->statii, eb->target_abspath);
if (tgt_status)
{
- if (tgt_status->versioned
- && tgt_status->kind == svn_node_dir)
+ if (tgt_status->has_descendants)
{
SVN_ERR(get_dir_status(&eb->wb,
eb->target_abspath, TRUE,
@@ -2202,7 +2241,7 @@ close_directory(void *dir_baton,
}
if (is_sendable_status(tgt_status, eb->no_ignore, eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, eb->target_abspath,
- tgt_status, scratch_pool));
+ &tgt_status->s, scratch_pool));
}
}
else
@@ -2211,15 +2250,15 @@ close_directory(void *dir_baton,
Note that our directory couldn't have been deleted,
because it is the root of the edit drive. */
SVN_ERR(handle_statii(eb,
- eb->anchor_status->repos_root_url,
- eb->anchor_status->repos_relpath,
- eb->anchor_status->repos_uuid,
+ eb->anchor_status->s.repos_root_url,
+ eb->anchor_status->s.repos_relpath,
+ eb->anchor_status->s.repos_uuid,
db->statii, FALSE, eb->default_depth,
scratch_pool));
if (is_sendable_status(eb->anchor_status, eb->no_ignore,
eb->get_all))
SVN_ERR((eb->status_func)(eb->status_baton, db->local_abspath,
- eb->anchor_status, scratch_pool));
+ &eb->anchor_status->s, scratch_pool));
eb->anchor_status = NULL;
}
}
@@ -2375,6 +2414,7 @@ close_file(void *file_baton,
}
return tweak_statushash(fb, NULL, FALSE, fb->edit_baton->db,
+ fb->edit_baton->wb.check_working_copy,
fb->local_abspath, repos_node_status,
repos_text_status, repos_prop_status,
SVN_INVALID_REVNUM, repos_lock, pool);
@@ -2393,18 +2433,18 @@ close_edit(void *edit_baton,
if (eb->root_opened)
return SVN_NO_ERROR;
- SVN_ERR(svn_wc_walk_status(eb->wc_ctx,
- eb->target_abspath,
- eb->default_depth,
- eb->get_all,
- eb->no_ignore,
- FALSE,
- eb->ignores,
- eb->status_func,
- eb->status_baton,
- eb->cancel_func,
- eb->cancel_baton,
- pool));
+ SVN_ERR(svn_wc__internal_walk_status(eb->db,
+ eb->target_abspath,
+ eb->default_depth,
+ eb->get_all,
+ eb->no_ignore,
+ FALSE,
+ eb->ignores,
+ eb->status_func,
+ eb->status_baton,
+ eb->cancel_func,
+ eb->cancel_baton,
+ pool));
return SVN_NO_ERROR;
}
@@ -2423,6 +2463,7 @@ svn_wc__get_status_editor(const svn_delta_editor_t **editor,
const char *target_basename,
svn_depth_t depth,
svn_boolean_t get_all,
+ svn_boolean_t check_working_copy,
svn_boolean_t no_ignore,
svn_boolean_t depth_as_sticky,
svn_boolean_t server_performs_filtering,
@@ -2447,7 +2488,6 @@ svn_wc__get_status_editor(const svn_delta_editor_t **editor,
eb->default_depth = depth;
eb->target_revision = edit_revision;
eb->db = wc_ctx->db;
- eb->wc_ctx = wc_ctx;
eb->get_all = get_all;
eb->no_ignore = no_ignore;
eb->status_func = status_func;
@@ -2463,7 +2503,8 @@ svn_wc__get_status_editor(const svn_delta_editor_t **editor,
eb->wb.db = wc_ctx->db;
eb->wb.target_abspath = eb->target_abspath;
- eb->wb.ignore_text_mods = FALSE;
+ eb->wb.ignore_text_mods = !check_working_copy;
+ eb->wb.check_working_copy = check_working_copy;
eb->wb.repos_locks = NULL;
eb->wb.repos_root = NULL;
@@ -2488,7 +2529,7 @@ svn_wc__get_status_editor(const svn_delta_editor_t **editor,
/* The edit baton's status structure maps to PATH, and the editor
have to be aware of whether that is the anchor or the target. */
SVN_ERR(internal_status(&(eb->anchor_status), wc_ctx->db, anchor_abspath,
- result_pool, scratch_pool));
+ check_working_copy, result_pool, scratch_pool));
/* Construct an editor. */
tree_editor->set_target_revision = set_target_revision;
@@ -2594,6 +2635,7 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
wb.db = db;
wb.target_abspath = local_abspath;
wb.ignore_text_mods = ignore_text_mods;
+ wb.check_working_copy = TRUE;
wb.repos_root = NULL;
wb.repos_locks = NULL;
@@ -2608,6 +2650,7 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
}
err = svn_wc__db_read_single_info(&info, db, local_abspath,
+ FALSE /* base_tree_only */,
scratch_pool, scratch_pool);
if (err)
@@ -2636,7 +2679,7 @@ svn_wc__internal_walk_status(svn_wc__db_t *db,
}
if (info
- && info->kind == svn_node_dir
+ && info->has_descendants /* is dir, or was dir and has tc descendants */
&& info->status != svn_wc__db_status_not_present
&& info->status != svn_wc__db_status_excluded
&& info->status != svn_wc__db_status_server_excluded)
@@ -2756,30 +2799,26 @@ svn_wc_get_default_ignores(apr_array_header_t **patterns,
/* */
static svn_error_t *
-internal_status(svn_wc_status3_t **status,
+internal_status(svn_wc__internal_status_t **status,
svn_wc__db_t *db,
const char *local_abspath,
+ svn_boolean_t check_working_copy,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- const svn_io_dirent2_t *dirent;
- svn_node_kind_t node_kind;
+ const svn_io_dirent2_t *dirent = NULL;
const char *parent_repos_relpath;
const char *parent_repos_root_url;
const char *parent_repos_uuid;
- svn_wc__db_status_t node_status;
- svn_boolean_t conflicted;
+ const struct svn_wc__db_info_t *info;
svn_boolean_t is_root = FALSE;
svn_error_t *err;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- err = svn_wc__db_read_info(&node_status, &node_kind, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, &conflicted,
- NULL, NULL, NULL, NULL, NULL, NULL,
- db, local_abspath,
- scratch_pool, scratch_pool);
+ err = svn_wc__db_read_single_info(&info, db, local_abspath,
+ !check_working_copy,
+ scratch_pool, scratch_pool);
if (err)
{
@@ -2787,30 +2826,25 @@ internal_status(svn_wc_status3_t **status,
return svn_error_trace(err);
svn_error_clear(err);
- node_kind = svn_node_unknown;
- /* Ensure conflicted is always set, but don't hide tree conflicts
- on 'hidden' nodes. */
- conflicted = FALSE;
+ info = NULL;
- SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, TRUE,
- scratch_pool, scratch_pool));
+ if (check_working_copy)
+ SVN_ERR(svn_io_stat_dirent2(&dirent, local_abspath, FALSE, TRUE,
+ scratch_pool, scratch_pool));
}
- else
+ else if (check_working_copy)
SVN_ERR(stat_wc_dirent_case_sensitive(&dirent, db, local_abspath,
scratch_pool, scratch_pool));
- if (node_kind != svn_node_unknown
- && (node_status == svn_wc__db_status_not_present
- || node_status == svn_wc__db_status_server_excluded
- || node_status == svn_wc__db_status_excluded))
- {
- node_kind = svn_node_unknown;
- }
-
- if (node_kind == svn_node_unknown)
+ if (!info
+ || info->kind == svn_node_unknown
+ || info->status == svn_wc__db_status_not_present
+ || info->status == svn_wc__db_status_server_excluded
+ || info->status == svn_wc__db_status_excluded)
return svn_error_trace(assemble_unversioned(status,
db, local_abspath,
- dirent, conflicted,
+ dirent,
+ info ? info->conflicted : FALSE,
FALSE /* is_ignored */,
result_pool, scratch_pool));
@@ -2819,30 +2853,31 @@ internal_status(svn_wc_status3_t **status,
else
SVN_ERR(svn_wc__db_is_wcroot(&is_root, db, local_abspath, scratch_pool));
+ /* Even though passing parent_repos_* is not required, assemble_status needs
+ these values to determine if a node is switched */
if (!is_root)
{
- svn_wc__db_status_t parent_status;
- const char *parent_abspath = svn_dirent_dirname(local_abspath,
- scratch_pool);
-
- err = svn_wc__db_read_info(&parent_status, NULL, NULL,
- &parent_repos_relpath, &parent_repos_root_url,
- &parent_repos_uuid, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL,
- db, parent_abspath,
- result_pool, scratch_pool);
-
- if (err && (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND
- || SVN_WC__ERR_IS_NOT_CURRENT_WC(err)))
- {
- svn_error_clear(err);
- parent_repos_root_url = NULL;
- parent_repos_relpath = NULL;
- parent_repos_uuid = NULL;
- }
- else SVN_ERR(err);
+ const char *const parent_abspath = svn_dirent_dirname(local_abspath,
+ scratch_pool);
+ if (check_working_copy)
+ SVN_ERR(svn_wc__db_read_info(NULL, NULL, NULL,
+ &parent_repos_relpath,
+ &parent_repos_root_url,
+ &parent_repos_uuid,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ db, parent_abspath,
+ result_pool, scratch_pool));
+ else
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL,
+ &parent_repos_relpath,
+ &parent_repos_root_url,
+ &parent_repos_uuid,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ db, parent_abspath,
+ result_pool, scratch_pool));
}
else
{
@@ -2855,10 +2890,10 @@ internal_status(svn_wc_status3_t **status,
parent_repos_root_url,
parent_repos_relpath,
parent_repos_uuid,
- NULL,
+ info,
dirent,
TRUE /* get_all */,
- FALSE,
+ FALSE, check_working_copy,
NULL /* repos_lock */,
result_pool, scratch_pool));
}
@@ -2871,16 +2906,21 @@ svn_wc_status3(svn_wc_status3_t **status,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- return svn_error_trace(
- internal_status(status, wc_ctx->db, local_abspath, result_pool,
- scratch_pool));
+ svn_wc__internal_status_t *stat;
+ SVN_ERR(internal_status(&stat, wc_ctx->db, local_abspath,
+ TRUE /* check_working_copy */,
+ result_pool, scratch_pool));
+ *status = &stat->s;
+ return SVN_NO_ERROR;
}
svn_wc_status3_t *
svn_wc_dup_status3(const svn_wc_status3_t *orig_stat,
apr_pool_t *pool)
{
- svn_wc_status3_t *new_stat = apr_palloc(pool, sizeof(*new_stat));
+ /* Allocate slightly more room */
+ svn_wc__internal_status_t *new_istat = apr_palloc(pool, sizeof(*new_istat));
+ svn_wc_status3_t *new_stat = &new_istat->s;
/* Shallow copy all members. */
*new_stat = *orig_stat;
diff --git a/subversion/libsvn_wc/token-map.h b/subversion/libsvn_wc/token-map.h
index 9da12b8aaafc..9bf80d6acbce 100644
--- a/subversion/libsvn_wc/token-map.h
+++ b/subversion/libsvn_wc/token-map.h
@@ -33,6 +33,7 @@
extern "C" {
#endif
+/* The kind values used on NODES */
static const svn_token_map_t kind_map[] = {
{ "file", svn_node_file }, /* MAP_FILE */
{ "dir", svn_node_dir }, /* MAP_DIR */
@@ -41,6 +42,16 @@ static const svn_token_map_t kind_map[] = {
{ NULL }
};
+/* Like kind_map, but also supports 'none' */
+static const svn_token_map_t kind_map_none[] = {
+ { "none", svn_node_none },
+ { "file", svn_node_file },
+ { "dir", svn_node_dir },
+ { "symlink", svn_node_symlink },
+ { "unknown", svn_node_unknown },
+ { NULL }
+};
+
/* Note: we only decode presence values from the database. These are a
subset of all the status values. */
static const svn_token_map_t presence_map[] = {
diff --git a/subversion/libsvn_wc/translate.c b/subversion/libsvn_wc/translate.c
index 9e0b2656853a..0e16235d7827 100644
--- a/subversion/libsvn_wc/translate.c
+++ b/subversion/libsvn_wc/translate.c
@@ -30,6 +30,7 @@
#include <apr_file_io.h>
#include <apr_strings.h>
+#include "svn_private_config.h"
#include "svn_types.h"
#include "svn_string.h"
#include "svn_dirent_uri.h"
@@ -45,25 +46,9 @@
#include "translate.h"
#include "props.h"
-#include "svn_private_config.h"
#include "private/svn_wc_private.h"
-
-/* */
-static svn_error_t *
-read_handler_unsupported(void *baton, char *buffer, apr_size_t *len)
-{
- SVN_ERR_MALFUNCTION();
-}
-
-/* */
-static svn_error_t *
-write_handler_unsupported(void *baton, const char *buffer, apr_size_t *len)
-{
- SVN_ERR_MALFUNCTION();
-}
-
svn_error_t *
svn_wc__internal_translated_stream(svn_stream_t **stream,
svn_wc__db_t *db,
@@ -133,16 +118,18 @@ svn_wc__internal_translated_stream(svn_stream_t **stream,
FALSE /* expand */,
result_pool);
- /* Enforce our contract. TO_NF streams are readonly */
- svn_stream_set_write(*stream, write_handler_unsupported);
+ /* streams enforce our contract that TO_NF streams are read-only
+ * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
+ * write to them. */
}
else
{
*stream = svn_subst_stream_translated(*stream, eol, TRUE,
keywords, TRUE, result_pool);
- /* Enforce our contract. FROM_NF streams are write-only */
- svn_stream_set_read(*stream, read_handler_unsupported);
+ /* streams enforce our contract that FROM_NF streams are write-only
+ * by returning SVN_ERR_STREAM_NOT_SUPPORTED when trying to
+ * read them. */
}
}
@@ -329,12 +316,15 @@ svn_wc__expand_keywords(apr_hash_t **keywords,
db, local_abspath,
scratch_pool, scratch_pool));
- if (repos_relpath)
- url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- scratch_pool);
- else
- SVN_ERR(svn_wc__db_read_url(&url, db, local_abspath, scratch_pool,
- scratch_pool));
+ /* Handle special statuses (e.g. added) */
+ if (!repos_relpath)
+ SVN_ERR(svn_wc__db_read_repos_info(NULL, &repos_relpath,
+ &repos_root_url, NULL,
+ db, local_abspath,
+ scratch_pool, scratch_pool));
+
+ url = svn_path_url_add_component2(repos_root_url, repos_relpath,
+ scratch_pool);
}
else
{
diff --git a/subversion/libsvn_wc/tree_conflicts.c b/subversion/libsvn_wc/tree_conflicts.c
index 4445c96ec09c..caf39eda9878 100644
--- a/subversion/libsvn_wc/tree_conflicts.c
+++ b/subversion/libsvn_wc/tree_conflicts.c
@@ -46,6 +46,7 @@ static const svn_token_map_t node_kind_map[] =
{ "file", svn_node_file },
{ "dir", svn_node_dir },
{ "", svn_node_unknown },
+ /* ### should also map svn_node_symlink */
{ NULL }
};
@@ -353,13 +354,13 @@ svn_wc__serialize_conflict(svn_skel_t **skel,
else
SVN_ERR(prepend_version_info_skel(c_skel, &null_version, result_pool));
- /* reason */
- skel_prepend_enum(c_skel, svn_wc__conflict_reason_map, conflict->reason,
- result_pool);
+ /* local change */
+ skel_prepend_enum(c_skel, svn_wc__conflict_reason_map,
+ conflict->reason, result_pool);
- /* action */
- skel_prepend_enum(c_skel, svn_wc__conflict_action_map, conflict->action,
- result_pool);
+ /* incoming change */
+ skel_prepend_enum(c_skel, svn_wc__conflict_action_map,
+ conflict->action, result_pool);
/* operation */
skel_prepend_enum(c_skel, svn_wc__operation_map, conflict->operation,
@@ -367,8 +368,10 @@ svn_wc__serialize_conflict(svn_skel_t **skel,
/* node_kind */
SVN_ERR_ASSERT(conflict->node_kind == svn_node_dir
- || conflict->node_kind == svn_node_file);
- skel_prepend_enum(c_skel, node_kind_map, conflict->node_kind, result_pool);
+ || conflict->node_kind == svn_node_file
+ || conflict->node_kind == svn_node_none);
+ skel_prepend_enum(c_skel, node_kind_map, conflict->node_kind,
+ result_pool);
/* Victim path (escaping separator chars). */
victim_basename = svn_dirent_basename(conflict->local_abspath, result_pool);
@@ -409,10 +412,9 @@ svn_wc__add_tree_conflict(svn_wc_context_t *wc_ctx,
svn_error_t *err;
SVN_ERR_ASSERT(conflict != NULL);
- SVN_ERR_ASSERT(conflict->operation == svn_wc_operation_merge
- || (conflict->reason != svn_wc_conflict_reason_moved_away
- && conflict->reason != svn_wc_conflict_reason_moved_here)
- );
+ SVN_ERR_ASSERT(conflict->operation == svn_wc_operation_merge ||
+ (conflict->reason != svn_wc_conflict_reason_moved_away &&
+ conflict->reason != svn_wc_conflict_reason_moved_here));
/* Re-adding an existing tree conflict victim is an error. */
err = svn_wc__internal_conflicted_p(NULL, NULL, &existing_conflict,
@@ -443,7 +445,7 @@ svn_wc__add_tree_conflict(svn_wc_context_t *wc_ctx,
NULL,
scratch_pool, scratch_pool));
- switch(conflict->operation)
+ switch (conflict->operation)
{
case svn_wc_operation_update:
default:
@@ -483,8 +485,10 @@ svn_wc__get_tree_conflict(const svn_wc_conflict_description2_t **tree_conflict,
int i;
SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
- SVN_ERR(svn_wc__read_conflicts(&conflicts,
- wc_ctx->db, local_abspath, FALSE,
+ SVN_ERR(svn_wc__read_conflicts(&conflicts, NULL,
+ wc_ctx->db, local_abspath,
+ FALSE /* temp files */,
+ TRUE /* only tree conflicts */,
scratch_pool, scratch_pool));
if (!conflicts || conflicts->nelts == 0)
@@ -501,8 +505,7 @@ svn_wc__get_tree_conflict(const svn_wc_conflict_description2_t **tree_conflict,
if (desc->kind == svn_wc_conflict_kind_tree)
{
- *tree_conflict = svn_wc__conflict_description2_dup(desc,
- result_pool);
+ *tree_conflict = svn_wc_conflict_description2_dup(desc, result_pool);
return SVN_NO_ERROR;
}
}
diff --git a/subversion/libsvn_wc/update_editor.c b/subversion/libsvn_wc/update_editor.c
index fd3e9ca92eb1..5f4d64826713 100644
--- a/subversion/libsvn_wc/update_editor.c
+++ b/subversion/libsvn_wc/update_editor.c
@@ -211,7 +211,7 @@ struct edit_baton
/* If this is a 'switch' operation, the new relpath of target_abspath,
else NULL. */
- const char *switch_relpath;
+ const char *switch_repos_relpath;
/* The URL to the root of the repository. */
const char *repos_root;
@@ -258,6 +258,9 @@ struct edit_baton
/* Absolute path of the working copy root or NULL if not initialized yet */
const char *wcroot_abspath;
+ /* After closing the root directory a copy of its edited value */
+ svn_boolean_t edited;
+
apr_pool_t *pool;
};
@@ -295,7 +298,7 @@ struct dir_baton
const char *local_abspath;
/* The repository relative path this directory will correspond to. */
- const char *new_relpath;
+ const char *new_repos_relpath;
/* The revision of the directory before updating */
svn_revnum_t old_revision;
@@ -342,9 +345,10 @@ struct dir_baton
and reinstall it. */
apr_hash_t *deletion_conflicts;
- /* A hash of file names (only the hash key matters) seen by add_file
- and not yet added to the database by close_file. */
- apr_hash_t *not_present_files;
+ /* A hash of file names (only the hash key matters) seen by add_file and
+ add_directory and not yet added to the database, mapping to a const
+ char * node kind (via svn_node_kind_to_word(). */
+ apr_hash_t *not_present_nodes;
/* Set if an unversioned dir of the same name already existed in
this directory. */
@@ -398,7 +402,7 @@ struct handler_baton
struct file_baton *fb;
/* Where we are assembling the new file. */
- const char *new_text_base_tmp_abspath;
+ svn_wc__db_install_data_t *install_data;
/* The expected source checksum of the text source or NULL if no base
checksum is available (MD5 if the server provides a checksum, SHA1 if
@@ -412,7 +416,7 @@ struct handler_baton
provide a sha1, so we may not have to calculate both, but for the time
being, that's the way it is. */
- /* The calculated checksum of the text source or NULL if the acual
+ /* The calculated checksum of the text source or NULL if the actual
checksum is not being calculated. The checksum kind is identical to the
kind of expected_source_checksum. */
svn_checksum_t *actual_source_checksum;
@@ -486,47 +490,20 @@ cleanup_edit_baton(void *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.
- ADDING should be TRUE if we are adding this directory. */
+/* Calculate the new repos_relpath for a directory or file */
static svn_error_t *
-make_dir_baton(struct dir_baton **d_p,
- const char *path,
- struct edit_baton *eb,
- struct dir_baton *pb,
- svn_boolean_t adding,
- apr_pool_t *scratch_pool)
+calculate_repos_relpath(const char **new_repos_relpath,
+ const char *local_abspath,
+ const char *old_repos_relpath,
+ struct edit_baton *eb,
+ struct dir_baton *pb,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *dir_pool;
- struct dir_baton *d;
-
- if (pb != NULL)
- dir_pool = svn_pool_create(pb->pool);
- else
- dir_pool = svn_pool_create(eb->pool);
-
- SVN_ERR_ASSERT(path || (! pb));
-
- /* Okay, no easy out, so allocate and initialize a dir baton. */
- d = apr_pcalloc(dir_pool, sizeof(*d));
-
- /* Construct the PATH and baseNAME of this directory. */
- if (path)
- {
- d->name = svn_dirent_basename(path, dir_pool);
- SVN_ERR(path_join_under_root(&d->local_abspath,
- pb->local_abspath, d->name, dir_pool));
- }
- else
- {
- /* This is the root baton. */
- d->name = NULL;
- d->local_abspath = eb->anchor_abspath;
- }
+ const char *name = svn_dirent_basename(local_abspath, NULL);
- /* Figure out the new_relpath for this directory. */
- if (eb->switch_relpath)
+ /* Figure out the new_repos_relpath for this directory. */
+ if (eb->switch_repos_relpath)
{
/* Handle switches... */
@@ -535,18 +512,16 @@ make_dir_baton(struct dir_baton **d_p,
if (*eb->target_basename == '\0')
{
/* No parent baton and target_basename=="" means that we are
- the target of the switch. Thus, our NEW_RELPATH will be
- the SWITCH_RELPATH. */
- d->new_relpath = eb->switch_relpath;
+ the target of the switch. Thus, our new_repos_relpath will be
+ the switch_repos_relpath. */
+ *new_repos_relpath = eb->switch_repos_relpath;
}
else
{
/* This node is NOT the target of the switch (one of our
children is the target); therefore, it must already exist.
Get its old REPOS_RELPATH, as it won't be changing. */
- SVN_ERR(svn_wc__db_scan_base_repos(&d->new_relpath, NULL, NULL,
- eb->db, d->local_abspath,
- dir_pool, scratch_pool));
+ *new_repos_relpath = apr_pstrdup(result_pool, old_repos_relpath);
}
}
else
@@ -554,36 +529,76 @@ make_dir_baton(struct dir_baton **d_p,
/* This directory is *not* the root (has a parent). If there is
no grandparent, then we may have anchored at the parent,
and self is the target. If we match the target, then set
- NEW_RELPATH to the SWITCH_RELPATH.
+ new_repos_relpath to the switch_repos_relpath.
+
+ Otherwise, we simply extend new_repos_relpath from the parent. */
- Otherwise, we simply extend NEW_RELPATH from the parent. */
if (pb->parent_baton == NULL
- && strcmp(eb->target_basename, d->name) == 0)
- d->new_relpath = eb->switch_relpath;
+ && strcmp(eb->target_basename, name) == 0)
+ *new_repos_relpath = eb->switch_repos_relpath;
else
- d->new_relpath = svn_relpath_join(pb->new_relpath, d->name,
- dir_pool);
+ *new_repos_relpath = svn_relpath_join(pb->new_repos_relpath, name,
+ result_pool);
}
}
else /* must be an update */
{
/* If we are adding the node, then simply extend the parent's
relpath for our own. */
- if (adding)
+ if (old_repos_relpath == NULL)
{
SVN_ERR_ASSERT(pb != NULL);
- d->new_relpath = svn_relpath_join(pb->new_relpath, d->name,
- dir_pool);
+ *new_repos_relpath = svn_relpath_join(pb->new_repos_relpath, name,
+ result_pool);
}
else
{
- SVN_ERR(svn_wc__db_scan_base_repos(&d->new_relpath, NULL, NULL,
- eb->db, d->local_abspath,
- dir_pool, scratch_pool));
- SVN_ERR_ASSERT(d->new_relpath);
+ *new_repos_relpath = apr_pstrdup(result_pool, old_repos_relpath);
}
}
+ return SVN_NO_ERROR;
+}
+
+/* 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.
+ ADDING should be TRUE if we are adding this directory. */
+static svn_error_t *
+make_dir_baton(struct dir_baton **d_p,
+ const char *path,
+ struct edit_baton *eb,
+ struct dir_baton *pb,
+ svn_boolean_t adding,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *dir_pool;
+ struct dir_baton *d;
+
+ if (pb != NULL)
+ dir_pool = svn_pool_create(pb->pool);
+ else
+ dir_pool = svn_pool_create(eb->pool);
+
+ SVN_ERR_ASSERT(path || (! pb));
+
+ /* Okay, no easy out, so allocate and initialize a dir baton. */
+ d = apr_pcalloc(dir_pool, sizeof(*d));
+
+ /* Construct the PATH and baseNAME of this directory. */
+ if (path)
+ {
+ d->name = svn_dirent_basename(path, dir_pool);
+ SVN_ERR(path_join_under_root(&d->local_abspath,
+ pb->local_abspath, d->name, dir_pool));
+ }
+ else
+ {
+ /* This is the root baton. */
+ d->name = NULL;
+ d->local_abspath = eb->anchor_abspath;
+ }
+
d->edit_baton = eb;
d->parent_baton = pb;
d->pool = dir_pool;
@@ -594,7 +609,7 @@ make_dir_baton(struct dir_baton **d_p,
d->old_revision = SVN_INVALID_REVNUM;
d->adding_dir = adding;
d->changed_rev = SVN_INVALID_REVNUM;
- d->not_present_files = apr_hash_make(dir_pool);
+ d->not_present_nodes = apr_hash_make(dir_pool);
/* Copy some flags from the parent baton */
if (pb)
@@ -614,7 +629,6 @@ make_dir_baton(struct dir_baton **d_p,
return SVN_NO_ERROR;
}
-
/* Forward declarations. */
static svn_error_t *
already_in_a_tree_conflict(svn_boolean_t *conflicted,
@@ -680,7 +694,7 @@ struct file_baton
const char *local_abspath;
/* The repository relative path this file will correspond to. */
- const char *new_relpath;
+ const char *new_repos_relpath;
/* The revision of the file before updating */
svn_revnum_t old_revision;
@@ -764,7 +778,6 @@ make_file_baton(struct file_baton **f_p,
svn_boolean_t adding,
apr_pool_t *scratch_pool)
{
- struct edit_baton *eb = pb->edit_baton;
apr_pool_t *file_pool = svn_pool_create(pb->pool);
struct file_baton *f = apr_pcalloc(file_pool, sizeof(*f));
@@ -776,37 +789,6 @@ make_file_baton(struct file_baton **f_p,
SVN_ERR(path_join_under_root(&f->local_abspath,
pb->local_abspath, f->name, file_pool));
- /* Figure out the new URL for this file. */
- if (eb->switch_relpath)
- {
- /* Handle switches... */
-
- /* This file has a parent directory. If there is
- no grandparent, then we may have anchored at the parent,
- and self is the target. If we match the target, then set
- NEW_RELPATH to the SWITCH_RELPATH.
-
- Otherwise, we simply extend NEW_RELPATH from the parent. */
- if (pb->parent_baton == NULL
- && strcmp(eb->target_basename, f->name) == 0)
- f->new_relpath = eb->switch_relpath;
- else
- f->new_relpath = svn_relpath_join(pb->new_relpath, f->name,
- file_pool);
- }
- else /* must be an update */
- {
- if (adding)
- f->new_relpath = svn_relpath_join(pb->new_relpath, f->name, file_pool);
- else
- {
- SVN_ERR(svn_wc__db_scan_base_repos(&f->new_relpath, NULL, NULL,
- eb->db, f->local_abspath,
- file_pool, scratch_pool));
- SVN_ERR_ASSERT(f->new_relpath);
- }
- }
-
f->pool = file_pool;
f->edit_baton = pb->edit_baton;
f->propchanges = apr_array_make(file_pool, 1, sizeof(svn_prop_t));
@@ -843,13 +825,16 @@ complete_conflict(svn_skel_t *conflict,
const char *new_repos_relpath,
svn_node_kind_t local_kind,
svn_node_kind_t target_kind,
+ const svn_skel_t *delete_conflict,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- svn_wc_conflict_version_t *original_version;
+ const svn_wc_conflict_version_t *original_version = NULL;
svn_wc_conflict_version_t *target_version;
svn_boolean_t is_complete;
+ SVN_ERR_ASSERT(new_repos_relpath);
+
if (!conflict)
return SVN_NO_ERROR; /* Not conflicted */
@@ -865,20 +850,30 @@ complete_conflict(svn_skel_t *conflict,
old_revision,
local_kind,
result_pool);
- else
- original_version = NULL;
+ else if (delete_conflict)
+ {
+ const apr_array_header_t *locations;
- 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;
+ SVN_ERR(svn_wc__conflict_read_info(NULL, &locations, NULL, NULL, NULL,
+ eb->db, local_abspath,
+ delete_conflict,
+ scratch_pool, scratch_pool));
+
+ if (locations)
+ {
+ original_version = APR_ARRAY_IDX(locations, 0,
+ const svn_wc_conflict_version_t *);
+ }
+ }
- if (eb->switch_relpath)
+ target_version = svn_wc_conflict_version_create2(eb->repos_root,
+ eb->repos_uuid,
+ new_repos_relpath,
+ *eb->target_revision,
+ target_kind,
+ result_pool);
+
+ if (eb->switch_repos_relpath)
SVN_ERR(svn_wc__conflict_skel_set_op_switch(conflict,
original_version,
target_version,
@@ -913,8 +908,9 @@ mark_directory_edited(struct dir_baton *db, apr_pool_t *scratch_pool)
SVN_ERR(complete_conflict(db->edit_conflict, db->edit_baton,
db->local_abspath,
db->old_repos_relpath, db->old_revision,
- db->new_relpath,
+ db->new_repos_relpath,
svn_node_dir, svn_node_dir,
+ NULL,
db->pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_conflict(db->edit_baton->db,
db->local_abspath,
@@ -924,7 +920,6 @@ mark_directory_edited(struct dir_baton *db, apr_pool_t *scratch_pool)
do_notification(db->edit_baton, db->local_abspath, svn_node_dir,
svn_wc_notify_tree_conflict, scratch_pool);
db->already_notified = TRUE;
-
}
return SVN_NO_ERROR;
@@ -948,8 +943,9 @@ mark_file_edited(struct file_baton *fb, apr_pool_t *scratch_pool)
SVN_ERR(complete_conflict(fb->edit_conflict, fb->edit_baton,
fb->local_abspath, fb->old_repos_relpath,
- fb->old_revision, fb->new_relpath,
+ fb->old_revision, fb->new_repos_relpath,
svn_node_file, svn_node_file,
+ NULL,
fb->pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_conflict(fb->edit_baton->db,
@@ -974,7 +970,6 @@ window_handler(svn_txdelta_window_t *window, void *baton)
{
struct handler_baton *hb = baton;
struct file_baton *fb = hb->fb;
- svn_wc__db_t *db = fb->edit_baton->db;
svn_error_t *err;
/* Apply this window. We may be done at that point. */
@@ -1014,10 +1009,10 @@ window_handler(svn_txdelta_window_t *window, void *baton)
{
/* We failed to apply the delta; clean up the temporary file if it
already created by lazy_open_target(). */
- if (hb->new_text_base_tmp_abspath)
+ if (hb->install_data)
{
- svn_error_clear(svn_io_remove_file2(hb->new_text_base_tmp_abspath,
- TRUE, hb->pool));
+ svn_error_clear(svn_wc__db_pristine_install_abort(hb->install_data,
+ hb->pool));
}
}
else
@@ -1031,7 +1026,7 @@ window_handler(svn_txdelta_window_t *window, void *baton)
/* Store the new pristine text in the pristine store now. Later, in a
single transaction we will update the BASE_NODE to include a
reference to this pristine text's checksum. */
- SVN_ERR(svn_wc__db_pristine_install(db, hb->new_text_base_tmp_abspath,
+ SVN_ERR(svn_wc__db_pristine_install(hb->install_data,
fb->new_text_base_sha1_checksum,
fb->new_text_base_md5_checksum,
hb->pool));
@@ -1154,17 +1149,6 @@ set_target_revision(void *edit_baton,
return SVN_NO_ERROR;
}
-static svn_error_t *
-check_tree_conflict(svn_skel_t **pconflict,
- struct edit_baton *eb,
- const char *local_abspath,
- svn_wc__db_status_t working_status,
- 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);
-
/* An svn_delta_editor_t function. */
static svn_error_t *
open_root(void *edit_baton,
@@ -1228,10 +1212,27 @@ open_root(void *edit_baton,
eb->db, db->local_abspath,
db->pool, pool));
- if (conflict_ignored)
+ if (have_work)
{
- db->shadowed = TRUE;
+ 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));
}
+ else
+ base_status = status;
+
+ SVN_ERR(calculate_repos_relpath(&db->new_repos_relpath, db->local_abspath,
+ db->old_repos_relpath, eb, NULL,
+ db->pool, pool));
+
+ if (conflict_ignored)
+ db->shadowed = TRUE;
else if (have_work)
{
const char *move_src_root_abspath;
@@ -1239,16 +1240,6 @@ open_root(void *edit_baton,
SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL, &move_src_root_abspath,
NULL, eb->db, db->local_abspath,
pool, pool));
- if (move_src_root_abspath || *eb->target_basename == '\0')
- 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));
if (move_src_root_abspath)
{
@@ -1271,9 +1262,10 @@ open_root(void *edit_baton,
SVN_ERR(complete_conflict(tree_conflict, eb,
move_src_root_abspath,
db->old_repos_relpath,
- db->old_revision, db->new_relpath,
+ db->old_revision,
+ db->new_repos_relpath,
svn_node_dir, svn_node_dir,
- pool, pool));
+ NULL, pool, pool));
SVN_ERR(svn_wc__db_op_mark_conflict(eb->db,
move_src_root_abspath,
tree_conflict,
@@ -1288,8 +1280,6 @@ open_root(void *edit_baton,
db->shadowed = TRUE; /* Needed for the close_directory() on the root, to
make sure it doesn't use the ACTUAL tree */
}
- else
- base_status = status;
if (*eb->target_basename == '\0')
{
@@ -1308,7 +1298,7 @@ open_root(void *edit_baton,
SVN_ERR(svn_wc__db_temp_op_start_directory_update(eb->db,
db->local_abspath,
- db->new_relpath,
+ db->new_repos_relpath,
*eb->target_revision,
pool));
}
@@ -1320,99 +1310,6 @@ open_root(void *edit_baton,
/* ===================================================================== */
/* Checking for local modifications. */
-/* A baton for use with modcheck_found_entry(). */
-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 */
-} modcheck_baton_t;
-
-/* An implementation of svn_wc_status_func4_t. */
-static svn_error_t *
-modcheck_callback(void *baton,
- const char *local_abspath,
- const svn_wc_status3_t *status,
- apr_pool_t *scratch_pool)
-{
- modcheck_baton_t *mb = 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:
- case svn_wc_status_external:
- break;
-
- case svn_wc_status_deleted:
- mb->found_mod = TRUE;
- break;
-
- case svn_wc_status_missing:
- case svn_wc_status_obstructed:
- 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);
-
- default:
- case svn_wc_status_added:
- case svn_wc_status_replaced:
- case svn_wc_status_modified:
- 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);
- }
-
- return SVN_NO_ERROR;
-}
-
-
-/* Set *MODIFIED to true iff there are any local modifications within the
- * 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. */
-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 };
- svn_error_t *err;
-
- modcheck_baton.db = db;
-
- /* 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
- * no local mods in the pieces that aren't present in the WC. */
-
- err = svn_wc__internal_walk_status(db, local_abspath,
- svn_depth_infinity,
- FALSE, FALSE, FALSE, NULL,
- modcheck_callback, &modcheck_baton,
- cancel_func, cancel_baton,
- scratch_pool);
-
- if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
- svn_error_clear(err);
- else
- SVN_ERR(err);
-
- *modified = modcheck_baton.found_mod;
- *all_edits_are_deletes = (modcheck_baton.found_mod
- && !modcheck_baton.found_not_delete);
-
- return SVN_NO_ERROR;
-}
-
/* Indicates an unset svn_wc_conflict_reason_t. */
#define SVN_WC_CONFLICT_REASON_NONE (svn_wc_conflict_reason_t)(-1)
@@ -1447,7 +1344,6 @@ check_tree_conflict(svn_skel_t **pconflict,
{
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 *move_src_op_root_abspath = NULL;
*pconflict = NULL;
@@ -1486,15 +1382,15 @@ check_tree_conflict(svn_skel_t **pconflict,
}
else
{
- /* The node is locally replaced but could also be moved-away. */
- SVN_ERR(svn_wc__db_base_moved_to(NULL, NULL, NULL,
- &move_src_op_root_abspath,
- eb->db, local_abspath,
- scratch_pool, scratch_pool));
- if (move_src_op_root_abspath)
- reason = svn_wc_conflict_reason_moved_away;
- else
- reason = svn_wc_conflict_reason_replaced;
+ /* The node is locally replaced but could also be moved-away,
+ but we can't report that it is moved away and replaced.
+
+ And we wouldn't be able to store that each of a dozen
+ descendants was moved to other locations...
+
+ Replaced is what actually happened... */
+
+ reason = svn_wc_conflict_reason_replaced;
}
break;
@@ -1557,14 +1453,14 @@ check_tree_conflict(svn_skel_t **pconflict,
* not visit the subdirectories of a directory that it wants to delete.
* Therefore, we need to start a separate crawl here. */
- SVN_ERR(svn_wc__node_has_local_mods(&modified, &all_mods_are_deletes,
- eb->db, local_abspath,
+ SVN_ERR(svn_wc__node_has_local_mods(&modified, NULL,
+ eb->db, local_abspath, FALSE,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
if (modified)
{
- if (all_mods_are_deletes)
+ if (working_status == svn_wc__db_status_deleted)
reason = svn_wc_conflict_reason_deleted;
else
reason = svn_wc_conflict_reason_edited;
@@ -1711,7 +1607,8 @@ delete_entry(const char *path,
const char *base = svn_relpath_basename(path, NULL);
const char *local_abspath;
const char *repos_relpath;
- svn_node_kind_t kind, base_kind;
+ const char *deleted_repos_relpath;
+ svn_node_kind_t kind;
svn_revnum_t old_revision;
svn_boolean_t conflicted;
svn_boolean_t have_work;
@@ -1721,8 +1618,6 @@ delete_entry(const char *path,
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;
@@ -1740,6 +1635,7 @@ delete_entry(const char *path,
{
svn_boolean_t is_root;
+
SVN_ERR(svn_wc__db_is_wcroot(&is_root, eb->db, local_abspath,
scratch_pool));
@@ -1767,10 +1663,9 @@ delete_entry(const char *path,
if (!have_work)
{
base_status = status;
- base_kind = kind;
}
else
- SVN_ERR(svn_wc__db_base_get_info(&base_status, &base_kind, &old_revision,
+ SVN_ERR(svn_wc__db_base_get_info(&base_status, NULL, &old_revision,
&repos_relpath,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
@@ -1815,11 +1710,9 @@ delete_entry(const char *path,
|| base_status == svn_wc__db_status_excluded
|| base_status == svn_wc__db_status_server_excluded)
{
- SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
- FALSE /* keep_as_working */,
- FALSE /* queue_deletes */,
- FALSE /* remove_locks */,
- SVN_INVALID_REVNUM /* not_present_rev */,
+ SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath, TRUE,
+ deleting_target, FALSE,
+ *eb->target_revision,
NULL, NULL,
scratch_pool));
@@ -1842,18 +1735,13 @@ delete_entry(const char *path,
{
SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
status, TRUE,
- (kind == svn_node_dir)
- ? svn_node_dir
- : svn_node_file,
+ kind,
svn_wc_conflict_action_delete,
pb->pool, scratch_pool));
}
- else
- queue_deletes = FALSE; /* There is no in-wc representation */
if (tree_conflict != NULL)
{
- svn_wc_conflict_reason_t reason;
/* When we raise a tree conflict on a node, we don't want to mark the
* node as skipped, to allow a replacement to continue doing at least
* a bit of its work (possibly adding a not present node, for the
@@ -1864,45 +1752,19 @@ delete_entry(const char *path,
svn_hash_sets(pb->deletion_conflicts, apr_pstrdup(pb->pool, base),
tree_conflict);
- 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
- || 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.
- *
- * To prepare the "accept mine" resolution for the tree conflict,
- * we must schedule the existing content for re-addition as a copy
- * of what it was, but with its local modifications preserved. */
- keep_as_working = TRUE;
-
- /* Fall through to remove the BASE_NODEs properly, with potentially
- keeping a not-present marker */
- }
- else if (reason == svn_wc_conflict_reason_deleted
- || reason == svn_wc_conflict_reason_moved_away
- || reason == svn_wc_conflict_reason_replaced)
- {
- /* The item does not exist locally because it was already shadowed.
- * We must complete the deletion, leaving the tree conflict info
- * as the only difference from a normal deletion. */
-
- /* Fall through to the normal "delete" code path. */
- }
- else
- SVN_ERR_MALFUNCTION(); /* other reasons are not expected here */
+ /* Whatever the kind of conflict, we can just clear BASE
+ by turning whatever is there into a copy */
}
+ /* Calculate the repository-relative path of the entry which was
+ * deleted. For updates it's the same as REPOS_RELPATH but for
+ * switches it is within the switch target. */
+ SVN_ERR(calculate_repos_relpath(&deleted_repos_relpath, local_abspath,
+ repos_relpath, eb, pb, scratch_pool,
+ scratch_pool));
SVN_ERR(complete_conflict(tree_conflict, eb, local_abspath, repos_relpath,
- old_revision, NULL,
- (kind == svn_node_dir)
- ? svn_node_dir
- : svn_node_file,
- svn_node_none,
+ old_revision, deleted_repos_relpath,
+ kind, svn_node_none, NULL,
pb->pool, scratch_pool));
/* Issue a wq operation to delete the BASE_NODE data and to delete actual
@@ -1917,7 +1779,8 @@ delete_entry(const char *path,
{
/* Delete, and do not leave a not-present node. */
SVN_ERR(svn_wc__db_base_remove(eb->db, local_abspath,
- keep_as_working, queue_deletes, FALSE,
+ (tree_conflict != NULL),
+ FALSE, FALSE,
SVN_INVALID_REVNUM /* not_present_rev */,
tree_conflict, NULL,
scratch_pool));
@@ -1926,7 +1789,8 @@ 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, queue_deletes, FALSE,
+ (tree_conflict != NULL),
+ TRUE, FALSE,
*eb->target_revision,
tree_conflict, NULL,
scratch_pool));
@@ -1948,6 +1812,7 @@ delete_entry(const char *path,
{
if (eb->conflict_func)
SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, local_abspath,
+ kind,
tree_conflict,
NULL /* merge_options */,
eb->conflict_func,
@@ -1955,23 +1820,17 @@ delete_entry(const char *path,
eb->cancel_func,
eb->cancel_baton,
scratch_pool));
- do_notification(eb, local_abspath, svn_node_unknown,
+ do_notification(eb, local_abspath, kind,
svn_wc_notify_tree_conflict, scratch_pool);
}
else
{
svn_wc_notify_action_t action = svn_wc_notify_update_delete;
- svn_node_kind_t node_kind;
if (pb->shadowed || pb->edit_obstructed)
action = svn_wc_notify_update_shadowed_delete;
- if (kind == svn_node_dir)
- node_kind = svn_node_dir;
- else
- node_kind = svn_node_file;
-
- do_notification(eb, local_abspath, node_kind, action, scratch_pool);
+ do_notification(eb, local_abspath, kind, action, scratch_pool);
}
svn_pool_destroy(scratch_pool);
@@ -1991,6 +1850,7 @@ add_directory(const char *path,
struct dir_baton *pb = parent_baton;
struct edit_baton *eb = pb->edit_baton;
struct dir_baton *db;
+ apr_pool_t *scratch_pool = svn_pool_create(pool);
svn_node_kind_t kind;
svn_wc__db_status_t status;
svn_node_kind_t wc_kind;
@@ -2008,6 +1868,9 @@ add_directory(const char *path,
if (db->skip_this)
return SVN_NO_ERROR;
+ SVN_ERR(calculate_repos_relpath(&db->new_repos_relpath, db->local_abspath,
+ NULL, eb, pb, db->pool, scratch_pool));
+
SVN_ERR(mark_directory_edited(db, pool));
if (strcmp(eb->target_abspath, db->local_abspath) == 0)
@@ -2037,13 +1900,26 @@ add_directory(const char *path,
"administrative directory"),
svn_dirent_local_style(db->local_abspath, pool));
- SVN_ERR(svn_io_check_path(db->local_abspath, &kind, db->pool));
+ if (!eb->clean_checkout)
+ {
+ SVN_ERR(svn_io_check_path(db->local_abspath, &kind, db->pool));
+
+ err = svn_wc__db_read_info(&status, &wc_kind, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ &conflicted, NULL, NULL, NULL, NULL, NULL, NULL,
+ eb->db, db->local_abspath,
+ scratch_pool, scratch_pool);
+ }
+ else
+ {
+ kind = svn_node_none;
+ status = svn_wc__db_status_not_present;
+ wc_kind = svn_node_unknown;
+ conflicted = FALSE;
+ err = NULL;
+ }
- err = svn_wc__db_read_info(&status, &wc_kind, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- NULL, NULL, NULL, NULL, NULL,
- &conflicted, NULL, NULL, NULL, NULL, NULL, NULL,
- eb->db, db->local_abspath, db->pool, db->pool);
if (err)
{
if (err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
@@ -2056,63 +1932,68 @@ add_directory(const char *path,
versioned_locally_and_present = FALSE;
}
- else if (wc_kind == svn_node_dir
- && status == svn_wc__db_status_normal)
+ else if (status == svn_wc__db_status_normal && wc_kind == svn_node_unknown)
{
- /* !! We found the root of a separate working copy obstructing the wc !!
-
- If the directory would be part of our own working copy then
- we wouldn't have been called as an add_directory().
-
- The only thing we can do is add a not-present node, to allow
- a future update to bring in the new files when the problem is
- resolved. Note that svn_wc__db_base_add_not_present_node()
- explicitly adds the node into the parent's node database. */
-
- SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db, db->local_abspath,
- db->new_relpath,
- eb->repos_root,
- eb->repos_uuid,
- *eb->target_revision,
- svn_node_file,
- NULL, NULL,
- pool));
-
- SVN_ERR(remember_skipped_tree(eb, db->local_abspath, pool));
- db->skip_this = TRUE;
- db->already_notified = TRUE;
-
- do_notification(eb, db->local_abspath, svn_node_dir,
- svn_wc_notify_update_skip_obstruction, pool);
-
- return SVN_NO_ERROR;
+ SVN_ERR_ASSERT(conflicted);
+ versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
}
else if (status == svn_wc__db_status_normal
- && (wc_kind == svn_node_file
- || wc_kind == svn_node_symlink))
+ || status == svn_wc__db_status_incomplete)
{
- /* We found a file external occupating the place we need in BASE.
+ svn_boolean_t root;
+
+ SVN_ERR(svn_wc__db_is_wcroot(&root, eb->db, db->local_abspath,
+ scratch_pool));
- We can't add a not-present node in this case as that would overwrite
- the file external. Luckily the file external itself stops us from
- forgetting a child of this parent directory like an obstructing
- working copy would.
+ if (root)
+ {
+ /* !! We found the root of a working copy obstructing the wc !!
- The reason we get here is that the adm crawler doesn't report
- file externals.
- */
+ If the directory would be part of our own working copy then
+ we wouldn't have been called as an add_directory().
- SVN_ERR(remember_skipped_tree(eb, db->local_abspath, pool));
+ The only thing we can do is add a not-present node, to allow
+ a future update to bring in the new files when the problem is
+ resolved. Note that svn_wc__db_base_add_not_present_node()
+ explicitly adds the node into the parent's node database. */
+
+ svn_hash_sets(pb->not_present_nodes,
+ apr_pstrdup(pb->pool, db->name),
+ svn_node_kind_to_word(svn_node_dir));
+ }
+ else if (wc_kind == svn_node_dir)
+ {
+ /* We have an editor violation. Github sometimes does this
+ in its subversion compatibility code, when changing the
+ depth of a working copy, or on updates from incomplete */
+ }
+ else
+ {
+ /* We found a file external occupating the place we need in BASE.
+
+ We can't add a not-present node in this case as that would overwrite
+ the file external. Luckily the file external itself stops us from
+ forgetting a child of this parent directory like an obstructing
+ working copy would.
+
+ The reason we get here is that the adm crawler doesn't report
+ file externals.
+ */
+ SVN_ERR_ASSERT(wc_kind == svn_node_file
+ || wc_kind == svn_node_symlink);
+ }
+
+ SVN_ERR(remember_skipped_tree(eb, db->local_abspath, scratch_pool));
db->skip_this = TRUE;
db->already_notified = TRUE;
- do_notification(eb, db->local_abspath, svn_node_file,
- svn_wc_notify_update_skip_obstruction, pool);
+ do_notification(eb, db->local_abspath, wc_kind,
+ svn_wc_notify_update_skip_obstruction, scratch_pool);
+
+ svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
- else if (wc_kind == svn_node_unknown)
- versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
else
versioned_locally_and_present = IS_NODE_PRESENT(status);
@@ -2134,7 +2015,7 @@ add_directory(const char *path,
eb->db,
db->local_abspath,
tree_conflict,
- db->pool, db->pool));
+ db->pool, scratch_pool));
tree_conflict = svn_wc__conflict_skel_create(db->pool);
@@ -2143,7 +2024,7 @@ add_directory(const char *path,
eb->db, db->local_abspath,
reason, svn_wc_conflict_action_replace,
move_src_op_root_abspath,
- db->pool, db->pool));
+ db->pool, scratch_pool));
/* And now stop checking for conflicts here and just perform
a shadowed update */
@@ -2154,7 +2035,8 @@ add_directory(const char *path,
}
else
SVN_ERR(node_already_conflicted(&conflicted, &conflict_ignored,
- eb->db, db->local_abspath, pool));
+ eb->db, db->local_abspath,
+ scratch_pool));
}
/* Now the "usual" behaviour if already conflicted. Skip it. */
@@ -2177,18 +2059,13 @@ add_directory(const char *path,
Note that we can safely assume that no present base node exists,
because then we would not have received an add_directory.
*/
- SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db, db->local_abspath,
- db->new_relpath,
- eb->repos_root,
- eb->repos_uuid,
- *eb->target_revision,
- svn_node_dir,
- NULL, NULL,
- pool));
+ svn_hash_sets(pb->not_present_nodes, apr_pstrdup(pb->pool, db->name),
+ svn_node_kind_to_word(svn_node_dir));
- /* ### TODO: Also print victim_path in the skip msg. */
do_notification(eb, db->local_abspath, svn_node_dir,
- svn_wc_notify_skip_conflicted, pool);
+ svn_wc_notify_skip_conflicted, scratch_pool);
+
+ svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
else if (conflict_ignored)
@@ -2221,7 +2098,7 @@ add_directory(const char *path,
SVN_ERR(svn_wc__db_scan_addition(&add_status, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL,
eb->db, db->local_abspath,
- pool, pool));
+ scratch_pool, scratch_pool));
/* Is there *something* that is not a dir? */
@@ -2244,7 +2121,7 @@ add_directory(const char *path,
db->local_abspath,
status, FALSE, svn_node_none,
svn_wc_conflict_action_add,
- pool, pool));
+ db->pool, scratch_pool));
}
if (tree_conflict == NULL)
@@ -2272,7 +2149,7 @@ add_directory(const char *path,
eb->db, db->local_abspath,
svn_wc_conflict_reason_unversioned,
svn_wc_conflict_action_add, NULL,
- db->pool, pool));
+ db->pool, scratch_pool));
db->edit_conflict = tree_conflict;
}
}
@@ -2280,14 +2157,17 @@ add_directory(const char *path,
if (tree_conflict)
SVN_ERR(complete_conflict(tree_conflict, eb, db->local_abspath,
db->old_repos_relpath, db->old_revision,
- db->new_relpath,
- wc_kind,
- svn_node_dir,
- db->pool, pool));
+ db->new_repos_relpath,
+ wc_kind, svn_node_dir,
+ pb->deletion_conflicts
+ ? svn_hash_gets(pb->deletion_conflicts,
+ db->name)
+ : NULL,
+ db->pool, scratch_pool));
SVN_ERR(svn_wc__db_base_add_incomplete_directory(
eb->db, db->local_abspath,
- db->new_relpath,
+ db->new_repos_relpath,
eb->repos_root,
eb->repos_uuid,
*eb->target_revision,
@@ -2296,28 +2176,20 @@ add_directory(const char *path,
(! db->shadowed
&& status == svn_wc__db_status_added),
tree_conflict, NULL,
- pool));
+ scratch_pool));
/* Make sure there is a real directory at LOCAL_ABSPATH, unless we are just
updating the DB */
if (!db->shadowed)
- SVN_ERR(svn_wc__ensure_directory(db->local_abspath, pool));
+ SVN_ERR(svn_wc__ensure_directory(db->local_abspath, scratch_pool));
if (tree_conflict != NULL)
{
- if (eb->conflict_func)
- SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, db->local_abspath,
- tree_conflict,
- NULL /* merge_options */,
- eb->conflict_func,
- eb->conflict_baton,
- eb->cancel_func,
- eb->cancel_baton,
- pool));
+ db->edit_conflict = tree_conflict;
db->already_notified = TRUE;
do_notification(eb, db->local_abspath, svn_node_dir,
- svn_wc_notify_tree_conflict, pool);
+ svn_wc_notify_tree_conflict, scratch_pool);
}
@@ -2339,9 +2211,12 @@ add_directory(const char *path,
db->already_notified = TRUE;
- do_notification(eb, db->local_abspath, svn_node_dir, action, pool);
+ do_notification(eb, db->local_abspath, svn_node_dir, action,
+ scratch_pool);
}
+ svn_pool_destroy(scratch_pool);
+
return SVN_NO_ERROR;
}
@@ -2416,6 +2291,10 @@ open_directory(const char *path,
db->was_incomplete = (base_status == svn_wc__db_status_incomplete);
+ SVN_ERR(calculate_repos_relpath(&db->new_repos_relpath, db->local_abspath,
+ db->old_repos_relpath, eb, pb,
+ db->pool, pool));
+
/* Is this path a conflict victim? */
if (db->shadowed)
conflicted = FALSE; /* Conflict applies to WORKING */
@@ -2475,7 +2354,7 @@ open_directory(const char *path,
/* Mark directory as being at target_revision and URL, but incomplete. */
SVN_ERR(svn_wc__db_temp_op_start_directory_update(eb->db, db->local_abspath,
- db->new_relpath,
+ db->new_repos_relpath,
*eb->target_revision,
pool));
@@ -2498,7 +2377,7 @@ change_dir_prop(void *dir_baton,
propchange = apr_array_push(db->propchanges);
propchange->name = apr_pstrdup(db->pool, name);
- propchange->value = value ? svn_string_dup(value, db->pool) : NULL;
+ propchange->value = svn_string_dup(value, db->pool);
if (!db->edited && svn_property_kind2(name) == svn_prop_regular_kind)
SVN_ERR(mark_directory_edited(db, pool));
@@ -2619,7 +2498,7 @@ close_directory(void *dir_baton,
hi != NULL;
hi = apr_hash_next(hi))
{
- const char *propname = svn__apr_hash_index_key(hi);
+ const char *propname = apr_hash_this_key(hi);
svn_prop_t *prop = apr_array_push(regular_prop_changes);
/* Record a deletion for PROPNAME. */
@@ -2702,7 +2581,8 @@ close_directory(void *dir_baton,
/* Check if we should add some not-present markers before marking the
directory complete (Issue #3569) */
{
- apr_hash_t *new_children = svn_hash_gets(eb->dir_dirents, db->new_relpath);
+ apr_hash_t *new_children = svn_hash_gets(eb->dir_dirents,
+ db->new_repos_relpath);
if (new_children != NULL)
{
@@ -2723,11 +2603,11 @@ close_directory(void *dir_baton,
svn_pool_clear(iterpool);
- child_name = svn__apr_hash_index_key(hi);
+ child_name = apr_hash_this_key(hi);
child_abspath = svn_dirent_join(db->local_abspath, child_name,
iterpool);
- dirent = svn__apr_hash_index_val(hi);
+ dirent = apr_hash_this_val(hi);
child_kind = (dirent->kind == svn_node_dir)
? svn_node_dir
: svn_node_file;
@@ -2758,7 +2638,7 @@ close_directory(void *dir_baton,
svn_error_clear(err);
- child_relpath = svn_relpath_join(db->new_relpath, child_name,
+ child_relpath = svn_relpath_join(db->new_repos_relpath, child_name,
iterpool);
SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db,
@@ -2776,7 +2656,7 @@ close_directory(void *dir_baton,
}
}
- if (apr_hash_count(db->not_present_files))
+ if (apr_hash_count(db->not_present_nodes))
{
apr_hash_index_t *hi;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
@@ -2786,17 +2666,18 @@ close_directory(void *dir_baton,
transaction, but I can't even trigger it. I've tried
ra_local, ra_svn, ra_neon, ra_serf and they all call
close_file before close_dir. */
- for (hi = apr_hash_first(scratch_pool, db->not_present_files);
+ for (hi = apr_hash_first(scratch_pool, db->not_present_nodes);
hi;
hi = apr_hash_next(hi))
{
- const char *child = svn__apr_hash_index_key(hi);
+ const char *child = apr_hash_this_key(hi);
const char *child_abspath, *child_relpath;
+ svn_node_kind_t kind = svn_node_kind_from_word(apr_hash_this_val(hi));
svn_pool_clear(iterpool);
child_abspath = svn_dirent_join(db->local_abspath, child, iterpool);
- child_relpath = svn_dirent_join(db->new_relpath, child, iterpool);
+ child_relpath = svn_dirent_join(db->new_repos_relpath, child, iterpool);
SVN_ERR(svn_wc__db_base_add_not_present_node(eb->db,
child_abspath,
@@ -2804,7 +2685,7 @@ close_directory(void *dir_baton,
eb->repos_root,
eb->repos_uuid,
*eb->target_revision,
- svn_node_file,
+ kind,
NULL, NULL,
iterpool));
}
@@ -2872,8 +2753,14 @@ close_directory(void *dir_baton,
db->local_abspath,
db->old_repos_relpath,
db->old_revision,
- db->new_relpath,
+ db->new_repos_relpath,
svn_node_dir, svn_node_dir,
+ (db->parent_baton
+ && db->parent_baton->deletion_conflicts)
+ ? svn_hash_gets(
+ db->parent_baton->deletion_conflicts,
+ db->name)
+ : NULL,
db->pool, scratch_pool));
SVN_ERR(svn_wc__conflict_create_markers(&work_item,
@@ -2904,7 +2791,7 @@ close_directory(void *dir_baton,
SVN_ERR(svn_wc__db_base_add_directory(
eb->db, db->local_abspath,
eb->wcroot_abspath,
- db->new_relpath,
+ db->new_repos_relpath,
eb->repos_root, eb->repos_uuid,
*eb->target_revision,
props,
@@ -2914,10 +2801,9 @@ close_directory(void *dir_baton,
(dav_prop_changes->nelts > 0)
? svn_prop_array_to_hash(dav_prop_changes, pool)
: NULL,
- conflict_skel,
(! db->shadowed) && new_base_props != NULL,
- new_actual_props,
- iprops, all_work_items,
+ new_actual_props, iprops,
+ conflict_skel, all_work_items,
scratch_pool));
}
@@ -2926,8 +2812,12 @@ close_directory(void *dir_baton,
eb->cancel_func, eb->cancel_baton,
scratch_pool));
+ if (db->parent_baton)
+ svn_hash_sets(db->parent_baton->not_present_nodes, db->name, NULL);
+
if (conflict_skel && eb->conflict_func)
SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, db->local_abspath,
+ svn_node_dir,
conflict_skel,
NULL /* merge_options */,
eb->conflict_func,
@@ -2962,6 +2852,9 @@ close_directory(void *dir_baton,
eb->notify_func(eb->notify_baton, notify, scratch_pool);
}
+ if (db->edited)
+ eb->edited = db->edited;
+
/* We're done with this directory, so remove one reference from the
bump information. */
SVN_ERR(maybe_release_dir_info(db));
@@ -2985,6 +2878,7 @@ absent_node(const char *path,
svn_error_t *err;
svn_wc__db_status_t status;
svn_node_kind_t kind;
+ svn_skel_t *tree_conflict = NULL;
if (pb->skip_this)
return SVN_NO_ERROR;
@@ -3073,24 +2967,26 @@ absent_node(const char *path,
{
/* We have a local addition. If this would be a BASE node it would have
been deleted before we get here. (Which might have turned it into
- a copy).
-
- ### This should be recorded as a tree conflict and the update
- ### can just continue, as we can just record the absent status
- ### in BASE.
- */
+ a copy). */
SVN_ERR_ASSERT(status != svn_wc__db_status_normal);
- return svn_error_createf(
- SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
- _("Failed to mark '%s' absent: item of the same name is already "
- "scheduled for addition"),
- svn_dirent_local_style(local_abspath, pool));
+ if (!pb->shadowed && !pb->edit_obstructed)
+ SVN_ERR(check_tree_conflict(&tree_conflict, eb, local_abspath,
+ status, FALSE, svn_node_unknown,
+ svn_wc_conflict_action_add,
+ scratch_pool, scratch_pool));
+
}
{
const char *repos_relpath;
- repos_relpath = svn_relpath_join(pb->new_relpath, name, scratch_pool);
+ repos_relpath = svn_relpath_join(pb->new_repos_relpath, name, scratch_pool);
+
+ if (tree_conflict)
+ SVN_ERR(complete_conflict(tree_conflict, eb, local_abspath,
+ NULL, SVN_INVALID_REVNUM, repos_relpath,
+ kind, svn_node_unknown, NULL,
+ scratch_pool, scratch_pool));
/* Insert an excluded node below the parent node to note that this child
is absent. (This puts it in the parent db if the child is obstructed) */
@@ -3100,8 +2996,24 @@ absent_node(const char *path,
*(eb->target_revision),
absent_kind,
svn_wc__db_status_server_excluded,
- NULL, NULL,
+ tree_conflict, NULL,
scratch_pool));
+
+ if (tree_conflict)
+ {
+ if (eb->conflict_func)
+ SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, local_abspath,
+ kind,
+ tree_conflict,
+ NULL /* merge_options */,
+ eb->conflict_func,
+ eb->conflict_baton,
+ eb->cancel_func,
+ eb->cancel_baton,
+ scratch_pool));
+ do_notification(eb, local_abspath, kind, svn_wc_notify_tree_conflict,
+ scratch_pool);
+ }
}
svn_pool_destroy(scratch_pool);
@@ -3142,13 +3054,13 @@ add_file(const char *path,
struct dir_baton *pb = parent_baton;
struct edit_baton *eb = pb->edit_baton;
struct file_baton *fb;
- svn_node_kind_t kind = svn_node_none;
- svn_node_kind_t wc_kind = svn_node_unknown;
- svn_wc__db_status_t status = svn_wc__db_status_normal;
+ svn_node_kind_t kind;
+ svn_node_kind_t wc_kind;
+ svn_wc__db_status_t status;
apr_pool_t *scratch_pool;
- svn_boolean_t conflicted = FALSE;
+ svn_boolean_t conflicted;
svn_boolean_t conflict_ignored = FALSE;
- svn_boolean_t versioned_locally_and_present = FALSE;
+ svn_boolean_t versioned_locally_and_present;
svn_skel_t *tree_conflict = NULL;
svn_error_t *err = SVN_NO_ERROR;
@@ -3160,6 +3072,8 @@ add_file(const char *path,
if (fb->skip_this)
return SVN_NO_ERROR;
+ SVN_ERR(calculate_repos_relpath(&fb->new_repos_relpath, fb->local_abspath,
+ NULL, eb, pb, fb->pool, pool));
SVN_ERR(mark_file_edited(fb, pool));
/* The file_pool can stick around for a *long* time, so we want to
@@ -3186,6 +3100,13 @@ add_file(const char *path,
eb->db, fb->local_abspath,
scratch_pool, scratch_pool);
}
+ else
+ {
+ kind = svn_node_none;
+ status = svn_wc__db_status_not_present;
+ wc_kind = svn_node_unknown;
+ conflicted = FALSE;
+ }
if (err)
{
@@ -3198,58 +3119,68 @@ add_file(const char *path,
versioned_locally_and_present = FALSE;
}
- else if (wc_kind == svn_node_dir
- && status == svn_wc__db_status_normal)
+ else if (status == svn_wc__db_status_normal && wc_kind == svn_node_unknown)
+ {
+ SVN_ERR_ASSERT(conflicted);
+ versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
+ }
+ else if (status == svn_wc__db_status_normal
+ || status == svn_wc__db_status_incomplete)
{
- /* !! We found the root of a separate working copy obstructing the wc !!
+ svn_boolean_t root;
- If the directory would be part of our own working copy then
- we wouldn't have been called as an add_file().
+ SVN_ERR(svn_wc__db_is_wcroot(&root, eb->db, fb->local_abspath,
+ scratch_pool));
- The only thing we can do is add a not-present node, to allow
- a future update to bring in the new files when the problem is
- resolved. */
- svn_hash_sets(pb->not_present_files, apr_pstrdup(pb->pool, fb->name),
- (void *)1);
+ if (root)
+ {
+ /* !! We found the root of a working copy obstructing the wc !!
- SVN_ERR(remember_skipped_tree(eb, fb->local_abspath, pool));
- fb->skip_this = TRUE;
- fb->already_notified = TRUE;
+ If the directory would be part of our own working copy then
+ we wouldn't have been called as an add_directory().
- do_notification(eb, fb->local_abspath, svn_node_file,
- svn_wc_notify_update_skip_obstruction, scratch_pool);
+ The only thing we can do is add a not-present node, to allow
+ a future update to bring in the new files when the problem is
+ resolved. Note that svn_wc__db_base_add_not_present_node()
+ explicitly adds the node into the parent's node database. */
- svn_pool_destroy(scratch_pool);
+ svn_hash_sets(pb->not_present_nodes,
+ apr_pstrdup(pb->pool, fb->name),
+ svn_node_kind_to_word(svn_node_dir));
+ }
+ else if (wc_kind == svn_node_dir)
+ {
+ /* We have an editor violation. Github sometimes does this
+ in its subversion compatibility code, when changing the
+ depth of a working copy, or on updates from incomplete */
+ }
+ else
+ {
+ /* We found a file external occupating the place we need in BASE.
- return SVN_NO_ERROR;
- }
- else if (status == svn_wc__db_status_normal
- && (wc_kind == svn_node_file
- || wc_kind == svn_node_symlink))
- {
- /* We found a file external occupating the place we need in BASE.
+ We can't add a not-present node in this case as that would overwrite
+ the file external. Luckily the file external itself stops us from
+ forgetting a child of this parent directory like an obstructing
+ working copy would.
- We can't add a not-present node in this case as that would overwrite
- the file external. Luckily the file external itself stops us from
- forgetting a child of this parent directory like an obstructing
- working copy would.
+ The reason we get here is that the adm crawler doesn't report
+ file externals.
+ */
+ SVN_ERR_ASSERT(wc_kind == svn_node_file
+ || wc_kind == svn_node_symlink);
+ }
- The reason we get here is that the adm crawler doesn't report
- file externals.
- */
SVN_ERR(remember_skipped_tree(eb, fb->local_abspath, pool));
fb->skip_this = TRUE;
fb->already_notified = TRUE;
- do_notification(eb, fb->local_abspath, svn_node_file,
+ do_notification(eb, fb->local_abspath, wc_kind,
svn_wc_notify_update_skip_obstruction, scratch_pool);
svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
- else if (wc_kind == svn_node_unknown)
- versioned_locally_and_present = FALSE; /* Tree conflict ACTUAL-only node */
else
versioned_locally_and_present = IS_NODE_PRESENT(status);
@@ -3274,7 +3205,7 @@ add_file(const char *path,
eb->db,
fb->local_abspath,
tree_conflict,
- fb->pool, fb->pool));
+ fb->pool, scratch_pool));
tree_conflict = svn_wc__conflict_skel_create(fb->pool);
@@ -3283,7 +3214,7 @@ add_file(const char *path,
eb->db, fb->local_abspath,
reason, svn_wc_conflict_action_replace,
move_src_op_root_abspath,
- fb->pool, fb->pool));
+ fb->pool, scratch_pool));
/* And now stop checking for conflicts here and just perform
a shadowed update */
@@ -3316,10 +3247,10 @@ add_file(const char *path,
Note that we can safely assume that no present base node exists,
because then we would not have received an add_file.
*/
- svn_hash_sets(pb->not_present_files, apr_pstrdup(pb->pool, fb->name),
- (void *)1);
+ svn_hash_sets(pb->not_present_nodes, apr_pstrdup(pb->pool, fb->name),
+ svn_node_kind_to_word(svn_node_file));
- do_notification(eb, fb->local_abspath, svn_node_unknown,
+ do_notification(eb, fb->local_abspath, svn_node_file,
svn_wc_notify_skip_conflicted, scratch_pool);
svn_pool_destroy(scratch_pool);
@@ -3380,7 +3311,7 @@ add_file(const char *path,
fb->local_abspath,
status, FALSE, svn_node_none,
svn_wc_conflict_action_add,
- scratch_pool, scratch_pool));
+ fb->pool, scratch_pool));
}
if (tree_conflict == NULL)
@@ -3421,8 +3352,8 @@ add_file(const char *path,
|| *eb->target_basename == '\0'
|| (strcmp(fb->local_abspath, eb->target_abspath) != 0))
{
- svn_hash_sets(pb->not_present_files, apr_pstrdup(pb->pool, fb->name),
- (void *)1);
+ svn_hash_sets(pb->not_present_nodes, apr_pstrdup(pb->pool, fb->name),
+ svn_node_kind_to_word(svn_node_file));
}
if (tree_conflict != NULL)
@@ -3432,9 +3363,12 @@ add_file(const char *path,
fb->local_abspath,
fb->old_repos_relpath,
fb->old_revision,
- fb->new_relpath,
- wc_kind,
- svn_node_file,
+ fb->new_repos_relpath,
+ wc_kind, svn_node_file,
+ pb->deletion_conflicts
+ ? svn_hash_gets(pb->deletion_conflicts,
+ fb->name)
+ : NULL,
fb->pool, scratch_pool));
SVN_ERR(svn_wc__db_op_mark_conflict(eb->db,
@@ -3442,15 +3376,7 @@ add_file(const char *path,
tree_conflict, NULL,
scratch_pool));
- if (eb->conflict_func)
- SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, fb->local_abspath,
- tree_conflict,
- NULL /* merge_options */,
- eb->conflict_func,
- eb->conflict_baton,
- eb->cancel_func,
- eb->cancel_baton,
- scratch_pool));
+ fb->edit_conflict = tree_conflict;
fb->already_notified = TRUE;
do_notification(eb, fb->local_abspath, svn_node_file,
@@ -3514,7 +3440,6 @@ open_file(const char *path,
/* Sanity check. */
- /* If replacing, make sure the .svn entry already exists. */
SVN_ERR(svn_wc__db_read_info(&status, &wc_kind, &fb->old_revision,
&fb->old_repos_relpath, NULL, NULL,
&fb->changed_rev, &fb->changed_date,
@@ -3536,6 +3461,10 @@ open_file(const char *path,
eb->db, fb->local_abspath,
fb->pool, scratch_pool));
+ SVN_ERR(calculate_repos_relpath(&fb->new_repos_relpath, fb->local_abspath,
+ fb->old_repos_relpath, eb, pb,
+ fb->pool, scratch_pool));
+
/* Is this path a conflict victim? */
if (fb->shadowed)
conflicted = FALSE; /* Conflict applies to WORKING */
@@ -3615,12 +3544,6 @@ lazy_open_source(svn_stream_t **stream,
return SVN_NO_ERROR;
}
-struct lazy_target_baton {
- struct file_baton *fb;
- struct handler_baton *hb;
- struct edit_baton *eb;
-};
-
/* Implements svn_stream_lazyopen_func_t. */
static svn_error_t *
lazy_open_target(svn_stream_t **stream,
@@ -3628,13 +3551,23 @@ lazy_open_target(svn_stream_t **stream,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- struct lazy_target_baton *tb = baton;
-
- SVN_ERR(svn_wc__open_writable_base(stream, &tb->hb->new_text_base_tmp_abspath,
- NULL, &tb->hb->new_text_base_sha1_checksum,
- tb->fb->edit_baton->db,
- tb->eb->wcroot_abspath,
- result_pool, scratch_pool));
+ struct handler_baton *hb = baton;
+ svn_wc__db_install_data_t *install_data;
+
+ /* By convention return value is undefined on error, but we rely
+ on HB->INSTALL_DATA value in window_handler() and abort
+ INSTALL_STREAM if is not NULL on error.
+ So we store INSTALL_DATA to local variable first, to leave
+ HB->INSTALL_DATA unchanged on error. */
+ SVN_ERR(svn_wc__db_pristine_prepare_install(stream,
+ &install_data,
+ &hb->new_text_base_sha1_checksum,
+ NULL,
+ hb->fb->edit_baton->db,
+ hb->fb->dir_baton->local_abspath,
+ result_pool, scratch_pool));
+
+ hb->install_data = install_data;
return SVN_NO_ERROR;
}
@@ -3654,7 +3587,6 @@ apply_textdelta(void *file_baton,
const svn_checksum_t *recorded_base_checksum;
svn_checksum_t *expected_base_checksum;
svn_stream_t *source;
- struct lazy_target_baton *tb;
svn_stream_t *target;
if (fb->skip_this)
@@ -3748,16 +3680,12 @@ apply_textdelta(void *file_baton,
hb->source_checksum_stream = source;
}
- tb = apr_palloc(handler_pool, sizeof(struct lazy_target_baton));
- tb->hb = hb;
- tb->fb = fb;
- tb->eb = eb;
- target = svn_stream_lazyopen_create(lazy_open_target, tb, TRUE, handler_pool);
+ target = svn_stream_lazyopen_create(lazy_open_target, hb, TRUE, handler_pool);
/* Prepare to apply the delta. */
svn_txdelta_apply(source, target,
hb->new_text_base_md5_digest,
- hb->new_text_base_tmp_abspath /* error_info */,
+ fb->local_abspath /* error_info */,
handler_pool,
&hb->apply_handler, &hb->apply_baton);
@@ -3788,7 +3716,7 @@ change_file_prop(void *file_baton,
/* Push a new propchange to the file baton's array of propchanges */
propchange = apr_array_push(fb->propchanges);
propchange->name = apr_pstrdup(fb->pool, name);
- propchange->value = value ? svn_string_dup(value, fb->pool) : NULL;
+ propchange->value = svn_string_dup(value, fb->pool);
if (!fb->edited && svn_property_kind2(name) == svn_prop_regular_kind)
SVN_ERR(mark_file_edited(fb, scratch_pool));
@@ -3851,9 +3779,9 @@ change_file_prop(void *file_baton,
SVN_ERR(complete_conflict(fb->edit_conflict, fb->edit_baton,
fb->local_abspath, fb->old_repos_relpath,
- fb->old_revision, fb->new_relpath,
+ fb->old_revision, fb->new_repos_relpath,
svn_node_file, svn_node_file,
- fb->pool, scratch_pool));
+ NULL, fb->pool, scratch_pool));
/* Create a copy of the existing (pre update) BASE node in WORKING,
mark a tree conflict and handle the rest of the update as
@@ -3913,13 +3841,13 @@ svn_wc__perform_file_merge(svn_skel_t **work_items,
const char *merge_left;
svn_boolean_t delete_left = FALSE;
const char *path_ext = "";
- const char *new_text_base_tmp_abspath;
+ const char *new_pristine_abspath;
enum svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_unchanged;
svn_skel_t *work_item;
*work_items = NULL;
- SVN_ERR(svn_wc__db_pristine_get_path(&new_text_base_tmp_abspath,
+ SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath,
db, wri_abspath, new_checksum,
scratch_pool, scratch_pool));
@@ -3972,7 +3900,7 @@ svn_wc__perform_file_merge(svn_skel_t **work_items,
&merge_outcome,
db,
merge_left,
- new_text_base_tmp_abspath,
+ new_pristine_abspath,
local_abspath,
wri_abspath,
oldrev_str, newrev_str, mine_str,
@@ -4321,11 +4249,11 @@ close_file(void *file_baton,
{
/* 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)
+ if (! eb->switch_repos_relpath
+ || strcmp(fb->new_repos_relpath, fb->old_repos_relpath) == 0)
{
SVN_ERR_ASSERT(prop->value == NULL);
- SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath,
+ SVN_ERR(svn_wc__db_lock_remove(eb->db, fb->local_abspath, NULL,
scratch_pool));
lock_state = svn_wc_notify_lock_state_unlocked;
@@ -4564,8 +4492,13 @@ close_file(void *file_baton,
fb->local_abspath,
fb->old_repos_relpath,
fb->old_revision,
- fb->new_relpath,
+ fb->new_repos_relpath,
svn_node_file, svn_node_file,
+ fb->dir_baton->deletion_conflicts
+ ? svn_hash_gets(
+ fb->dir_baton->deletion_conflicts,
+ fb->name)
+ : NULL,
fb->pool, scratch_pool));
SVN_ERR(svn_wc__conflict_create_markers(&work_item,
@@ -4593,7 +4526,7 @@ close_file(void *file_baton,
SVN_ERR(svn_wc__db_base_add_file(eb->db, fb->local_abspath,
eb->wcroot_abspath,
- fb->new_relpath,
+ fb->new_repos_relpath,
eb->repos_root, eb->repos_uuid,
*eb->target_revision,
new_base_props,
@@ -4618,6 +4551,7 @@ close_file(void *file_baton,
if (conflict_skel && eb->conflict_func)
SVN_ERR(svn_wc__conflict_invoke_resolver(eb->db, fb->local_abspath,
+ svn_node_file,
conflict_skel,
NULL /* merge_options */,
eb->conflict_func,
@@ -4628,7 +4562,7 @@ close_file(void *file_baton,
/* Deal with the WORKING tree, based on updates to the BASE tree. */
- svn_hash_sets(fb->dir_baton->not_present_files, fb->name, NULL);
+ svn_hash_sets(fb->dir_baton->not_present_nodes, fb->name, NULL);
/* Send a notification to the callback function. (Skip notifications
about files which were already notified for another reason.) */
@@ -4687,6 +4621,78 @@ close_file(void *file_baton,
}
+/* Implements svn_wc__proplist_receiver_t.
+ * Check for the presence of an svn:keywords property and queues an install_file
+ * work queue item if present. Thus, when the work queue is run to complete the
+ * switch operation, all files with keywords will go through the translation
+ * process so URLs etc are updated. */
+static svn_error_t *
+update_keywords_after_switch_cb(void *baton,
+ const char *local_abspath,
+ apr_hash_t *props,
+ apr_pool_t *scratch_pool)
+{
+ struct edit_baton *eb = baton;
+ svn_string_t *propval;
+ svn_boolean_t modified;
+ svn_boolean_t record_fileinfo;
+ svn_skel_t *work_items;
+ const char *install_from;
+
+ propval = svn_hash_gets(props, SVN_PROP_KEYWORDS);
+ if (!propval)
+ return SVN_NO_ERROR;
+
+ SVN_ERR(svn_wc__internal_file_modified_p(&modified, eb->db,
+ local_abspath, FALSE,
+ scratch_pool));
+ if (modified)
+ {
+ const char *temp_dir_abspath;
+ svn_stream_t *working_stream;
+ svn_stream_t *install_from_stream;
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath, eb->db,
+ local_abspath, scratch_pool,
+ scratch_pool));
+ SVN_ERR(svn_stream_open_readonly(&working_stream, local_abspath,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_open_unique(&install_from_stream, &install_from,
+ temp_dir_abspath, svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_stream_copy3(working_stream, install_from_stream,
+ eb->cancel_func, eb->cancel_baton,
+ scratch_pool));
+ record_fileinfo = FALSE;
+ }
+ else
+ {
+ install_from = NULL;
+ record_fileinfo = TRUE;
+ }
+
+ SVN_ERR(svn_wc__wq_build_file_install(&work_items, eb->db, local_abspath,
+ install_from,
+ eb->use_commit_times,
+ record_fileinfo,
+ scratch_pool, scratch_pool));
+ if (install_from)
+ {
+ svn_skel_t *work_item;
+
+ SVN_ERR(svn_wc__wq_build_file_remove(&work_item, eb->db,
+ local_abspath, install_from,
+ scratch_pool, scratch_pool));
+ work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool);
+ }
+
+ SVN_ERR(svn_wc__db_wq_add(eb->db, local_abspath, work_items,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
+
/* An svn_delta_editor_t function. */
static svn_error_t *
close_edit(void *edit_baton,
@@ -4728,12 +4734,13 @@ close_edit(void *edit_baton,
SVN_ERR(svn_wc__db_op_bump_revisions_post_update(eb->db,
eb->target_abspath,
eb->requested_depth,
- eb->switch_relpath,
+ eb->switch_repos_relpath,
eb->repos_root,
eb->repos_uuid,
*(eb->target_revision),
eb->skipped_trees,
eb->wcroot_iprops,
+ ! eb->edited,
eb->notify_func,
eb->notify_baton,
eb->pool));
@@ -4773,15 +4780,36 @@ 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 /* keep_as_working */,
- FALSE /* queue_deletes */,
- FALSE /* remove_locks */,
+ TRUE, FALSE, FALSE,
SVN_INVALID_REVNUM,
NULL, NULL, scratch_pool));
}
}
}
+ /* Update keywords in switched files.
+ GOTO #1975 (the year of the Altair 8800). */
+ if (eb->switch_repos_relpath)
+ {
+ svn_depth_t depth;
+
+ if (eb->requested_depth > svn_depth_empty)
+ depth = eb->requested_depth;
+ else
+ depth = svn_depth_infinity;
+
+ SVN_ERR(svn_wc__db_read_props_streamily(eb->db,
+ eb->target_abspath,
+ depth,
+ FALSE, /* pristine */
+ NULL, /* changelists */
+ update_keywords_after_switch_cb,
+ eb,
+ eb->cancel_func,
+ eb->cancel_baton,
+ scratch_pool));
+ }
+
/* The edit is over: run the wq with proper cancel support,
but first kill the handler that would run it on the pool
cleanup at the end of this function. */
@@ -4854,9 +4882,11 @@ make_editor(svn_revnum_t *target_revision,
/* Get the anchor's repository root and uuid. The anchor must already exist
in BASE. */
- SVN_ERR(svn_wc__db_scan_base_repos(NULL, &repos_root, &repos_uuid,
- db, anchor_abspath,
- result_pool, scratch_pool));
+ SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, &repos_root,
+ &repos_uuid, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL,
+ db, anchor_abspath,
+ result_pool, scratch_pool));
/* With WC-NG we need a valid repository root */
SVN_ERR_ASSERT(repos_root != NULL && repos_uuid != NULL);
@@ -4884,10 +4914,10 @@ make_editor(svn_revnum_t *target_revision,
edit_pool, scratch_pool));
if (switch_url)
- eb->switch_relpath =
+ eb->switch_repos_relpath =
svn_uri_skip_ancestor(repos_root, switch_url, scratch_pool);
else
- eb->switch_relpath = NULL;
+ eb->switch_repos_relpath = NULL;
if (svn_path_is_empty(target_basename))
eb->target_abspath = eb->anchor_abspath;
@@ -4968,8 +4998,8 @@ make_editor(svn_revnum_t *target_revision,
apr_hash_t *dirents;
/* If we switch, we should look at the new relpath */
- if (eb->switch_relpath)
- dir_repos_relpath = eb->switch_relpath;
+ if (eb->switch_repos_relpath)
+ dir_repos_relpath = eb->switch_repos_relpath;
SVN_ERR(fetch_dirents_func(fetch_dirents_baton, &dirents,
repos_root, dir_repos_relpath,
@@ -5022,9 +5052,9 @@ make_editor(svn_revnum_t *target_revision,
apr_hash_t *dirents;
/* If we switch, we should look at the new relpath */
- if (eb->switch_relpath)
+ if (eb->switch_repos_relpath)
dir_repos_relpath = svn_relpath_join(
- eb->switch_relpath,
+ eb->switch_repos_relpath,
child_name, iterpool);
SVN_ERR(fetch_dirents_func(fetch_dirents_baton, &dirents,
@@ -5223,6 +5253,8 @@ svn_wc_add_repos_file4(svn_wc_context_t *wc_ctx,
svn_revnum_t changed_rev;
apr_time_t changed_date;
const char *changed_author;
+ svn_stream_t *tmp_base_contents;
+ svn_wc__db_install_data_t *install_data;
svn_error_t *err;
apr_pool_t *pool = scratch_pool;
@@ -5344,18 +5376,35 @@ svn_wc_add_repos_file4(svn_wc_context_t *wc_ctx,
/* Copy NEW_BASE_CONTENTS into a temporary file so our log can refer to
it, and set TMP_TEXT_BASE_ABSPATH to its path. Compute its
NEW_TEXT_BASE_MD5_CHECKSUM and NEW_TEXT_BASE_SHA1_CHECKSUM as we copy. */
- {
- svn_stream_t *tmp_base_contents;
+ if (copyfrom_url)
+ {
+ SVN_ERR(svn_wc__db_pristine_prepare_install(&tmp_base_contents,
+ &install_data,
+ &new_text_base_sha1_checksum,
+ &new_text_base_md5_checksum,
+ wc_ctx->db, local_abspath,
+ scratch_pool, scratch_pool));
+ }
+ else
+ {
+ const char *tmp_dir_abspath;
- SVN_ERR(svn_wc__open_writable_base(&tmp_base_contents,
- &tmp_text_base_abspath,
- &new_text_base_md5_checksum,
- &new_text_base_sha1_checksum,
- wc_ctx->db, local_abspath,
- pool, pool));
- SVN_ERR(svn_stream_copy3(new_base_contents, tmp_base_contents,
- cancel_func, cancel_baton, pool));
- }
+ /* We are not installing a PRISTINE file, but we use the same code to
+ create whatever we want to install */
+
+ SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir_abspath,
+ db, dir_abspath,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_stream_open_unique(&tmp_base_contents, &tmp_text_base_abspath,
+ tmp_dir_abspath, svn_io_file_del_none,
+ scratch_pool, scratch_pool));
+
+ new_text_base_sha1_checksum = NULL;
+ new_text_base_md5_checksum = NULL;
+ }
+ SVN_ERR(svn_stream_copy3(new_base_contents, tmp_base_contents,
+ cancel_func, cancel_baton, pool));
/* If the caller gave us a new working file, copy it to a safe (temporary)
location and set SOURCE_ABSPATH to that path. We'll then translate/copy
@@ -5378,7 +5427,7 @@ svn_wc_add_repos_file4(svn_wc_context_t *wc_ctx,
text base. */
if (copyfrom_url != NULL)
{
- SVN_ERR(svn_wc__db_pristine_install(db, tmp_text_base_abspath,
+ SVN_ERR(svn_wc__db_pristine_install(install_data,
new_text_base_sha1_checksum,
new_text_base_md5_checksum, pool));
}
@@ -5445,9 +5494,6 @@ svn_wc_add_repos_file4(svn_wc_context_t *wc_ctx,
}
}
- /* ### ideally, we would have a single DB operation, and queue the work
- ### items on that. for now, we'll queue them with the second call. */
-
SVN_ERR(svn_wc__db_op_copy_file(db, local_abspath,
new_base_props,
changed_rev,
diff --git a/subversion/libsvn_wc/upgrade.c b/subversion/libsvn_wc/upgrade.c
index af615fd61ba2..aebf4eb1eb88 100644
--- a/subversion/libsvn_wc/upgrade.c
+++ b/subversion/libsvn_wc/upgrade.c
@@ -37,6 +37,7 @@
#include "tree_conflicts.h"
#include "wc-queries.h" /* for STMT_* */
#include "workqueue.h"
+#include "token-map.h"
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
@@ -193,7 +194,7 @@ read_many_wcprops(apr_hash_t **all_wcprops,
hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
+ const char *name = apr_hash_this_key(hi);
svn_pool_clear(iterpool);
@@ -293,15 +294,15 @@ get_versioned_subdirs(apr_array_header_t **children,
hi;
hi = apr_hash_next(hi))
{
- const char *name = svn__apr_hash_index_key(hi);
- const svn_wc_entry_t *entry = svn__apr_hash_index_val(hi);
+ const char *name = apr_hash_this_key(hi);
+ const svn_wc_entry_t *entry = apr_hash_this_val(hi);
const char *child_abspath;
svn_boolean_t hidden;
/* skip "this dir" */
if (*name == '\0')
{
- this_dir = svn__apr_hash_index_val(hi);
+ this_dir = apr_hash_this_val(hi);
continue;
}
else if (entry->kind != svn_node_dir)
@@ -400,7 +401,7 @@ build_lockfile_path(const char *local_dir_abspath,
local_dir_abspath,
svn_wc_get_adm_dir(result_pool),
ADM_LOCK,
- NULL);
+ SVN_VA_NULL);
}
@@ -612,13 +613,13 @@ 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_ancestor(svn__apr_hash_index_key(hi), entry->url))
+ if (svn_uri__is_ancestor(apr_hash_this_key(hi), entry->url))
{
if (!entry->repos)
- entry->repos = svn__apr_hash_index_key(hi);
+ entry->repos = apr_hash_this_key(hi);
if (!entry->uuid)
- entry->uuid = svn__apr_hash_index_val(hi);
+ entry->uuid = apr_hash_this_val(hi);
return SVN_NO_ERROR;
}
@@ -727,8 +728,7 @@ migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
hi;
hi = apr_hash_next(hi))
{
- const svn_wc_conflict_description2_t *conflict =
- svn__apr_hash_index_val(hi);
+ const svn_wc_conflict_description2_t *conflict = apr_hash_this_val(hi);
const char *conflict_relpath;
const char *conflict_data;
svn_sqlite__stmt_t *stmt;
@@ -755,13 +755,13 @@ migrate_single_tree_conflict_data(svn_sqlite__db_t *sdb,
{
/* There is an existing ACTUAL row, so just update it. */
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
- STMT_UPDATE_ACTUAL_CONFLICT_DATA));
+ STMT_UPDATE_ACTUAL_CONFLICT));
}
else
{
/* We need to insert an ACTUAL row with the tree conflict data. */
SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
- STMT_INSERT_ACTUAL_CONFLICT_DATA));
+ STMT_INSERT_ACTUAL_CONFLICT));
}
SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,
@@ -825,6 +825,190 @@ migrate_tree_conflict_data(svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
return SVN_NO_ERROR;
}
+/* ### need much more docco
+
+ ### this function should be called within a sqlite transaction. it makes
+ ### assumptions around this fact.
+
+ Apply the various sets of properties to the database nodes based on
+ their existence/presence, the current state of the node, and the original
+ format of the working copy which provided these property sets.
+*/
+static svn_error_t *
+upgrade_apply_props(svn_sqlite__db_t *sdb,
+ const char *dir_abspath,
+ const char *local_relpath,
+ apr_hash_t *base_props,
+ apr_hash_t *revert_props,
+ apr_hash_t *working_props,
+ int original_format,
+ apr_int64_t wc_id,
+ apr_pool_t *scratch_pool)
+{
+ svn_sqlite__stmt_t *stmt;
+ svn_boolean_t have_row;
+ int top_op_depth = -1;
+ int below_op_depth = -1;
+ svn_wc__db_status_t top_presence;
+ svn_wc__db_status_t below_presence;
+ int affected_rows;
+
+ /* ### working_props: use set_props_txn.
+ ### if working_props == NULL, then skip. what if they equal the
+ ### pristine props? we should probably do the compare here.
+ ###
+ ### base props go into WORKING_NODE if avail, otherwise BASE.
+ ###
+ ### revert only goes into BASE. (and WORKING better be there!)
+
+ Prior to 1.4.0 (ORIGINAL_FORMAT < 8), REVERT_PROPS did not exist. If a
+ file was deleted, then a copy (potentially with props) was disallowed
+ and could not replace the deletion. An addition *could* be performed,
+ but that would never bring its own props.
+
+ 1.4.0 through 1.4.5 created the concept of REVERT_PROPS, but had a
+ bug in svn_wc_add_repos_file2() whereby a copy-with-props did NOT
+ construct a REVERT_PROPS if the target had no props. Thus, reverting
+ the delete/copy would see no REVERT_PROPS to restore, leaving the
+ props from the copy source intact, and appearing as if they are (now)
+ the base props for the previously-deleted file. (wc corruption)
+
+ 1.4.6 ensured that an empty REVERT_PROPS would be established at all
+ times. See issue 2530, and r861670 as starting points.
+
+ We will use ORIGINAL_FORMAT and SVN_WC__NO_REVERT_FILES to determine
+ the handling of our inputs, relative to the state of this node.
+ */
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODE_INFO));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ top_op_depth = svn_sqlite__column_int(stmt, 0);
+ top_presence = svn_sqlite__column_token(stmt, 3, presence_map);
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+ if (have_row)
+ {
+ below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
+
+ /* There might be an intermediate layer on mixed-revision copies,
+ or when BASE is shadowed */
+ if (below_presence == svn_wc__db_status_not_present
+ || below_presence == svn_wc__db_status_deleted)
+ SVN_ERR(svn_sqlite__step(&have_row, stmt));
+
+ if (have_row)
+ {
+ below_presence = svn_sqlite__column_token(stmt, 3, presence_map);
+ below_op_depth = svn_sqlite__column_int(stmt, 0);
+ }
+ }
+ }
+ SVN_ERR(svn_sqlite__reset(stmt));
+
+ /* Detect the buggy scenario described above. We cannot upgrade this
+ working copy if we have no idea where BASE_PROPS should go. */
+ if (original_format > SVN_WC__NO_REVERT_FILES
+ && revert_props == NULL
+ && top_op_depth != -1
+ && top_presence == svn_wc__db_status_normal
+ && below_op_depth != -1
+ && below_presence != svn_wc__db_status_not_present)
+ {
+ /* There should be REVERT_PROPS, so it appears that we just ran into
+ the described bug. Sigh. */
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ _("The properties of '%s' are in an "
+ "indeterminate state and cannot be "
+ "upgraded. See issue #2530."),
+ svn_dirent_local_style(
+ svn_dirent_join(dir_abspath, local_relpath,
+ scratch_pool), scratch_pool));
+ }
+
+ /* Need at least one row, or two rows if there are revert props */
+ if (top_op_depth == -1
+ || (below_op_depth == -1 && revert_props))
+ return svn_error_createf(SVN_ERR_WC_CORRUPT, NULL,
+ _("Insufficient NODES rows for '%s'"),
+ svn_dirent_local_style(
+ svn_dirent_join(dir_abspath, local_relpath,
+ scratch_pool), scratch_pool));
+
+ /* one row, base props only: upper row gets base props
+ two rows, base props only: lower row gets base props
+ two rows, revert props only: lower row gets revert props
+ two rows, base and revert props: upper row gets base, lower gets revert */
+
+
+ if (revert_props || below_op_depth == -1)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_UPDATE_NODE_PROPS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd",
+ wc_id, local_relpath, top_op_depth));
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 4, base_props, scratch_pool));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ SVN_ERR_ASSERT(affected_rows == 1);
+ }
+
+ if (below_op_depth != -1)
+ {
+ apr_hash_t *props = revert_props ? revert_props : base_props;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_UPDATE_NODE_PROPS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "isd",
+ wc_id, local_relpath, below_op_depth));
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 4, props, scratch_pool));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ SVN_ERR_ASSERT(affected_rows == 1);
+ }
+
+ /* If there are WORKING_PROPS, then they always go into ACTUAL_NODE. */
+ if (working_props != NULL
+ && base_props != NULL)
+ {
+ apr_array_header_t *diffs;
+
+ SVN_ERR(svn_prop_diffs(&diffs, working_props, base_props, scratch_pool));
+
+ if (diffs->nelts == 0)
+ working_props = NULL; /* No differences */
+ }
+
+ if (working_props != NULL)
+ {
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_UPDATE_ACTUAL_PROPS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 3, working_props,
+ scratch_pool));
+ SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+ if (affected_rows == 0)
+ {
+ /* We have to insert a row in ACTUAL */
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_INSERT_ACTUAL_PROPS));
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+ if (*local_relpath != '\0')
+ SVN_ERR(svn_sqlite__bind_text(stmt, 3,
+ svn_relpath_dirname(local_relpath,
+ scratch_pool)));
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 4, working_props,
+ scratch_pool));
+ return svn_error_trace(svn_sqlite__step_done(stmt));
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
struct bump_baton {
const char *wcroot_abspath;
@@ -875,21 +1059,21 @@ migrate_node_props(const char *dir_abspath,
apr_pstrcat(scratch_pool,
name,
SVN_WC__BASE_EXT,
- (char *)NULL),
+ SVN_VA_NULL),
scratch_pool);
revert_abspath = svn_dirent_join(basedir_abspath,
apr_pstrcat(scratch_pool,
name,
SVN_WC__REVERT_EXT,
- (char *)NULL),
+ SVN_VA_NULL),
scratch_pool);
working_abspath = svn_dirent_join(propsdir_abspath,
apr_pstrcat(scratch_pool,
name,
SVN_WC__WORK_EXT,
- (char *)NULL),
+ SVN_VA_NULL),
scratch_pool);
}
@@ -900,7 +1084,7 @@ migrate_node_props(const char *dir_abspath,
SVN_ERR(read_propfile(&working_props, working_abspath,
scratch_pool, scratch_pool));
- return svn_error_trace(svn_wc__db_upgrade_apply_props(
+ return svn_error_trace(upgrade_apply_props(
sdb, new_wcroot_abspath,
svn_relpath_join(dir_relpath, name, scratch_pool),
base_props, revert_props, working_props,
@@ -1017,7 +1201,7 @@ migrate_text_bases(apr_hash_t **text_bases_info,
for (hi = apr_hash_first(scratch_pool, dirents); hi;
hi = apr_hash_next(hi))
{
- const char *text_base_basename = svn__apr_hash_index_key(hi);
+ const char *text_base_basename = apr_hash_this_key(hi);
svn_checksum_t *md5_checksum;
svn_checksum_t *sha1_checksum;
@@ -1248,7 +1432,7 @@ rename_pristine_file(void *baton,
== PRISTINE_BASENAME_OLD_LEN))
{
const char *new_abspath
- = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, (char *)NULL);
+ = apr_pstrcat(pool, abspath, PRISTINE_STORAGE_EXT, SVN_VA_NULL);
SVN_ERR(svn_io_file_rename(abspath, new_abspath, pool));
}
@@ -1349,7 +1533,8 @@ bump_to_29(void *baton, svn_sqlite__db_t *sdb, apr_pool_t *scratch_pool)
/* Rename all pristine files, adding a ".svn-base" suffix. */
pristine_dir_abspath = svn_dirent_join_many(scratch_pool, wcroot_abspath,
svn_wc_get_adm_dir(scratch_pool),
- PRISTINE_STORAGE_RELPATH, NULL);
+ PRISTINE_STORAGE_RELPATH,
+ SVN_VA_NULL);
SVN_ERR(svn_io_dir_walk2(pristine_dir_abspath, APR_FINFO_MIN,
rename_pristine_file, NULL, scratch_pool));
@@ -1671,6 +1856,43 @@ bump_to_31(void *baton,
return SVN_NO_ERROR;
}
+static svn_error_t *
+upgrade_apply_dav_cache(svn_sqlite__db_t *sdb,
+ const char *dir_relpath,
+ apr_int64_t wc_id,
+ apr_hash_t *cache_values,
+ apr_pool_t *scratch_pool)
+{
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_hash_index_t *hi;
+ svn_sqlite__stmt_t *stmt;
+
+ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
+ STMT_UPDATE_BASE_NODE_DAV_CACHE));
+
+ /* Iterate over all the wcprops, writing each one to the wc_db. */
+ for (hi = apr_hash_first(scratch_pool, cache_values);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const char *name = apr_hash_this_key(hi);
+ apr_hash_t *props = apr_hash_this_val(hi);
+ const char *local_relpath;
+
+ svn_pool_clear(iterpool);
+
+ local_relpath = svn_relpath_join(dir_relpath, name, iterpool);
+
+ SVN_ERR(svn_sqlite__bindf(stmt, "is", wc_id, local_relpath));
+ SVN_ERR(svn_sqlite__bind_properties(stmt, 3, props, iterpool));
+ SVN_ERR(svn_sqlite__step_done(stmt));
+ }
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
struct upgrade_data_t {
svn_sqlite__db_t *sdb;
@@ -1808,8 +2030,8 @@ upgrade_to_wcng(void **dir_baton,
SVN_ERR(read_wcprops(&all_wcprops, dir_abspath,
scratch_pool, scratch_pool));
- SVN_ERR(svn_wc__db_upgrade_apply_dav_cache(data->sdb, dir_relpath,
- all_wcprops, scratch_pool));
+ SVN_ERR(upgrade_apply_dav_cache(data->sdb, dir_relpath, wc_id,
+ all_wcprops, scratch_pool));
}
/* Upgrade all the properties (including "this dir").
@@ -2144,40 +2366,6 @@ is_old_wcroot(const char *local_abspath,
svn_dirent_local_style(parent_abspath, scratch_pool));
}
-/* Data for upgrade_working_copy_txn(). */
-typedef struct upgrade_working_copy_baton_t
-{
- svn_wc__db_t *db;
- const char *dir_abspath;
- svn_wc_upgrade_get_repos_info_t repos_info_func;
- void *repos_info_baton;
- apr_hash_t *repos_cache;
- const struct upgrade_data_t *data;
- svn_cancel_func_t cancel_func;
- void *cancel_baton;
- svn_wc_notify_func2_t notify_func;
- void *notify_baton;
- apr_pool_t *result_pool;
-} upgrade_working_copy_baton_t;
-
-
-/* Helper for svn_wc_upgrade. Implements svn_sqlite__transaction_callback_t */
-static svn_error_t *
-upgrade_working_copy_txn(void *baton,
- svn_sqlite__db_t *sdb,
- apr_pool_t *scratch_pool)
-{
- upgrade_working_copy_baton_t *b = baton;
-
- /* Upgrade the pre-wcng into a wcng in a temporary location. */
- return(upgrade_working_copy(NULL, b->db, b->dir_abspath,
- b->repos_info_func, b->repos_info_baton,
- b->repos_cache, b->data,
- b->cancel_func, b->cancel_baton,
- b->notify_func, b->notify_baton,
- b->result_pool, scratch_pool));
-}
-
svn_error_t *
svn_wc_upgrade(svn_wc_context_t *wc_ctx,
const char *local_abspath,
@@ -2197,7 +2385,6 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
svn_wc_entry_t *this_dir;
apr_hash_t *entries;
const char *root_adm_abspath;
- upgrade_working_copy_baton_t cb_baton;
svn_error_t *err;
int result_format;
svn_boolean_t bumped_format;
@@ -2295,22 +2482,14 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
SVN_ERR(svn_wc__db_wclock_obtain(db, data.root_abspath, 0, FALSE,
scratch_pool));
- cb_baton.db = db;
- cb_baton.dir_abspath = local_abspath;
- cb_baton.repos_info_func = repos_info_func;
- cb_baton.repos_info_baton = repos_info_baton;
- cb_baton.repos_cache = repos_cache;
- cb_baton.data = &data;
- cb_baton.cancel_func = cancel_func;
- cb_baton.cancel_baton = cancel_baton;
- cb_baton.notify_func = notify_func;
- cb_baton.notify_baton = notify_baton;
- cb_baton.result_pool = scratch_pool;
-
- SVN_ERR(svn_sqlite__with_lock(data.sdb,
- upgrade_working_copy_txn,
- &cb_baton,
- scratch_pool));
+ SVN_SQLITE__WITH_LOCK(
+ upgrade_working_copy(NULL, db, local_abspath,
+ repos_info_func, repos_info_baton,
+ repos_cache, &data,
+ cancel_func, cancel_baton,
+ notify_func, notify_baton,
+ scratch_pool, scratch_pool),
+ data.sdb);
/* A workqueue item to move the pristine dir into place */
pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH,
diff --git a/subversion/libsvn_wc/util.c b/subversion/libsvn_wc/util.c
index a527eda51b93..7bb2179ad1d4 100644
--- a/subversion/libsvn_wc/util.c
+++ b/subversion/libsvn_wc/util.c
@@ -248,9 +248,34 @@ svn_wc_conflict_description_create_tree2(
return conflict;
}
+svn_wc_conflict_version_t *
+svn_wc_conflict_version_create2(const char *repos_url,
+ const char *repos_uuid,
+ const char *repos_relpath,
+ svn_revnum_t revision,
+ svn_node_kind_t kind,
+ apr_pool_t *result_pool)
+{
+ svn_wc_conflict_version_t *version;
+
+ version = apr_pcalloc(result_pool, sizeof(*version));
+
+ SVN_ERR_ASSERT_NO_RETURN(svn_uri_is_canonical(repos_url, result_pool)
+ && svn_relpath_is_canonical(repos_relpath)
+ && SVN_IS_VALID_REVNUM(revision)
+ /* ### repos_uuid can be NULL :( */);
+
+ version->repos_url = repos_url;
+ version->peg_rev = revision;
+ version->path_in_repos = repos_relpath;
+ version->node_kind = kind;
+ version->repos_uuid = repos_uuid;
+
+ return version;
+}
svn_wc_conflict_description2_t *
-svn_wc__conflict_description2_dup(const svn_wc_conflict_description2_t *conflict,
+svn_wc_conflict_description2_dup(const svn_wc_conflict_description2_t *conflict,
apr_pool_t *pool)
{
svn_wc_conflict_description2_t *new_conflict;
@@ -281,36 +306,27 @@ svn_wc__conflict_description2_dup(const svn_wc_conflict_description2_t *conflict
new_conflict->src_right_version =
svn_wc_conflict_version_dup(conflict->src_right_version, pool);
- return new_conflict;
-}
+ /* ### For property conflicts, cd2 stores prop_reject_abspath in
+ * ### their_abspath, and stores theirs_abspath in merged_file. */
+ if (conflict->prop_reject_abspath)
+ new_conflict->prop_reject_abspath = new_conflict->their_abspath;
+
+ if (conflict->prop_value_base)
+ new_conflict->prop_value_base =
+ svn_string_dup(conflict->prop_value_base, pool);
+ if (conflict->prop_value_working)
+ new_conflict->prop_value_working =
+ svn_string_dup(conflict->prop_value_working, pool);
+ if (conflict->prop_value_incoming_old)
+ new_conflict->prop_value_incoming_old =
+ svn_string_dup(conflict->prop_value_incoming_old, pool);
+ if (conflict->prop_value_incoming_new)
+ new_conflict->prop_value_incoming_new =
+ svn_string_dup(conflict->prop_value_incoming_new, pool);
-svn_wc_conflict_version_t *
-svn_wc_conflict_version_create2(const char *repos_url,
- const char *repos_uuid,
- const char *repos_relpath,
- svn_revnum_t revision,
- svn_node_kind_t kind,
- apr_pool_t *result_pool)
-{
- svn_wc_conflict_version_t *version;
-
- version = apr_pcalloc(result_pool, sizeof(*version));
-
- SVN_ERR_ASSERT_NO_RETURN(svn_uri_is_canonical(repos_url, result_pool)
- && svn_relpath_is_canonical(repos_relpath)
- && SVN_IS_VALID_REVNUM(revision)
- /* ### repos_uuid can be NULL :( */);
-
- version->repos_url = repos_url;
- version->peg_rev = revision;
- version->path_in_repos = repos_relpath;
- version->node_kind = kind;
- version->repos_uuid = repos_uuid;
-
- return version;
+ return new_conflict;
}
-
svn_wc_conflict_version_t *
svn_wc_conflict_version_dup(const svn_wc_conflict_version_t *version,
apr_pool_t *result_pool)
@@ -339,7 +355,6 @@ svn_wc_conflict_version_dup(const svn_wc_conflict_version_t *version,
return new_version;
}
-
svn_wc_conflict_description_t *
svn_wc__cd2_to_cd(const svn_wc_conflict_description2_t *conflict,
apr_pool_t *result_pool)
@@ -403,145 +418,6 @@ svn_wc__cd2_to_cd(const svn_wc_conflict_description2_t *conflict,
svn_error_t *
-svn_wc__status2_from_3(svn_wc_status2_t **status,
- const svn_wc_status3_t *old_status,
- svn_wc_context_t *wc_ctx,
- const char *local_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- const svn_wc_entry_t *entry = NULL;
-
- if (old_status == NULL)
- {
- *status = NULL;
- return SVN_NO_ERROR;
- }
-
- *status = apr_pcalloc(result_pool, sizeof(**status));
-
- if (old_status->versioned)
- {
- svn_error_t *err;
- err= svn_wc__get_entry(&entry, wc_ctx->db, local_abspath, FALSE,
- svn_node_unknown, result_pool, scratch_pool);
-
- if (err && err->apr_err == SVN_ERR_NODE_UNEXPECTED_KIND)
- svn_error_clear(err);
- else
- SVN_ERR(err);
- }
-
- (*status)->entry = entry;
- (*status)->copied = old_status->copied;
- (*status)->repos_lock = svn_lock_dup(old_status->repos_lock, result_pool);
-
- if (old_status->repos_relpath)
- (*status)->url = svn_path_url_add_component2(old_status->repos_root_url,
- old_status->repos_relpath,
- result_pool);
- (*status)->ood_last_cmt_rev = old_status->ood_changed_rev;
- (*status)->ood_last_cmt_date = old_status->ood_changed_date;
- (*status)->ood_kind = old_status->ood_kind;
- (*status)->ood_last_cmt_author = old_status->ood_changed_author;
-
- if (old_status->conflicted)
- {
- const svn_wc_conflict_description2_t *tree_conflict;
- SVN_ERR(svn_wc__get_tree_conflict(&tree_conflict, wc_ctx, local_abspath,
- scratch_pool, scratch_pool));
- (*status)->tree_conflict = svn_wc__cd2_to_cd(tree_conflict, result_pool);
- }
-
- (*status)->switched = old_status->switched;
-
- (*status)->text_status = old_status->node_status;
- (*status)->prop_status = old_status->prop_status;
-
- (*status)->repos_text_status = old_status->repos_node_status;
- (*status)->repos_prop_status = old_status->repos_prop_status;
-
- /* Some values might be inherited from properties */
- if (old_status->node_status == svn_wc_status_modified
- || old_status->node_status == svn_wc_status_conflicted)
- (*status)->text_status = old_status->text_status;
-
- /* (Currently a no-op, but just make sure it is ok) */
- if (old_status->repos_node_status == svn_wc_status_modified
- || old_status->repos_node_status == svn_wc_status_conflicted)
- (*status)->repos_text_status = old_status->repos_text_status;
-
- if (old_status->node_status == svn_wc_status_added)
- (*status)->prop_status = svn_wc_status_none; /* No separate info */
-
- /* Find pristine_text_status value */
- switch (old_status->text_status)
- {
- case svn_wc_status_none:
- case svn_wc_status_normal:
- case svn_wc_status_modified:
- (*status)->pristine_text_status = old_status->text_status;
- break;
- case svn_wc_status_conflicted:
- default:
- /* ### Fetch compare data, or fall back to the documented
- not retrieved behavior? */
- (*status)->pristine_text_status = svn_wc_status_none;
- break;
- }
-
- /* Find pristine_prop_status value */
- switch (old_status->prop_status)
- {
- case svn_wc_status_none:
- case svn_wc_status_normal:
- case svn_wc_status_modified:
- if (old_status->node_status != svn_wc_status_added
- && old_status->node_status != svn_wc_status_deleted
- && old_status->node_status != svn_wc_status_replaced)
- {
- (*status)->pristine_prop_status = old_status->prop_status;
- }
- else
- (*status)->pristine_prop_status = svn_wc_status_none;
- break;
- case svn_wc_status_conflicted:
- default:
- /* ### Fetch compare data, or fall back to the documented
- not retrieved behavior? */
- (*status)->pristine_prop_status = svn_wc_status_none;
- break;
- }
-
- if (old_status->versioned
- && old_status->conflicted
- && old_status->node_status != svn_wc_status_obstructed
- && (old_status->kind == svn_node_file
- || old_status->node_status != svn_wc_status_missing))
- {
- svn_boolean_t text_conflict_p, prop_conflict_p;
-
- /* The entry says there was a conflict, but the user might have
- marked it as resolved by deleting the artifact files, so check
- for that. */
- SVN_ERR(svn_wc__internal_conflicted_p(&text_conflict_p,
- &prop_conflict_p,
- NULL,
- wc_ctx->db, local_abspath,
- scratch_pool));
-
- if (text_conflict_p)
- (*status)->text_status = svn_wc_status_conflicted;
-
- if (prop_conflict_p)
- (*status)->prop_status = svn_wc_status_conflicted;
- }
-
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
svn_wc__fetch_kind_func(svn_node_kind_t *kind,
void *baton,
const char *path,
diff --git a/subversion/libsvn_wc/wc-checks.h b/subversion/libsvn_wc/wc-checks.h
index ebc73ed03472..5888626ac030 100644
--- a/subversion/libsvn_wc/wc-checks.h
+++ b/subversion/libsvn_wc/wc-checks.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-checks.sql and .dist_sandbox/subversion-1.9.2/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_VERIFICATION_TRIGGERS 0
@@ -42,14 +42,189 @@
"END; " \
""
+#define STMT_STATIC_VERIFY 1
+#define STMT_1_INFO {"STMT_STATIC_VERIFY", NULL}
+#define STMT_1 \
+ "SELECT local_relpath, op_depth, 1, 'Invalid parent relpath set in NODES' " \
+ "FROM nodes n WHERE local_relpath != '' " \
+ " AND (parent_relpath IS NULL " \
+ " OR NOT (((local_relpath) > (CASE (parent_relpath) WHEN '' THEN '' ELSE (parent_relpath) || '/' END)) AND ((local_relpath) < CASE (parent_relpath) WHEN '' THEN X'FFFF' ELSE (parent_relpath) || '0' END)) " \
+ " OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1) " \
+ "UNION ALL " \
+ "SELECT local_relpath, -1, 2, 'Invalid parent relpath set in ACTUAL' " \
+ "FROM actual_node a WHERE local_relpath != '' " \
+ " AND (parent_relpath IS NULL " \
+ " OR NOT (((local_relpath) > (CASE (parent_relpath) WHEN '' THEN '' ELSE (parent_relpath) || '/' END)) AND ((local_relpath) < CASE (parent_relpath) WHEN '' THEN X'FFFF' ELSE (parent_relpath) || '0' END)) " \
+ " OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1) " \
+ "UNION ALL " \
+ "SELECT local_relpath, -1, 10, 'No ancestor in ACTUAL' " \
+ "FROM actual_node a WHERE local_relpath != '' " \
+ " AND NOT EXISTS(SELECT 1 from nodes i " \
+ " WHERE i.wc_id=a.wc_id " \
+ " AND i.local_relpath=a.parent_relpath) " \
+ " AND NOT EXISTS(SELECT 1 from nodes i " \
+ " WHERE i.wc_id=a.wc_id " \
+ " AND i.local_relpath=a.local_relpath) " \
+ "UNION ALL " \
+ "SELECT a.local_relpath, -1, 11, 'Bad or Unneeded actual data' " \
+ "FROM actual_node a " \
+ "LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath " \
+ " AND n.op_depth = (SELECT MAX(op_depth) from nodes i " \
+ " WHERE i.wc_id=a.wc_id AND i.local_relpath=a.local_relpath) " \
+ "WHERE (a.properties IS NOT NULL " \
+ " AND (n.presence IS NULL " \
+ " OR n.presence NOT IN ('normal', 'incomplete'))) " \
+ " OR (a.changelist IS NOT NULL AND (n.kind IS NOT NULL AND n.kind != 'file')) " \
+ " OR (a.conflict_data IS NULL AND a.properties IS NULL AND a.changelist IS NULL) " \
+ " AND NOT EXISTS(SELECT 1 from nodes i " \
+ " WHERE i.wc_id=a.wc_id " \
+ " AND i.local_relpath=a.parent_relpath) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 20, 'No ancestor in NODES' " \
+ "FROM nodes n WHERE local_relpath != '' " \
+ " AND file_external IS NULL " \
+ " AND NOT EXISTS(SELECT 1 from nodes i " \
+ " WHERE i.wc_id=n.wc_id " \
+ " AND i.local_relpath=n.parent_relpath " \
+ " AND i.op_depth <= n.op_depth) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 21, 'Unneeded node data' " \
+ "FROM nodes " \
+ "WHERE presence NOT IN ('normal', 'incomplete') " \
+ "AND (properties IS NOT NULL " \
+ " OR checksum IS NOT NULL " \
+ " OR depth IS NOT NULL " \
+ " OR symlink_target IS NOT NULL " \
+ " OR changed_revision IS NOT NULL " \
+ " OR (changed_date IS NOT NULL AND changed_date != 0) " \
+ " OR changed_author IS NOT NULL " \
+ " OR translated_size IS NOT NULL " \
+ " OR last_mod_time IS NOT NULL " \
+ " OR dav_cache IS NOT NULL " \
+ " OR file_external IS NOT NULL " \
+ " OR inherited_props IS NOT NULL) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 22, 'Unneeded base-deleted node data' " \
+ "FROM nodes " \
+ "WHERE presence IN ('base-deleted') " \
+ "AND (repos_id IS NOT NULL " \
+ " OR repos_path IS NOT NULL " \
+ " OR revision IS NOT NULL) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 23, 'Kind specific data invalid on normal' " \
+ "FROM nodes " \
+ "WHERE presence IN ('normal', 'incomplete') " \
+ "AND (kind IS NULL " \
+ " OR (repos_path IS NULL " \
+ " AND (properties IS NOT NULL " \
+ " OR changed_revision IS NOT NULL " \
+ " OR changed_author IS NOT NULL " \
+ " OR (changed_date IS NOT NULL AND changed_date != 0))) " \
+ " OR (CASE WHEN kind = 'file' AND repos_path IS NOT NULL " \
+ " THEN checksum IS NULL " \
+ " ELSE checksum IS NOT NULL END) " \
+ " OR (CASE WHEN kind = 'dir' THEN depth IS NULL " \
+ " ELSE depth IS NOT NULL END) " \
+ " OR (CASE WHEN kind = 'symlink' THEN symlink_target IS NULL " \
+ " ELSE symlink_target IS NOT NULL END)) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 24, 'Invalid op-depth for local add' " \
+ "FROM nodes " \
+ "WHERE presence IN ('normal', 'incomplete') " \
+ " AND repos_path IS NULL " \
+ " AND op_depth != relpath_depth(local_relpath) " \
+ "UNION ALL " \
+ "SELECT local_relpath, op_depth, 25, 'Node missing op-depth ancestor' " \
+ "FROM nodes n " \
+ "WHERE op_depth < relpath_depth(local_relpath) " \
+ " AND file_external IS NULL " \
+ " AND NOT EXISTS(SELECT 1 FROM nodes p " \
+ " WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath " \
+ " AND p.op_depth=n.op_depth " \
+ " AND (p.presence IN ('normal', 'incomplete') " \
+ " OR (p.presence IN ('base-deleted', 'not-present') " \
+ " AND n.presence = 'base-deleted'))) " \
+ "UNION ALL " \
+ "SELECT n.local_relpath, n.op_depth, 26, 'Copied descendant mismatch' " \
+ "FROM nodes n " \
+ "JOIN nodes p " \
+ " ON p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath " \
+ " AND n.op_depth=p.op_depth " \
+ "WHERE n.op_depth > 0 AND n.presence IN ('normal', 'incomplete') " \
+ " AND (n.repos_id != p.repos_id " \
+ " OR n.repos_path != " \
+ " (CASE WHEN (n.parent_relpath) = '' THEN (CASE WHEN (p.repos_path) = '' THEN (n.local_relpath) WHEN (n.local_relpath) = '' THEN (p.repos_path) ELSE (p.repos_path) || '/' || (n.local_relpath) END) WHEN (p.repos_path) = '' THEN (CASE WHEN (n.parent_relpath) = '' THEN (n.local_relpath) WHEN SUBSTR((n.local_relpath), 1, LENGTH(n.parent_relpath)) = (n.parent_relpath) THEN CASE WHEN LENGTH(n.parent_relpath) = LENGTH(n.local_relpath) THEN '' WHEN SUBSTR((n.local_relpath), LENGTH(n.parent_relpath)+1, 1) = '/' THEN SUBSTR((n.local_relpath), LENGTH(n.parent_relpath)+2) END END) WHEN SUBSTR((n.local_relpath), 1, LENGTH(n.parent_relpath)) = (n.parent_relpath) THEN CASE WHEN LENGTH(n.parent_relpath) = LENGTH(n.local_relpath) THEN (p.repos_path) WHEN SUBSTR((n.local_relpath), LENGTH(n.parent_relpath)+1, 1) = '/' THEN (p.repos_path) || SUBSTR((n.local_relpath), LENGTH(n.parent_relpath)+1) END END) " \
+ " OR n.revision != p.revision " \
+ " OR p.kind != 'dir' " \
+ " OR n.moved_here IS NOT p.moved_here) " \
+ "UNION ALL " \
+ "SELECT n.local_relpath, n.op_depth, 27, 'Invalid op-root presence' " \
+ "FROM nodes n " \
+ "WHERE n.op_depth = relpath_depth(local_relpath) " \
+ " AND presence NOT IN ('normal', 'incomplete', 'base-deleted') " \
+ "UNION ALL " \
+ "SELECT n.local_relpath, s.op_depth, 28, 'Incomplete shadowing' " \
+ "FROM nodes n " \
+ "JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath " \
+ " AND s.op_depth = relpath_depth(s.local_relpath) " \
+ " AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d " \
+ " WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath " \
+ " AND d.op_depth > n.op_depth) " \
+ "WHERE n.presence IN ('normal', 'incomplete') " \
+ " AND EXISTS(SELECT 1 " \
+ " FROM nodes dn " \
+ " WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth " \
+ " AND dn.presence IN ('normal', 'incomplete') " \
+ " AND (((dn.local_relpath) > (CASE (n.local_relpath) WHEN '' THEN '' ELSE (n.local_relpath) || '/' END)) AND ((dn.local_relpath) < CASE (n.local_relpath) WHEN '' THEN X'FFFF' ELSE (n.local_relpath) || '0' END)) " \
+ " AND dn.file_external IS NULL " \
+ " AND NOT EXISTS(SELECT 1 " \
+ " FROM nodes ds " \
+ " WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth " \
+ " AND ds.local_relpath=dn.local_relpath)) " \
+ "UNION ALL " \
+ "SELECT s.local_relpath, s.op_depth, 29, 'Invalid base-delete' " \
+ "FROM nodes s " \
+ "LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath " \
+ " AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d " \
+ " WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath " \
+ " AND d.op_depth < s.op_depth) " \
+ "WHERE s.presence = 'base-deleted' " \
+ " AND (n.presence IS NULL " \
+ " OR n.presence NOT IN ('normal', 'incomplete') " \
+ " ) " \
+ "UNION ALL " \
+ "SELECT n.local_relpath, n.op_depth, 30, 'Invalid data for BASE' " \
+ "FROM nodes n " \
+ "WHERE n.op_depth = 0 " \
+ " AND (n.moved_to IS NOT NULL " \
+ " OR n.moved_here IS NOT NULL) " \
+ "UNION ALL " \
+ "SELECT d.local_relpath, d.op_depth, 60, 'Moved here without origin' " \
+ "FROM nodes d " \
+ "WHERE d.op_depth = relpath_depth(d.local_relpath) " \
+ " AND d.moved_here IS NOT NULL " \
+ " AND NOT EXISTS(SELECT 1 FROM nodes s " \
+ " WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath) " \
+ "UNION ALL " \
+ "SELECT s.local_relpath, s.op_depth, 61, 'Moved to without target' " \
+ "FROM nodes s " \
+ "WHERE s.moved_to IS NOT NULL " \
+ " AND NOT EXISTS(SELECT 1 FROM nodes d " \
+ " WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to " \
+ " AND d.op_depth = relpath_depth(d.local_relpath) " \
+ " AND d.moved_here =1 AND d.repos_path IS NOT NULL) " \
+ ""
+
#define WC_CHECKS_SQL_DECLARE_STATEMENTS(varname) \
static const char * const varname[] = { \
STMT_0, \
+ STMT_1, \
NULL \
}
#define WC_CHECKS_SQL_DECLARE_STATEMENT_INFO(varname) \
static const char * const varname[][2] = { \
STMT_0_INFO, \
+ STMT_1_INFO, \
{NULL, NULL} \
}
diff --git a/subversion/libsvn_wc/wc-checks.sql b/subversion/libsvn_wc/wc-checks.sql
index a677270f3600..fce7b4908c7f 100644
--- a/subversion/libsvn_wc/wc-checks.sql
+++ b/subversion/libsvn_wc/wc-checks.sql
@@ -75,3 +75,217 @@ BEGIN
SELECT RAISE(FAIL, 'WC DB validity check 04 failed');
END;
+-- STMT_STATIC_VERIFY
+SELECT local_relpath, op_depth, 1, 'Invalid parent relpath set in NODES'
+FROM nodes n WHERE local_relpath != ''
+ AND (parent_relpath IS NULL
+ OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
+ OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
+
+UNION ALL
+
+SELECT local_relpath, -1, 2, 'Invalid parent relpath set in ACTUAL'
+FROM actual_node a WHERE local_relpath != ''
+ AND (parent_relpath IS NULL
+ OR NOT IS_STRICT_DESCENDANT_OF(local_relpath, parent_relpath)
+ OR relpath_depth(local_relpath) != relpath_depth(parent_relpath)+1)
+
+UNION ALL
+
+/* All ACTUAL nodes must have an equivalent NODE in NODES
+ or be only one level deep (delete-delete tc) */
+SELECT local_relpath, -1, 10, 'No ancestor in ACTUAL'
+FROM actual_node a WHERE local_relpath != ''
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.parent_relpath)
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.local_relpath)
+
+UNION ALL
+/* Verify if the ACTUAL data makes sense for the related node.
+ Only conflict data is valid if there is none */
+SELECT a.local_relpath, -1, 11, 'Bad or Unneeded actual data'
+FROM actual_node a
+LEFT JOIN nodes n on n.wc_id = a.wc_id AND n.local_relpath = a.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) from nodes i
+ WHERE i.wc_id=a.wc_id AND i.local_relpath=a.local_relpath)
+WHERE (a.properties IS NOT NULL
+ AND (n.presence IS NULL
+ OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)))
+ OR (a.changelist IS NOT NULL AND (n.kind IS NOT NULL AND n.kind != MAP_FILE))
+ OR (a.conflict_data IS NULL AND a.properties IS NULL AND a.changelist IS NULL)
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=a.wc_id
+ AND i.local_relpath=a.parent_relpath)
+
+UNION ALL
+
+/* A parent node must exist for every normal node except the root.
+ That node must exist at a lower or equal op-depth */
+SELECT local_relpath, op_depth, 20, 'No ancestor in NODES'
+FROM nodes n WHERE local_relpath != ''
+ AND file_external IS NULL
+ AND NOT EXISTS(SELECT 1 from nodes i
+ WHERE i.wc_id=n.wc_id
+ AND i.local_relpath=n.parent_relpath
+ AND i.op_depth <= n.op_depth)
+
+UNION ALL
+/* If a node is not present in the working copy (normal, add, copy) it doesn't
+ have revision details stored on this record */
+SELECT local_relpath, op_depth, 21, 'Unneeded node data'
+FROM nodes
+WHERE presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+AND (properties IS NOT NULL
+ OR checksum IS NOT NULL
+ OR depth IS NOT NULL
+ OR symlink_target IS NOT NULL
+ OR changed_revision IS NOT NULL
+ OR (changed_date IS NOT NULL AND changed_date != 0)
+ OR changed_author IS NOT NULL
+ OR translated_size IS NOT NULL
+ OR last_mod_time IS NOT NULL
+ OR dav_cache IS NOT NULL
+ OR file_external IS NOT NULL
+ OR inherited_props IS NOT NULL)
+
+UNION ALL
+/* base-deleted nodes don't have a repository location. They are just
+ shadowing without a replacement */
+SELECT local_relpath, op_depth, 22, 'Unneeded base-deleted node data'
+FROM nodes
+WHERE presence IN (MAP_BASE_DELETED)
+AND (repos_id IS NOT NULL
+ OR repos_path IS NOT NULL
+ OR revision IS NOT NULL)
+
+UNION ALL
+/* Verify if type specific data is set (or not set for wrong type) */
+SELECT local_relpath, op_depth, 23, 'Kind specific data invalid on normal'
+FROM nodes
+WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+AND (kind IS NULL
+ OR (repos_path IS NULL
+ AND (properties IS NOT NULL
+ OR changed_revision IS NOT NULL
+ OR changed_author IS NOT NULL
+ OR (changed_date IS NOT NULL AND changed_date != 0)))
+ OR (CASE WHEN kind = MAP_FILE AND repos_path IS NOT NULL
+ THEN checksum IS NULL
+ ELSE checksum IS NOT NULL END)
+ OR (CASE WHEN kind = MAP_DIR THEN depth IS NULL
+ ELSE depth IS NOT NULL END)
+ OR (CASE WHEN kind = MAP_SYMLINK THEN symlink_target IS NULL
+ ELSE symlink_target IS NOT NULL END))
+
+UNION ALL
+/* Local-adds are always their own operation (read: they don't have
+ op-depth descendants, nor are op-depth descendants */
+SELECT local_relpath, op_depth, 24, 'Invalid op-depth for local add'
+FROM nodes
+WHERE presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND repos_path IS NULL
+ AND op_depth != relpath_depth(local_relpath)
+
+UNION ALL
+/* op-depth descendants are only valid if they have a direct parent
+ node at the same op-depth. Only certain types allow further
+ descendants */
+SELECT local_relpath, op_depth, 25, 'Node missing op-depth ancestor'
+FROM nodes n
+WHERE op_depth < relpath_depth(local_relpath)
+ AND file_external IS NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes p
+ WHERE p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
+ AND p.op_depth=n.op_depth
+ AND (p.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ OR (p.presence IN (MAP_BASE_DELETED, MAP_NOT_PRESENT)
+ AND n.presence = MAP_BASE_DELETED)))
+
+UNION ALL
+/* Present op-depth descendants have the repository location implied by their
+ ancestor */
+SELECT n.local_relpath, n.op_depth, 26, 'Copied descendant mismatch'
+FROM nodes n
+JOIN nodes p
+ ON p.wc_id=n.wc_id AND p.local_relpath=n.parent_relpath
+ AND n.op_depth=p.op_depth
+WHERE n.op_depth > 0 AND n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND (n.repos_id != p.repos_id
+ OR n.repos_path !=
+ RELPATH_SKIP_JOIN(n.parent_relpath, p.repos_path, n.local_relpath)
+ OR n.revision != p.revision
+ OR p.kind != MAP_DIR
+ OR n.moved_here IS NOT p.moved_here)
+
+UNION ALL
+/* Only certain presence values are valid as op-root.
+ Note that the wc-root always has presence normal or incomplete */
+SELECT n.local_relpath, n.op_depth, 27, 'Invalid op-root presence'
+FROM nodes n
+WHERE n.op_depth = relpath_depth(local_relpath)
+ AND presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE, MAP_BASE_DELETED)
+
+UNION ALL
+/* If a node is shadowed, all its present op-depth descendants
+ must be shadowed at the same op-depth as well */
+SELECT n.local_relpath, s.op_depth, 28, 'Incomplete shadowing'
+FROM nodes n
+JOIN nodes s ON s.wc_id=n.wc_id AND s.local_relpath=n.local_relpath
+ AND s.op_depth = relpath_depth(s.local_relpath)
+ AND s.op_depth = (SELECT MIN(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth > n.op_depth)
+WHERE n.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND EXISTS(SELECT 1
+ FROM nodes dn
+ WHERE dn.wc_id=n.wc_id AND dn.op_depth=n.op_depth
+ AND dn.presence IN (MAP_NORMAL, MAP_INCOMPLETE)
+ AND IS_STRICT_DESCENDANT_OF(dn.local_relpath, n.local_relpath)
+ AND dn.file_external IS NULL
+ AND NOT EXISTS(SELECT 1
+ FROM nodes ds
+ WHERE ds.wc_id=n.wc_id AND ds.op_depth=s.op_depth
+ AND ds.local_relpath=dn.local_relpath))
+
+UNION ALL
+/* A base-delete is only valid if it directly deletes a present node */
+SELECT s.local_relpath, s.op_depth, 29, 'Invalid base-delete'
+FROM nodes s
+LEFT JOIN nodes n ON n.wc_id=s.wc_id AND n.local_relpath=s.local_relpath
+ AND n.op_depth = (SELECT MAX(op_depth) FROM nodes d
+ WHERE d.wc_id=s.wc_id AND d.local_relpath=s.local_relpath
+ AND d.op_depth < s.op_depth)
+WHERE s.presence = MAP_BASE_DELETED
+ AND (n.presence IS NULL
+ OR n.presence NOT IN (MAP_NORMAL, MAP_INCOMPLETE)
+ /*OR n.kind != s.kind*/)
+
+UNION ALL
+/* Moves are stored in the working layers, not in BASE */
+SELECT n.local_relpath, n.op_depth, 30, 'Invalid data for BASE'
+FROM nodes n
+WHERE n.op_depth = 0
+ AND (n.moved_to IS NOT NULL
+ OR n.moved_here IS NOT NULL)
+
+UNION ALL
+/* If moved_here is set on an op-root, there must be a proper moved_to */
+SELECT d.local_relpath, d.op_depth, 60, 'Moved here without origin'
+FROM nodes d
+WHERE d.op_depth = relpath_depth(d.local_relpath)
+ AND d.moved_here IS NOT NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes s
+ WHERE s.wc_id = d.wc_id AND s.moved_to = d.local_relpath)
+
+UNION ALL
+/* If moved_to is set there should be an moved op root at the target */
+SELECT s.local_relpath, s.op_depth, 61, 'Moved to without target'
+FROM nodes s
+WHERE s.moved_to IS NOT NULL
+ AND NOT EXISTS(SELECT 1 FROM nodes d
+ WHERE d.wc_id = s.wc_id AND d.local_relpath = s.moved_to
+ AND d.op_depth = relpath_depth(d.local_relpath)
+ AND d.moved_here =1 AND d.repos_path IS NOT NULL)
diff --git a/subversion/libsvn_wc/wc-metadata.h b/subversion/libsvn_wc/wc-metadata.h
index 83854d779d01..8367adc6ec37 100644
--- a/subversion/libsvn_wc/wc-metadata.h
+++ b/subversion/libsvn_wc/wc-metadata.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-metadata.sql and .dist_sandbox/subversion-1.9.2/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_CREATE_SCHEMA 0
diff --git a/subversion/libsvn_wc/wc-metadata.sql b/subversion/libsvn_wc/wc-metadata.sql
index 2a2358d7d635..f52df93f462a 100644
--- a/subversion/libsvn_wc/wc-metadata.sql
+++ b/subversion/libsvn_wc/wc-metadata.sql
@@ -108,7 +108,7 @@ CREATE TABLE PRISTINE (
);
CREATE INDEX I_PRISTINE_MD5 ON PRISTINE (md5_checksum);
-
+
/* ------------------------------------------------------------------------- */
/* The ACTUAL_NODE table describes text changes and property changes
@@ -150,7 +150,7 @@ CREATE TABLE ACTUAL_NODE (
/* if not NULL, this node is part of a changelist. */
changelist TEXT,
-
+
/* ### need to determine values. "unknown" (no info), "admin" (they
### used something like 'svn edit'), "noticed" (saw a mod while
### scanning the filesystem). */
@@ -170,7 +170,7 @@ CREATE TABLE ACTUAL_NODE (
/* stsp: This is meant for text conflicts, right? What about property
conflicts? Why do we need these in a column to refer to the
pristine store? Can't we just parse the checksums from
- conflict_data as well?
+ conflict_data as well?
rhuijben: Because that won't allow triggers to handle refcounts.
We would have to scan all conflict skels before cleaning up the
a single file from the pristine stor */
@@ -200,7 +200,7 @@ CREATE TABLE LOCK (
lock_owner TEXT,
lock_comment TEXT,
lock_date INTEGER, /* an APR date/time (usec since 1970) */
-
+
PRIMARY KEY (repos_id, repos_relpath)
);
@@ -553,7 +553,7 @@ CREATE TABLE EXTERNALS (
/* the kind of the external. */
kind TEXT NOT NULL,
- /* The local relpath of the directory NODE defining this external
+ /* The local relpath of the directory NODE defining this external
(Defaults to the parent directory of the file external after upgrade) */
def_local_relpath TEXT NOT NULL,
@@ -577,7 +577,7 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED ON EXTERNALS (wc_id,
indexes to make better decisions in the query planner.
For every interesting index this contains a number of rows where the
- statistics ar calculated for and then for every column in the index the
+ statistics are calculated for and then for every column in the index the
average number of rows with the same value in all columns left of this
column including the column itself.
@@ -779,7 +779,7 @@ LIMIT 1
/* ------------------------------------------------------------------------- */
-/* Format 28 involves no schema changes, it only converts MD5 pristine
+/* Format 28 involves no schema changes, it only converts MD5 pristine
references to SHA1. */
-- STMT_UPGRADE_TO_28
diff --git a/subversion/libsvn_wc/wc-queries.h b/subversion/libsvn_wc/wc-queries.h
index 50a1d9770dbf..523a6a169076 100644
--- a/subversion/libsvn_wc/wc-queries.h
+++ b/subversion/libsvn_wc/wc-queries.h
@@ -1,4 +1,4 @@
-/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.8.14/subversion/libsvn_wc/token-map.h.
+/* This file is automatically generated from wc-queries.sql and .dist_sandbox/subversion-1.9.2/subversion/libsvn_wc/token-map.h.
* Do not edit this file -- edit the source and rerun gen-make.py */
#define STMT_SELECT_NODE_INFO 0
@@ -55,6 +55,15 @@
#define STMT_4_INFO {"STMT_SELECT_BASE_CHILDREN_INFO", NULL}
#define STMT_4 \
"SELECT local_relpath, nodes.repos_id, nodes.repos_path, presence, kind, " \
+ " revision, depth, file_external " \
+ "FROM nodes " \
+ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 " \
+ ""
+
+#define STMT_SELECT_BASE_CHILDREN_INFO_LOCK 5
+#define STMT_5_INFO {"STMT_SELECT_BASE_CHILDREN_INFO_LOCK", NULL}
+#define STMT_5 \
+ "SELECT local_relpath, nodes.repos_id, nodes.repos_path, presence, kind, " \
" revision, depth, file_external, " \
" lock_token, lock_owner, lock_comment, lock_date " \
"FROM nodes " \
@@ -63,9 +72,9 @@
"WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 " \
""
-#define STMT_SELECT_WORKING_NODE 5
-#define STMT_5_INFO {"STMT_SELECT_WORKING_NODE", NULL}
-#define STMT_5 \
+#define STMT_SELECT_WORKING_NODE 6
+#define STMT_6_INFO {"STMT_SELECT_WORKING_NODE", NULL}
+#define STMT_6 \
"SELECT op_depth, presence, kind, checksum, translated_size, " \
" changed_revision, changed_date, changed_author, depth, symlink_target, " \
" repos_id, repos_path, revision, " \
@@ -76,19 +85,19 @@
"LIMIT 1 " \
""
-#define STMT_SELECT_DEPTH_NODE 6
-#define STMT_6_INFO {"STMT_SELECT_DEPTH_NODE", NULL}
-#define STMT_6 \
+#define STMT_SELECT_DEPTH_NODE 7
+#define STMT_7_INFO {"STMT_SELECT_DEPTH_NODE", NULL}
+#define STMT_7 \
"SELECT repos_id, repos_path, presence, kind, revision, checksum, " \
" translated_size, changed_revision, changed_date, changed_author, depth, " \
- " symlink_target, last_mod_time, properties " \
+ " symlink_target, properties, moved_to, moved_here " \
"FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \
""
-#define STMT_SELECT_LOWEST_WORKING_NODE 7
-#define STMT_7_INFO {"STMT_SELECT_LOWEST_WORKING_NODE", NULL}
-#define STMT_7 \
+#define STMT_SELECT_LOWEST_WORKING_NODE 8
+#define STMT_8_INFO {"STMT_SELECT_LOWEST_WORKING_NODE", NULL}
+#define STMT_8 \
"SELECT op_depth, presence, kind, moved_to " \
"FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 " \
@@ -96,9 +105,9 @@
"LIMIT 1 " \
""
-#define STMT_SELECT_HIGHEST_WORKING_NODE 8
-#define STMT_8_INFO {"STMT_SELECT_HIGHEST_WORKING_NODE", NULL}
-#define STMT_8 \
+#define STMT_SELECT_HIGHEST_WORKING_NODE 9
+#define STMT_9_INFO {"STMT_SELECT_HIGHEST_WORKING_NODE", NULL}
+#define STMT_9 \
"SELECT op_depth " \
"FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth < ?3 " \
@@ -106,17 +115,17 @@
"LIMIT 1 " \
""
-#define STMT_SELECT_ACTUAL_NODE 9
-#define STMT_9_INFO {"STMT_SELECT_ACTUAL_NODE", NULL}
-#define STMT_9 \
+#define STMT_SELECT_ACTUAL_NODE 10
+#define STMT_10_INFO {"STMT_SELECT_ACTUAL_NODE", NULL}
+#define STMT_10 \
"SELECT changelist, properties, conflict_data " \
"FROM actual_node " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
""
-#define STMT_SELECT_NODE_CHILDREN_INFO 10
-#define STMT_10_INFO {"STMT_SELECT_NODE_CHILDREN_INFO", NULL}
-#define STMT_10 \
+#define STMT_SELECT_NODE_CHILDREN_INFO 11
+#define STMT_11_INFO {"STMT_SELECT_NODE_CHILDREN_INFO", NULL}
+#define STMT_11 \
"SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision, " \
" checksum, translated_size, changed_revision, changed_date, changed_author, " \
" depth, symlink_target, last_mod_time, properties, lock_token, lock_owner, " \
@@ -125,51 +134,67 @@
"LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id " \
" AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
+ "ORDER BY local_relpath DESC, op_depth DESC " \
""
-#define STMT_SELECT_NODE_CHILDREN_WALKER_INFO 11
-#define STMT_11_INFO {"STMT_SELECT_NODE_CHILDREN_WALKER_INFO", NULL}
-#define STMT_11 \
+#define STMT_SELECT_BASE_NODE_CHILDREN_INFO 12
+#define STMT_12_INFO {"STMT_SELECT_BASE_NODE_CHILDREN_INFO", NULL}
+#define STMT_12 \
+ "SELECT op_depth, nodes.repos_id, nodes.repos_path, presence, kind, revision, " \
+ " checksum, translated_size, changed_revision, changed_date, changed_author, " \
+ " depth, symlink_target, last_mod_time, properties, lock_token, lock_owner, " \
+ " lock_comment, lock_date, local_relpath, moved_here, moved_to, file_external " \
+ "FROM nodes " \
+ "LEFT OUTER JOIN lock ON nodes.repos_id = lock.repos_id " \
+ " AND nodes.repos_path = lock.repos_relpath AND op_depth = 0 " \
+ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 " \
+ "ORDER BY local_relpath DESC " \
+ ""
+
+#define STMT_SELECT_NODE_CHILDREN_WALKER_INFO 13
+#define STMT_13_INFO {"STMT_SELECT_NODE_CHILDREN_WALKER_INFO", NULL}
+#define STMT_13 \
"SELECT local_relpath, op_depth, presence, kind " \
"FROM nodes_current " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
+ "ORDER BY local_relpath " \
""
-#define STMT_SELECT_ACTUAL_CHILDREN_INFO 12
-#define STMT_12_INFO {"STMT_SELECT_ACTUAL_CHILDREN_INFO", NULL}
-#define STMT_12 \
+#define STMT_SELECT_ACTUAL_CHILDREN_INFO 14
+#define STMT_14_INFO {"STMT_SELECT_ACTUAL_CHILDREN_INFO", NULL}
+#define STMT_14 \
"SELECT local_relpath, changelist, properties, conflict_data " \
"FROM actual_node " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
""
-#define STMT_SELECT_REPOSITORY_BY_ID 13
-#define STMT_13_INFO {"STMT_SELECT_REPOSITORY_BY_ID", NULL}
-#define STMT_13 \
+#define STMT_SELECT_REPOSITORY_BY_ID 15
+#define STMT_15_INFO {"STMT_SELECT_REPOSITORY_BY_ID", NULL}
+#define STMT_15 \
"SELECT root, uuid FROM repository WHERE id = ?1 " \
""
-#define STMT_SELECT_WCROOT_NULL 14
-#define STMT_14_INFO {"STMT_SELECT_WCROOT_NULL", NULL}
-#define STMT_14 \
+#define STMT_SELECT_WCROOT_NULL 16
+#define STMT_16_INFO {"STMT_SELECT_WCROOT_NULL", NULL}
+#define STMT_16 \
"SELECT id FROM wcroot WHERE local_abspath IS NULL " \
""
-#define STMT_SELECT_REPOSITORY 15
-#define STMT_15_INFO {"STMT_SELECT_REPOSITORY", NULL}
-#define STMT_15 \
+#define STMT_SELECT_REPOSITORY 17
+#define STMT_17_INFO {"STMT_SELECT_REPOSITORY", NULL}
+#define STMT_17 \
"SELECT id FROM repository WHERE root = ?1 " \
""
-#define STMT_INSERT_REPOSITORY 16
-#define STMT_16_INFO {"STMT_INSERT_REPOSITORY", NULL}
-#define STMT_16 \
+#define STMT_INSERT_REPOSITORY 18
+#define STMT_18_INFO {"STMT_INSERT_REPOSITORY", NULL}
+#define STMT_18 \
"INSERT INTO repository (root, uuid) VALUES (?1, ?2) " \
""
-#define STMT_INSERT_NODE 17
-#define STMT_17_INFO {"STMT_INSERT_NODE", NULL}
-#define STMT_17 \
+#define STMT_INSERT_NODE 19
+#define STMT_19_INFO {"STMT_INSERT_NODE", NULL}
+#define STMT_19 \
"INSERT OR REPLACE INTO nodes ( " \
" wc_id, local_relpath, op_depth, parent_relpath, repos_id, repos_path, " \
" revision, presence, depth, kind, changed_revision, changed_date, " \
@@ -180,22 +205,9 @@
" ?15, ?16, ?17, ?18, ?19, ?20, ?21, ?22, ?23) " \
""
-#define STMT_SELECT_BASE_PRESENT 18
-#define STMT_18_INFO {"STMT_SELECT_BASE_PRESENT", NULL}
-#define STMT_18 \
- "SELECT local_relpath, kind FROM nodes n " \
- "WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
- " AND op_depth = 0 " \
- " AND presence in ('normal', 'incomplete') " \
- " AND NOT EXISTS(SELECT 1 FROM NODES w " \
- " WHERE w.wc_id = ?1 AND w.local_relpath = n.local_relpath " \
- " AND op_depth > 0) " \
- "ORDER BY local_relpath DESC " \
- ""
-
-#define STMT_SELECT_WORKING_PRESENT 19
-#define STMT_19_INFO {"STMT_SELECT_WORKING_PRESENT", NULL}
-#define STMT_19 \
+#define STMT_SELECT_WORKING_PRESENT 20
+#define STMT_20_INFO {"STMT_SELECT_WORKING_PRESENT", NULL}
+#define STMT_20 \
"SELECT local_relpath, kind, checksum, translated_size, last_mod_time " \
"FROM nodes n " \
"WHERE wc_id = ?1 " \
@@ -208,25 +220,25 @@
"ORDER BY local_relpath DESC " \
""
-#define STMT_DELETE_NODE_RECURSIVE 20
-#define STMT_20_INFO {"STMT_DELETE_NODE_RECURSIVE", NULL}
-#define STMT_20 \
+#define STMT_DELETE_NODE_RECURSIVE 21
+#define STMT_21_INFO {"STMT_DELETE_NODE_RECURSIVE", NULL}
+#define STMT_21 \
"DELETE FROM NODES " \
"WHERE wc_id = ?1 " \
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
""
-#define STMT_DELETE_NODE 21
-#define STMT_21_INFO {"STMT_DELETE_NODE", NULL}
-#define STMT_21 \
+#define STMT_DELETE_NODE 22
+#define STMT_22_INFO {"STMT_DELETE_NODE", NULL}
+#define STMT_22 \
"DELETE " \
"FROM NODES " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \
""
-#define STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE 22
-#define STMT_22_INFO {"STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE", NULL}
-#define STMT_22 \
+#define STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE 23
+#define STMT_23_INFO {"STMT_DELETE_ACTUAL_FOR_BASE_RECURSIVE", NULL}
+#define STMT_23 \
"DELETE FROM actual_node " \
"WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
" AND EXISTS(SELECT 1 FROM NODES b " \
@@ -240,113 +252,161 @@
" AND presence in ('normal', 'incomplete', 'not-present')) " \
""
-#define STMT_DELETE_WORKING_BASE_DELETE 23
-#define STMT_23_INFO {"STMT_DELETE_WORKING_BASE_DELETE", NULL}
-#define STMT_23 \
+#define STMT_DELETE_WORKING_BASE_DELETE 24
+#define STMT_24_INFO {"STMT_DELETE_WORKING_BASE_DELETE", NULL}
+#define STMT_24 \
"DELETE FROM nodes " \
- "WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
+ "WHERE wc_id = ?1 AND local_relpath = ?2 " \
" AND presence = 'base-deleted' " \
- " AND op_depth > 0 " \
+ " AND op_depth > ?3 " \
" AND op_depth = (SELECT MIN(op_depth) FROM nodes n " \
" WHERE n.wc_id = ?1 " \
" AND n.local_relpath = nodes.local_relpath " \
- " AND op_depth > 0) " \
+ " AND op_depth > ?3) " \
""
-#define STMT_DELETE_WORKING_RECURSIVE 24
-#define STMT_24_INFO {"STMT_DELETE_WORKING_RECURSIVE", NULL}
-#define STMT_24 \
- "DELETE FROM nodes " \
- "WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
- " AND op_depth > 0 " \
- ""
-
-#define STMT_DELETE_BASE_RECURSIVE 25
-#define STMT_25_INFO {"STMT_DELETE_BASE_RECURSIVE", NULL}
+#define STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE 25
+#define STMT_25_INFO {"STMT_DELETE_WORKING_BASE_DELETE_RECURSIVE", NULL}
#define STMT_25 \
"DELETE FROM nodes " \
"WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
- " AND op_depth = 0 " \
+ " AND presence = 'base-deleted' " \
+ " AND op_depth > ?3 " \
+ " AND op_depth = (SELECT MIN(op_depth) FROM nodes n " \
+ " WHERE n.wc_id = ?1 " \
+ " AND n.local_relpath = nodes.local_relpath " \
+ " AND op_depth > ?3) " \
""
-#define STMT_DELETE_WORKING_OP_DEPTH 26
-#define STMT_26_INFO {"STMT_DELETE_WORKING_OP_DEPTH", NULL}
+#define STMT_DELETE_WORKING_RECURSIVE 26
+#define STMT_26_INFO {"STMT_DELETE_WORKING_RECURSIVE", NULL}
#define STMT_26 \
"DELETE FROM nodes " \
- "WHERE wc_id = ?1 " \
- " AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
- " AND op_depth = ?3 " \
+ "WHERE wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
+ " AND op_depth > 0 " \
""
-#define STMT_DELETE_WORKING_OP_DEPTH_ABOVE 27
-#define STMT_27_INFO {"STMT_DELETE_WORKING_OP_DEPTH_ABOVE", NULL}
+#define STMT_DELETE_BASE_RECURSIVE 27
+#define STMT_27_INFO {"STMT_DELETE_BASE_RECURSIVE", NULL}
#define STMT_27 \
"DELETE FROM nodes " \
- "WHERE wc_id = ?1 " \
- " AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
- " AND op_depth > ?3 " \
+ "WHERE wc_id = ?1 AND (local_relpath = ?2 " \
+ " OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
+ " AND op_depth = 0 " \
""
-#define STMT_SELECT_LOCAL_RELPATH_OP_DEPTH 28
-#define STMT_28_INFO {"STMT_SELECT_LOCAL_RELPATH_OP_DEPTH", NULL}
+#define STMT_DELETE_WORKING_OP_DEPTH 28
+#define STMT_28_INFO {"STMT_DELETE_WORKING_OP_DEPTH", NULL}
#define STMT_28 \
- "SELECT local_relpath " \
- "FROM nodes " \
+ "DELETE FROM nodes " \
"WHERE wc_id = ?1 " \
" AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
" AND op_depth = ?3 " \
""
-#define STMT_SELECT_CHILDREN_OP_DEPTH 29
-#define STMT_29_INFO {"STMT_SELECT_CHILDREN_OP_DEPTH", NULL}
+#define STMT_SELECT_LAYER_FOR_REPLACE 29
+#define STMT_29_INFO {"STMT_SELECT_LAYER_FOR_REPLACE", NULL}
#define STMT_29 \
+ "SELECT s.local_relpath, s.kind, " \
+ " (CASE WHEN (?2) = '' THEN (CASE WHEN (?4) = '' THEN (s.local_relpath) WHEN (s.local_relpath) = '' THEN (?4) ELSE (?4) || '/' || (s.local_relpath) END) WHEN (?4) = '' THEN (CASE WHEN (?2) = '' THEN (s.local_relpath) WHEN SUBSTR((s.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(s.local_relpath) THEN '' WHEN SUBSTR((s.local_relpath), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((s.local_relpath), LENGTH(?2)+2) END END) WHEN SUBSTR((s.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(s.local_relpath) THEN (?4) WHEN SUBSTR((s.local_relpath), LENGTH(?2)+1, 1) = '/' THEN (?4) || SUBSTR((s.local_relpath), LENGTH(?2)+1) END END) drp, 'normal' " \
+ "FROM nodes s " \
+ "WHERE s.wc_id = ?1 AND s.local_relpath = ?2 AND s.op_depth = ?3 " \
+ "UNION ALL " \
+ "SELECT s.local_relpath, s.kind, " \
+ " (CASE WHEN (?2) = '' THEN (CASE WHEN (?4) = '' THEN (s.local_relpath) WHEN (s.local_relpath) = '' THEN (?4) ELSE (?4) || '/' || (s.local_relpath) END) WHEN (?4) = '' THEN (CASE WHEN (?2) = '' THEN (s.local_relpath) WHEN SUBSTR((s.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(s.local_relpath) THEN '' WHEN SUBSTR((s.local_relpath), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((s.local_relpath), LENGTH(?2)+2) END END) WHEN SUBSTR((s.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(s.local_relpath) THEN (?4) WHEN SUBSTR((s.local_relpath), LENGTH(?2)+1, 1) = '/' THEN (?4) || SUBSTR((s.local_relpath), LENGTH(?2)+1) END END) drp, d.presence " \
+ "FROM nodes s " \
+ "LEFT OUTER JOIN nodes d ON d.wc_id= ?1 AND d.op_depth = ?5 " \
+ " AND d.local_relpath = drp " \
+ "WHERE s.wc_id = ?1 " \
+ " AND (((s.local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((s.local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
+ " AND s.op_depth = ?3 " \
+ "ORDER BY s.local_relpath " \
+ ""
+
+#define STMT_SELECT_DESCENDANTS_OP_DEPTH_RV 30
+#define STMT_30_INFO {"STMT_SELECT_DESCENDANTS_OP_DEPTH_RV", NULL}
+#define STMT_30 \
"SELECT local_relpath, kind " \
"FROM nodes " \
"WHERE wc_id = ?1 " \
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
" AND op_depth = ?3 " \
+ " AND presence in ('normal', 'incomplete') " \
"ORDER BY local_relpath DESC " \
""
-#define STMT_COPY_NODE_MOVE 30
-#define STMT_30_INFO {"STMT_COPY_NODE_MOVE", NULL}
-#define STMT_30 \
+#define STMT_COPY_NODE_MOVE 31
+#define STMT_31_INFO {"STMT_COPY_NODE_MOVE", NULL}
+#define STMT_31 \
"INSERT OR REPLACE INTO nodes ( " \
" wc_id, local_relpath, op_depth, parent_relpath, repos_id, repos_path, " \
" revision, presence, depth, kind, changed_revision, changed_date, " \
" changed_author, checksum, properties, translated_size, last_mod_time, " \
" symlink_target, moved_here, moved_to ) " \
"SELECT " \
- " wc_id, ?4 , ?5 , ?6 , " \
- " repos_id, " \
- " repos_path, revision, presence, depth, kind, changed_revision, " \
- " changed_date, changed_author, checksum, properties, translated_size, " \
- " last_mod_time, symlink_target, 1, " \
- " (SELECT dst.moved_to FROM nodes AS dst " \
- " WHERE dst.wc_id = ?1 " \
- " AND dst.local_relpath = ?4 " \
- " AND dst.op_depth = ?5) " \
- "FROM nodes " \
- "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \
- ""
-
-#define STMT_SELECT_OP_DEPTH_CHILDREN 31
-#define STMT_31_INFO {"STMT_SELECT_OP_DEPTH_CHILDREN", NULL}
-#define STMT_31 \
+ " s.wc_id, ?4 , ?5 , ?6 , " \
+ " s.repos_id, " \
+ " s.repos_path, s.revision, s.presence, s.depth, s.kind, s.changed_revision, " \
+ " s.changed_date, s.changed_author, s.checksum, s.properties, " \
+ " CASE WHEN d.checksum=s.checksum THEN d.translated_size END, " \
+ " CASE WHEN d.checksum=s.checksum THEN d.last_mod_time END, " \
+ " s.symlink_target, 1, d.moved_to " \
+ "FROM nodes s " \
+ "LEFT JOIN nodes d ON d.wc_id=?1 AND d.local_relpath=?4 AND d.op_depth=?5 " \
+ "WHERE s.wc_id = ?1 AND s.local_relpath = ?2 AND s.op_depth = ?3 " \
+ ""
+
+#define STMT_SELECT_NO_LONGER_MOVED_RV 32
+#define STMT_32_INFO {"STMT_SELECT_NO_LONGER_MOVED_RV", NULL}
+#define STMT_32 \
+ "SELECT d.local_relpath, (CASE WHEN (?2) = '' THEN (CASE WHEN (?4) = '' THEN (d.local_relpath) WHEN (d.local_relpath) = '' THEN (?4) ELSE (?4) || '/' || (d.local_relpath) END) WHEN (?4) = '' THEN (CASE WHEN (?2) = '' THEN (d.local_relpath) WHEN SUBSTR((d.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(d.local_relpath) THEN '' WHEN SUBSTR((d.local_relpath), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((d.local_relpath), LENGTH(?2)+2) END END) WHEN SUBSTR((d.local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(d.local_relpath) THEN (?4) WHEN SUBSTR((d.local_relpath), LENGTH(?2)+1, 1) = '/' THEN (?4) || SUBSTR((d.local_relpath), LENGTH(?2)+1) END END) srp, " \
+ " b.presence, b.op_depth " \
+ "FROM nodes d " \
+ "LEFT OUTER JOIN nodes b ON b.wc_id = ?1 AND b.local_relpath = d.local_relpath " \
+ " AND b.op_depth = (SELECT MAX(x.op_depth) FROM nodes x " \
+ " WHERE x.wc_id = ?1 " \
+ " AND x.local_relpath = b.local_relpath " \
+ " AND x.op_depth < ?3) " \
+ "WHERE d.wc_id = ?1 " \
+ " AND (((d.local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((d.local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
+ " AND d.op_depth = ?3 " \
+ " AND NOT EXISTS(SELECT * FROM nodes s " \
+ " WHERE s.wc_id = ?1 " \
+ " AND s.local_relpath = srp " \
+ " AND s.op_depth = ?5) " \
+ "ORDER BY d.local_relpath DESC " \
+ ""
+
+#define STMT_SELECT_OP_DEPTH_CHILDREN 33
+#define STMT_33_INFO {"STMT_SELECT_OP_DEPTH_CHILDREN", NULL}
+#define STMT_33 \
"SELECT local_relpath, kind FROM nodes " \
"WHERE wc_id = ?1 " \
" AND parent_relpath = ?2 " \
" AND op_depth = ?3 " \
" AND presence != 'base-deleted' " \
" AND file_external is NULL " \
+ "ORDER BY local_relpath " \
""
-#define STMT_SELECT_GE_OP_DEPTH_CHILDREN 32
-#define STMT_32_INFO {"STMT_SELECT_GE_OP_DEPTH_CHILDREN", NULL}
-#define STMT_32 \
+#define STMT_SELECT_OP_DEPTH_CHILDREN_EXISTS 34
+#define STMT_34_INFO {"STMT_SELECT_OP_DEPTH_CHILDREN_EXISTS", NULL}
+#define STMT_34 \
+ "SELECT local_relpath, kind FROM nodes " \
+ "WHERE wc_id = ?1 " \
+ " AND parent_relpath = ?2 " \
+ " AND op_depth = ?3 " \
+ " AND presence IN ('normal', 'incomplete') " \
+ "ORDER BY local_relpath " \
+ ""
+
+#define STMT_SELECT_GE_OP_DEPTH_CHILDREN 35
+#define STMT_35_INFO {"STMT_SELECT_GE_OP_DEPTH_CHILDREN", NULL}
+#define STMT_35 \
"SELECT 1 FROM nodes " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
- " AND (op_depth > ?3 OR (op_depth = ?3 AND presence != 'base-deleted')) " \
+ " AND (op_depth > ?3 OR (op_depth = ?3 " \
+ " AND presence IN ('normal', 'incomplete'))) " \
"UNION ALL " \
"SELECT 1 FROM ACTUAL_NODE a " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
@@ -354,9 +414,9 @@
" WHERE wc_id = ?1 AND n.local_relpath = a.local_relpath) " \
""
-#define STMT_DELETE_SHADOWED_RECURSIVE 33
-#define STMT_33_INFO {"STMT_DELETE_SHADOWED_RECURSIVE", NULL}
-#define STMT_33 \
+#define STMT_DELETE_SHADOWED_RECURSIVE 36
+#define STMT_36_INFO {"STMT_DELETE_SHADOWED_RECURSIVE", NULL}
+#define STMT_36 \
"DELETE FROM nodes " \
"WHERE wc_id = ?1 " \
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
@@ -364,32 +424,33 @@
" OR (op_depth = ?3 AND presence = 'base-deleted')) " \
""
-#define STMT_CLEAR_MOVED_TO_FROM_DEST 34
-#define STMT_34_INFO {"STMT_CLEAR_MOVED_TO_FROM_DEST", NULL}
-#define STMT_34 \
+#define STMT_CLEAR_MOVED_TO_FROM_DEST 37
+#define STMT_37_INFO {"STMT_CLEAR_MOVED_TO_FROM_DEST", NULL}
+#define STMT_37 \
"UPDATE NODES SET moved_to = NULL " \
"WHERE wc_id = ?1 " \
" AND moved_to = ?2 " \
""
-#define STMT_SELECT_NOT_PRESENT_DESCENDANTS 35
-#define STMT_35_INFO {"STMT_SELECT_NOT_PRESENT_DESCENDANTS", NULL}
-#define STMT_35 \
+#define STMT_SELECT_NOT_PRESENT_DESCENDANTS 38
+#define STMT_38_INFO {"STMT_SELECT_NOT_PRESENT_DESCENDANTS", NULL}
+#define STMT_38 \
"SELECT local_relpath FROM nodes " \
"WHERE wc_id = ?1 AND op_depth = ?3 " \
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
" AND presence = 'not-present' " \
""
-#define STMT_COMMIT_DESCENDANTS_TO_BASE 36
-#define STMT_36_INFO {"STMT_COMMIT_DESCENDANTS_TO_BASE", NULL}
-#define STMT_36 \
+#define STMT_COMMIT_DESCENDANTS_TO_BASE 39
+#define STMT_39_INFO {"STMT_COMMIT_DESCENDANTS_TO_BASE", NULL}
+#define STMT_39 \
"UPDATE NODES SET op_depth = 0, " \
" repos_id = ?4, " \
- " repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1), " \
+ " repos_path = (CASE WHEN (?2) = '' THEN (CASE WHEN (?5) = '' THEN (local_relpath) WHEN (local_relpath) = '' THEN (?5) ELSE (?5) || '/' || (local_relpath) END) WHEN (?5) = '' THEN (CASE WHEN (?2) = '' THEN (local_relpath) WHEN SUBSTR((local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(local_relpath) THEN '' WHEN SUBSTR((local_relpath), LENGTH(?2)+1, 1) = '/' THEN SUBSTR((local_relpath), LENGTH(?2)+2) END END) WHEN SUBSTR((local_relpath), 1, LENGTH(?2)) = (?2) THEN CASE WHEN LENGTH(?2) = LENGTH(local_relpath) THEN (?5) WHEN SUBSTR((local_relpath), LENGTH(?2)+1, 1) = '/' THEN (?5) || SUBSTR((local_relpath), LENGTH(?2)+1) END END), " \
" revision = ?6, " \
" dav_cache = NULL, " \
" moved_here = NULL, " \
+ " moved_to = NULL, " \
" presence = CASE presence " \
" WHEN 'normal' THEN 'normal' " \
" WHEN 'excluded' THEN 'excluded' " \
@@ -400,67 +461,78 @@
" AND op_depth = ?3 " \
""
-#define STMT_SELECT_NODE_CHILDREN 37
-#define STMT_37_INFO {"STMT_SELECT_NODE_CHILDREN", NULL}
-#define STMT_37 \
- "SELECT local_relpath FROM nodes " \
+#define STMT_SELECT_NODE_CHILDREN 40
+#define STMT_40_INFO {"STMT_SELECT_NODE_CHILDREN", NULL}
+#define STMT_40 \
+ "SELECT DISTINCT local_relpath FROM nodes " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
+ "ORDER BY local_relpath " \
""
-#define STMT_SELECT_WORKING_CHILDREN 38
-#define STMT_38_INFO {"STMT_SELECT_WORKING_CHILDREN", NULL}
-#define STMT_38 \
- "SELECT local_relpath FROM nodes " \
+#define STMT_SELECT_WORKING_CHILDREN 41
+#define STMT_41_INFO {"STMT_SELECT_WORKING_CHILDREN", NULL}
+#define STMT_41 \
+ "SELECT DISTINCT local_relpath FROM nodes " \
"WHERE wc_id = ?1 AND parent_relpath = ?2 " \
" AND (op_depth > (SELECT MAX(op_depth) FROM nodes " \
" WHERE wc_id = ?1 AND local_relpath = ?2) " \
" OR " \
" (op_depth = (SELECT MAX(op_depth) FROM nodes " \
" WHERE wc_id = ?1 AND local_relpath = ?2) " \
- " AND presence != 'base-deleted')) " \
+ " AND presence IN ('normal', 'incomplete'))) " \
+ "ORDER BY local_relpath " \
""
-#define STMT_SELECT_NODE_PROPS 39
-#define STMT_39_INFO {"STMT_SELECT_NODE_PROPS", NULL}
-#define STMT_39 \
+#define STMT_SELECT_BASE_NOT_PRESENT_CHILDREN 42
+#define STMT_42_INFO {"STMT_SELECT_BASE_NOT_PRESENT_CHILDREN", NULL}
+#define STMT_42 \
+ "SELECT local_relpath FROM nodes " \
+ "WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 " \
+ " AND presence = 'not-present' " \
+ "ORDER BY local_relpath " \
+ ""
+
+#define STMT_SELECT_NODE_PROPS 43
+#define STMT_43_INFO {"STMT_SELECT_NODE_PROPS", NULL}
+#define STMT_43 \
"SELECT properties, presence FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
"ORDER BY op_depth DESC " \
""
-#define STMT_SELECT_ACTUAL_PROPS 40
-#define STMT_40_INFO {"STMT_SELECT_ACTUAL_PROPS", NULL}
-#define STMT_40 \
+#define STMT_SELECT_ACTUAL_PROPS 44
+#define STMT_44_INFO {"STMT_SELECT_ACTUAL_PROPS", NULL}
+#define STMT_44 \
"SELECT properties FROM actual_node " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
""
-#define STMT_UPDATE_ACTUAL_PROPS 41
-#define STMT_41_INFO {"STMT_UPDATE_ACTUAL_PROPS", NULL}
-#define STMT_41 \
+#define STMT_UPDATE_ACTUAL_PROPS 45
+#define STMT_45_INFO {"STMT_UPDATE_ACTUAL_PROPS", NULL}
+#define STMT_45 \
"UPDATE actual_node SET properties = ?3 " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
""
-#define STMT_INSERT_ACTUAL_PROPS 42
-#define STMT_42_INFO {"STMT_INSERT_ACTUAL_PROPS", NULL}
-#define STMT_42 \
+#define STMT_INSERT_ACTUAL_PROPS 46
+#define STMT_46_INFO {"STMT_INSERT_ACTUAL_PROPS", NULL}
+#define STMT_46 \
"INSERT INTO actual_node (wc_id, local_relpath, parent_relpath, properties) " \
"VALUES (?1, ?2, ?3, ?4) " \
""
-#define STMT_INSERT_LOCK 43
-#define STMT_43_INFO {"STMT_INSERT_LOCK", NULL}
-#define STMT_43 \
+#define STMT_INSERT_LOCK 47
+#define STMT_47_INFO {"STMT_INSERT_LOCK", NULL}
+#define STMT_47 \
"INSERT OR REPLACE INTO lock " \
"(repos_id, repos_relpath, lock_token, lock_owner, lock_comment, " \
" lock_date) " \
"VALUES (?1, ?2, ?3, ?4, ?5, ?6) " \
""
-#define STMT_SELECT_BASE_NODE_LOCK_TOKENS_RECURSIVE 44
-#define STMT_44_INFO {"STMT_SELECT_BASE_NODE_LOCK_TOKENS_RECURSIVE", NULL}
-#define STMT_44 \
+#define STMT_SELECT_BASE_NODE_LOCK_TOKENS_RECURSIVE 48
+#define STMT_48_INFO {"STMT_SELECT_BASE_NODE_LOCK_TOKENS_RECURSIVE", NULL}
+#define STMT_48 \
"SELECT nodes.repos_id, nodes.repos_path, lock_token " \
"FROM nodes " \
"LEFT JOIN lock ON nodes.repos_id = lock.repos_id " \
@@ -469,93 +541,73 @@
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
""
-#define STMT_INSERT_WCROOT 45
-#define STMT_45_INFO {"STMT_INSERT_WCROOT", NULL}
-#define STMT_45 \
+#define STMT_INSERT_WCROOT 49
+#define STMT_49_INFO {"STMT_INSERT_WCROOT", NULL}
+#define STMT_49 \
"INSERT INTO wcroot (local_abspath) " \
"VALUES (?1) " \
""
-#define STMT_UPDATE_BASE_NODE_DAV_CACHE 46
-#define STMT_46_INFO {"STMT_UPDATE_BASE_NODE_DAV_CACHE", NULL}
-#define STMT_46 \
+#define STMT_UPDATE_BASE_NODE_DAV_CACHE 50
+#define STMT_50_INFO {"STMT_UPDATE_BASE_NODE_DAV_CACHE", NULL}
+#define STMT_50 \
"UPDATE nodes SET dav_cache = ?3 " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = 0 " \
""
-#define STMT_SELECT_BASE_DAV_CACHE 47
-#define STMT_47_INFO {"STMT_SELECT_BASE_DAV_CACHE", NULL}
-#define STMT_47 \
+#define STMT_SELECT_BASE_DAV_CACHE 51
+#define STMT_51_INFO {"STMT_SELECT_BASE_DAV_CACHE", NULL}
+#define STMT_51 \
"SELECT dav_cache FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = 0 " \
""
-#define STMT_SELECT_DELETION_INFO 48
-#define STMT_48_INFO {"STMT_SELECT_DELETION_INFO", NULL}
-#define STMT_48 \
- "SELECT (SELECT b.presence FROM nodes AS b " \
- " WHERE b.wc_id = ?1 AND b.local_relpath = ?2 AND b.op_depth = 0), " \
- " work.presence, work.op_depth " \
- "FROM nodes_current AS work " \
- "WHERE work.wc_id = ?1 AND work.local_relpath = ?2 AND work.op_depth > 0 " \
- "LIMIT 1 " \
- ""
-
-#define STMT_SELECT_DELETION_INFO_SCAN 49
-#define STMT_49_INFO {"STMT_SELECT_DELETION_INFO_SCAN", NULL}
-#define STMT_49 \
- "SELECT (SELECT b.presence FROM nodes AS b " \
- " WHERE b.wc_id = ?1 AND b.local_relpath = ?2 AND b.op_depth = 0), " \
- " work.presence, work.op_depth, moved.moved_to " \
- "FROM nodes_current AS work " \
- "LEFT OUTER JOIN nodes AS moved " \
- " ON moved.wc_id = work.wc_id " \
- " AND moved.local_relpath = work.local_relpath " \
- " AND moved.moved_to IS NOT NULL " \
- "WHERE work.wc_id = ?1 AND work.local_relpath = ?2 AND work.op_depth > 0 " \
+#define STMT_SELECT_DELETION_INFO 52
+#define STMT_52_INFO {"STMT_SELECT_DELETION_INFO", NULL}
+#define STMT_52 \
+ "SELECT b.presence, w.presence, w.op_depth, w.moved_to " \
+ "FROM nodes w " \
+ "LEFT JOIN nodes b ON b.wc_id = ?1 AND b.local_relpath = ?2 AND b.op_depth = 0 " \
+ "WHERE w.wc_id = ?1 AND w.local_relpath = ?2 " \
+ " AND w.op_depth = (SELECT MAX(op_depth) FROM nodes d " \
+ " WHERE d.wc_id = ?1 AND d.local_relpath = ?2 " \
+ " AND d.op_depth > 0) " \
"LIMIT 1 " \
""
-#define STMT_SELECT_MOVED_TO_NODE 50
-#define STMT_50_INFO {"STMT_SELECT_MOVED_TO_NODE", NULL}
-#define STMT_50 \
+#define STMT_SELECT_MOVED_TO_NODE 53
+#define STMT_53_INFO {"STMT_SELECT_MOVED_TO_NODE", NULL}
+#define STMT_53 \
"SELECT op_depth, moved_to " \
"FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND moved_to IS NOT NULL " \
"ORDER BY op_depth DESC " \
""
-#define STMT_SELECT_OP_DEPTH_MOVED_TO 51
-#define STMT_51_INFO {"STMT_SELECT_OP_DEPTH_MOVED_TO", NULL}
-#define STMT_51 \
- "SELECT op_depth, moved_to, repos_path, revision " \
+#define STMT_SELECT_OP_DEPTH_MOVED_TO 54
+#define STMT_54_INFO {"STMT_SELECT_OP_DEPTH_MOVED_TO", NULL}
+#define STMT_54 \
+ "SELECT op_depth, moved_to " \
"FROM nodes " \
- "WHERE wc_id = ?1 AND local_relpath = ?2 " \
- " AND op_depth <= (SELECT MIN(op_depth) FROM nodes " \
- " WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3) " \
- "ORDER BY op_depth DESC " \
+ "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3 " \
+ " AND EXISTS(SELECT * from nodes " \
+ " WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \
+ " AND presence IN ('normal', 'incomplete')) " \
+ "ORDER BY op_depth ASC " \
+ "LIMIT 1 " \
""
-#define STMT_SELECT_MOVED_TO 52
-#define STMT_52_INFO {"STMT_SELECT_MOVED_TO", NULL}
-#define STMT_52 \
+#define STMT_SELECT_MOVED_TO 55
+#define STMT_55_INFO {"STMT_SELECT_MOVED_TO", NULL}
+#define STMT_55 \
"SELECT moved_to " \
"FROM nodes " \
"WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 " \
""
-#define STMT_SELECT_MOVED_HERE 53
-#define STMT_53_INFO {"STMT_SELECT_MOVED_HERE", NULL}
-#define STMT_53 \
- "SELECT moved_here, presence, repos_path, revision " \
- "FROM nodes " \
- "WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth >= ?3 " \
- "ORDER BY op_depth " \
- ""
-
-#define STMT_SELECT_MOVED_BACK 54
-#define STMT_54_INFO {"STMT_SELECT_MOVED_BACK", NULL}
-#define STMT_54 \
+#define STMT_SELECT_MOVED_BACK 56
+#define STMT_56_INFO {"STMT_SELECT_MOVED_BACK", NULL}
+#define STMT_56 \
"SELECT u.local_relpath, " \
" u.presence, u.repos_id, u.repos_path, u.revision, " \
" l.presence, l.repos_id, l.repos_path, l.revision, " \
@@ -581,81 +633,71 @@
" AND u.op_depth = ?4 " \
""
-#define STMT_DELETE_MOVED_BACK 55
-#define STMT_55_INFO {"STMT_DELETE_MOVED_BACK", NULL}
-#define STMT_55 \
- "DELETE FROM nodes " \
- "WHERE wc_id = ?1 " \
- " AND (local_relpath = ?2 " \
- " OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
- " AND op_depth = ?3 " \
- ""
-
-#define STMT_DELETE_LOCK 56
-#define STMT_56_INFO {"STMT_DELETE_LOCK", NULL}
-#define STMT_56 \
+#define STMT_DELETE_LOCK 57
+#define STMT_57_INFO {"STMT_DELETE_LOCK", NULL}
+#define STMT_57 \
"DELETE FROM lock " \
"WHERE repos_id = ?1 AND repos_relpath = ?2 " \
""
-#define STMT_DELETE_LOCK_RECURSIVELY 57
-#define STMT_57_INFO {"STMT_DELETE_LOCK_RECURSIVELY", NULL}
-#define STMT_57 \
+#define STMT_DELETE_LOCK_RECURSIVELY 58
+#define STMT_58_INFO {"STMT_DELETE_LOCK_RECURSIVELY", NULL}
+#define STMT_58 \
"DELETE FROM lock " \
"WHERE repos_id = ?1 AND (repos_relpath = ?2 OR (((repos_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((repos_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
""
-#define STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE 58
-#define STMT_58_INFO {"STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE", NULL}
-#define STMT_58 \
+#define STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE 59
+#define STMT_59_INFO {"STMT_CLEAR_BASE_NODE_RECURSIVE_DAV_CACHE", NULL}
+#define STMT_59 \
"UPDATE nodes SET dav_cache = NULL " \
"WHERE dav_cache IS NOT NULL AND wc_id = ?1 AND op_depth = 0 " \
" AND (local_relpath = ?2 " \
" OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
""
-#define STMT_RECURSIVE_UPDATE_NODE_REPO 59
-#define STMT_59_INFO {"STMT_RECURSIVE_UPDATE_NODE_REPO", NULL}
-#define STMT_59 \
+#define STMT_RECURSIVE_UPDATE_NODE_REPO 60
+#define STMT_60_INFO {"STMT_RECURSIVE_UPDATE_NODE_REPO", NULL}
+#define STMT_60 \
"UPDATE nodes SET repos_id = ?4, dav_cache = NULL " \
"WHERE (wc_id = ?1 AND local_relpath = ?2 AND repos_id = ?3) " \
" OR (wc_id = ?1 AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
" AND repos_id = ?3) " \
""
-#define STMT_UPDATE_LOCK_REPOS_ID 60
-#define STMT_60_INFO {"STMT_UPDATE_LOCK_REPOS_ID", NULL}
-#define STMT_60 \
+#define STMT_UPDATE_LOCK_REPOS_ID 61
+#define STMT_61_INFO {"STMT_UPDATE_LOCK_REPOS_ID", NULL}
+#define STMT_61 \
"UPDATE lock SET repos_id = ?2 " \
"WHERE repos_id = ?1 " \
""
-#define STMT_UPDATE_NODE_FILEINFO 61
-#define STMT_61_INFO {"STMT_UPDATE_NODE_FILEINFO", NULL}
-#define STMT_61 \
+#define STMT_UPDATE_NODE_FILEINFO 62
+#define STMT_62_INFO {"STMT_UPDATE_NODE_FILEINFO", NULL}
+#define STMT_62 \
"UPDATE nodes SET translated_size = ?3, last_mod_time = ?4 " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
" AND op_depth = (SELECT MAX(op_depth) FROM nodes " \
" WHERE wc_id = ?1 AND local_relpath = ?2) " \
""
-#define STMT_INSERT_ACTUAL_CONFLICT 62
-#define STMT_62_INFO {"STMT_INSERT_ACTUAL_CONFLICT", NULL}
-#define STMT_62 \
+#define STMT_INSERT_ACTUAL_CONFLICT 63
+#define STMT_63_INFO {"STMT_INSERT_ACTUAL_CONFLICT", NULL}
+#define STMT_63 \
"INSERT INTO actual_node (wc_id, local_relpath, conflict_data, parent_relpath) " \
"VALUES (?1, ?2, ?3, ?4) " \
""
-#define STMT_UPDATE_ACTUAL_CONFLICT 63
-#define STMT_63_INFO {"STMT_UPDATE_ACTUAL_CONFLICT", NULL}
-#define STMT_63 \
+#define STMT_UPDATE_ACTUAL_CONFLICT 64
+#define STMT_64_INFO {"STMT_UPDATE_ACTUAL_CONFLICT", NULL}
+#define STMT_64 \
"UPDATE actual_node SET conflict_data = ?3 " \
"WHERE wc_id = ?1 AND local_relpath = ?2 " \
""
-#define STMT_UPDATE_ACTUAL_CHANGELISTS 64
-#define STMT_64_INFO {"STMT_UPDATE_ACTUAL_CHANGELISTS", NULL}
-#define STMT_64 \
+#define STMT_UPDATE_ACTUAL_CHANGELISTS 65
+#define STMT_65_INFO {"STMT_UPDATE_ACTUAL_CHANGELISTS", NULL}
+#define STMT_65 \
"UPDATE actual_node SET changelist = ?3 " \
"WHERE wc_id = ?1 " \
" AND (local_relpath = ?2 OR (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END))) " \
@@ -665,16 +707,16 @@
" AND kind = 'file') " \
""
-#define STMT_UPDATE_ACTUAL_CLEAR_CHANGELIST 65
-#define STMT_65_INFO {"STMT_UPDATE_ACTUAL_CLEAR_CHANGELIST", NULL}
-#define STMT_65 \
+#define STMT_UPDATE_ACTUAL_CLEAR_CHANGELIST 66
+#define STMT_66_INFO {"STMT_UPDATE_ACTUAL_CLEAR_CHANGELIST", NULL}
+#define STMT_66 \
"UPDATE actual_node SET changelist = NULL " \
" WHERE wc_id = ?1 AND local_relpath = ?2 " \
""
-#define STMT_MARK_SKIPPED_CHANGELIST_DIRS 66
-#define STMT_66_INFO {"STMT_MARK_SKIPPED_CHANGELIST_DIRS", NULL}
-#define STMT_66 \
+#define STMT_MARK_SKIPPED_CHANGELIST_DIRS 67
+#define STMT_67_INFO {"STMT_MARK_SKIPPED_CHANGELIST_DIRS", NULL}
+#define STMT_67 \
"INSERT INTO changelist_list (wc_id, local_relpath, notify, changelist) " \
"SELECT wc_id, local_relpath, 7, ?3 " \
"FROM targets_list " \
@@ -683,17 +725,17 @@
" AND kind = 'dir' " \
""
-#define STMT_RESET_ACTUAL_WITH_CHANGELIST 67
-#define STMT_67_INFO {"STMT_RESET_ACTUAL_WITH_CHANGELIST", NULL}
-#define STMT_67 \
+#define STMT_RESET_ACTUAL_WITH_CHANGELIST 68
+#define STMT_68_INFO {"STMT_RESET_ACTUAL_WITH_CHANGELIST", NULL}
+#define STMT_68 \
"REPLACE INTO actual_node ( " \
" wc_id, local_relpath, parent_relpath, changelist) " \
"VALUES (?1, ?2, ?3, ?4) " \
""
-#define STMT_CREATE_CHANGELIST_LIST 68
-#define STMT_68_INFO {"STMT_CREATE_CHANGELIST_LIST", NULL}
-#define STMT_68 \
+#define STMT_CREATE_CHANGELIST_LIST 69
+#define STMT_69_INFO {"STMT_CREATE_CHANGELIST_LIST", NULL}
+#define STMT_69 \
"DROP TABLE IF EXISTS changelist_list; " \
"CREATE TEMPORARY TABLE changelist_list ( " \
" wc_id INTEGER NOT NULL, " \
@@ -704,9 +746,9 @@
") " \
""
-#define STMT_CREATE_CHANGELIST_TRIGGER 69
-#define STMT_69_INFO {"STMT_CREATE_CHANGELIST_TRIGGER", NULL}
-#define STMT_69 \
+#define STMT_CREATE_CHANGELIST_TRIGGER 70
+#define STMT_70_INFO {"STMT_CREATE_CHANGELIST_TRIGGER", NULL}
+#define STMT_70 \
"DROP TRIGGER IF EXISTS trigger_changelist_list_change; " \
"CREATE TEMPORARY TRIGGER trigger_changelist_list_change " \
"BEFORE UPDATE ON actual_node " \
@@ -721,25 +763,25 @@
"END " \
""
-#define STMT_FINALIZE_CHANGELIST 70
-#define STMT_70_INFO {"STMT_FINALIZE_CHANGELIST", NULL}
-#define STMT_70 \
+#define STMT_FINALIZE_CHANGELIST 71
+#define STMT_71_INFO {"STMT_FINALIZE_CHANGELIST", NULL}
+#define STMT_71 \
"DROP TRIGGER trigger_changelist_list_change; " \
"DROP TABLE changelist_list; " \
"DROP TABLE targets_list " \
""
-#define STMT_SELECT_CHANGELIST_LIST 71
-#define STMT_71_INFO {"STMT_SELECT_CHANGELIST_LIST", NULL}
-#define STMT_71 \
+#define STMT_SELECT_CHANGELIST_LIST 72
+#define STMT_72_INFO {"STMT_SELECT_CHANGELIST_LIST", NULL}
+#define STMT_72 \
"SELECT wc_id, local_relpath, notify, changelist " \
"FROM changelist_list " \
"ORDER BY wc_id, local_relpath ASC, notify DESC " \
""
-#define STMT_CREATE_TARGETS_LIST 72
-#define STMT_72_INFO {"STMT_CREATE_TARGETS_LIST", NULL}
-#define STMT_72 \
+#define STMT_CREATE_TARGETS_LIST 73
+#define STMT_73_INFO {"STMT_CREATE_TARGETS_LIST", NULL}
+#define STMT_73 \
"DROP TABLE IF EXISTS targets_list; " \
"CREATE TEMPORARY TABLE targets_list ( " \
" wc_id INTEGER NOT NULL, " \
@@ -750,15 +792,15 @@
" ); " \
""
-#define STMT_DROP_TARGETS_LIST 73
-#define STMT_73_INFO {"STMT_DROP_TARGETS_LIST", NULL}
-#define STMT_73 \
+#define STMT_DROP_TARGETS_LIST 74
+#define STMT_74_INFO {"STMT_DROP_TARGETS_LIST", NULL}
+#define STMT_74 \
"DROP TABLE targets_list " \
""
-#define STMT_INSERT_TARGET 74
-#define STMT_74_INFO {"STMT_INSERT_TARGET", NULL}
-#define STMT_74 \
+#define STMT_INSERT_TARGET 75
+#define STMT_75_INFO {"STMT_INSERT_TARGET", NULL}
+#define STMT_75 \
"INSERT INTO targets_list(wc_id, local_relpath, parent_relpath, kind) " \
"SELECT wc_id, local_relpath, parent_relpath, kind " \
"FROM nodes_current " \
@@ -766,9 +808,9 @@
" AND local_relpath = ?2 " \
""
-#define STMT_INSERT_TARGET_DEPTH_FILES 75
-#define STMT_75_INFO {"STMT_INSERT_TARGET_DEPTH_FILES", NULL}
-#define STMT_75 \
+#define STMT_INSERT_TARGET_DEPTH_FILES 76
+#define STMT_76_INFO {"STMT_INSERT_TARGET_DEPTH_FILES", NULL}
+#define STMT_76 \
"INSERT INTO targets_list(wc_id, local_relpath, parent_relpath, kind) " \
"SELECT wc_id, local_relpath, parent_relpath, kind " \
"FROM nodes_current " \
@@ -777,9 +819,9 @@
" AND kind = 'file' " \
""
-#define STMT_INSERT_TARGET_DEPTH_IMMEDIATES 76
-#define STMT_76_INFO {"STMT_INSERT_TARGET_DEPTH_IMMEDIATES", NULL}
-#define STMT_76 \
+#define STMT_INSERT_TARGET_DEPTH_IMMEDIATES 77
+#define STMT_77_INFO {"STMT_INSERT_TARGET_DEPTH_IMMEDIATES", NULL}
+#define STMT_77 \
"INSERT INTO targets_list(wc_id, local_relpath, parent_relpath, kind) " \
"SELECT wc_id, local_relpath, parent_relpath, kind " \
"FROM nodes_current " \
@@ -787,9 +829,9 @@
" AND parent_relpath = ?2 " \
""
-#define STMT_INSERT_TARGET_DEPTH_INFINITY 77
-#define STMT_77_INFO {"STMT_INSERT_TARGET_DEPTH_INFINITY", NULL}
-#define STMT_77 \
+#define STMT_INSERT_TARGET_DEPTH_INFINITY 78
+#define STMT_78_INFO {"STMT_INSERT_TARGET_DEPTH_INFINITY", NULL}
+#define STMT_78 \
"INSERT INTO targets_list(wc_id, local_relpath, parent_relpath, kind) " \
"SELECT wc_id, local_relpath, parent_relpath, kind " \
"FROM nodes_current " \
@@ -797,9 +839,9 @@
" AND (((local_relpath) > (CASE (?2) WHEN '' THEN '' ELSE (?2) || '/' END)) AND ((local_relpath) < CASE (?2) WHEN '' THEN X'FFFF' ELSE (?2) || '0' END)) " \
""
-#define STMT_INSERT_TARGET_WITH_CHANGELIST 78
-#define STMT_78_INFO {"STMT_INSERT_TARGET_WITH_CHANGELIST", NULL}
-#define STMT_78 \
+#define STMT_INSERT_TARGET_WITH_CHANGELIST 79
+#define STMT_79_INFO {"STMT_INSERT_TARGET_WITH_CHANGELIST", NULL}
+#define STMT_79 \
"INSERT INTO targets_list(wc_id