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(&timestamp_sleep,
                                          url,
-                                         &copy_src_peg_revision,
-                                         &copy_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(&copy_src_revnum, timestamp_sleep,
+    err = svn_client__checkout_internal(NULL /*result_rev*/, timestamp_sleep,
                                         src_url,
                                         tmp_abspath,
-                                        src_peg_revision,
-                                        src_op_revision,
+                                        &copy_src_revision,
+                                        &copy_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(&timestamp_sleep,
                                                copyfrom_path,
-                                               &copy_src_peg_revision,
-                                               &copy_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(&timestamp_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;
 }


Reply via email to