You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by da...@apache.org on 2010/11/23 04:52:56 UTC

svn commit: r1037989 - in /subversion/trunk/subversion: include/svn_client.h libsvn_client/export.c tests/cmdline/export_tests.py

Author: danielsh
Date: Tue Nov 23 03:52:56 2010
New Revision: 1037989

URL: http://svn.apache.org/viewvc?rev=1037989&view=rev
Log:
Fix 'svn export' of a file source with a directory target.

* subversion/include/svn_client.h
  (svn_client_export5):
    Document the 'file source, dir target' case.
    Add some punctuation.

* subversion/libsvn_client/export.c
  (append_basename_if_dir): New helper.
  (copy_versioned_files): Use new helper for the "WC source" case.
  (svn_client_export5): Use new helper for the "URL source" case.

* subversion/tests/cmdline/export_tests.py
  (export_to_explicit_cwd):  Rename to..
  (export_url_to_explicit_cwd): .. this.
  (export_file_to_explicit_cwd): New test, similar to export_url_* variant.
  (test_list): Run new test, passing, and track rename.

Modified:
    subversion/trunk/subversion/include/svn_client.h
    subversion/trunk/subversion/libsvn_client/export.c
    subversion/trunk/subversion/tests/cmdline/export_tests.py

Modified: subversion/trunk/subversion/include/svn_client.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_client.h?rev=1037989&r1=1037988&r2=1037989&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_client.h (original)
+++ subversion/trunk/subversion/include/svn_client.h Tue Nov 23 03:52:56 2010
@@ -4486,11 +4486,13 @@ svn_client_revprop_list(apr_hash_t **pro
  * @a from_path_or_url is either the path the working copy on disk, or
  * a URL to the repository you wish to export.
  *
- * When exporting a directory @a to_path is the path to the directory
- * where you wish to create the exported tree, when exporting a file
- * it is the path of the file that will be created.  If @a to_path is
- * the empty path the name of the file/directory in the repository
- * will be used.
+ * When exporting a directory, @a to_path is the path to the directory
+ * where you wish to create the exported tree; when exporting a file, it
+ * is the path of the file that will be created.  If @a to_path is the
+ * empty path, then the basename of the export file/directory in the repository
+ * will be used.  If @a to_path represents an existing directory, and a
+ * file is being exported, then a file with the that basename will be
+ * created under that directory (as with 'copy' operations).
  *
  * @a peg_revision is the revision where the path is first looked up
  * when exporting from a repository.  If @a peg_revision->kind is

Modified: subversion/trunk/subversion/libsvn_client/export.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/export.c?rev=1037989&r1=1037988&r2=1037989&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/export.c (original)
+++ subversion/trunk/subversion/libsvn_client/export.c Tue Nov 23 03:52:56 2010
@@ -95,6 +95,36 @@ get_eol_style(svn_subst_eol_style_t *sty
   return SVN_NO_ERROR;
 }
 
+/* If *APPENDABLE_DIRENT_P represents an existing directory, then append
+ * to it the basename of BASENAME_OF and return the result in
+ * *APPENDABLE_DIRENT_P.  The kind of BASENAME_OF is either dirent or uri,
+ * as given by IS_URI.
+ */
+static svn_error_t *
+append_basename_if_dir(const char **appendable_dirent_p,
+                       const char *basename_of,
+                       svn_boolean_t is_uri,
+                       apr_pool_t *pool)
+{
+  svn_node_kind_t local_kind;
+  SVN_ERR(svn_io_check_resolved_path(*appendable_dirent_p, &local_kind, pool));
+  if (local_kind == svn_node_dir)
+    {
+      const char *basename2; /* _2 because it shadows basename() */
+      
+      if (is_uri)
+        basename2 = svn_path_uri_decode(svn_uri_basename(basename_of, NULL), pool);
+      else
+        basename2 = svn_dirent_basename(basename_of, NULL);
+
+      *appendable_dirent_p = svn_dirent_join(*appendable_dirent_p,
+                                             basename2,
+                                             pool);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 copy_one_versioned_file(const char *from_abspath,
                         const char *to_abspath,
@@ -495,6 +525,7 @@ copy_versioned_files(const char *from,
     }
   else if (from_kind == svn_node_file)
     {
+      SVN_ERR(append_basename_if_dir(&to_abspath, from_abspath, FALSE, pool));
       SVN_ERR(copy_one_versioned_file(from_abspath, to_abspath, ctx->wc_ctx,
                                       revision, native_eol, ignore_keywords,
                                       pool));
@@ -1000,6 +1031,13 @@ svn_client_export5(svn_revnum_t *result_
                                                              NULL), pool);
               eb->root_path = to_path;
             }
+          else
+            {
+              SVN_ERR(append_basename_if_dir(&to_path, from_path_or_url, 
+                                             TRUE, pool));
+              eb->root_path = to_path;
+            }
+
           
           /* Since you cannot actually root an editor at a file, we
            * manually drive a few functions of our editor. */

Modified: subversion/trunk/subversion/tests/cmdline/export_tests.py
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/export_tests.py?rev=1037989&r1=1037988&r2=1037989&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/export_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/export_tests.py Tue Nov 23 03:52:56 2010
@@ -413,8 +413,8 @@ def export_HEADplus1_fails(sbox):
                                      'export', sbox.repo_url, sbox.wc_dir,
                                      '-r', 38956)
 
-def export_to_explicit_cwd(sbox):
-  "export a single file to '.'"
+def export_url_to_explicit_cwd(sbox):
+  "export a single file to '.', via url"
   sbox.build(create_wc = False, read_only = True)
 
   svntest.main.safe_rmtree(sbox.wc_dir)
@@ -431,6 +431,38 @@ def export_to_explicit_cwd(sbox):
                                         '.', expected_output,
                                         expected_disk)
 
+def export_file_to_explicit_cwd(sbox):
+  "export a single file to '.', via wc"
+  sbox.build(create_wc = True, read_only = True)
+
+  iota_path = os.path.abspath(os.path.join(sbox.wc_dir, 'iota'))
+  expected_output = svntest.wc.State('', {
+      'iota': Item(status='A '),
+      })
+  expected_disk = svntest.wc.State('', {
+      'iota': Item(contents="This is the file 'iota'.\n"),
+      })
+
+  # prepare some variables
+  oldcwd = os.path.abspath(os.getcwd())
+  tmpdir = sbox.get_tempname('file-exports')
+  os.mkdir(tmpdir)
+
+  # do the work
+  os.chdir(tmpdir)
+  svntest.actions.run_and_verify_svn(None, None, [], 
+                                     'export', iota_path, '.')
+
+  # TODO: avoid manual validation
+  try:
+    if open('iota').readlines() == ["This is the file 'iota'.\n"]:
+      return
+    else:
+      raise
+  except:
+    target_file = os.path.join(oldcwd, tmpdir, 'iota')
+    raise svntest.Failure("'%s' not properly exported" % target_file)
+
 def export_ignoring_keyword_translation(sbox):
   "export ignoring keyword translation"
   sbox.build()
@@ -674,7 +706,8 @@ test_list = [ None,
               export_with_state_deleted,
               export_creates_intermediate_folders,
               export_HEADplus1_fails,
-              export_to_explicit_cwd,
+              export_url_to_explicit_cwd,
+              export_file_to_explicit_cwd,
               export_ignoring_keyword_translation,
               export_working_copy_ignoring_keyword_translation,
               export_with_url_unsafe_characters,