On Mon, Mar 21, 2011 at 10:20 AM, Philip Martin
<philip.mar...@wandisco.com> wrote:
> Danny Trebbien <dtrebb...@gmail.com> writes:
>> Attached are the patch, the log message, and the two TGZ archives of
>> DUMP files (for the tests).
>
> The patch is missing.
>
> --
> Philip

Sorry.  Attached is the patch with a .txt extension.
Index: subversion/svnsync/sync.h
===================================================================
--- subversion/svnsync/sync.h   (revision 1082876)
+++ subversion/svnsync/sync.h   (working copy)
@@ -33,15 +33,20 @@ extern "C" {
 #include "svn_delta.h"
 
 
-/* Normalize the line ending style of the values of properties in REV_PROPS
- * that "need translation" (according to svn_prop_needs_translation(),
- * currently all svn:* props) so that they contain only LF (\n) line endings.
- * The number of properties that needed normalization is returned in
+/* Normalize the encoding and line ending style of the values of properties
+ * in REV_PROPS that "need translation" (according to
+ * svn_prop_needs_translation(), which is currently all svn:* props) so that
+ * they are encoded in UTF-8 and contain only LF (\n) line endings.
+ *
+ * The number of properties that needed line ending normalization is returned 
in
  * *NORMALIZED_COUNT.
+ *
+ * No re-encoding is performed if SOURCE_PROP_ENCODING is NULL.
  */
 svn_error_t *
 svnsync_normalize_revprops(apr_hash_t *rev_props,
                            int *normalized_count,
+                           const char *source_prop_encoding,
                            apr_pool_t *pool);
 
 
@@ -51,15 +56,21 @@ svnsync_normalize_revprops(apr_hash_t *rev_props,
  * the commit.  TO_URL is the URL of the root of the repository into
  * which the commit is being made.
  *
+ * If SOURCE_PROP_ENCODING is NULL, then property values are presumed to be
+ * encoded in UTF-8 and are not re-encoded. Otherwise, the property values are
+ * presumed to be encoded in SOURCE_PROP_ENCODING, and are normalized to UTF-8.
+ *
  * As the sync editor encounters property values, it might see the need to
- * normalize them (to LF line endings). Each carried out normalization adds 1
- * to the *NORMALIZED_NODE_PROPS_COUNTER (for notification).
+ * normalize them (re-encode and/or change to LF line endings). Each 
carried-out
+ * line ending normalization adds 1 to the *NORMALIZED_NODE_PROPS_COUNTER
+ * (for notification).
  */
 svn_error_t *
 svnsync_get_sync_editor(const svn_delta_editor_t *wrapped_editor,
                         void *wrapped_edit_baton,
                         svn_revnum_t base_revision,
                         const char *to_url,
+                        const char *source_prop_encoding,
                         svn_boolean_t quiet,
                         const svn_delta_editor_t **editor,
                         void **edit_baton,
Index: subversion/svnsync/main.c
===================================================================
--- subversion/svnsync/main.c   (revision 1082876)
+++ subversion/svnsync/main.c   (working copy)
@@ -61,6 +61,7 @@ enum svnsync__opt {
   svnsync_opt_sync_password,
   svnsync_opt_config_dir,
   svnsync_opt_config_options,
+  svnsync_opt_source_prop_encoding,
   svnsync_opt_disable_locking,
   svnsync_opt_version,
   svnsync_opt_trust_server_cert,
@@ -105,8 +106,9 @@ static const svn_opt_subcommand_desc2_t svnsync_cm
          "the destination repository by any method other than 'svnsync'.\n"
          "In other words, the destination repository should be a read-only\n"
          "mirror of the source repository.\n"),
-      { SVNSYNC_OPTS_DEFAULT, 'q', svnsync_opt_allow_non_empty,
-        svnsync_opt_disable_locking, svnsync_opt_steal_lock } },
+      { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q',
+        svnsync_opt_allow_non_empty, svnsync_opt_disable_locking,
+        svnsync_opt_steal_lock } },
     { "synchronize", synchronize_cmd, { "sync" },
       N_("usage: svnsync synchronize DEST_URL [SOURCE_URL]\n"
          "\n"
@@ -118,8 +120,8 @@ static const svn_opt_subcommand_desc2_t svnsync_cm
          "source URL.  Specifying SOURCE_URL is recommended in particular\n"
          "if untrusted users/administrators may have write access to the\n"
          "DEST_URL repository.\n"),
-      { SVNSYNC_OPTS_DEFAULT, 'q', svnsync_opt_disable_locking,
-        svnsync_opt_steal_lock } },
+      { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q',
+        svnsync_opt_disable_locking, svnsync_opt_steal_lock } },
     { "copy-revprops", copy_revprops_cmd, { 0 },
       N_("usage:\n"
          "\n"
@@ -139,8 +141,8 @@ static const svn_opt_subcommand_desc2_t svnsync_cm
          "DEST_URL repository.\n"
          "\n"
          "Form 2 is deprecated syntax, equivalent to specifying 
\"-rREV[:REV2]\".\n"),
-      { SVNSYNC_OPTS_DEFAULT, 'q', 'r', svnsync_opt_disable_locking,
-        svnsync_opt_steal_lock } },
+      { SVNSYNC_OPTS_DEFAULT, svnsync_opt_source_prop_encoding, 'q', 'r',
+        svnsync_opt_disable_locking, svnsync_opt_steal_lock } },
     { "info", info_cmd, { 0 },
       N_("usage: svnsync info DEST_URL\n"
          "\n"
@@ -203,6 +205,12 @@ static const apr_getopt_option_t svnsync_options[]
                           "For example:\n"
                           "                             "
                           "    servers:global:http-library=serf")},
