Index: subversion/svnsync/sync.h =================================================================== --- subversion/svnsync/sync.h (revision 1052903) +++ 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 - * *NORMALIZED_COUNT. +/* 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_LE_COUNT. + * + * No re-encoding is performed if ENCODING is NULL. */ svn_error_t * svnsync_normalize_revprops(apr_hash_t *rev_props, - int *normalized_count, + int *normalized_le_count, + const char *encoding, apr_pool_t *pool); @@ -51,19 +56,25 @@ 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 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 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 *LE_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 *prop_encoding, svn_boolean_t quiet, const svn_delta_editor_t **editor, void **edit_baton, - int *normalized_node_props_counter, + int *le_normalized_node_props_counter, apr_pool_t *pool); Index: subversion/svnsync/main.c =================================================================== --- subversion/svnsync/main.c (revision 1052903) +++ 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_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_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_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_encoding, 'q', 'r', + svnsync_opt_disable_locking, svnsync_opt_steal_lock } }, { "info", info_cmd, { 0 }, N_("usage: svnsync info DEST_URL\n" "\n" @@ -159,7 +161,7 @@ static const apr_getopt_option_t svnsync_options[] { {"quiet", 'q', 0, N_("print as little as possible") }, - {"revision", 'r', 1, + {"revision", 'r', 1, N_("operate on revision ARG (or range ARG1:ARG2)\n" " " "A revision argument can be one of:\n" @@ -203,6 +205,12 @@ static const apr_getopt_option_t svnsync_options[] "For example:\n" " " " servers:global:http-library=serf")}, + {"source-encoding", svnsync_opt_source_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" " " @@ -226,7 +234,7 @@ static const apr_getopt_option_t svnsync_options[] { 0, 0, 0, 0 } }; -typedef struct { +typedef struct { /* opt_baton_t */ svn_boolean_t non_interactive; svn_boolean_t trust_server_cert; svn_boolean_t no_auth_cache; @@ -238,6 +246,7 @@ static const apr_getopt_option_t svnsync_options[] const char *sync_password; const char *config_dir; apr_hash_t *config; + const char *source_encoding; svn_boolean_t disable_locking; svn_boolean_t steal_lock; svn_boolean_t quiet; @@ -355,7 +364,7 @@ get_lock(const svn_string_t **lock_string_p, /* Baton for the various subcommands to share. */ -typedef struct { +typedef struct { /* subcommand_baton_t */ /* common to all subcommands */ apr_hash_t *config; svn_ra_callbacks2_t source_callbacks; @@ -364,6 +373,9 @@ get_lock(const svn_string_t **lock_string_p, svn_boolean_t allow_non_empty; const char *to_url; + /* initialize, synchronize, and copy-revprops only */ + const char *source_encoding; + /* initialize only */ const char *from_url; @@ -441,7 +453,7 @@ check_if_session_is_at_repos_root(svn_ra_session_t * revision REV of the repository associated with RA session SESSION. * * For REV zero, don't remove properties with the "svn:sync-" prefix. - * + * * All allocations will be done in a subpool of POOL. */ static svn_error_t * @@ -585,22 +597,22 @@ log_properties_copied(svn_boolean_t syncprops_foun return SVN_NO_ERROR; } -/* Print a notification that NORMALIZED_REV_PROPS_COUNT rev-props and - * NORMALIZED_NODE_PROPS_COUNT node-props were normalized to LF line +/* Print a notification that LE_NORMALIZED_REV_PROPS_COUNT rev-props and + * LE_NORMALIZED_NODE_PROPS_COUNT node-props were normalized to LF line * endings, if either of those numbers is non-zero. */ static svn_error_t * -log_properties_normalized(int normalized_rev_props_count, - int normalized_node_props_count, +log_properties_normalized(int le_normalized_rev_props_count, + int le_normalized_node_props_count, apr_pool_t *pool) { - if (normalized_rev_props_count > 0 || normalized_node_props_count > 0) + if (le_normalized_rev_props_count > 0 || le_normalized_node_props_count > 0) SVN_ERR(svn_cmdline_printf(pool, _("NOTE: Normalized %s* properties " "to LF line endings (%d rev-props, " "%d node-props).\n"), SVN_PROP_PREFIX, - normalized_rev_props_count, - normalized_node_props_count)); + le_normalized_rev_props_count, + le_normalized_node_props_count)); return SVN_NO_ERROR; } @@ -613,9 +625,12 @@ static svn_error_t * * 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 - * of properties that were normalized is returned in *NORMALIZED_COUNT. + * line ending style, correcting their values as necessary. The number + * of properties that were normalized is returned in *NORMALIZED_LE_COUNT. */ static svn_error_t * copy_revprops(svn_ra_session_t *from_session, @@ -623,7 +638,8 @@ copy_revprops(svn_ra_session_t *from_session, svn_revnum_t rev, svn_boolean_t sync, svn_boolean_t quiet, - int *normalized_count, + const char *prop_encoding, + int *normalized_le_count, apr_pool_t *pool) { apr_pool_t *subpool = svn_pool_create(pool); @@ -638,9 +654,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 changes in int *NORMALIZED_LE_COUNT. */ + SVN_ERR(svnsync_normalize_revprops(rev_props, normalized_le_count, + prop_encoding, pool)); /* Copy all but the svn:svnsync properties. */ SVN_ERR(write_revprops(&filtered_count, to_session, rev, rev_props, pool)); @@ -681,6 +698,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_encoding = opt_baton->source_encoding; b->from_url = from_url; b->start_rev = start_rev; b->end_rev = end_rev; @@ -708,7 +726,7 @@ do_initialize(svn_ra_session_t *to_session, svn_string_t *from_url; svn_revnum_t latest, from_latest; const char *uuid, *root_url; - int normalized_rev_props_count; + int le_normalized_rev_props_count; /* First, sanity check to see that we're copying into a brand new repos. If we aren't, and we aren't being asked to forcibly @@ -785,10 +803,11 @@ 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_encoding, &le_normalized_rev_props_count, + pool)); - SVN_ERR(log_properties_normalized(normalized_rev_props_count, 0, pool)); + SVN_ERR(log_properties_normalized(le_normalized_rev_props_count, 0, pool)); /* TODO: It would be nice if we could set the dest repos UUID to be equal to the UUID of the source repos, at least optionally. That @@ -930,13 +949,13 @@ open_target_session(svn_ra_session_t **target_sess } /* Replay baton, used during sychnronization. */ -typedef struct { +typedef struct { /* replay_baton_t */ svn_ra_session_t *from_session; svn_ra_session_t *to_session; subcommand_baton_t *sb; svn_boolean_t has_commit_revprops_capability; - int normalized_rev_props_count; - int normalized_node_props_count; + int le_normalized_rev_props_count; + int le_normalized_node_props_count; } replay_baton_t; /* Return a replay baton allocated from POOL and populated with @@ -1024,7 +1043,7 @@ replay_rev_started(svn_revnum_t revision, replay_baton_t *rb = replay_baton; apr_hash_t *filtered; int filtered_count; - int normalized_count; + int normalized_le_count; /* We set this property so that if we error out for some reason we can later determine where we were in the process of @@ -1063,10 +1082,12 @@ 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)); - rb->normalized_rev_props_count += normalized_count; + /* If necessary, normalize encoding and line ending style. Add the number + of properties that required line ending normalization to the overall count + in the replay baton. */ + SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_le_count, + rb->sb->source_encoding, pool)); + rb->le_normalized_rev_props_count += normalized_le_count; SVN_ERR(svn_ra_get_commit_editor3(rb->to_session, &commit_editor, &commit_baton, @@ -1078,9 +1099,9 @@ 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->normalized_node_props_count), pool)); + rb->sb->to_url, rb->sb->source_encoding, + rb->sb->quiet, &sync_editor, &sync_baton, + &(rb->le_normalized_node_props_count), pool)); SVN_ERR(svn_delta_get_cancellation_editor(check_cancel, NULL, sync_editor, sync_baton, @@ -1108,7 +1129,7 @@ replay_rev_finished(svn_revnum_t revision, replay_baton_t *rb = replay_baton; apr_hash_t *filtered, *existing_props; int filtered_count; - int normalized_count; + int normalized_le_count; SVN_ERR(editor->close_edit(edit_baton, pool)); @@ -1133,10 +1154,11 @@ replay_rev_finished(svn_revnum_t revision, : filter_exclude_log), subpool); - /* If necessary, normalize line ending style, and add the number + /* If necessary, normalize encoding and 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)); - rb->normalized_rev_props_count += normalized_count; + SVN_ERR(svnsync_normalize_revprops(filtered, &normalized_le_count, + rb->sb->source_encoding, pool)); + rb->le_normalized_rev_props_count += normalized_le_count; SVN_ERR(write_revprops(&filtered_count, rb->to_session, revision, filtered, subpool)); @@ -1187,7 +1209,7 @@ do_synchronize(svn_ra_session_t *to_session, svn_revnum_t to_latest, copying, last_merged; svn_revnum_t start_revision, end_revision; replay_baton_t *rb; - int normalized_rev_props_count = 0; + int le_normalized_rev_props_count = 0; SVN_ERR(open_source_session(&from_session, &last_merged_rev, baton->from_url, to_session, @@ -1239,10 +1261,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_encoding, + &le_normalized_rev_props_count, pool)); last_merged = copying; last_merged_rev = svn_string_create (apr_psprintf(pool, "%ld", last_merged), pool); @@ -1301,9 +1322,9 @@ do_synchronize(svn_ra_session_t *to_session, 0, TRUE, replay_rev_started, replay_rev_finished, rb, pool)); - SVN_ERR(log_properties_normalized(rb->normalized_rev_props_count - + normalized_rev_props_count, - rb->normalized_node_props_count, + SVN_ERR(log_properties_normalized(rb->le_normalized_rev_props_count + + le_normalized_rev_props_count, + rb->le_normalized_node_props_count, pool)); @@ -1374,7 +1395,7 @@ do_copy_revprops(svn_ra_session_t *to_session, svn_string_t *last_merged_rev; svn_revnum_t i; svn_revnum_t step = 1; - int normalized_rev_props_count = 0; + int le_normalized_rev_props_count = 0; SVN_ERR(open_source_session(&from_session, &last_merged_rev, baton->from_url, to_session, @@ -1403,15 +1424,16 @@ do_copy_revprops(svn_ra_session_t *to_session, step = (baton->start_rev > baton->end_rev) ? -1 : 1; for (i = baton->start_rev; i != baton->end_rev + step; i = i + step) { - int normalized_count; + int normalized_le_count; SVN_ERR(check_cancel(NULL)); - SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, - baton->quiet, &normalized_count, pool)); - normalized_rev_props_count += normalized_count; + SVN_ERR(copy_revprops(from_session, to_session, i, TRUE, baton->quiet, + baton->source_encoding, &normalized_le_count, + pool)); + le_normalized_rev_props_count += normalized_le_count; } /* Notify about normalized props, if any. */ - SVN_ERR(log_properties_normalized(normalized_rev_props_count, 0, pool)); + SVN_ERR(log_properties_normalized(le_normalized_rev_props_count, 0, pool)); return SVN_NO_ERROR; } @@ -1482,7 +1504,7 @@ resolve_revnums(svn_revnum_t *start_revnum, _("Invalid revision number (%ld)"), end_rev); } - + *start_revnum = start_rev; *end_revnum = end_rev; return SVN_NO_ERROR; @@ -1552,7 +1574,7 @@ copy_revprops_cmd(apr_getopt_t *os, void *b, apr_p from_url = NULL; } } - + if (! to_url) { /* This is the "... TO_URL SOURCE_URL" syntax. Revisions @@ -1580,7 +1602,7 @@ copy_revprops_cmd(apr_getopt_t *os, void *b, apr_p if (from_url && (! svn_path_is_url(from_url))) return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL, _("Path '%s' is not a URL"), from_url); - + baton = make_subcommand_baton(opt_baton, to_url, from_url, start_rev, end_rev, pool); SVN_ERR(open_target_session(&to_session, baton, pool)); @@ -1707,6 +1729,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; + opt_baton.source_encoding = NULL; apr_allocator_t *allocator; if (svn_cmdline_init("svnsync", stderr) != EXIT_SUCCESS) @@ -1831,6 +1854,10 @@ main(int argc, const char *argv[]) return svn_cmdline_handle_exit_error(err, pool, "svnsync: "); break; + case svnsync_opt_source_encoding: + opt_baton.source_encoding = apr_pstrdup(pool, opt_arg); + break; + case svnsync_opt_disable_locking: opt_baton.disable_locking = TRUE; break; Index: subversion/svnsync/sync.c =================================================================== --- subversion/svnsync/sync.c (revision 1052903) +++ subversion/svnsync/sync.c (working copy) @@ -45,56 +45,72 @@ #include -/* 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 ENCODING is NULL, then *STR is presumed to be encoded in UTF-8. + * + * *WAS_LE_NORMALIZED is set to TRUE when *STR needed line ending normalization. + * + * 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) + svn_boolean_t *was_le_normalized, + const char *encoding, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - *was_normalized = FALSE; + *was_le_normalized = FALSE; if (*str == NULL) return SVN_NO_ERROR; 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) + if (encoding) { + svn_string_t *new_str = NULL; + SVN_ERR(svn_subst_translate_string2(&new_str, NULL, was_le_normalized, + *str, encoding, result_pool, + scratch_pool)); + *str = new_str; + } + + /* Only detect inconsistent line ending style. This is accomplished by simply + looking for carriage return (\r) characters. */ + else if (memchr((*str)->data, (unsigned char) '\r', (*str)->len) != 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; + scratch_pool)); + *str = svn_string_create(cstring, result_pool); + *was_le_normalized = TRUE; } 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 - * *NORMALIZED_COUNT. +/* 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_LE_COUNT. No re-encoding is performed if ENCODING is NULL. */ svn_error_t * svnsync_normalize_revprops(apr_hash_t *rev_props, - int *normalized_count, + int *normalized_le_count, + const char *encoding, apr_pool_t *pool) { apr_hash_index_t *hi; - *normalized_count = 0; + *normalized_le_count = 0; for (hi = apr_hash_first(pool, rev_props); hi; @@ -105,15 +121,15 @@ 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)); - if (was_normalized) - { - /* Replace the existing prop value. */ - apr_hash_set(rev_props, propname, APR_HASH_KEY_STRING, propval); - /* And count this. */ - (*normalized_count)++; - } + svn_boolean_t was_le_normalized; + SVN_ERR(normalize_string(&propval, &was_le_normalized, encoding, pool, + pool)); + + /* Replace the existing prop value. */ + apr_hash_set(rev_props, propname, APR_HASH_KEY_STRING, propval); + + if (was_le_normalized) + (*normalized_le_count)++; /* Count it. */ } } return SVN_NO_ERROR; @@ -141,6 +157,7 @@ typedef struct { 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 *prop_encoding; svn_boolean_t called_open_root; svn_boolean_t got_textdeltas; svn_revnum_t base_revision; @@ -150,7 +167,8 @@ typedef struct { svn_boolean_t mergeinfo_stripped; /* Did we strip svn:mergeinfo? */ svn_boolean_t svnmerge_migrated; /* Did we convert svnmerge.py data? */ svn_boolean_t svnmerge_blocked; /* Was there any blocked svnmerge data? */ - int *normalized_node_props_counter; /* Where to count normalizations? */ + int *le_normalized_node_props_counter; /* Where to count line ending + normalizations? */ } edit_baton_t; @@ -407,9 +425,10 @@ 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->prop_encoding, + pool, pool)); if (was_normalized) - (*(eb->normalized_node_props_counter))++; + (*(eb->le_normalized_node_props_counter))++; } return eb->wrapped_editor->change_file_prop(fb->wrapped_node_baton, @@ -505,9 +524,10 @@ 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->prop_encoding, + pool, pool)); if (was_normalized) - (*(eb->normalized_node_props_counter))++; + (*(eb->le_normalized_node_props_counter))++; } return eb->wrapped_editor->change_dir_prop(db->wrapped_node_baton, @@ -572,10 +592,11 @@ svnsync_get_sync_editor(const svn_delta_editor_t * void *wrapped_edit_baton, svn_revnum_t base_revision, const char *to_url, + const char *prop_encoding, svn_boolean_t quiet, const svn_delta_editor_t **editor, void **edit_baton, - int *normalized_node_props_counter, + int *le_normalized_node_props_counter, apr_pool_t *pool) { svn_delta_editor_t *tree_editor = svn_delta_default_editor(pool); @@ -602,8 +623,9 @@ 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->prop_encoding = prop_encoding; eb->quiet = quiet; - eb->normalized_node_props_counter = normalized_node_props_counter; + eb->le_normalized_node_props_counter = le_normalized_node_props_counter; if (getenv("SVNSYNC_UNSUPPORTED_STRIP_MERGEINFO")) { @@ -629,4 +651,3 @@ svnsync_get_sync_editor(const svn_delta_editor_t * return SVN_NO_ERROR; } - Index: subversion/tests/cmdline/svnsync_tests.py =================================================================== --- subversion/tests/cmdline/svnsync_tests.py (revision 1052903) +++ subversion/tests/cmdline/svnsync_tests.py (working copy) @@ -186,7 +186,7 @@ def verify_mirror(dest_sbox, exp_dump_file_content svntest.verify.compare_and_display_lines( "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): """Load a dump file, sync repositories, and compare contents with the original @@ -214,9 +214,9 @@ or another dump file.""" exp_master_dumpfile_contents = master_dumpfile_contents verify_mirror(dest_sbox, exp_master_dumpfile_contents) - + ###################################################################### # Tests @@ -780,11 +780,17 @@ def info_not_synchronized(sbox): #---------------------------------------------------------------------- def copy_bad_line_endings(sbox): - "copy with inconsistent lineendings in svn:props" + "copy with inconsistent line endings in svn:* props" run_test(sbox, "copy-bad-line-endings.dump", 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 delete_svn_props(sbox): @@ -818,8 +824,8 @@ def commit_a_copy_of_root(sbox): # svnsync: File not found: revision 4, path '/trunk/H/Z/B/lambda' # # See also http://svn.haxx.se/dev/archive-2010-11/0411.shtml and -# # +# # Note: For those who may poke around this test in the future, r3 of # delete-revprops.dump was created with the following svnmucc command: # @@ -904,6 +910,7 @@ test_list = [ None, info_synchronized, info_not_synchronized, copy_bad_line_endings, + copy_bad_line_endings2, delete_svn_props, commit_a_copy_of_root, XFail(descend_into_replace),