Hi Philip,

On 7/17/2017 4:14 AM, Philip Martin wrote:
>  - move the conversion from export_directory to svn_client_export5
>  - change the parameter names in export_file_ev2, export_file,
>    export_directory
>  - remove the path code from those functions as it is never used
>  - add SVN_ERR_ASSERT(svn_path_is_url(from_url))

Thanks for your feedback! That change makes perfect sense. Here is a
second attempt at this patch that I think addresses everything you
listed. Patch with log message is attached.

Doug
Add ability to specify revision when exporting from a working copy.

Although svn_client_export5's documentation previously specified that the
revision was only relevant when exporting from a repository URL, it is still a
useful feature to be able to specify a revision when exporting from a working
copy.

This patch ensures that svn_client_export5 only deals with the repository URL
in cases where a revision is supplied. This resolves an assertion failure if a
working copy path is supplied and there are relative externals.

* subversion/include/svn_client.h
  (svn_client_export5): Update documentation to indicate that revision is no
   longer only used when exporting from a repository URL.

* subversion/libsvn_client/export.c
  (export_file_ev2, export_file, export_directory): Change to only handle URLs
   and assert that the supplied from_url parameter is actually a URL.
  (svn_client_export5): If exporting a working copy requires a URL, convert
   the working copy path to a URL prior to passing it to the export_* functions
   mentioned above.

* subversion/tests/cmdline/export_tests.py
  (export_revision_with_root_relative_external): Remove XFail tag, and update
   the test to check for correct output and export results

Index: subversion/include/svn_client.h
===================================================================
--- subversion/include/svn_client.h     (revision 1802187)
+++ subversion/include/svn_client.h     (working copy)
@@ -6251,8 +6251,7 @@ svn_client_revprop_list(apr_hash_t **props,
  * #svn_opt_revision_unspecified, then it defaults to #svn_opt_revision_head
  * for URLs or #svn_opt_revision_working for WC targets.
  *
- * @a revision is the revision that should be exported, which is only used
- * when exporting from a repository.
+ * @a revision is the revision that should be exported.
  *
  * @a peg_revision and @a revision must not be @c NULL.
  *
Index: subversion/libsvn_client/export.c
===================================================================
--- subversion/libsvn_client/export.c   (revision 1802187)
+++ subversion/libsvn_client/export.c   (working copy)
@@ -1148,7 +1148,7 @@ get_editor_ev2(const svn_delta_editor_t **export_e
 }
 
 static svn_error_t *
-export_file_ev2(const char *from_path_or_url,
+export_file_ev2(const char *from_url,
                 const char *to_path,
                 struct edit_baton *eb,
                 svn_client__pathrev_t *loc,
@@ -1156,23 +1156,21 @@ static svn_error_t *
                 svn_boolean_t overwrite,
                 apr_pool_t *scratch_pool)
 {
-  svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
   apr_hash_t *props;
   svn_stream_t *tmp_stream;
   svn_node_kind_t to_kind;
 
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
+
   if (svn_path_is_empty(to_path))
     {
-      if (from_is_url)
-        to_path = svn_uri_basename(from_path_or_url, scratch_pool);
-      else
-        to_path = svn_dirent_basename(from_path_or_url, NULL);
+      to_path = svn_uri_basename(from_url, scratch_pool);
       eb->root_path = to_path;
     }
   else
     {
-      SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
-                                     from_is_url, scratch_pool));
+      SVN_ERR(append_basename_if_dir(&to_path, from_url,
+                                     TRUE, scratch_pool));
       eb->root_path = to_path;
     }
 
@@ -1204,7 +1202,7 @@ static svn_error_t *
 }
 
 static svn_error_t *
-export_file(const char *from_path_or_url,
+export_file(const char *from_url,
             const char *to_path,
             struct edit_baton *eb,
             svn_client__pathrev_t *loc,
@@ -1216,20 +1214,18 @@ static svn_error_t *
   apr_hash_index_t *hi;
   struct file_baton *fb = apr_pcalloc(scratch_pool, sizeof(*fb));
   svn_node_kind_t to_kind;
-  svn_boolean_t from_is_url = svn_path_is_url(from_path_or_url);
 
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
+
   if (svn_path_is_empty(to_path))
     {
-      if (from_is_url)
-        to_path = svn_uri_basename(from_path_or_url, scratch_pool);
-      else
-        to_path = svn_dirent_basename(from_path_or_url, NULL);
+      to_path = svn_uri_basename(from_url, scratch_pool);
       eb->root_path = to_path;
     }
   else
     {
-      SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url,
-                                     from_is_url, scratch_pool));
+      SVN_ERR(append_basename_if_dir(&to_path, from_url,
+                                     TRUE, scratch_pool));
       eb->root_path = to_path;
     }
 
@@ -1288,7 +1284,7 @@ static svn_error_t *
 }
 
 static svn_error_t *