+    {"source-prop-encoding", svnsync_opt_source_prop_encoding, 1,
+                       N_("convert translatable properties from encoding ARG\n"
+                          "                             "
+                          "to UTF-8. If not specified, then properties are\n"
+                          "                             "
+                          "presumed to be encoded in UTF-8.")},
     {"disable-locking",  svnsync_opt_disable_locking, 0,
                        N_("Disable built-in locking.  Use of this option can\n"
                           "                             "
@@ -238,6 +246,7 @@ typedef struct opt_baton_t {
   const char *sync_password;
   const char *config_dir;
   apr_hash_t *config;
+  const char *source_prop_encoding;
   svn_boolean_t disable_locking;
   svn_boolean_t steal_lock;
   svn_boolean_t quiet;
@@ -364,6 +373,9 @@ typedef struct subcommand_baton_t {
   svn_boolean_t allow_non_empty;
   const char *to_url;
 
+  /* initialize, synchronize, and copy-revprops only */
+  const char *source_prop_encoding;
+
   /* initialize only */
   const char *from_url;
 
@@ -614,8 +626,11 @@ log_properties_normalized(int normalized_rev_props
  * If SYNC is TRUE, then properties on the destination revision that
  * do not exist on the source revision will be removed.
  *
+ * If QUIET is FALSE, then log_properties_copied() is called to log that
+ * properties were copied for revision REV.
+ *
  * Make sure the values of svn:* revision properties use only LF (\n)
- * lineending style, correcting their values as necessary. The number
+ * line ending style, correcting their values as necessary. The number
  * of properties that were normalized is returned in *NORMALIZED_COUNT.
  */
 static svn_error_t *
@@ -624,6 +639,7 @@ copy_revprops(svn_ra_session_t *from_session,
               svn_revnum_t rev,
               svn_boolean_t sync,
               svn_boolean_t quiet,
+              const char *source_prop_encoding,
               int *normalized_count,
               apr_pool_t *pool)
 {
@@ -639,9 +655,10 @@ copy_revprops(svn_ra_session_t *from_session,
   /* Get the list of revision properties on REV of SOURCE. */
   SVN_ERR(svn_ra_rev_proplist(from_session, rev, &rev_props, subpool));
 
-  /* If necessary, normalize line ending style, and return the count
-     of changes in int *NORMALIZED_COUNT. */
-  SVN_ERR(svnsync_normalize_revprops(rev_props, normalized_count, pool));
+  /* If necessary, normalize encoding and line ending style and return the 
count
+     of EOL-normalized properties in int *NORMALIZED_COUNT. */
+  SVN_ERR(svnsync_normalize_revprops(rev_props, normalized_count,
+                                     source_prop_encoding, pool));
 
   /* Copy all but the svn:svnsync properties. */
   SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props, pool));
@@ -682,6 +699,7 @@ make_subcommand_baton(opt_baton_t *opt_baton,
   b->quiet = opt_baton->quiet;
   b->allow_non_empty = opt_baton->allow_non_empty;
   b->to_url = to_url;
+  b->source_prop_encoding = opt_baton->source_prop_encoding;
   b->from_url = from_url;
   b->start_rev = start_rev;
   b->end_rev = end_rev;
@@ -786,8 +804,9 @@ do_initialize(svn_ra_session_t *to_session,
      LATEST is not 0, this really serves merely aesthetic and
      informational purposes, keeping the output of this command
      consistent while allowing folks to see what the latest revision is.  */
-  SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE,
-                        baton->quiet, &normalized_rev_props_count, pool));
+  SVN_ERR(copy_revprops(from_session, to_session, latest, FALSE, baton->quiet,
+                        baton->source_prop_encoding, 
&normalized_rev_props_count,
+                        pool));
 
   SVN_ERR(log_properties_normalized(normalized_rev_props_count, 0, pool));
 
@@ -930,7 +949,7 @@ open_target_session(svn_ra_session_t **target_sess
   return SVN_NO_ERROR;
 }
 
-/* Replay baton, used during sychnronization. */
+/* Replay baton, used during synchronization. */
 typedef struct replay_baton_t {
   svn_ra_session_t *from_session;
   svn_ra_session_t *to_session;
@@ -1064,9 +1083,11 @@ replay_rev_started(svn_revnum_t revision,
     apr_hash_set(filtered, SVN_PROP_REVISION_LOG, APR_HASH_KEY_STRING,
                  svn_string_create("", pool));
 
-  /* If necessary, normalize line ending style, and add the number
-     of changes to the overall count in the replay baton. */
-  SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_count, pool));
+  /* If necessary, normalize encoding and line ending style. Add the number
+     of properties that required EOL normalization to the overall count
+     in the replay baton. */
+  SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_count,
+                                     rb->sb->source_prop_encoding, pool));
   rb->normalized_rev_props_count += normalized_count;
 
   SVN_ERR(svn_ra_get_commit_editor3(rb->to_session, &commit_editor,
@@ -1079,8 +1100,8 @@ replay_rev_started(svn_revnum_t revision,
      over the RA interface, so we need an editor that's smart enough
      to filter those out for us.  */
   SVN_ERR(svnsync_get_sync_editor(commit_editor, commit_baton, revision - 1,
-                                  rb->sb->to_url, rb->sb->quiet,
-                                  &sync_editor, &sync_baton,
+                                  rb->sb->to_url, rb->sb->source_prop_encoding,
+                                  rb->sb->quiet, &sync_editor, &sync_baton,
                                   &(rb->normalized_node_props_count), pool));
 
   SVN_ERR(svn_delta_get_cancellation_editor(check_cancel, NULL,
@@ -1134,9 +1155,10 @@ replay_rev_finished(svn_revnum_t revision,
                             : filter_exclude_log),
                           subpool);
 
-  /* If necessary, normalize line ending style, and add the number
-     of changes to the overall count in the replay baton. */
-  SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_count, pool));
+  /* If necessary, normalize encoding and line ending style, and add the number
+     of EOL-normalized properties to the overall count in the replay baton. */
+  SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_count,
+                                     rb->sb->source_prop_encoding, pool));
   rb->normalized_rev_props_count += normalized_count;
 
   SVN_ERR(write_revprops(&filtered_count, rb->to_session, revision, filtered,
@@ -1240,10 +1262,9 @@ do_synchronize(svn_ra_session_t *to_session,
         {
           if (copying > last_merged)
             {
-              SVN_ERR(copy_revprops(from_session, to_session,
-                                    to_latest, TRUE, baton->quiet,
-                                    &normalized_rev_props_count,
-                                    pool));
+              SVN_ERR(copy_revprops(from_session, to_session, to_latest, TRUE,
+                                    baton->quiet, baton->source_prop_encoding,
+                                    &normalized_rev_props_count, pool));
               last_merged = copying;
               last_merged_rev = svn_string_create
                 (apr_psprintf(pool, "%ld", last_merged), pool);
@@ -1406,8 +1427,9 @@ do_copy_revprops(svn_ra_session_t *to_session,
     {
       int normalized_count;
       SVN_ERR(check_cancel(NULL));
-      SVN_ERR(copy_revprops(from_session, to_session, i, TRUE,
-                            baton->quiet, &normalized_count, pool));
+      SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, baton->quiet,
+                            baton->source_prop_encoding, &normalized_count,
+                            pool));
       normalized_rev_props_count += normalized_count;
     }
 
@@ -1709,6 +1731,7 @@ main(int argc, const char *argv[])
   const char *username = NULL, *source_username = NULL, *sync_username = NULL;
   const char *password = NULL, *source_password = NULL, *sync_password = NULL;
   apr_array_header_t *config_options = NULL;
+  const char *source_prop_encoding = NULL;
   apr_allocator_t *allocator;
 
   if (svn_cmdline_init("svnsync", stderr) != EXIT_SUCCESS)
@@ -1833,6 +1856,11 @@ main(int argc, const char *argv[])
               return svn_cmdline_handle_exit_error(err, pool, "svnsync: ");
             break;
 
+          case svnsync_opt_source_prop_encoding:
+            opt_err = svn_utf_cstring_to_utf8(&source_prop_encoding, opt_arg,
+                                              pool);
+            break;
+
           case svnsync_opt_disable_locking:
             opt_baton.disable_locking = TRUE;
             break;
@@ -2034,6 +2062,8 @@ main(int argc, const char *argv[])
   config = apr_hash_get(opt_baton.config, SVN_CONFIG_CATEGORY_CONFIG,
                         APR_HASH_KEY_STRING);
 
+  opt_baton.source_prop_encoding = source_prop_encoding;
+
   apr_signal(SIGINT, signal_handler);
 
 #ifdef SIGBREAK
Index: subversion/svnsync/sync.c
===================================================================
--- subversion/svnsync/sync.c   (revision 1082876)
+++ subversion/svnsync/sync.c   (working copy)
@@ -45,18 +45,27 @@
 #include <apr_uuid.h>
 
 
-/* Normalize the line ending style of *STR, so that it contains only
- * LF (\n) line endings. After return, *STR may point at a new
- * svn_string_t* allocated from POOL.
+/* Normalize the encoding and line ending style of *STR, so that it contains
+ * only LF (\n) line endings and is encoded in UTF-8. After return, *STR may
+ * point at a new svn_string_t* allocated in RESULT_POOL.
  *
- * *WAS_NORMALIZED is set to TRUE when *STR needed to be normalized,
- * and to FALSE if *STR remains unchanged.
+ * If SOURCE_PROP_ENCODING is NULL, then *STR is presumed to be encoded in
+ * UTF-8.
+ *
+ * *WAS_NORMALIZED is set to TRUE when *STR needed line ending normalization.
+ * Otherwise it is set to FALSE.
+ *
+ * SCRATCH_POOL is used for temporary allocations.
  */
 static svn_error_t *
 normalize_string(const svn_string_t **str,
                  svn_boolean_t *was_normalized,
-                 apr_pool_t *pool)
+                 const char *source_prop_encoding,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
+  svn_string_t *new_str;
+
   *was_normalized = FALSE;
 
   if (*str == NULL)
@@ -64,33 +73,33 @@ normalize_string(const svn_string_t **str,
 
   SVN_ERR_ASSERT((*str)->data != NULL);
 
-  /* Detect inconsistent line ending style simply by looking
-     for carriage return (\r) characters. */
-  if (strchr((*str)->data, '\r') != NULL)
-    {
-      /* Found some. Normalize. */
-      const char* cstring = NULL;
-      SVN_ERR(svn_subst_translate_cstring2((*str)->data, &cstring,
-                                           "\n", TRUE,
-                                           NULL, FALSE,
-                                           pool));
-      *str = svn_string_create(cstring, pool);
-      *was_normalized = TRUE;
-    }
+  if (source_prop_encoding == NULL)
+    source_prop_encoding = "UTF-8";
 
+  new_str = NULL;
+  SVN_ERR(svn_subst_translate_string2(&new_str, NULL, was_normalized,
+                                      *str, source_prop_encoding, TRUE,
+                                      result_pool, scratch_pool));
+  *str = new_str;
+
   return SVN_NO_ERROR;
 }
 
 
-/* Normalize the line ending style of the values of properties in REV_PROPS
- * that "need translation" (according to svn_prop_needs_translation(),
- * currently all svn:* props) so that they contain only LF (\n) line endings.
- * The number of properties that needed normalization is returned in
+/* Normalize the encoding and line ending style of the values of properties
+ * in REV_PROPS that "need translation" (according to
+ * svn_prop_needs_translation(), which is currently all svn:* props) so that
+ * they are encoded in UTF-8 and contain only LF (\n) line endings.
+ *
+ * The number of properties that needed line ending normalization is returned 
in
  * *NORMALIZED_COUNT.
+ *
+ * No re-encoding is performed if SOURCE_PROP_ENCODING is NULL.
  */
 svn_error_t *
 svnsync_normalize_revprops(apr_hash_t *rev_props,
                            int *normalized_count,
+                           const char *source_prop_encoding,
                            apr_pool_t *pool)
 {
   apr_hash_index_t *hi;
@@ -106,14 +115,14 @@ svnsync_normalize_revprops(apr_hash_t *rev_props,
       if (svn_prop_needs_translation(propname))
         {
           svn_boolean_t was_normalized;
-          SVN_ERR(normalize_string(&propval, &was_normalized, pool));
+          SVN_ERR(normalize_string(&propval, &was_normalized,
+                  source_prop_encoding, pool, pool));
+
+          /* Replace the existing prop value. */
+          apr_hash_set(rev_props, propname, APR_HASH_KEY_STRING, propval);
+
           if (was_normalized)
-            {
-              /* Replace the existing prop value. */
-              apr_hash_set(rev_props, propname, APR_HASH_KEY_STRING, propval);
-              /* And count this. */
-              (*normalized_count)++;
-            }
+            (*normalized_count)++; /* Count it. */
         }
     }
   return SVN_NO_ERROR;
@@ -141,6 +150,7 @@ typedef struct edit_baton_t {
   const svn_delta_editor_t *wrapped_editor;
   void *wrapped_edit_baton;
   const char *to_url;  /* URL we're copying into, for correct copyfrom URLs */
+  const char *source_prop_encoding;
   svn_boolean_t called_open_root;
   svn_boolean_t got_textdeltas;
   svn_revnum_t base_revision;
@@ -407,7 +417,8 @@ change_file_prop(void *file_baton,
   if (svn_prop_needs_translation(name))
     {
       svn_boolean_t was_normalized;
-      SVN_ERR(normalize_string(&value, &was_normalized, pool));
+      SVN_ERR(normalize_string(&value, &was_normalized,
+                               eb->source_prop_encoding, pool, pool));
       if (was_normalized)
         (*(eb->normalized_node_props_counter))++;
     }
@@ -505,7 +516,8 @@ change_dir_prop(void *dir_baton,
   if (svn_prop_needs_translation(name))
     {
       svn_boolean_t was_normalized;
-      SVN_ERR(normalize_string(&value, &was_normalized, pool));
+      SVN_ERR(normalize_string(&value, &was_normalized, 
eb->source_prop_encoding,
+                               pool, pool));
       if (was_normalized)
         (*(eb->normalized_node_props_counter))++;
     }
@@ -572,6 +584,7 @@ svnsync_get_sync_editor(const svn_delta_editor_t *
                         void *wrapped_edit_baton,
                         svn_revnum_t base_revision,
                         const char *to_url,
+                        const char *source_prop_encoding,
                         svn_boolean_t quiet,
                         const svn_delta_editor_t **editor,
                         void **edit_baton,
@@ -602,6 +615,7 @@ svnsync_get_sync_editor(const svn_delta_editor_t *
   eb->wrapped_edit_baton = wrapped_edit_baton;
   eb->base_revision = base_revision;
   eb->to_url = to_url;
+  eb->source_prop_encoding = source_prop_encoding;
   eb->quiet = quiet;
   eb->normalized_node_props_counter = normalized_node_props_counter;
 
@@ -629,4 +643,3 @@ svnsync_get_sync_editor(const svn_delta_editor_t *
 
   return SVN_NO_ERROR;
 }
-
Index: subversion/tests/cmdline/svnrdump_tests.py
===================================================================
--- subversion/tests/cmdline/svnrdump_tests.py  (revision 1082876)
+++ subversion/tests/cmdline/svnrdump_tests.py  (working copy)
@@ -305,11 +305,17 @@ def url_encoding_load(sbox):
   run_load_test(sbox, "url-encoding-bug.dump")
 
 def copy_bad_line_endings_dump(sbox):
-  "dump: inconsistent line endings in svn:props"
+  "dump: inconsistent line endings in svn:* props"
   run_dump_test(sbox, "copy-bad-line-endings.dump",
                 expected_dumpfile_name="copy-bad-line-endings.expected.dump",
                 bypass_prop_validation=True)
 
+def copy_bad_line_endings2_dump(sbox):
+  "dump: non-LF line endings in svn:* props"
+  run_dump_test(sbox, "copy-bad-line-endings2.dump",
+                expected_dumpfile_name="copy-bad-line-endings2.expected.dump",
+                bypass_prop_validation=True)
+
 def commit_a_copy_of_root_dump(sbox):
   "dump: commit a copy of root"
   run_dump_test(sbox, "repo-with-copy-of-root-dir.dump")
@@ -365,6 +371,7 @@ test_list = [ None,
               move_and_modify_in_the_same_revision_dump,
               move_and_modify_in_the_same_revision_load,
               copy_bad_line_endings_dump,
+              copy_bad_line_endings2_dump,
               commit_a_copy_of_root_dump,
               commit_a_copy_of_root_load,
               descend_into_replace_dump,
Index: subversion/tests/cmdline/svnsync_tests.py
===================================================================
--- subversion/tests/cmdline/svnsync_tests.py   (revision 1082876)
+++ subversion/tests/cmdline/svnsync_tests.py   (working copy)
@@ -27,6 +27,9 @@
 # General modules
 import sys, os
 
+# Test suite-specific modules
+import locale
+
 # Our testing module
 import svntest
 from svntest.verify import SVNUnexpectedStdout, SVNUnexpectedStderr
@@ -57,18 +60,22 @@ def build_repos(sbox):
   svntest.main.create_repos(sbox.repo_dir)
 
 
-def run_sync(url, source_url=None, expected_error=None):
+def run_sync(url, source_url=None, expected_error=None,
+             source_prop_encoding=None):
   "Synchronize the mirror repository with the master"
   if source_url is not None:
-    exit_code, output, errput = svntest.main.run_svnsync(
-      "synchronize", url, source_url,
+    args = ["synchronize", url, source_url,
       "--username", svntest.main.wc_author,
-      "--password", svntest.main.wc_passwd)
+      "--password", svntest.main.wc_passwd]
   else: # Allow testing of old source-URL-less syntax
-    exit_code, output, errput = svntest.main.run_svnsync(
-      "synchronize", url,
+    args = ["synchronize", url,
       "--username", svntest.main.wc_author,
-      "--password", svntest.main.wc_passwd)
+      "--password", svntest.main.wc_passwd]
+  if source_prop_encoding:
+    args.append("--source-prop-encoding")
+    args.append(source_prop_encoding)
+
+  exit_code, output, errput = svntest.main.run_svnsync(*args)
   if errput:
     if expected_error is None:
       raise SVNUnexpectedStderr(errput)
@@ -83,12 +90,17 @@ def build_repos(sbox):
     # should be: ['Committed revision 1.\n', 'Committed revision 2.\n']
     raise SVNUnexpectedStdout("Missing stdout")
 
-def run_copy_revprops(url, source_url, expected_error=None):
+def run_copy_revprops(url, source_url, expected_error=None,
+                      source_prop_encoding=None):
   "Copy revprops to the mirror repository from the master"
-  exit_code, output, errput = svntest.main.run_svnsync(
-    "copy-revprops", url, source_url,
+  args = ["copy-revprops", url, source_url,
     "--username", svntest.main.wc_author,
-    "--password", svntest.main.wc_passwd)
+    "--password", svntest.main.wc_passwd]
+  if source_prop_encoding:
+    args.append("--source-prop-encoding")
+    args.append(source_prop_encoding)
+
+  exit_code, output, errput = svntest.main.run_svnsync(*args)
   if errput:
     if expected_error is None:
       raise SVNUnexpectedStderr(errput)
@@ -104,12 +116,16 @@ def build_repos(sbox):
     #             'Copied properties for revision 2.\n']
     raise SVNUnexpectedStdout("Missing stdout")
 
-def run_init(dst_url, src_url):
+def run_init(dst_url, src_url, source_prop_encoding=None):
   "Initialize the mirror repository from the master"
-  exit_code, output, errput = svntest.main.run_svnsync(
-    "initialize", dst_url, src_url,
+  args = ["initialize", dst_url, src_url,
     "--username", svntest.main.wc_author,
-    "--password", svntest.main.wc_passwd)
+    "--password", svntest.main.wc_passwd]
+  if source_prop_encoding:
+    args.append("--source-prop-encoding")
+    args.append(source_prop_encoding)
+
+  exit_code, output, errput = svntest.main.run_svnsync(*args)
   if errput:
     raise SVNUnexpectedStderr(errput)
   if output != ['Copied properties for revision 0.\n']:
@@ -139,7 +155,7 @@ def run_info(url, expected_error=None):
 
 
 def setup_and_sync(sbox, dump_file_contents, subdir=None,
-                   bypass_prop_validation=False):
+                   bypass_prop_validation=False, source_prop_encoding=None):
   """Create a repository for SBOX, load it with DUMP_FILE_CONTENTS, then 
create a mirror repository and sync it with SBOX.  Return the mirror sandbox."""
 
   # Create the empty master repository.
@@ -165,10 +181,12 @@ def setup_and_sync(sbox, dump_file_contents, subdi
   repo_url = sbox.repo_url
   if subdir:
     repo_url = repo_url + subdir
-  run_init(dest_sbox.repo_url, repo_url)
+  run_init(dest_sbox.repo_url, repo_url, source_prop_encoding)
 
-  run_sync(dest_sbox.repo_url, repo_url)
-  run_copy_revprops(dest_sbox.repo_url, repo_url)
+  run_sync(dest_sbox.repo_url, repo_url,
+           source_prop_encoding=source_prop_encoding)
+  run_copy_revprops(dest_sbox.repo_url, repo_url,
+                    source_prop_encoding=source_prop_encoding)
 
   return dest_sbox
 
@@ -190,7 +208,7 @@ def verify_mirror(dest_sbox, exp_dump_file_content
     "Dump files", "DUMP", exp_dump_file_contents, dest_dump)
 
 def run_test(sbox, dump_file_name, subdir=None, exp_dump_file_name=None,
-             bypass_prop_validation=False):
+             bypass_prop_validation=False, source_prop_encoding=None):
   """Load a dump file, sync repositories, and compare contents with the 
original
 or another dump file."""
 
@@ -204,7 +222,7 @@ or another dump file."""
                                   'rb').readlines()
 
   dest_sbox = setup_and_sync(sbox, master_dumpfile_contents, subdir,
-                             bypass_prop_validation)
+                             bypass_prop_validation, source_prop_encoding)
 
   # Compare the dump produced by the mirror repository with either the original
   # dump file (used to create the master repository) or another specified dump
@@ -794,6 +812,40 @@ def copy_bad_line_endings(sbox):
            exp_dump_file_name="copy-bad-line-endings.expected.dump",
            bypass_prop_validation=True)
 
+def copy_bad_line_endings2(sbox):
+  "copy with non-LF line endings in svn:* props"
+  run_test(sbox, "copy-bad-line-endings2.dump",
+           exp_dump_file_name="copy-bad-line-endings2.expected.dump",
+           bypass_prop_validation=True)
+
+def copy_bad_encoding(sbox):
+  "copy and reencode non-UTF-8 svn:* props"
+  run_test(sbox, "copy-bad-encoding.dump",
+           exp_dump_file_name="copy-bad-encoding.expected.dump",
+           bypass_prop_validation=True, source_prop_encoding="ISO-8859-3")
+
+def identity_copy(sbox):
+  "copy UTF-8 svn:* props identically"
+  orig_lc_all = locale.setlocale(locale.LC_ALL)
+  other_locales = [ "English.1252", "German.1252", "French.1252",
+                    "en_US.ISO-8859-1", "en_GB.ISO-8859-1", "de_DE.ISO-8859-1",
+                    "en_US.ISO8859-1", "en_GB.ISO8859-1", "de_DE.ISO8859-1" ]
+  for other_locale in other_locales:
+    try:
+      locale.setlocale(locale.LC_ALL, other_locale)
+      break
+    except:
+      pass
+  if locale.setlocale(locale.LC_ALL) != other_locale:
+    raise svntest.Skip
+
+  try:
+    run_test(sbox, "copy-bad-encoding.expected.dump",
+             exp_dump_file_name="copy-bad-encoding.expected.dump",
+             bypass_prop_validation=True)
+  finally:
+    locale.setlocale(locale.LC_ALL, orig_lc_all)
+
 #----------------------------------------------------------------------
 
 def delete_svn_props(sbox):
@@ -912,6 +964,9 @@ test_list = [ None,
               info_synchronized,
               info_not_synchronized,
               copy_bad_line_endings,
+              copy_bad_line_endings2,
+              copy_bad_encoding,
+              identity_copy,
               delete_svn_props,
               commit_a_copy_of_root,
               descend_into_replace,

Reply via email to