Author: julianfoad
Date: Mon Nov 19 17:35:47 2018
New Revision: 1846929
URL: http://svn.apache.org/viewvc?rev=1846929&view=rev
Log:
Support copies, for issue SVN-4786: Create a WC working-mods editor.
* subversion/include/private/svn_client_private.h
(svn_client__repos_to_wc_copy_dir): Also support copies from a foreign
repository. Take a resolved URL and revision instead of URL:peg:op-rev.
(svn_client__repos_to_wc_copy_file): New.
(svn_client__wc_editor,
svn_client__wc_editor_internal): To support copies, take an RA session.
* subversion/libsvn_client/conflicts.c
(merge_incoming_added_dir_replace): Adjust the call to
svn_client__repos_to_wc_copy_dir().
* subversion/libsvn_client/copy.c
(svn_client__repos_to_wc_copy_dir): As above.
(svn_client__repos_to_wc_copy_file): New, extracted ...
(repos_to_wc_copy_single): ... from here.
* subversion/libsvn_client/copy_foreign.c
(copy_foreign_dir): Adjust the call to svn_client__wc_editor_internal().
* subversion/libsvn_client/wc_editor.c
(edit_baton_t): Add an RA session.
(is_same_repository): New.
(dir_add): Adjust to support copying from same repo or foreign repo.
(file_add): Add support for copying from same repo or foreign repo.
(svn_client__wc_editor_internal,
svn_client__wc_editor): Accept an RA session.
Modified:
subversion/trunk/subversion/include/private/svn_client_private.h
subversion/trunk/subversion/libsvn_client/conflicts.c
subversion/trunk/subversion/libsvn_client/copy.c
subversion/trunk/subversion/libsvn_client/copy_foreign.c
subversion/trunk/subversion/libsvn_client/wc_editor.c
Modified: subversion/trunk/subversion/include/private/svn_client_private.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_client_private.h?rev=1846929&r1=1846928&r2=1846929&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_client_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_client_private.h Mon Nov 19
17:35:47 2018
@@ -414,26 +414,48 @@ svn_client__get_diff_summarize_callbacks
apr_pool_t *result_pool,
apr_pool_t *scratch_pool);
-/* Copy a directory tree from SRC_URL @ SRC_PEG_REVISION, operative revision
- * SRC_OP_REVISION, to DST_ABSPATH in a WC.
+/* Copy a directory tree from SRC_URL @ SRC_REV, to DST_ABSPATH in a WC.
*
* The caller should be holding a WC write lock that allows DST_ABSPATH to
* be created, such as on the parent of DST_ABSPATH.
*
- * If RA_SESSION is NOT NULL, it may be used to avoid creating a new
- * session. The session may point to a different URL after returning.
+ * Use RA_SESSION to fetch the data. The session may point to a different
+ * URL after returning.
*/
svn_error_t *
svn_client__repos_to_wc_copy_dir(svn_boolean_t *timestamp_sleep,
const char *src_url,
- const svn_opt_revision_t *src_peg_revision,
- const svn_opt_revision_t *src_op_revision,
+ svn_revnum_t src_rev,
const char *dst_abspath,
svn_boolean_t ignore_externals,
+ svn_boolean_t same_repositories,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *pool);
+/* Copy a file from SRC_URL @ SRC_REV, to DST_ABSPATH in a WC.
+ *
+ * The caller should be holding a WC write lock that allows DST_ABSPATH to
+ * be created, such as on the parent of DST_ABSPATH.
+ *
+ * SAME_REPOSITORIES must be true if and only if the source of this copy
+ * is from the same repository at the WC parent of DST_ABSPATH.
+ * If SAME_REPOSITORIES, then fill in the 'copy-from' in the WC target.
+ * If not SAME_REPOSITORIES, then remove any svn:mergeinfo property.
+ *
+ * Use RA_SESSION to fetch the data. The session may point to a different
+ * URL after returning.
+ */
+svn_error_t *
+svn_client__repos_to_wc_copy_file(svn_boolean_t *timestamp_sleep,
+ const char *src_url,
+ svn_revnum_t src_rev,
+ const char *dst_abspath,
+ svn_boolean_t same_repositories,
+ svn_ra_session_t *ra_session,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool);
+
/** Return an editor for applying local modifications to a WC.
*
* Return an editor in @a *editor_p, @a *edit_baton_p that will apply
@@ -441,6 +463,8 @@ svn_client__repos_to_wc_copy_dir(svn_boo
*
* Send notifications via @a notify_func / @a notify_baton.
*
+ * RA_SESSION is used to fetch the original content for copies.
+ *
* Ignore changes to non-regular property (entry-props, DAV/WC-props).
*/
svn_error_t *
@@ -449,6 +473,7 @@ svn_client__wc_editor(const svn_delta_ed
const char *dst_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
@@ -471,6 +496,7 @@ svn_client__wc_editor_internal(const svn
svn_boolean_t ignore_mergeinfo_changes,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool);
Modified: subversion/trunk/subversion/libsvn_client/conflicts.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/conflicts.c?rev=1846929&r1=1846928&r2=1846929&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/conflicts.c (original)
+++ subversion/trunk/subversion/libsvn_client/conflicts.c Mon Nov 19 17:35:47
2018
@@ -8004,7 +8004,6 @@ merge_incoming_added_dir_replace(svn_cli
const char *local_abspath;
const char *lock_abspath;
svn_error_t *err;
- svn_opt_revision_t copy_src_peg_revision;
svn_boolean_t timestamp_sleep;
local_abspath = svn_client_conflict_get_local_abspath(conflict);
@@ -8026,9 +8025,6 @@ merge_incoming_added_dir_replace(svn_cli
if (corrected_url)
url = corrected_url;
- copy_src_peg_revision.kind = svn_opt_revision_number;
- copy_src_peg_revision.value.number = incoming_new_pegrev;
-
/* ### The following WC modifications should be atomic. */
SVN_ERR(svn_wc__acquire_write_lock_for_resolve(&lock_abspath, ctx->wc_ctx,
@@ -8047,10 +8043,10 @@ merge_incoming_added_dir_replace(svn_cli
err = svn_client__repos_to_wc_copy_dir(×tamp_sleep,
url,
- ©_src_peg_revision,
- ©_src_peg_revision,
+ incoming_new_pegrev,
local_abspath,
TRUE, /* we want to ignore externals
*/
+ TRUE /*same_repositories*/,
ra_session, ctx, scratch_pool);
if (err)
goto unlock_wc;
Modified: subversion/trunk/subversion/libsvn_client/copy.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy.c?rev=1846929&r1=1846928&r2=1846929&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy.c Mon Nov 19 17:35:47 2018
@@ -2340,19 +2340,37 @@ notification_adjust_func(void *baton,
svn_error_t *
svn_client__repos_to_wc_copy_dir(svn_boolean_t *timestamp_sleep,
const char *src_url,
- const svn_opt_revision_t *src_peg_revision,
- const svn_opt_revision_t *src_op_revision,
+ svn_revnum_t src_revnum,
const char *dst_abspath,
svn_boolean_t ignore_externals,
+ svn_boolean_t same_repositories,
svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *scratch_pool)
{
const char *tmpdir_abspath, *tmp_abspath;
- svn_revnum_t copy_src_revnum;
SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
+ if (!same_repositories)
+ {
+ svn_opt_revision_t src_revision;
+
+ *timestamp_sleep = TRUE;
+
+ src_revision.kind = svn_opt_revision_number;
+ src_revision.value.number = src_revnum;
+ SVN_ERR(svn_client__copy_foreign(src_url,
+ dst_abspath,
+ &src_revision,
+ &src_revision,
+ svn_depth_infinity,
+ FALSE /* make_parents */,
+ ctx, scratch_pool));
+
+ return SVN_NO_ERROR;
+ }
+
/* 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,
scratch_pool, scratch_pool));
@@ -2372,6 +2390,10 @@ svn_client__repos_to_wc_copy_dir(svn_boo
void *old_notify_baton2 = ctx->notify_baton2;
struct notification_adjust_baton nb;
svn_error_t *err;
+ svn_opt_revision_t copy_src_revision;
+
+ copy_src_revision.kind = svn_opt_revision_number;
+ copy_src_revision.value.number = src_revnum;
nb.inner_func = ctx->notify_func2;
nb.inner_baton = ctx->notify_baton2;
@@ -2380,11 +2402,11 @@ svn_client__repos_to_wc_copy_dir(svn_boo
ctx->notify_func2 = notification_adjust_func;
ctx->notify_baton2 = &nb;
- err = svn_client__checkout_internal(©_src_revnum, timestamp_sleep,
+ err = svn_client__checkout_internal(NULL /*result_rev*/, timestamp_sleep,
src_url,
tmp_abspath,
- src_peg_revision,
- src_op_revision,
+ ©_src_revision,
+ ©_src_revision,
svn_depth_infinity,
ignore_externals,
FALSE, /* we don't allow obstructions
*/
@@ -2418,6 +2440,40 @@ svn_client__repos_to_wc_copy_dir(svn_boo
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_client__repos_to_wc_copy_file(svn_boolean_t *timestamp_sleep,
+ const char *src_url,
+ svn_revnum_t src_rev,
+ const char *dst_abspath,
+ svn_boolean_t same_repositories,
+ svn_ra_session_t *ra_session,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ const char *src_rel;
+ apr_hash_t *new_props;
+ svn_stream_t *new_base_contents = svn_stream_buffered(scratch_pool);
+
+ SVN_ERR(svn_ra_get_path_relative_to_session(ra_session, &src_rel, src_url,
+ scratch_pool));
+ /* Fetch the file content. */
+ SVN_ERR(svn_ra_get_file(ra_session, src_rel, src_rev,
+ new_base_contents, NULL, &new_props,
+ scratch_pool));
+ if (!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,
+ same_repositories ? src_url : NULL,
+ same_repositories ? src_rev : SVN_INVALID_REVNUM,
+ ctx->cancel_func, ctx->cancel_baton,
+ scratch_pool));
+ return SVN_NO_ERROR;
+}
+
/* Peform each individual copy operation for a repos -> wc copy. A
helper for repos_to_wc_copy().
@@ -2459,38 +2515,23 @@ repos_to_wc_copy_single(svn_boolean_t *t
if (pair->src_kind == svn_node_dir)
{
- if (same_repositories)
- {
- /* Avoid a chicken-and-egg problem:
- * If pinning externals we'll need to adjust externals
- * properties before checking out any externals.
- * But copy needs to happen before pinning because else there
- * are no svn:externals properties to pin. */
- if (pin_externals)
- ignore_externals = TRUE;
-
- SVN_ERR(svn_client__repos_to_wc_copy_dir(timestamp_sleep,
- pair->src_original,
- &pair->src_peg_revision,
- &pair->src_op_revision,
- dst_abspath,
- ignore_externals,
- ra_session, ctx, pool));
- }
- else
- {
- *timestamp_sleep = TRUE;
+ /* Avoid a chicken-and-egg problem:
+ * If pinning externals we'll need to adjust externals
+ * properties before checking out any externals.
+ * But copy needs to happen before pinning because else there
+ * are no svn:externals properties to pin. */
+ if (pin_externals)
+ ignore_externals = TRUE;
- SVN_ERR(svn_client__copy_foreign(pair->src_original,
- dst_abspath,
- &pair->src_peg_revision,
- &pair->src_op_revision,
- svn_depth_infinity,
- FALSE /* make_parents */,
- ctx, pool));
-
- return SVN_NO_ERROR;
- }
+ SVN_ERR(svn_client__repos_to_wc_copy_dir(timestamp_sleep,
+ pair->src_abspath_or_url,
+ pair->src_revnum,
+ dst_abspath,
+ ignore_externals,
+ same_repositories,
+ ra_session, ctx, pool));
+ if (!same_repositories)
+ return SVN_NO_ERROR;
if (pin_externals)
{
@@ -2550,31 +2591,13 @@ repos_to_wc_copy_single(svn_boolean_t *t
else if (pair->src_kind == svn_node_file)
{
- apr_hash_t *new_props;
- const char *src_rel;
- 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,
- new_base_contents,
- NULL, &new_props, 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,
- same_repositories ? pair->src_abspath_or_url : NULL,
- same_repositories ? pair->src_revnum : SVN_INVALID_REVNUM,
- ctx->cancel_func, ctx->cancel_baton,
- pool));
+ SVN_ERR(svn_client__repos_to_wc_copy_file(timestamp_sleep,
+ pair->src_abspath_or_url,
+ pair->src_revnum,
+ dst_abspath,
+ same_repositories,
+ ra_session,
+ ctx, pool));
}
/* Record the implied mergeinfo (before the notification callback
Modified: subversion/trunk/subversion/libsvn_client/copy_foreign.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/copy_foreign.c?rev=1846929&r1=1846928&r2=1846929&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/copy_foreign.c (original)
+++ subversion/trunk/subversion/libsvn_client/copy_foreign.c Mon Nov 19
17:35:47 2018
@@ -72,11 +72,14 @@ copy_foreign_dir(svn_ra_session_t *ra_se
const svn_ra_reporter3_t *reporter;
void *reporter_baton;
+ /* Get a WC editor. It does not need an RA session because we will not
+ be sending it any 'copy from' requests, only 'add' requests. */
SVN_ERR(svn_client__wc_editor_internal(&editor, &eb,
dst_abspath,
TRUE /*root_dir_add*/,
TRUE /*ignore_mergeinfo_changes*/,
notify_func, notify_baton,
+ NULL /*ra_session*/,
ctx, scratch_pool));
SVN_ERR(svn_delta_get_cancellation_editor(cancel_func, cancel_baton,
Modified: subversion/trunk/subversion/libsvn_client/wc_editor.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/wc_editor.c?rev=1846929&r1=1846928&r2=1846929&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/wc_editor.c (original)
+++ subversion/trunk/subversion/libsvn_client/wc_editor.c Mon Nov 19 17:35:47
2018
@@ -68,6 +68,8 @@ struct edit_baton_t
/* True => filter out any incoming svn:mergeinfo property changes */
svn_boolean_t ignore_mergeinfo_changes;
+ svn_ra_session_t *ra_session;
+
svn_wc_context_t *wc_ctx;
svn_client_ctx_t *ctx;
svn_wc_notify_func2_t notify_func;
@@ -207,6 +209,28 @@ dir_open(const char *path,
return SVN_NO_ERROR;
}
+/* Are RA_SESSION and the versioned *parent* dir of WC_TARGET_ABSPATH in
+ * the same repository?
+ */
+static svn_error_t *
+is_same_repository(svn_boolean_t *same_repository,
+ svn_ra_session_t *ra_session,
+ const char *wc_target_abspath,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *scratch_pool)
+{
+ const char *src_uuid, *dst_uuid;
+
+ /* Get the repository UUIDs of copy source URL and WC parent path */
+ SVN_ERR(svn_ra_get_uuid2(ra_session, &src_uuid, scratch_pool));
+ SVN_ERR(svn_client_get_repos_root(NULL /*root_url*/, &dst_uuid,
+ svn_dirent_dirname(wc_target_abspath,
+ scratch_pool),
+ ctx, scratch_pool, scratch_pool));
+ *same_repository = (strcmp(src_uuid, dst_uuid) == 0);
+ return SVN_NO_ERROR;
+}
+
static svn_error_t *
dir_add(const char *path,
void *parent_baton,
@@ -222,18 +246,20 @@ dir_add(const char *path,
if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
{
- svn_opt_revision_t copy_src_peg_revision;
+ svn_boolean_t same_repository;
+ svn_boolean_t timestamp_sleep;
- copy_src_peg_revision.kind = svn_opt_revision_number;
- copy_src_peg_revision.value.number = copyfrom_revision;
+ SVN_ERR(is_same_repository(&same_repository,
+ db->eb->ra_session, db->local_abspath,
+ db->eb->ctx, db->pool));
- SVN_ERR(svn_client__repos_to_wc_copy_dir(NULL /*timestamp_sleep*/,
+ SVN_ERR(svn_client__repos_to_wc_copy_dir(×tamp_sleep,
copyfrom_path,
- ©_src_peg_revision,
- ©_src_peg_revision,
+ copyfrom_revision,
db->local_abspath,
TRUE /*ignore_externals*/,
- NULL /*ra_session*/,
+ same_repository,
+ db->eb->ra_session,
db->eb->ctx, db->pool));
}
@@ -408,6 +434,24 @@ file_add(const char *path,
SVN_ERR(file_open_or_add(path, parent_baton, &fb));
+ if (copyfrom_path && SVN_IS_VALID_REVNUM(copyfrom_revision))
+ {
+ svn_boolean_t same_repository;
+ svn_boolean_t timestamp_sleep;
+
+ SVN_ERR(is_same_repository(&same_repository,
+ fb->eb->ra_session, fb->local_abspath,
+ fb->eb->ctx, fb->pool));
+
+ SVN_ERR(svn_client__repos_to_wc_copy_file(×tamp_sleep,
+ copyfrom_path,
+ copyfrom_revision,
+ fb->local_abspath,
+ same_repository,
+ fb->eb->ra_session,
+ fb->eb->ctx, fb->pool));
+ }
+
*file_baton = fb;
return SVN_NO_ERROR;
}
@@ -547,6 +591,7 @@ svn_client__wc_editor_internal(const svn
svn_boolean_t ignore_mergeinfo_changes,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool)
{
@@ -558,6 +603,7 @@ svn_client__wc_editor_internal(const svn
eb->root_dir_add = root_dir_add;
eb->ignore_mergeinfo_changes = ignore_mergeinfo_changes;
+ eb->ra_session = ra_session;
eb->wc_ctx = ctx->wc_ctx;
eb->ctx = ctx;
eb->notify_func = notify_func;
@@ -590,6 +636,7 @@ svn_client__wc_editor(const svn_delta_ed
const char *dst_abspath,
svn_wc_notify_func2_t notify_func,
void *notify_baton,
+ svn_ra_session_t *ra_session,
svn_client_ctx_t *ctx,
apr_pool_t *result_pool)
{
@@ -598,6 +645,7 @@ svn_client__wc_editor(const svn_delta_ed
FALSE /*root_dir_add*/,
FALSE /*ignore_mergeinfo_changes*/,
notify_func, notify_baton,
+ ra_session,
ctx, result_pool));
return SVN_NO_ERROR;
}