summaryrefslogtreecommitdiff
path: root/subversion/libsvn_client/copy.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_client/copy.c')
-rw-r--r--subversion/libsvn_client/copy.c1049
1 files changed, 530 insertions, 519 deletions
diff --git a/subversion/libsvn_client/copy.c b/subversion/libsvn_client/copy.c
index 4efadd2..f204bbc 100644
--- a/subversion/libsvn_client/copy.c
+++ b/subversion/libsvn_client/copy.c
@@ -28,6 +28,7 @@
/*** Includes. ***/
#include <string.h>
+#include "svn_hash.h"
#include "svn_client.h"
#include "svn_error.h"
#include "svn_error_codes.h"
@@ -44,7 +45,9 @@
#include "svn_private_config.h"
#include "private/svn_wc_private.h"
+#include "private/svn_ra_private.h"
#include "private/svn_mergeinfo_private.h"
+#include "private/svn_client_private.h"
/*
@@ -68,71 +71,6 @@
/*** Code. ***/
-/* Obtain the implied mergeinfo and the existing mergeinfo of the
- source path, combine them and return the result in
- *TARGET_MERGEINFO. One of LOCAL_ABSPATH and SRC_URL must be valid,
- the other must be NULL. */
-static svn_error_t *
-calculate_target_mergeinfo(svn_ra_session_t *ra_session,
- apr_hash_t **target_mergeinfo,
- const char *local_abspath,
- const char *src_url,
- svn_revnum_t src_revnum,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
-{
- svn_boolean_t locally_added = FALSE;
- apr_hash_t *src_mergeinfo = NULL;
-
- SVN_ERR_ASSERT((local_abspath && !src_url) || (!local_abspath && src_url));
-
- /* If we have a schedule-add WC path (which was not copied from
- elsewhere), it doesn't have any repository mergeinfo, so don't
- bother checking. */
- if (local_abspath)
- {
- const char *repos_root_url;
- const char *repos_relpath;
-
- SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
-
- SVN_ERR(svn_wc__node_get_origin(NULL, &src_revnum,
- &repos_relpath, &repos_root_url,
- NULL, NULL,
- ctx->wc_ctx, local_abspath, FALSE,
- pool, pool));
-
- if (repos_relpath)
- {
- src_url = svn_path_url_add_component2(repos_root_url, repos_relpath,
- pool);
- }
- else
- locally_added = TRUE;
- }
-
- if (! locally_added)
- {
- /* Fetch any existing (explicit) mergeinfo. We'll temporarily
- reparent to the target URL here, just to keep the code simple.
- We could, as an alternative, first see if the target URL was a
- child of the session URL and use the relative "remainder",
- falling back to this reparenting as necessary. */
- const char *old_session_url = NULL;
- SVN_ERR(svn_client__ensure_ra_session_url(&old_session_url,
- ra_session, src_url, pool));
- SVN_ERR(svn_client__get_repos_mergeinfo(ra_session, &src_mergeinfo,
- "", src_revnum,
- svn_mergeinfo_inherited,
- TRUE, pool));
- if (old_session_url)
- SVN_ERR(svn_ra_reparent(ra_session, old_session_url, pool));
- }
-
- *target_mergeinfo = src_mergeinfo;
- return SVN_NO_ERROR;
-}
-
/* Extend the mergeinfo for the single WC path TARGET_WCPATH, adding
MERGEINFO to any mergeinfo pre-existing in the WC. */
static svn_error_t *
@@ -150,7 +88,7 @@ extend_wc_mergeinfo(const char *target_abspath,
/* Combine the provided mergeinfo with any mergeinfo from the WC. */
if (wc_mergeinfo && mergeinfo)
- SVN_ERR(svn_mergeinfo_merge(wc_mergeinfo, mergeinfo, pool));
+ SVN_ERR(svn_mergeinfo_merge2(wc_mergeinfo, mergeinfo, pool, pool));
else if (! wc_mergeinfo)
wc_mergeinfo = mergeinfo;
@@ -240,47 +178,42 @@ get_copy_pair_ancestors(const apr_array_header_t *copy_pairs,
}
-struct do_wc_to_wc_copies_with_write_lock_baton {
- const apr_array_header_t *copy_pairs;
- svn_client_ctx_t *ctx;
- const char *dst_parent;
-};
-
/* The guts of do_wc_to_wc_copies */
static svn_error_t *
-do_wc_to_wc_copies_with_write_lock(void *baton,
- apr_pool_t *result_pool,
+do_wc_to_wc_copies_with_write_lock(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *copy_pairs,
+ const char *dst_parent,
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
- struct do_wc_to_wc_copies_with_write_lock_baton *b = baton;
int i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_error_t *err = SVN_NO_ERROR;
- for (i = 0; i < b->copy_pairs->nelts; i++)
+ for (i = 0; i < copy_pairs->nelts; i++)
{
const char *dst_abspath;
- svn_client__copy_pair_t *pair = APR_ARRAY_IDX(b->copy_pairs, i,
+ svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
svn_pool_clear(iterpool);
/* Check for cancellation */
- if (b->ctx->cancel_func)
- SVN_ERR(b->ctx->cancel_func(b->ctx->cancel_baton));
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
/* Perform the copy */
dst_abspath = svn_dirent_join(pair->dst_parent_abspath, pair->base_name,
iterpool);
- err = svn_wc_copy3(b->ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath,
+ *timestamp_sleep = TRUE;
+ err = svn_wc_copy3(ctx->wc_ctx, pair->src_abspath_or_url, dst_abspath,
FALSE /* metadata_only */,
- b->ctx->cancel_func, b->ctx->cancel_baton,
- b->ctx->notify_func2, b->ctx->notify_baton2, iterpool);
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2, iterpool);
if (err)
break;
}
svn_pool_destroy(iterpool);
- svn_io_sleep_for_timestamps(b->dst_parent, scratch_pool);
SVN_ERR(err);
return SVN_NO_ERROR;
}
@@ -288,12 +221,12 @@ do_wc_to_wc_copies_with_write_lock(void *baton,
/* Copy each COPY_PAIR->SRC into COPY_PAIR->DST. Use POOL for temporary
allocations. */
static svn_error_t *
-do_wc_to_wc_copies(const apr_array_header_t *copy_pairs,
+do_wc_to_wc_copies(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *copy_pairs,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
const char *dst_parent, *dst_parent_abspath;
- struct do_wc_to_wc_copies_with_write_lock_baton baton;
SVN_ERR(get_copy_pair_ancestors(copy_pairs, NULL, &dst_parent, NULL, pool));
if (copy_pairs->nelts == 1)
@@ -301,59 +234,63 @@ do_wc_to_wc_copies(const apr_array_header_t *copy_pairs,
SVN_ERR(svn_dirent_get_absolute(&dst_parent_abspath, dst_parent, pool));
- baton.copy_pairs = copy_pairs;
- baton.ctx = ctx;
- baton.dst_parent = dst_parent;
- SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_copies_with_write_lock,
- &baton, ctx->wc_ctx, dst_parent_abspath,
- FALSE, pool, pool));
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ do_wc_to_wc_copies_with_write_lock(timestamp_sleep, copy_pairs, dst_parent,
+ ctx, pool),
+ ctx->wc_ctx, dst_parent_abspath, FALSE, pool);
return SVN_NO_ERROR;
}
-struct do_wc_to_wc_moves_with_locks_baton {
- svn_client_ctx_t *ctx;
- svn_client__copy_pair_t *pair;
- const char *dst_parent_abspath;
- svn_boolean_t lock_src;
- svn_boolean_t lock_dst;
-};
-
/* The locked bit of do_wc_to_wc_moves. */
static svn_error_t *
-do_wc_to_wc_moves_with_locks2(void *baton,
- apr_pool_t *result_pool,
+do_wc_to_wc_moves_with_locks2(svn_client__copy_pair_t *pair,
+ const char *dst_parent_abspath,
+ svn_boolean_t lock_src,
+ svn_boolean_t lock_dst,
+ svn_boolean_t allow_mixed_revisions,
+ svn_boolean_t metadata_only,
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
- struct do_wc_to_wc_moves_with_locks_baton *b = baton;
const char *dst_abspath;
- dst_abspath = svn_dirent_join(b->dst_parent_abspath, b->pair->base_name,
+ dst_abspath = svn_dirent_join(dst_parent_abspath, pair->base_name,
scratch_pool);
- SVN_ERR(svn_wc_move(b->ctx->wc_ctx, b->pair->src_abspath_or_url,
- dst_abspath, FALSE /* metadata_only */,
- b->ctx->cancel_func, b->ctx->cancel_baton,
- b->ctx->notify_func2, b->ctx->notify_baton2,
- scratch_pool));
+ SVN_ERR(svn_wc__move2(ctx->wc_ctx, pair->src_abspath_or_url,
+ dst_abspath, metadata_only,
+ allow_mixed_revisions,
+ ctx->cancel_func, ctx->cancel_baton,
+ ctx->notify_func2, ctx->notify_baton2,
+ scratch_pool));
return SVN_NO_ERROR;
}
/* Wrapper to add an optional second lock */
static svn_error_t *
-do_wc_to_wc_moves_with_locks1(void *baton,
- apr_pool_t *result_pool,
+do_wc_to_wc_moves_with_locks1(svn_client__copy_pair_t *pair,
+ const char *dst_parent_abspath,
+ svn_boolean_t lock_src,
+ svn_boolean_t lock_dst,
+ svn_boolean_t allow_mixed_revisions,
+ svn_boolean_t metadata_only,
+ svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
- struct do_wc_to_wc_moves_with_locks_baton *b = baton;
-
- if (b->lock_dst)
- SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks2, b,
- b->ctx->wc_ctx, b->dst_parent_abspath,
- FALSE, result_pool, scratch_pool));
+ if (lock_dst)
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src,
+ lock_dst, allow_mixed_revisions,
+ metadata_only,
+ ctx, scratch_pool),
+ ctx->wc_ctx, dst_parent_abspath, FALSE, scratch_pool);
else
- SVN_ERR(do_wc_to_wc_moves_with_locks2(b, result_pool, scratch_pool));
+ SVN_ERR(do_wc_to_wc_moves_with_locks2(pair, dst_parent_abspath, lock_src,
+ lock_dst, allow_mixed_revisions,
+ metadata_only,
+ ctx, scratch_pool));
return SVN_NO_ERROR;
}
@@ -361,8 +298,11 @@ do_wc_to_wc_moves_with_locks1(void *baton,
/* Move each COPY_PAIR->SRC into COPY_PAIR->DST, deleting COPY_PAIR->SRC
afterwards. Use POOL for temporary allocations. */
static svn_error_t *
-do_wc_to_wc_moves(const apr_array_header_t *copy_pairs,
+do_wc_to_wc_moves(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *copy_pairs,
const char *dst_path,
+ svn_boolean_t allow_mixed_revisions,
+ svn_boolean_t metadata_only,
svn_client_ctx_t *ctx,
apr_pool_t *pool)
{
@@ -373,7 +313,9 @@ do_wc_to_wc_moves(const apr_array_header_t *copy_pairs,
for (i = 0; i < copy_pairs->nelts; i++)
{
const char *src_parent_abspath;
- struct do_wc_to_wc_moves_with_locks_baton baton;
+ svn_boolean_t lock_src, lock_dst;
+ const char *src_wcroot_abspath;
+ const char *dst_wcroot_abspath;
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
@@ -386,6 +328,13 @@ do_wc_to_wc_moves(const apr_array_header_t *copy_pairs,
src_parent_abspath = svn_dirent_dirname(pair->src_abspath_or_url,
iterpool);
+ SVN_ERR(svn_wc__get_wcroot(&src_wcroot_abspath,
+ ctx->wc_ctx, src_parent_abspath,
+ iterpool, iterpool));
+ SVN_ERR(svn_wc__get_wcroot(&dst_wcroot_abspath,
+ ctx->wc_ctx, pair->dst_parent_abspath,
+ iterpool, iterpool));
+
/* We now need to lock the right combination of batons.
Four cases:
1) src_parent == dst_parent
@@ -394,56 +343,69 @@ do_wc_to_wc_moves(const apr_array_header_t *copy_pairs,
4) src_parent and dst_parent are disjoint
We can handle 1) as either 2) or 3) */
if (strcmp(src_parent_abspath, pair->dst_parent_abspath) == 0
- || svn_dirent_is_child(src_parent_abspath, pair->dst_parent_abspath,
- iterpool))
+ || (svn_dirent_is_child(src_parent_abspath, pair->dst_parent_abspath,
+ NULL)
+ && !svn_dirent_is_child(src_parent_abspath, dst_wcroot_abspath,
+ NULL)))
{
- baton.lock_src = TRUE;
- baton.lock_dst = FALSE;
+ lock_src = TRUE;
+ lock_dst = FALSE;
}
- else if (svn_dirent_is_child(pair->dst_parent_abspath, src_parent_abspath,
- iterpool))
+ else if (svn_dirent_is_child(pair->dst_parent_abspath,
+ src_parent_abspath, NULL)
+ && !svn_dirent_is_child(pair->dst_parent_abspath,
+ src_wcroot_abspath, NULL))
{
- baton.lock_src = FALSE;
- baton.lock_dst = TRUE;
+ lock_src = FALSE;
+ lock_dst = TRUE;
}
else
{
- baton.lock_src = TRUE;
- baton.lock_dst = TRUE;
+ lock_src = TRUE;
+ lock_dst = TRUE;
}
+ *timestamp_sleep = TRUE;
+
/* Perform the copy and then the delete. */
- baton.ctx = ctx;
- baton.pair = pair;
- baton.dst_parent_abspath = pair->dst_parent_abspath;
- if (baton.lock_src)
- SVN_ERR(svn_wc__call_with_write_lock(do_wc_to_wc_moves_with_locks1,
- &baton,
- ctx->wc_ctx, src_parent_abspath,
- FALSE, iterpool, iterpool));
+ if (lock_src)
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath,
+ lock_src, lock_dst,
+ allow_mixed_revisions,
+ metadata_only,
+ ctx, iterpool),
+ ctx->wc_ctx, src_parent_abspath,
+ FALSE, iterpool);
else
- SVN_ERR(do_wc_to_wc_moves_with_locks1(&baton, iterpool, iterpool));
+ SVN_ERR(do_wc_to_wc_moves_with_locks1(pair, pair->dst_parent_abspath,
+ lock_src, lock_dst,
+ allow_mixed_revisions,
+ metadata_only,
+ ctx, iterpool));
}
svn_pool_destroy(iterpool);
- svn_io_sleep_for_timestamps(dst_path, pool);
-
return svn_error_trace(err);
}
-
+/* Verify that the destinations stored in COPY_PAIRS are valid working copy
+ destinations and set pair->dst_parent_abspath and pair->base_name for each
+ item to the resulting location if they do */
static svn_error_t *
-verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
- svn_boolean_t make_parents,
- svn_boolean_t is_move,
- svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+verify_wc_dsts(const apr_array_header_t *copy_pairs,
+ svn_boolean_t make_parents,
+ svn_boolean_t is_move,
+ svn_boolean_t metadata_only,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
int i;
- apr_pool_t *iterpool = svn_pool_create(pool);
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- /* Check that all of our SRCs exist, and all the DSTs don't. */
+ /* Check that DST does not exist, but its parent does */
for (i = 0; i < copy_pairs->nelts; i++)
{
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
@@ -452,22 +414,48 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
svn_pool_clear(iterpool);
- /* Verify that SRC_PATH exists. */
- SVN_ERR(svn_io_check_path(pair->src_abspath_or_url, &pair->src_kind,
- iterpool));
- if (pair->src_kind == svn_node_none)
- return svn_error_createf(
- SVN_ERR_NODE_UNKNOWN_KIND, NULL,
- _("Path '%s' does not exist"),
- svn_dirent_local_style(pair->src_abspath_or_url, pool));
-
/* If DST_PATH does not exist, then its basename will become a new
file or dir added to its parent (possibly an implicit '.').
Else, just error out. */
- SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind,
+ SVN_ERR(svn_wc_read_kind2(&dst_kind, ctx->wc_ctx,
+ pair->dst_abspath_or_url,
+ FALSE /* show_deleted */,
+ TRUE /* show_hidden */,
iterpool));
if (dst_kind != svn_node_none)
{
+ svn_boolean_t is_excluded;
+ svn_boolean_t is_server_excluded;
+
+ SVN_ERR(svn_wc__node_is_not_present(NULL, &is_excluded,
+ &is_server_excluded, ctx->wc_ctx,
+ pair->dst_abspath_or_url, FALSE,
+ iterpool));
+
+ if (is_excluded || is_server_excluded)
+ {
+ return svn_error_createf(
+ SVN_ERR_WC_OBSTRUCTED_UPDATE,
+ NULL, _("Path '%s' exists, but is excluded"),
+ svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
+ }
+ else
+ return svn_error_createf(
+ SVN_ERR_ENTRY_EXISTS, NULL,
+ _("Path '%s' already exists"),
+ svn_dirent_local_style(pair->dst_abspath_or_url,
+ scratch_pool));
+ }
+
+ /* Check that there is no unversioned obstruction */
+ if (metadata_only)
+ dst_kind = svn_node_none;
+ else
+ SVN_ERR(svn_io_check_path(pair->dst_abspath_or_url, &dst_kind,
+ iterpool));
+
+ if (dst_kind != svn_node_none)
+ {
if (is_move
&& copy_pairs->nelts == 1
&& strcmp(svn_dirent_dirname(pair->src_abspath_or_url, iterpool),
@@ -483,7 +471,7 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
SVN_ERR(svn_path_cstring_from_utf8(&dst,
pair->dst_abspath_or_url,
- pool));
+ scratch_pool));
apr_err = apr_filepath_merge(&dst_apr, NULL, dst,
APR_FILEPATH_TRUENAME, iterpool);
@@ -500,7 +488,7 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
{
/* Ok, we have a single case only rename. Get out of here */
svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
- pair->dst_abspath_or_url, pool);
+ pair->dst_abspath_or_url, result_pool);
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
@@ -508,17 +496,20 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
}
return svn_error_createf(
- SVN_ERR_ENTRY_EXISTS, NULL,
- _("Path '%s' already exists"),
- svn_dirent_local_style(pair->dst_abspath_or_url, pool));
+ SVN_ERR_ENTRY_EXISTS, NULL,
+ _("Path '%s' already exists as unversioned node"),
+ svn_dirent_local_style(pair->dst_abspath_or_url,
+ scratch_pool));
}
svn_dirent_split(&pair->dst_parent_abspath, &pair->base_name,
- pair->dst_abspath_or_url, pool);
+ pair->dst_abspath_or_url, result_pool);
/* Make sure the destination parent is a directory and produce a clear
error message if it is not. */
- SVN_ERR(svn_io_check_path(pair->dst_parent_abspath, &dst_parent_kind,
+ SVN_ERR(svn_wc_read_kind2(&dst_parent_kind,
+ ctx->wc_ctx, pair->dst_parent_abspath,
+ FALSE, TRUE,
iterpool));
if (make_parents && dst_parent_kind == svn_node_none)
{
@@ -527,11 +518,20 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
}
else if (dst_parent_kind != svn_node_dir)
{
- return svn_error_createf(SVN_ERR_WC_NOT_WORKING_COPY, NULL,
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
_("Path '%s' is not a directory"),
svn_dirent_local_style(
- pair->dst_parent_abspath, pool));
+ pair->dst_parent_abspath, scratch_pool));
}
+
+ SVN_ERR(svn_io_check_path(pair->dst_parent_abspath,
+ &dst_parent_kind, scratch_pool));
+
+ if (dst_parent_kind != svn_node_dir)
+ return svn_error_createf(SVN_ERR_WC_MISSING, NULL,
+ _("Path '%s' is not a directory"),
+ svn_dirent_local_style(
+ pair->dst_parent_abspath, scratch_pool));
}
svn_pool_destroy(iterpool);
@@ -539,6 +539,49 @@ verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
return SVN_NO_ERROR;
}
+static svn_error_t *
+verify_wc_srcs_and_dsts(const apr_array_header_t *copy_pairs,
+ svn_boolean_t make_parents,
+ svn_boolean_t is_move,
+ svn_boolean_t metadata_only,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+ /* Check that all of our SRCs exist. */
+ for (i = 0; i < copy_pairs->nelts; i++)
+ {
+ svn_boolean_t deleted_ok;
+ svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
+ svn_client__copy_pair_t *);
+ svn_pool_clear(iterpool);
+
+ deleted_ok = (pair->src_peg_revision.kind == svn_opt_revision_base
+ || pair->src_op_revision.kind == svn_opt_revision_base);
+
+ /* Verify that SRC_PATH exists. */
+ SVN_ERR(svn_wc_read_kind2(&pair->src_kind, ctx->wc_ctx,
+ pair->src_abspath_or_url,
+ deleted_ok, FALSE, iterpool));
+ if (pair->src_kind == svn_node_none)
+ return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+ _("Path '%s' does not exist"),
+ svn_dirent_local_style(
+ pair->src_abspath_or_url,
+ scratch_pool));
+ }
+
+ SVN_ERR(verify_wc_dsts(copy_pairs, make_parents, is_move, metadata_only, ctx,
+ result_pool, iterpool));
+
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
/* Path-specific state used as part of path_driver_cb_baton. */
typedef struct path_driver_info_t
@@ -578,9 +621,7 @@ path_driver_cb_func(void **dir_baton,
{
struct path_driver_cb_baton *cb_baton = callback_baton;
svn_boolean_t do_delete = FALSE, do_add = FALSE;
- path_driver_info_t *path_info = apr_hash_get(cb_baton->action_hash,
- path,
- APR_HASH_KEY_STRING);
+ path_driver_info_t *path_info = svn_hash_gets(cb_baton->action_hash, path);
/* Initialize return value. */
*dir_baton = NULL;
@@ -761,8 +802,7 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
apr_hash_t *action_hash = apr_hash_make(pool);
apr_array_header_t *path_infos;
const char *top_url, *top_url_all, *top_url_dst;
- const char *message, *repos_root, *ignored_url;
- svn_revnum_t youngest = SVN_INVALID_REVNUM;
+ const char *message, *repos_root;
svn_ra_session_t *ra_session = NULL;
const svn_delta_editor_t *editor;
void *edit_baton;
@@ -777,10 +817,9 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
be verifying that every one of our copy source and destination
URLs is or is beneath this sucker's repository root URL as a form
of a cheap(ish) sanity check. */
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL,
- first_pair->src_abspath_or_url,
- NULL, NULL, FALSE, TRUE,
- ctx, pool));
+ SVN_ERR(svn_client_open_ra_session2(&ra_session,
+ first_pair->src_abspath_or_url, NULL,
+ ctx, pool, pool));
SVN_ERR(svn_ra_get_repos_root2(ra_session, &repos_root, pool));
/* Verify that sources and destinations are all at or under
@@ -795,8 +834,6 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
apr_hash_t *mergeinfo;
- svn_opt_revision_t *src_rev, *ignored_rev, dead_end_rev;
- dead_end_rev.kind = svn_opt_revision_unspecified;
/* Are the source and destination URLs at or under REPOS_ROOT? */
if (! (svn_uri__is_ancestor(repos_root, pair->src_abspath_or_url)
@@ -806,34 +843,24 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
_("Source and destination URLs appear not to point to the "
"same repository."));
- /* Resolve revision keywords and such into real revision number,
- passing NULL for the path (to ensure error if trying to get a
- revision based on the working copy). */
- SVN_ERR(svn_client__get_revision_number(&pair->src_revnum, &youngest,
- ctx->wc_ctx, NULL,
- ra_session,
- &pair->src_op_revision, pool));
-
- /* Run the history function to get the source's URL in the
+ /* Run the history function to get the source's URL and revnum in the
operational revision. */
- SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session,
- pair->src_abspath_or_url,
- pool));
- SVN_ERR(svn_client__repos_locations(&pair->src_abspath_or_url, &src_rev,
- &ignored_url, &ignored_rev,
+ SVN_ERR(svn_ra_reparent(ra_session, pair->src_abspath_or_url, pool));
+ SVN_ERR(svn_client__repos_locations(&pair->src_abspath_or_url,
+ &pair->src_revnum,
+ NULL, NULL,
ra_session,
pair->src_abspath_or_url,
&pair->src_peg_revision,
- &pair->src_op_revision,
- &dead_end_rev, ctx, pool));
+ &pair->src_op_revision, NULL,
+ ctx, pool));
/* Go ahead and grab mergeinfo from the source, too. */
- SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session,
- pair->src_abspath_or_url,
- pool));
- SVN_ERR(calculate_target_mergeinfo(ra_session, &mergeinfo, NULL,
- pair->src_abspath_or_url,
- pair->src_revnum, ctx, pool));
+ SVN_ERR(svn_ra_reparent(ra_session, pair->src_abspath_or_url, pool));
+ SVN_ERR(svn_client__get_repos_mergeinfo(
+ &mergeinfo, ra_session,
+ pair->src_abspath_or_url, pair->src_revnum,
+ svn_mergeinfo_inherited, TRUE /*squelch_incapable*/, pool));
if (mergeinfo)
SVN_ERR(svn_mergeinfo_to_string(&info->mergeinfo, mergeinfo, pool));
@@ -895,16 +922,13 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
}
/* Point the RA session to our current TOP_URL. */
- SVN_ERR(svn_client__ensure_ra_session_url(&ignored_url, ra_session,
- top_url, pool));
+ SVN_ERR(svn_ra_reparent(ra_session, top_url, pool));
/* If we're allowed to create nonexistent parent directories of our
destinations, then make a list in NEW_DIRS of the parent
directories of the destination that don't yet exist. */
if (make_parents)
{
- const char *dir;
-
new_dirs = apr_array_make(pool, 0, sizeof(const char *));
/* If this is a move, TOP_URL is at least the common ancestor of
@@ -927,17 +951,17 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
svn copy --parents URL/src URL/dst
- where src exists and dst does not. The svn_uri_dirname()
- call above will produce a string equivalent to TOP_URL,
- which means svn_uri_is_child() will return NULL. In this
- case, do not try to add dst to the NEW_DIRS list since it
+ where src exists and dst does not. If the dirname of the
+ destination path is equal to TOP_URL,
+ do not try to add dst to the NEW_DIRS list since it
will be added to the commit items array later in this
function. */
- dir = svn_uri__is_child(
- top_url,
- svn_uri_dirname(first_pair->dst_abspath_or_url, pool),
- pool);
- if (dir)
+ const char *dir = svn_uri_skip_ancestor(
+ top_url,
+ svn_uri_dirname(first_pair->dst_abspath_or_url,
+ pool),
+ pool);
+ if (dir && *dir)
SVN_ERR(find_absent_parents1(ra_session, dir, new_dirs, pool));
}
/* If, however, this is *not* a move, TOP_URL only points to the
@@ -956,8 +980,9 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
for (i = 0; i < new_urls->nelts; i++)
{
const char *new_url = APR_ARRAY_IDX(new_urls, i, const char *);
- dir = svn_uri__is_child(top_url, new_url, pool);
- APR_ARRAY_PUSH(new_dirs, const char *) = dir ? dir : "";
+ const char *dir = svn_uri_skip_ancestor(top_url, new_url, pool);
+
+ APR_ARRAY_PUSH(new_dirs, const char *) = dir;
}
}
}
@@ -973,10 +998,12 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_client__copy_pair_t *);
path_driver_info_t *info = APR_ARRAY_IDX(path_infos, i,
path_driver_info_t *);
+ const char *relpath = svn_uri_skip_ancestor(pair->dst_abspath_or_url,
+ pair->src_abspath_or_url,
+ pool);
if ((strcmp(pair->dst_abspath_or_url, repos_root) != 0)
- && (svn_uri__is_child(pair->dst_abspath_or_url,
- pair->src_abspath_or_url, pool) != NULL))
+ && (relpath != NULL && *relpath != '\0'))
{
info->resurrection = TRUE;
top_url = svn_uri_dirname(top_url, pool);
@@ -1000,21 +1027,15 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_node_kind_t dst_kind;
const char *src_rel, *dst_rel;
- src_rel = svn_uri__is_child(top_url, pair->src_abspath_or_url, pool);
+ src_rel = svn_uri_skip_ancestor(top_url, pair->src_abspath_or_url, pool);
if (src_rel)
{
SVN_ERR(svn_ra_check_path(ra_session, src_rel, pair->src_revnum,
&info->src_kind, pool));
}
- else if (strcmp(pair->src_abspath_or_url, top_url) == 0)
- {
- src_rel = "";
- SVN_ERR(svn_ra_check_path(ra_session, src_rel, pair->src_revnum,
- &info->src_kind, pool));
- }
else
{
- const char *old_url = NULL;
+ const char *old_url;
src_rel = NULL;
SVN_ERR_ASSERT(! is_move);
@@ -1033,10 +1054,8 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
/* Figure out the basename that will result from this operation,
and ensure that we aren't trying to overwrite existing paths. */
- dst_rel = svn_uri__is_child(top_url, pair->dst_abspath_or_url, pool);
- if (! dst_rel)
- dst_rel = "";
- SVN_ERR(svn_ra_check_path(ra_session, dst_rel, youngest,
+ dst_rel = svn_uri_skip_ancestor(top_url, pair->dst_abspath_or_url, pool);
+ SVN_ERR(svn_ra_check_path(ra_session, dst_rel, SVN_INVALID_REVNUM,
&dst_kind, pool));
if (dst_kind != svn_node_none)
return svn_error_createf(SVN_ERR_FS_ALREADY_EXISTS, NULL,
@@ -1046,9 +1065,9 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
info->src_path = src_rel;
info->dst_path = dst_rel;
- apr_hash_set(action_hash, info->dst_path, APR_HASH_KEY_STRING, info);
+ svn_hash_sets(action_hash, info->dst_path, info);
if (is_move && (! info->resurrection))
- apr_hash_set(action_hash, info->src_path, APR_HASH_KEY_STRING, info);
+ svn_hash_sets(action_hash, info->src_path, info);
}
if (SVN_CLIENT__HAS_LOG_MSG_FUNC(ctx))
@@ -1080,14 +1099,16 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
path_driver_info_t *);
item = svn_client_commit_item3_create(pool);
- item->url = svn_path_url_add_component2(top_url, info->dst_path, pool);
+ item->url = svn_path_url_add_component2(top_url, info->dst_path,
+ pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
if (is_move && (! info->resurrection))
{
item = apr_pcalloc(pool, sizeof(*item));
- item->url = svn_path_url_add_component2(top_url, info->src_path, pool);
+ item->url = svn_path_url_add_component2(top_url, info->src_path,
+ pool);
item->state_flags = SVN_CLIENT_COMMIT_ITEM_DELETE;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
}
@@ -1114,7 +1135,7 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
info->dir_add = TRUE;
APR_ARRAY_PUSH(paths, const char *) = relpath;
- apr_hash_set(action_hash, relpath, APR_HASH_KEY_STRING, info);
+ svn_hash_sets(action_hash, relpath, info);
}
}
@@ -1133,6 +1154,9 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
message, ctx, pool));
/* Fetch RA commit editor. */
+ SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+ svn_client__get_shim_callbacks(ctx->wc_ctx,
+ NULL, pool)));
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
commit_revprops,
commit_callback,
@@ -1147,13 +1171,14 @@ repos_to_repos_copy(const apr_array_header_t *copy_pairs,
cb_baton.is_move = is_move;
/* Call the path-based editor driver. */
- err = svn_delta_path_driver(editor, edit_baton, youngest, paths,
- path_driver_cb_func, &cb_baton, pool);
+ err = svn_delta_path_driver2(editor, edit_baton, paths, TRUE,
+ path_driver_cb_func, &cb_baton, pool);
if (err)
{
/* At least try to abort the edit (and fs txn) before throwing err. */
- svn_error_clear(editor->abort_edit(edit_baton, pool));
- return svn_error_trace(err);
+ return svn_error_compose_create(
+ err,
+ editor->abort_edit(edit_baton, pool));
}
/* Close the edit. */
@@ -1196,7 +1221,8 @@ check_url_kind(void *baton,
/* ### Copy ...
* COMMIT_INFO_P is ...
- * COPY_PAIRS is ...
+ * COPY_PAIRS is ... such that each 'src_abspath_or_url' is a local abspath
+ * and each 'dst_abspath_or_url' is a URL.
* MAKE_PARENTS is ...
* REVPROP_TABLE is ...
* CTX is ... */
@@ -1207,7 +1233,7 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_commit_callback2_t commit_callback,
void *commit_baton,
svn_client_ctx_t *ctx,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
const char *message;
const char *top_src_path, *top_dst_url;
@@ -1215,6 +1241,7 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
const char *top_src_abspath;
svn_ra_session_t *ra_session;
const svn_delta_editor_t *editor;
+ apr_hash_t *relpath_map = NULL;
void *edit_baton;
svn_client__committables_t *committables;
apr_array_header_t *commit_items;
@@ -1222,29 +1249,18 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
apr_array_header_t *new_dirs = NULL;
apr_hash_t *commit_revprops;
svn_client__copy_pair_t *first_pair;
+ apr_pool_t *session_pool = svn_pool_create(scratch_pool);
int i;
/* Find the common root of all the source paths */
- SVN_ERR(get_copy_pair_ancestors(copy_pairs, &top_src_path, NULL, NULL, pool));
+ SVN_ERR(get_copy_pair_ancestors(copy_pairs, &top_src_path, NULL, NULL,
+ scratch_pool));
/* Do we need to lock the working copy? 1.6 didn't take a write
lock, but what happens if the working copy changes during the copy
operation? */
- iterpool = svn_pool_create(pool);
-
- /* Verify that all the source paths exist, are versioned, etc.
- We'll do so by querying the base revisions of those things (which
- we'll need to know later anyway). */
- for (i = 0; i < copy_pairs->nelts; i++)
- {
- svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
- svn_client__copy_pair_t *);
- svn_pool_clear(iterpool);
-
- SVN_ERR(svn_wc__node_get_base_rev(&pair->src_revnum, ctx->wc_ctx,
- pair->src_abspath_or_url, iterpool));
- }
+ iterpool = svn_pool_create(scratch_pool);
/* Determine the longest common ancestor for the destinations, and open an RA
session to that location. */
@@ -1256,27 +1272,33 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
* It looks like the entire block of code hanging off this comment
* is redundant. */
first_pair = APR_ARRAY_IDX(copy_pairs, 0, svn_client__copy_pair_t *);
- top_dst_url = svn_uri_dirname(first_pair->dst_abspath_or_url, pool);
+ top_dst_url = svn_uri_dirname(first_pair->dst_abspath_or_url, scratch_pool);
for (i = 1; i < copy_pairs->nelts; i++)
{
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
top_dst_url = svn_uri_get_longest_ancestor(top_dst_url,
pair->dst_abspath_or_url,
- pool);
+ scratch_pool);
}
- SVN_ERR(svn_dirent_get_absolute(&top_src_abspath, top_src_path, pool));
+ SVN_ERR(svn_dirent_get_absolute(&top_src_abspath, top_src_path, scratch_pool));
+
+ /* Open a session to help while determining the exact targets */
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, top_dst_url,
- top_src_abspath, NULL, TRUE,
- TRUE, ctx, pool));
+ top_src_abspath, NULL,
+ FALSE /* write_dav_props */,
+ TRUE /* read_dav_props */,
+ ctx,
+ session_pool, session_pool));
/* If requested, determine the nearest existing parent of the destination,
and reparent the ra session there. */
if (make_parents)
{
- new_dirs = apr_array_make(pool, 0, sizeof(const char *));
- SVN_ERR(find_absent_parents2(ra_session, &top_dst_url, new_dirs, pool));
+ new_dirs = apr_array_make(scratch_pool, 0, sizeof(const char *));
+ SVN_ERR(find_absent_parents2(ra_session, &top_dst_url, new_dirs,
+ scratch_pool));
}
/* Figure out the basename that will result from each copy and check to make
@@ -1289,9 +1311,8 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
APR_ARRAY_IDX(copy_pairs, i, svn_client__copy_pair_t *);
svn_pool_clear(iterpool);
- dst_rel = svn_uri__is_child(top_dst_url,
- pair->dst_abspath_or_url,
- iterpool);
+ dst_rel = svn_uri_skip_ancestor(top_dst_url, pair->dst_abspath_or_url,
+ iterpool);
SVN_ERR(svn_ra_check_path(ra_session, dst_rel, SVN_INVALID_REVNUM,
&dst_kind, iterpool));
if (dst_kind != svn_node_none)
@@ -1308,7 +1329,8 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
mechanism used to acquire a log message. */
svn_client_commit_item3_t *item;
const char *tmp_file;
- commit_items = apr_array_make(pool, copy_pairs->nelts, sizeof(item));
+ commit_items = apr_array_make(scratch_pool, copy_pairs->nelts,
+ sizeof(item));
/* Add any intermediate directories to the message */
if (make_parents)
@@ -1317,7 +1339,7 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
{
const char *url = APR_ARRAY_IDX(new_dirs, i, const char *);
- item = svn_client_commit_item3_create(pool);
+ item = svn_client_commit_item3_create(scratch_pool);
item->url = url;
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
@@ -1329,28 +1351,26 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
- item = svn_client_commit_item3_create(pool);
+ item = svn_client_commit_item3_create(scratch_pool);
item->url = pair->dst_abspath_or_url;
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
}
SVN_ERR(svn_client__get_log_msg(&message, &tmp_file, commit_items,
- ctx, pool));
+ ctx, scratch_pool));
if (! message)
{
svn_pool_destroy(iterpool);
+ svn_pool_destroy(session_pool);
return SVN_NO_ERROR;
}
}
else
message = "";
- SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
- message, ctx, pool));
-
cukb.session = ra_session;
- SVN_ERR(svn_ra_get_repos_root2(ra_session, &cukb.repos_root_url, pool));
+ SVN_ERR(svn_ra_get_repos_root2(ra_session, &cukb.repos_root_url, session_pool));
cukb.should_reparent = FALSE;
/* Crawl the working copy for commit items. */
@@ -1358,16 +1378,15 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
SVN_ERR(svn_client__get_copy_committables(&committables,
copy_pairs,
check_url_kind, &cukb,
- ctx, pool, pool));
+ ctx, scratch_pool, iterpool));
/* The committables are keyed by the repository root */
- commit_items = apr_hash_get(committables->by_repository,
- cukb.repos_root_url,
- APR_HASH_KEY_STRING);
+ commit_items = svn_hash_gets(committables->by_repository,
+ cukb.repos_root_url);
SVN_ERR_ASSERT(commit_items != NULL);
if (cukb.should_reparent)
- SVN_ERR(svn_ra_reparent(ra_session, top_dst_url, pool));
+ SVN_ERR(svn_ra_reparent(ra_session, top_dst_url, session_pool));
/* If we are creating intermediate directories, tack them onto the list
of committables. */
@@ -1378,10 +1397,10 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
const char *url = APR_ARRAY_IDX(new_dirs, i, const char *);
svn_client_commit_item3_t *item;
- item = svn_client_commit_item3_create(pool);
+ item = svn_client_commit_item3_create(scratch_pool);
item->url = url;
item->state_flags = SVN_CLIENT_COMMIT_ITEM_ADD;
- item->incoming_prop_changes = apr_array_make(pool, 1,
+ item->incoming_prop_changes = apr_array_make(scratch_pool, 1,
sizeof(svn_prop_t *));
APR_ARRAY_PUSH(commit_items, svn_client_commit_item3_t *) = item;
}
@@ -1397,22 +1416,32 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
svn_client__copy_pair_t *);
svn_client_commit_item3_t *item =
APR_ARRAY_IDX(commit_items, i, svn_client_commit_item3_t *);
+ svn_client__pathrev_t *src_origin;
svn_pool_clear(iterpool);
+ SVN_ERR(svn_client__wc_node_get_origin(&src_origin,
+ pair->src_abspath_or_url,
+ ctx, iterpool, iterpool));
+
/* Set the mergeinfo for the destination to the combined merge
info known to the WC and the repository. */
- item->outgoing_prop_changes = apr_array_make(pool, 1,
+ item->outgoing_prop_changes = apr_array_make(scratch_pool, 1,
sizeof(svn_prop_t *));
- SVN_ERR(calculate_target_mergeinfo(ra_session, &mergeinfo,
- pair->src_abspath_or_url,
- NULL, SVN_INVALID_REVNUM,
- ctx, iterpool));
+ /* Repository mergeinfo (or NULL if it's locally added)... */
+ if (src_origin)
+ SVN_ERR(svn_client__get_repos_mergeinfo(
+ &mergeinfo, ra_session, src_origin->url, src_origin->rev,
+ svn_mergeinfo_inherited, TRUE /*sqelch_inc.*/, iterpool));
+ else
+ mergeinfo = NULL;
+ /* ... and WC mergeinfo. */
SVN_ERR(svn_client__parse_mergeinfo(&wc_mergeinfo, ctx->wc_ctx,
pair->src_abspath_or_url,
iterpool, iterpool));
if (wc_mergeinfo && mergeinfo)
- SVN_ERR(svn_mergeinfo_merge(mergeinfo, wc_mergeinfo, iterpool));
+ SVN_ERR(svn_mergeinfo_merge2(mergeinfo, wc_mergeinfo, iterpool,
+ iterpool));
else if (! mergeinfo)
mergeinfo = wc_mergeinfo;
if (mergeinfo)
@@ -1437,32 +1466,63 @@ wc_to_repos_copy(const apr_array_header_t *copy_pairs,
/* Sort and condense our COMMIT_ITEMS. */
SVN_ERR(svn_client__condense_commit_items(&top_dst_url,
- commit_items, pool));
+ commit_items, scratch_pool));
+
+#ifdef ENABLE_EV2_SHIMS
+ if (commit_items)
+ {
+ relpath_map = apr_hash_make(pool);
+ for (i = 0; i < commit_items->nelts; i++)
+ {
+ svn_client_commit_item3_t *item = APR_ARRAY_IDX(commit_items, i,
+ svn_client_commit_item3_t *);
+ const char *relpath;
+
+ if (!item->path)
+ continue;
+
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_wc__node_get_origin(NULL, NULL, &relpath, NULL, NULL, NULL,
+ ctx->wc_ctx, item->path, FALSE,
+ scratch_pool, iterpool));
+ if (relpath)
+ svn_hash_sets(relpath_map, relpath, item->path);
+ }
+ }
+#endif
+
+ /* Close the initial session, to reopen a new session with commit handling */
+ svn_pool_clear(session_pool);
- /* Open an RA session to DST_URL. */
+ /* Open a new RA session to DST_URL. */
SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, top_dst_url,
NULL, commit_items,
- FALSE, FALSE, ctx, pool));
+ FALSE, FALSE, ctx,
+ session_pool, session_pool));
+
+ SVN_ERR(svn_client__ensure_revprop_table(&commit_revprops, revprop_table,
+ message, ctx, session_pool));
/* Fetch RA commit editor. */
+ SVN_ERR(svn_ra__register_editor_shim_callbacks(ra_session,
+ svn_client__get_shim_callbacks(ctx->wc_ctx, relpath_map,
+ session_pool)));
SVN_ERR(svn_ra_get_commit_editor3(ra_session, &editor, &edit_baton,
commit_revprops,
commit_callback,
commit_baton, NULL,
TRUE, /* No lock tokens */
- pool));
+ session_pool));
/* Perform the commit. */
SVN_ERR_W(svn_client__do_commit(top_dst_url, commit_items,
editor, edit_baton,
0, /* ### any notify_path_offset needed? */
- NULL, NULL, ctx, pool, pool),
+ NULL, ctx, session_pool, session_pool),
_("Commit failed (details follow):"));
- /* Sleep to ensure timestamp integrity. */
- svn_io_sleep_for_timestamps(top_src_path, pool);
-
svn_pool_destroy(iterpool);
+ svn_pool_destroy(session_pool);
return SVN_NO_ERROR;
}
@@ -1501,7 +1561,8 @@ notification_adjust_func(void *baton,
Resolve PAIR->src_revnum to a real revision number if it isn't already. */
static svn_error_t *
-repos_to_wc_copy_single(svn_client__copy_pair_t *pair,
+repos_to_wc_copy_single(svn_boolean_t *timestamp_sleep,
+ svn_client__copy_pair_t *pair,
svn_boolean_t same_repositories,
svn_boolean_t ignore_externals,
svn_ra_session_t *ra_session,
@@ -1513,57 +1574,75 @@ repos_to_wc_copy_single(svn_client__copy_pair_t *pair,
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
- if (pair->src_kind == svn_node_dir)
+ if (!same_repositories && ctx->notify_func2)
{
- svn_boolean_t sleep_needed = FALSE;
- const char *tmp_abspath;
-
- /* Find a temporary location in which to check out the copy source.
- * (This function is deprecated, but we intend to replace this whole
- * code path with something else.) */
- SVN_ERR(svn_wc_create_tmp_file2(NULL, &tmp_abspath, dst_abspath,
- svn_io_file_del_on_close, pool));
-
- /* Make a new checkout of the requested source. While doing so,
- * resolve pair->src_revnum to an actual revision number in case it
- * was until now 'invalid' meaning 'head'. Ask this function not to
- * sleep for timestamps, by passing a sleep_needed output param.
- * Send notifications for all nodes except the root node, and adjust
- * them to refer to the destination rather than this temporary path. */
- {
- svn_wc_notify_func2_t old_notify_func2 = ctx->notify_func2;
- void *old_notify_baton2 = ctx->notify_baton2;
- struct notification_adjust_baton nb;
- svn_error_t *err;
-
- nb.inner_func = ctx->notify_func2;
- nb.inner_baton = ctx->notify_baton2;
- nb.checkout_abspath = tmp_abspath;
- nb.final_abspath = dst_abspath;
- ctx->notify_func2 = notification_adjust_func;
- ctx->notify_baton2 = &nb;
-
- err = svn_client__checkout_internal(&pair->src_revnum,
- pair->src_original,
- tmp_abspath,
- &pair->src_peg_revision,
- &pair->src_op_revision,
- svn_depth_infinity,
- ignore_externals, FALSE,
- &sleep_needed, ctx, pool);
+ svn_wc_notify_t *notify;
+ notify = svn_wc_create_notify_url(
+ pair->src_abspath_or_url,
+ svn_wc_notify_foreign_copy_begin,
+ pool);
+ notify->kind = pair->src_kind;
+ ctx->notify_func2(ctx->notify_baton2, notify, pool);
- ctx->notify_func2 = old_notify_func2;
- ctx->notify_baton2 = old_notify_baton2;
+ /* Allow a theoretical cancel to get through. */
+ if (ctx->cancel_func)
+ SVN_ERR(ctx->cancel_func(ctx->cancel_baton));
+ }
- SVN_ERR(err);
- }
+ if (pair->src_kind == svn_node_dir)
+ {
+ if (same_repositories)
+ {
+ svn_boolean_t sleep_needed = FALSE;
+ const char *tmpdir_abspath, *tmp_abspath;
+
+ /* Find a temporary location in which to check out the copy source. */
+ SVN_ERR(svn_wc__get_tmpdir(&tmpdir_abspath, ctx->wc_ctx, dst_abspath,
+ pool, pool));
+
+ SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_abspath, tmpdir_abspath,
+ svn_io_file_del_on_close, pool, pool));
+
+ /* Make a new checkout of the requested source. While doing so,
+ * resolve pair->src_revnum to an actual revision number in case it
+ * was until now 'invalid' meaning 'head'. Ask this function not to
+ * sleep for timestamps, by passing a sleep_needed output param.
+ * Send notifications for all nodes except the root node, and adjust
+ * them to refer to the destination rather than this temporary path. */
+ {
+ svn_wc_notify_func2_t old_notify_func2 = ctx->notify_func2;
+ void *old_notify_baton2 = ctx->notify_baton2;
+ struct notification_adjust_baton nb;
+ svn_error_t *err;
+
+ nb.inner_func = ctx->notify_func2;
+ nb.inner_baton = ctx->notify_baton2;
+ nb.checkout_abspath = tmp_abspath;
+ nb.final_abspath = dst_abspath;
+ ctx->notify_func2 = notification_adjust_func;
+ ctx->notify_baton2 = &nb;
+
+ err = svn_client__checkout_internal(&pair->src_revnum,
+ pair->src_original,
+ tmp_abspath,
+ &pair->src_peg_revision,
+ &pair->src_op_revision,
+ svn_depth_infinity,
+ ignore_externals, FALSE,
+ &sleep_needed, ctx, pool);
+
+ ctx->notify_func2 = old_notify_func2;
+ ctx->notify_baton2 = old_notify_baton2;
+
+ SVN_ERR(err);
+ }
+
+ *timestamp_sleep = TRUE;
/* Schedule dst_path for addition in parent, with copy history.
Don't send any notification here.
Then remove the temporary checkout's .svn dir in preparation for
moving the rest of it into the final destination. */
- if (same_repositories)
- {
SVN_ERR(svn_wc_copy3(ctx->wc_ctx, tmp_abspath, dst_abspath,
TRUE /* metadata_only */,
ctx->cancel_func, ctx->cancel_baton,
@@ -1582,47 +1661,41 @@ repos_to_wc_copy_single(svn_client__copy_pair_t *pair,
}
else
{
- /* ### We want to schedule this as a simple add, or even better
- a copy from a foreign repos, but we don't yet have the
- WC APIs to do that, so we will just move the whole WC into
- place as a disjoint, nested WC. */
+ *timestamp_sleep = TRUE;
- /* Move the working copy to where it is expected. */
- SVN_ERR(svn_wc__rename_wc(ctx->wc_ctx, tmp_abspath, dst_abspath,
- pool));
-
- svn_io_sleep_for_timestamps(dst_abspath, pool);
+ SVN_ERR(svn_client__copy_foreign(pair->src_abspath_or_url,
+ dst_abspath,
+ &pair->src_peg_revision,
+ &pair->src_op_revision,
+ svn_depth_infinity,
+ FALSE /* make_parents */,
+ TRUE /* already_locked */,
+ ctx, pool));
- return svn_error_createf(
- SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("Source URL '%s' is from foreign repository; "
- "leaving it as a disjoint WC"), pair->src_abspath_or_url);
+ return SVN_NO_ERROR;
}
} /* end directory case */
else if (pair->src_kind == svn_node_file)
{
- svn_stream_t *fstream;
- const char *new_text_path;
apr_hash_t *new_props;
const char *src_rel;
- svn_stream_t *new_base_contents;
-
- SVN_ERR(svn_stream_open_unique(&fstream, &new_text_path, NULL,
- svn_io_file_del_on_pool_cleanup, pool,
- pool));
+ svn_stream_t *new_base_contents = svn_stream_buffered(pool);
SVN_ERR(svn_ra_get_path_relative_to_session(ra_session, &src_rel,
pair->src_abspath_or_url,
pool));
/* Fetch the file content. While doing so, resolve pair->src_revnum
* to an actual revision number if it's 'invalid' meaning 'head'. */
- SVN_ERR(svn_ra_get_file(ra_session, src_rel, pair->src_revnum, fstream,
+ SVN_ERR(svn_ra_get_file(ra_session, src_rel, pair->src_revnum,
+ new_base_contents,
&pair->src_revnum, &new_props, pool));
- SVN_ERR(svn_stream_close(fstream));
- SVN_ERR(svn_stream_open_readonly(&new_base_contents, new_text_path,
- pool, pool));
+ if (new_props && ! same_repositories)
+ svn_hash_sets(new_props, SVN_PROP_MERGEINFO, NULL);
+
+ *timestamp_sleep = TRUE;
+
SVN_ERR(svn_wc_add_repos_file4(
ctx->wc_ctx, dst_abspath,
new_base_contents, NULL, new_props, NULL,
@@ -1634,9 +1707,10 @@ repos_to_wc_copy_single(svn_client__copy_pair_t *pair,
/* Record the implied mergeinfo (before the notification callback
is invoked for the root node). */
- SVN_ERR(calculate_target_mergeinfo(ra_session, &src_mergeinfo, NULL,
- pair->src_abspath_or_url,
- pair->src_revnum, ctx, pool));
+ SVN_ERR(svn_client__get_repos_mergeinfo(
+ &src_mergeinfo, ra_session,
+ pair->src_abspath_or_url, pair->src_revnum,
+ svn_mergeinfo_inherited, TRUE /*squelch_incapable*/, pool));
SVN_ERR(extend_wc_mergeinfo(dst_abspath, src_mergeinfo, ctx, pool));
/* Do our own notification for the root node, even if we could possibly
@@ -1651,13 +1725,12 @@ repos_to_wc_copy_single(svn_client__copy_pair_t *pair,
(*ctx->notify_func2)(ctx->notify_baton2, notify, pool);
}
- svn_io_sleep_for_timestamps(dst_abspath, pool);
-
return SVN_NO_ERROR;
}
-static svn_error_t*
-repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
+static svn_error_t *
+repos_to_wc_copy_locked(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *copy_pairs,
const char *top_dst_path,
svn_boolean_t ignore_externals,
svn_ra_session_t *ra_session,
@@ -1665,86 +1738,24 @@ repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
apr_pool_t *scratch_pool)
{
int i;
- const char *src_uuid = NULL, *dst_uuid = NULL;
svn_boolean_t same_repositories;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
/* We've already checked for physical obstruction by a working file.
But there could also be logical obstruction by an entry whose
working file happens to be missing.*/
- for (i = 0; i < copy_pairs->nelts; i++)
- {
- svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
- svn_client__copy_pair_t *);
- svn_node_kind_t kind;
- svn_boolean_t is_excluded;
- svn_boolean_t is_server_excluded;
-
- svn_pool_clear(iterpool);
-
- SVN_ERR(svn_wc_read_kind(&kind, ctx->wc_ctx, pair->dst_abspath_or_url,
- FALSE, iterpool));
- if (kind == svn_node_none)
- continue;
-
- /* ### TODO(#2843): Rework these error report. Maybe we can
- ### simplify the conditions? */
-
- /* Hidden by client exclusion */
- SVN_ERR(svn_wc__node_is_status_excluded(&is_excluded, ctx->wc_ctx,
- pair->dst_abspath_or_url,
- iterpool));
- if (is_excluded)
- {
- return svn_error_createf
- (SVN_ERR_ENTRY_EXISTS,
- NULL, _("'%s' is already under version control"),
- svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
- }
-
- /* Hidden by server exclusion (not authorized) */
- SVN_ERR(svn_wc__node_is_status_server_excluded(&is_server_excluded,
- ctx->wc_ctx,
- pair->dst_abspath_or_url,
- iterpool));
- if (is_server_excluded)
- {
- return svn_error_createf
- (SVN_ERR_ENTRY_EXISTS,
- NULL, _("'%s' is already under version control"),
- svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
- }
-
- /* Working file missing to something other than being scheduled
- for addition or in "deleted" state. */
- if (kind != svn_node_dir)
- {
- svn_boolean_t is_deleted;
- svn_boolean_t is_not_present;
-
- SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted, ctx->wc_ctx,
- pair->dst_abspath_or_url,
- iterpool));
- SVN_ERR(svn_wc__node_is_status_not_present(&is_not_present,
- ctx->wc_ctx,
- pair->dst_abspath_or_url,
- iterpool));
- if ((! is_deleted) && (! is_not_present))
- return svn_error_createf
- (SVN_ERR_WC_OBSTRUCTED_UPDATE, NULL,
- _("Entry for '%s' exists (though the working file is missing)"),
- svn_dirent_local_style(pair->dst_abspath_or_url, iterpool));
- }
- }
+ SVN_ERR(verify_wc_dsts(copy_pairs, FALSE, FALSE, FALSE /* metadata_only */,
+ ctx, scratch_pool, iterpool));
/* Decide whether the two repositories are the same or not. */
{
svn_error_t *src_err, *dst_err;
const char *parent;
const char *parent_abspath;
+ const char *src_uuid, *dst_uuid;
/* Get the repository uuid of SRC_URL */
- src_err = svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool);
+ src_err = svn_ra_get_uuid2(ra_session, &src_uuid, iterpool);
if (src_err && src_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
return svn_error_trace(src_err);
@@ -1757,8 +1768,9 @@ repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
parent = top_dst_path;
SVN_ERR(svn_dirent_get_absolute(&parent_abspath, parent, scratch_pool));
- dst_err = svn_client_uuid_from_path2(&dst_uuid, parent_abspath, ctx,
- scratch_pool, scratch_pool);
+ dst_err = svn_client_get_repos_root(NULL /* root_url */, &dst_uuid,
+ parent_abspath, ctx,
+ iterpool, iterpool);
if (dst_err && dst_err->apr_err != SVN_ERR_RA_NO_REPOS_UUID)
return dst_err;
@@ -1768,7 +1780,6 @@ repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
copy-history is attempted. */
if (src_err || dst_err || (! src_uuid) || (! dst_uuid))
same_repositories = FALSE;
-
else
same_repositories = (strcmp(src_uuid, dst_uuid) == 0);
}
@@ -1782,7 +1793,8 @@ repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
svn_pool_clear(iterpool);
- SVN_ERR(repos_to_wc_copy_single(APR_ARRAY_IDX(copy_pairs, i,
+ SVN_ERR(repos_to_wc_copy_single(timestamp_sleep,
+ APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *),
same_repositories,
ignore_externals,
@@ -1793,31 +1805,9 @@ repos_to_wc_copy_locked(const apr_array_header_t *copy_pairs,
return SVN_NO_ERROR;
}
-struct repos_to_wc_copy_baton {
- const apr_array_header_t *copy_pairs;
- const char *top_dst_path;
- svn_boolean_t ignore_externals;
- svn_ra_session_t *ra_session;
- svn_client_ctx_t *ctx;
-};
-
-/* Implements svn_wc__with_write_lock_func_t. */
-static svn_error_t *
-repos_to_wc_copy_cb(void *baton,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- struct repos_to_wc_copy_baton *b = baton;
-
- SVN_ERR(repos_to_wc_copy_locked(b->copy_pairs, b->top_dst_path,
- b->ignore_externals, b->ra_session,
- b->ctx, scratch_pool));
-
- return SVN_NO_ERROR;
-}
-
static svn_error_t *
-repos_to_wc_copy(const apr_array_header_t *copy_pairs,
+repos_to_wc_copy(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *copy_pairs,
svn_boolean_t make_parents,
svn_boolean_t ignore_externals,
svn_client_ctx_t *ctx,
@@ -1827,7 +1817,6 @@ repos_to_wc_copy(const apr_array_header_t *copy_pairs,
const char *top_src_url, *top_dst_path;
apr_pool_t *iterpool = svn_pool_create(pool);
const char *lock_abspath;
- struct repos_to_wc_copy_baton baton;
int i;
/* Get the real path for the source, based upon its peg revision. */
@@ -1835,19 +1824,15 @@ repos_to_wc_copy(const apr_array_header_t *copy_pairs,
{
svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
svn_client__copy_pair_t *);
- const char *src, *ignored_url;
- svn_opt_revision_t *new_rev, *ignored_rev, dead_end_rev;
+ const char *src;
svn_pool_clear(iterpool);
- dead_end_rev.kind = svn_opt_revision_unspecified;
- SVN_ERR(svn_client__repos_locations(&src, &new_rev,
- &ignored_url, &ignored_rev,
+ SVN_ERR(svn_client__repos_locations(&src, &pair->src_revnum, NULL, NULL,
NULL,
pair->src_abspath_or_url,
&pair->src_peg_revision,
- &pair->src_op_revision,
- &dead_end_rev,
+ &pair->src_op_revision, NULL,
ctx, iterpool));
pair->src_original = pair->src_abspath_or_url;
@@ -1866,21 +1851,8 @@ repos_to_wc_copy(const apr_array_header_t *copy_pairs,
/* Open a repository session to the longest common src ancestor. We do not
(yet) have a working copy, so we don't have a corresponding path and
tempfiles cannot go into the admin area. */
- SVN_ERR(svn_client__open_ra_session_internal(&ra_session, NULL, top_src_url,
- NULL, NULL, FALSE, TRUE,
- ctx, pool));
-
- /* Pass null for the path, to ensure error if trying to get a
- revision based on the working copy. */
- for (i = 0; i < copy_pairs->nelts; i++)
- {
- svn_client__copy_pair_t *pair = APR_ARRAY_IDX(copy_pairs, i,
- svn_client__copy_pair_t *);
-
- SVN_ERR(svn_client__get_revision_number(&pair->src_revnum, NULL,
- ctx->wc_ctx, NULL, ra_session,
- &pair->src_op_revision, pool));
- }
+ SVN_ERR(svn_client_open_ra_session2(&ra_session, top_src_url, lock_abspath,
+ ctx, pool, pool));
/* Get the correct src path for the peg revision used, and verify that we
aren't overwriting an existing path. */
@@ -1943,15 +1915,11 @@ repos_to_wc_copy(const apr_array_header_t *copy_pairs,
}
svn_pool_destroy(iterpool);
- baton.copy_pairs = copy_pairs;
- baton.top_dst_path = top_dst_path;
- baton.ignore_externals = ignore_externals;
- baton.ra_session = ra_session;
- baton.ctx = ctx;
-
- SVN_ERR(svn_wc__call_with_write_lock(repos_to_wc_copy_cb, &baton,
- ctx->wc_ctx, lock_abspath,
- FALSE, pool, pool));
+ SVN_WC__CALL_WITH_WRITE_LOCK(
+ repos_to_wc_copy_locked(timestamp_sleep,
+ copy_pairs, top_dst_path, ignore_externals,
+ ra_session, ctx, pool),
+ ctx->wc_ctx, lock_abspath, FALSE, pool);
return SVN_NO_ERROR;
}
@@ -1959,11 +1927,21 @@ repos_to_wc_copy(const apr_array_header_t *copy_pairs,
((revision.kind != svn_opt_revision_unspecified) \
&& (revision.kind != svn_opt_revision_working))
-/* Perform all allocations in POOL. */
+/* ...
+ *
+ * Set *TIMESTAMP_SLEEP to TRUE if a sleep is required; otherwise do not
+ * change *TIMESTAMP_SLEEP. This output will be valid even if the
+ * function returns an error.
+ *
+ * Perform all allocations in POOL.
+ */
static svn_error_t *
-try_copy(const apr_array_header_t *sources,
+try_copy(svn_boolean_t *timestamp_sleep,
+ const apr_array_header_t *sources,
const char *dst_path_in,
svn_boolean_t is_move,
+ svn_boolean_t allow_mixed_revisions,
+ svn_boolean_t metadata_only,
svn_boolean_t make_parents,
svn_boolean_t ignore_externals,
const apr_hash_t *revprop_table,
@@ -2161,9 +2139,9 @@ try_copy(const apr_array_header_t *sources,
{
if (!srcs_are_urls)
{
- /* If we are doing a wc->* move, but with an operational revision
+ /* If we are doing a wc->* copy, but with an operational revision
other than the working copy revision, we are really doing a
- repo->* move, because we're going to need to get the rev from the
+ repo->* copy, because we're going to need to get the rev from the
repo. */
svn_boolean_t need_repos_op_rev = FALSE;
@@ -2249,14 +2227,22 @@ try_copy(const apr_array_header_t *sources,
if ((! srcs_are_urls) && (! dst_is_url))
{
SVN_ERR(verify_wc_srcs_and_dsts(copy_pairs, make_parents, is_move,
- ctx, pool));
+ metadata_only, ctx, pool, pool));
/* Copy or move all targets. */
if (is_move)
- return svn_error_trace(do_wc_to_wc_moves(copy_pairs, dst_path_in, ctx,
- pool));
+ return svn_error_trace(do_wc_to_wc_moves(timestamp_sleep,
+ copy_pairs, dst_path_in,
+ allow_mixed_revisions,
+ metadata_only,
+ ctx, pool));
else
- return svn_error_trace(do_wc_to_wc_copies(copy_pairs, ctx, pool));
+ {
+ /* We ignore these values, so assert the default value */
+ SVN_ERR_ASSERT(allow_mixed_revisions && !metadata_only);
+ return svn_error_trace(do_wc_to_wc_copies(timestamp_sleep,
+ copy_pairs, ctx, pool));
+ }
}
else if ((! srcs_are_urls) && (dst_is_url))
{
@@ -2267,7 +2253,8 @@ try_copy(const apr_array_header_t *sources,
else if ((srcs_are_urls) && (! dst_is_url))
{
return svn_error_trace(
- repos_to_wc_copy(copy_pairs, make_parents, ignore_externals,
+ repos_to_wc_copy(timestamp_sleep,
+ copy_pairs, make_parents, ignore_externals,
ctx, pool));
}
else
@@ -2295,14 +2282,18 @@ svn_client_copy6(const apr_array_header_t *sources,
apr_pool_t *pool)
{
svn_error_t *err;
+ svn_boolean_t timestamp_sleep = FALSE;
apr_pool_t *subpool = svn_pool_create(pool);
if (sources->nelts > 1 && !copy_as_child)
return svn_error_create(SVN_ERR_CLIENT_MULTIPLE_SOURCES_DISALLOWED,
NULL, NULL);
- err = try_copy(sources, dst_path,
+ err = try_copy(&timestamp_sleep,
+ sources, dst_path,
FALSE /* is_move */,
+ TRUE /* allow_mixed_revisions */,
+ FALSE /* metadata_only */,
make_parents,
ignore_externals,
revprop_table,
@@ -2327,13 +2318,16 @@ svn_client_copy6(const apr_array_header_t *sources,
src_basename = src_is_url ? svn_uri_basename(src_path, subpool)
: svn_dirent_basename(src_path, subpool);
+ dst_path
+ = dst_is_url ? svn_path_url_add_component2(dst_path, src_basename,
+ subpool)
+ : svn_dirent_join(dst_path, src_basename, subpool);
- err = try_copy(sources,
- dst_is_url
- ? svn_path_url_add_component2(dst_path, src_basename,
- subpool)
- : svn_dirent_join(dst_path, src_basename, subpool),
+ err = try_copy(&timestamp_sleep,
+ sources, dst_path,
FALSE /* is_move */,
+ TRUE /* allow_mixed_revisions */,
+ FALSE /* metadata_only */,
make_parents,
ignore_externals,
revprop_table,
@@ -2342,16 +2336,22 @@ svn_client_copy6(const apr_array_header_t *sources,
subpool);
}
+ /* Sleep if required. DST_PATH is not a URL in these cases. */
+ if (timestamp_sleep)
+ svn_io_sleep_for_timestamps(dst_path, subpool);
+
svn_pool_destroy(subpool);
return svn_error_trace(err);
}
svn_error_t *
-svn_client_move6(const apr_array_header_t *src_paths,
+svn_client_move7(const apr_array_header_t *src_paths,
const char *dst_path,
svn_boolean_t move_as_child,
svn_boolean_t make_parents,
+ svn_boolean_t allow_mixed_revisions,
+ svn_boolean_t metadata_only,
const apr_hash_t *revprop_table,
svn_commit_callback2_t commit_callback,
void *commit_baton,
@@ -2361,6 +2361,7 @@ svn_client_move6(const apr_array_header_t *src_paths,
const svn_opt_revision_t head_revision
= { svn_opt_revision_head, { 0 } };
svn_error_t *err;
+ svn_boolean_t timestamp_sleep = FALSE;
int i;
apr_pool_t *subpool = svn_pool_create(pool);
apr_array_header_t *sources = apr_array_make(pool, src_paths->nelts,
@@ -2383,10 +2384,13 @@ svn_client_move6(const apr_array_header_t *src_paths,
APR_ARRAY_PUSH(sources, svn_client_copy_source_t *) = copy_source;
}
- err = try_copy(sources, dst_path,
+ err = try_copy(&timestamp_sleep,
+ sources, dst_path,
TRUE /* is_move */,
+ allow_mixed_revisions,
+ metadata_only,
make_parents,
- FALSE,
+ FALSE /* ignore_externals */,
revprop_table,
commit_callback, commit_baton,
ctx,
@@ -2408,21 +2412,28 @@ svn_client_move6(const apr_array_header_t *src_paths,
src_basename = src_is_url ? svn_uri_basename(src_path, pool)
: svn_dirent_basename(src_path, pool);
+ dst_path
+ = dst_is_url ? svn_path_url_add_component2(dst_path, src_basename,
+ subpool)
+ : svn_dirent_join(dst_path, src_basename, subpool);
- err = try_copy(sources,
- dst_is_url
- ? svn_path_url_add_component2(dst_path,
- src_basename, pool)
- : svn_dirent_join(dst_path, src_basename, pool),
+ err = try_copy(&timestamp_sleep,
+ sources, dst_path,
TRUE /* is_move */,
+ allow_mixed_revisions,
+ metadata_only,
make_parents,
- FALSE,
+ FALSE /* ignore_externals */,
revprop_table,
commit_callback, commit_baton,
ctx,
subpool);
}
+ /* Sleep if required. DST_PATH is not a URL in these cases. */
+ if (timestamp_sleep)
+ svn_io_sleep_for_timestamps(dst_path, subpool);
+
svn_pool_destroy(subpool);
return svn_error_trace(err);
}