-export_directory(const char *from_path_or_url,
+export_directory(const char *from_url,
                  const char *to_path,
                  struct edit_baton *eb,
                  svn_client__pathrev_t *loc,
@@ -1307,6 +1303,8 @@ static svn_error_t *
   void *report_baton;
   svn_node_kind_t kind;
 
+  SVN_ERR_ASSERT(svn_path_is_url(from_url));
+
   if (!ENABLE_EV2_IMPL)
     SVN_ERR(get_editor_ev1(&export_editor, &edit_baton, eb, ctx,
                            scratch_pool, scratch_pool));
@@ -1355,7 +1353,7 @@ static svn_error_t *
 
       SVN_ERR(svn_dirent_get_absolute(&to_abspath, to_path, scratch_pool));
       SVN_ERR(svn_client__export_externals(eb->externals,
-                                           from_path_or_url,
+                                           from_url,
                                            to_abspath, eb->repos_root_url,
                                            depth, native_eol,
                                            ignore_keywords,
@@ -1402,8 +1400,12 @@ svn_client_export5(svn_revnum_t *result_rev,
       svn_client__pathrev_t *loc;
       svn_ra_session_t *ra_session;
       svn_node_kind_t kind;
+      const char *from_url;
       struct edit_baton *eb = apr_pcalloc(pool, sizeof(*eb));
 
+      SVN_ERR(svn_client_url_from_path2(&from_url, from_path_or_url,
+                                        ctx, pool, pool));
+
       /* Get the RA connection. */
       SVN_ERR(svn_client__ra_session_from_path2(&ra_session, &loc,
                                                 from_path_or_url, NULL,
@@ -1428,15 +1430,15 @@ svn_client_export5(svn_revnum_t *result_rev,
       if (kind == svn_node_file)
         {
           if (!ENABLE_EV2_IMPL)
-            SVN_ERR(export_file(from_path_or_url, to_path, eb, loc, ra_session,
+            SVN_ERR(export_file(from_url, to_path, eb, loc, ra_session,
                                 overwrite, pool));
           else
-            SVN_ERR(export_file_ev2(from_path_or_url, to_path, eb, loc,
+            SVN_ERR(export_file_ev2(from_url, to_path, eb, loc,
                                     ra_session, overwrite, pool));
         }
       else if (kind == svn_node_dir)
         {
-          SVN_ERR(export_directory(from_path_or_url, to_path,
+          SVN_ERR(export_directory(from_url, to_path,
                                    eb, loc, ra_session, overwrite,
                                    ignore_externals, ignore_keywords, depth,
                                    native_eol, ctx, pool));
Index: subversion/tests/cmdline/export_tests.py
===================================================================
--- subversion/tests/cmdline/export_tests.py    (revision 1802187)
+++ subversion/tests/cmdline/export_tests.py    (working copy)
@@ -1070,7 +1070,6 @@ def export_file_externals2(sbox):
                                         expected_output,
                                         expected_disk)
 
-@XFail()
 def export_revision_with_root_relative_external(sbox):
   "export a revision with root-relative external"
   sbox.build()
@@ -1089,18 +1088,37 @@ def export_revision_with_root_relative_external(sb
   # Update the working copy to receive file external
   svntest.main.run_svn(None, 'up', wc_dir)
 
+  # Update the expected disk tree to include the external.
+  expected_disk = svntest.main.greek_state.copy()
+  expected_disk.add({
+      'A/C/exfile_alpha'  : Item("This is the file 'alpha'.\n"),
+      })
+
+  # Update the expected output to include the external.
+  expected_output = svntest.main.greek_state.copy()
+  expected_output.add({
+      'A/C/exfile_alpha'  : Item("This is the file 'alpha'.\r"),
+      })
+  expected_output.desc[''] = Item()
+  expected_output.tweak(contents=None, status='A ')
+
   # Export revision 2 from URL
   export_target = sbox.add_wc_path('export_url')
-  svntest.actions.run_and_verify_svn(None, [],
-                                     'export', sbox.repo_url, export_target,
-                                     '-r', 2)
+  expected_output.wc_dir = export_target
+  svntest.actions.run_and_verify_export(sbox.repo_url,
+                                        export_target,
+                                        expected_output,
+                                        expected_disk,
+                                        '-r', 2)
 
   # Export revision 2 from WC
-  # Fails (canonicalize: Assertion `*src != '/'' failed)
   export_target = sbox.add_wc_path('export_wc')
-  svntest.actions.run_and_verify_svn(None, [],
-                                     'export', sbox.wc_dir, export_target,
-                                     '-r', 2)
+  expected_output.wc_dir = export_target
+  svntest.actions.run_and_verify_export(sbox.wc_dir,
+                                        export_target,
+                                        expected_output,
+                                        expected_disk,
+                                        '-r', 2)
 
 
 ########################################################################

Reply via email to