Modified: subversion/branches/addremove/subversion/svnserve/serve.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/svnserve/serve.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/svnserve/serve.c (original)
+++ subversion/branches/addremove/subversion/svnserve/serve.c Tue Aug 22 
14:19:36 2017
@@ -2823,6 +2823,8 @@ static svn_error_t *file_rev_handler(voi
 
       /* If the connection does not support SVNDIFF1 or if we don't want to use
        * compression, use the non-compressing "version 0" implementation */
+      /* ### TODO: Check SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED and decide between
+       * ###       svndiff1[at compression_level] and svndiff2 */
       if (   svn_ra_svn_compression_level(frb->conn) > 0
           && svn_ra_svn_has_capability(frb->conn, SVN_RA_SVN_CAP_SVNDIFF1))
         svn_txdelta_to_svndiff3(d_handler, d_baton, stream, 1,
@@ -3804,6 +3806,7 @@ find_repos(const char *url,
 {
   const char *path, *full_path, *fs_path, *hooks_env;
   svn_stringbuf_t *url_buf;
+  svn_boolean_t sasl_requested;
 
   /* Skip past the scheme and authority part. */
   path = skip_scheme_part(url);
@@ -3877,14 +3880,16 @@ find_repos(const char *url,
   SVN_ERR(load_authz_config(repository, repository->repos_root, cfg,
                             result_pool));
 
-#ifdef SVN_HAVE_SASL
+  /* Should we use Cyrus SASL? */
+  SVN_ERR(svn_config_get_bool(cfg, &sasl_requested,
+                              SVN_CONFIG_SECTION_SASL,
+                              SVN_CONFIG_OPTION_USE_SASL, FALSE));
+  if (sasl_requested)
     {
+#ifdef SVN_HAVE_SASL
       const char *val;
 
-      /* Should we use Cyrus SASL? */
-      SVN_ERR(svn_config_get_bool(cfg, &repository->use_sasl,
-                                  SVN_CONFIG_SECTION_SASL,
-                                  SVN_CONFIG_OPTION_USE_SASL, FALSE));
+      repository->use_sasl = sasl_requested;
 
       svn_config_get(cfg, &val, SVN_CONFIG_SECTION_SASL,
                     SVN_CONFIG_OPTION_MIN_SSF, "0");
@@ -3893,8 +3898,18 @@ find_repos(const char *url,
       svn_config_get(cfg, &val, SVN_CONFIG_SECTION_SASL,
                     SVN_CONFIG_OPTION_MAX_SSF, "256");
       SVN_ERR(svn_cstring_atoui(&repository->max_ssf, val));
+#else /* !SVN_HAVE_SASL */
+      return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+                               _("SASL requested but not compiled in; "
+                                 "set '%s' to 'false' or recompile "
+                                 "svnserve with SASL support"),
+                               SVN_CONFIG_OPTION_USE_SASL);
+#endif /* SVN_HAVE_SASL */
+    }
+  else
+    {
+      repository->use_sasl = FALSE;
     }
-#endif
 
   /* Use the repository UUID as the default realm. */
   SVN_ERR(svn_fs_get_uuid(repository->fs, &repository->realm, scratch_pool));
@@ -4122,10 +4137,11 @@ construct_server_baton(server_baton_t **
    * send an empty mechlist. */
   if (params->compression_level > 0)
     SVN_ERR(svn_ra_svn__write_cmd_response(conn, scratch_pool,
-                                           "nn()(wwwwwwwwwwww)",
+                                           "nn()(wwwwwwwwwwwww)",
                                            (apr_uint64_t) 2, (apr_uint64_t) 2,
                                            SVN_RA_SVN_CAP_EDIT_PIPELINE,
                                            SVN_RA_SVN_CAP_SVNDIFF1,
+                                           SVN_RA_SVN_CAP_SVNDIFF2_ACCEPTED,
                                            SVN_RA_SVN_CAP_ABSENT_ENTRIES,
                                            SVN_RA_SVN_CAP_COMMIT_REVPROPS,
                                            SVN_RA_SVN_CAP_DEPTH,

Modified: subversion/branches/addremove/subversion/tests/cmdline/davautocheck.sh
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/davautocheck.sh?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/davautocheck.sh 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/davautocheck.sh Tue 
Aug 22 14:19:36 2017
@@ -313,6 +313,9 @@ if [ ${APACHE_MPM:+set} ]; then
     LOAD_MOD_MPM=$(get_loadmodule_config mod_mpm_$APACHE_MPM) \
       || fail "MPM module not found"
 fi
+if [ x"$APACHE_MPM" = x"event" ] && [ x"$FS_TYPE" = x"bdb" ]; then
+  fail "FS_TYPE=bdb and APACHE_MPM=event are mutually exclusive (see SVN-4157)"
+fi
 if [ ${USE_SSL:+set} ]; then
     LOAD_MOD_SSL=$(get_loadmodule_config mod_ssl) \
       || fail "SSL module not found"

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/externals_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/externals_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/externals_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/externals_tests.py 
Tue Aug 22 14:19:36 2017
@@ -4365,6 +4365,39 @@ def external_externally_removed(sbox):
   sbox.simple_propdel('svn:externals', '')
   sbox.simple_update() # Should succeed
 
+def invalid_uris_in_repo(sbox):
+  "invalid URIs in repo"
+
+  sbox.build(empty=True),
+
+  # Using a dump file because the client may not allow adding invalid URIs.
+  svntest.actions.load_repo(sbox,
+                            os.path.join(os.path.dirname(sys.argv[0]),
+                                         'externals_tests_data',
+                                         'invalid_uris_in_repo.dump'),
+                            create_wc=False)
+
+  # 'foo://host:-/D X'
+  expected_output = svntest.wc.State(sbox.wc_dir, {
+    '' : Item(status=' U')
+    })
+  expected_disk =  svntest.wc.State('', {
+    })
+  expected_error = ".*warning: W205011: Error handling externals definition.*"
+
+  # A repository might have invalid URIs and the client used to SEGV.
+  # r1 has 'foo://host:-/D X'
+  # r2 has 'foo://host::/D X'
+  # r3 has 'foo://host:123xx/D X'
+  # r4 has 'foo://host:123:123/D X'
+  for revision in range(1,4):
+    svntest.actions.run_and_verify_checkout(sbox.repo_url, sbox.wc_dir,
+                                            expected_output,
+                                            expected_disk,
+                                            expected_error,
+                                            "-r", revision)
+    svntest.main.safe_rmtree(sbox.wc_dir)
+
 ########################################################################
 # Run the tests
 
@@ -4440,6 +4473,7 @@ test_list = [ None,
               file_external_to_normal_file,
               file_external_recorded_info,
               external_externally_removed,
+              invalid_uris_in_repo,
              ]
 
 if __name__ == '__main__':

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
 (original)
+++ 
subversion/branches/addremove/subversion/tests/cmdline/getopt_tests_data/svn_help_log_switch_stdout
 Tue Aug 22 14:19:36 2017
@@ -209,15 +209,15 @@ Valid options:
                              'empty', 'files', 'immediates', or 'infinity')
   -q [--quiet]             : print nothing, or only summary information
   --diff3-cmd ARG          : use ARG as merge command
-  --relocate               : relocate via URL-rewriting
   --ignore-externals       : ignore externals definitions
   --ignore-ancestry        : allow switching to a node with no common ancestor
   --force                  : handle unversioned obstructions as changes
   --accept ARG             : specify automatic conflict resolution action
                              ('postpone', 'working', 'base', 'mine-conflict',
                              'theirs-conflict', 'mine-full', 'theirs-full',
-                             'edit', 'launch')
-                             (shorthand: 'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l')
+                             'edit', 'launch', 'recommended') (shorthand:
+                             'p', 'mc', 'tc', 'mf', 'tf', 'e', 'l', 'r')
+  --relocate               : deprecated; use 'svn relocate'
 
 Global options:
   --username ARG           : specify a username ARG

Modified: subversion/branches/addremove/subversion/tests/cmdline/merge_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/merge_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/merge_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/merge_tests.py Tue 
Aug 22 14:19:36 2017
@@ -17395,7 +17395,8 @@ def merge_target_selection(sbox):
     ' U   .\n',
   ] + svntest.main.summary_of_conflicts(tree_conflicts=1)
   svntest.actions.run_and_verify_svn(expected_output, [],
-                                     'merge', '^/dir/binary-file', '-c', '4', 
'.')
+                                     'merge', '^/dir/binary-file',
+                                     '-c', '4', '.', '--accept', 'postpone')
 
   svntest.main.run_svn(None, 'revert', '-R', '.')
 
@@ -17407,7 +17408,8 @@ def merge_target_selection(sbox):
     ' U   binary-file\n',
   ] + svntest.main.summary_of_conflicts(tree_conflicts=1)
   svntest.actions.run_and_verify_svn(expected_output, [],
-                                     'merge', '^/dir', '-c', '4', 
'binary-file')
+                                     'merge', '^/dir', '-c', '4', 
'binary-file',
+                                     '--accept', 'postpone')
 
 @SkipUnless(server_has_mergeinfo)
 @Issue(3405) # seems to be the wrong issue number

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/merge_tree_conflict_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/merge_tree_conflict_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/cmdline/merge_tree_conflict_tests.py
 (original)
+++ 
subversion/branches/addremove/subversion/tests/cmdline/merge_tree_conflict_tests.py
 Tue Aug 22 14:19:36 2017
@@ -1695,7 +1695,7 @@ def merge_replace_causes_tree_conflict(s
   ], target=A, two_url=True, tree_conflicts=4)
 
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    url_A, url_branch, A)
+    url_A, url_branch, A, '--accept=postpone')
 
   # svn st
   expected_status.tweak('A', status=' M')
@@ -1781,7 +1781,7 @@ def merge_replace_causes_tree_conflict2(
   ], target=A, two_url=True, tree_conflicts=1)
 
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    url_A, url_branch, A, '--depth=files')
+    url_A, url_branch, A, '--depth=files', '--accept=postpone')
   # New mergeinfo describing the merge.
   expected_status.tweak('A', status=' M')
   # Currently this fails because the local status is 'D'eleted rather than
@@ -1801,7 +1801,7 @@ def merge_replace_causes_tree_conflict2(
   ], target=A_B, two_url=True, tree_conflicts=1)
 
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    url_A_B, url_branch_B, A_B)
+    url_A_B, url_branch_B, A_B, '--accept=postpone')
   # New mergeinfo describing the merge.
   expected_status.tweak('A/B', status=' M')
   # Currently this fails because the local status shows a property mod (and
@@ -1821,7 +1821,7 @@ def merge_replace_causes_tree_conflict2(
   ], target=A_D, two_url=True, tree_conflicts=1)
 
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    '--depth=immediates', url_A_D, url_branch_D, A_D)
+    '--depth=immediates', url_A_D, url_branch_D, A_D, '--accept=postpone')
   # New mergeinfo describing the merge.
   expected_status.tweak('A/D', 'A/D/G', status=' M')
   # Currently this fails because the local status is 'D'eleted rather than
@@ -1841,7 +1841,7 @@ def merge_replace_causes_tree_conflict2(
   ], target=A_D_G, two_url=True, tree_conflicts=1)
 
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    url_A_D_G, url_branch_D_G, A_D_G)
+    url_A_D_G, url_branch_D_G, A_D_G, '--accept=postpone')
   # New mergeinfo describing the merge.
   expected_status.tweak('A/D/G', status=' M')
   # Currently this fails because the local status shows a property mod (and
@@ -1932,7 +1932,7 @@ def merge_replace_on_del_fails(sbox):
   #     cmdline\svn-test-work\working_copies\merge_tree_conflict_tests-24\
   #     branch\C' was not found.
   actions.run_and_verify_svn2(expected_stdout, [], 0, 'merge',
-    sbox.repo_url + '/A', branch_path)
+    sbox.repo_url + '/A', branch_path, '--accept=postpone')
 
 def merge_conflict_details(sbox):
   "merge conflict details"

Modified: subversion/branches/addremove/subversion/tests/cmdline/patch_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/patch_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/patch_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/patch_tests.py Tue 
Aug 22 14:19:36 2017
@@ -4696,6 +4696,7 @@ def patch_apply_no_fuz(sbox):
                                        expected_status, expected_skip,
                                        [], True, True)
 
+@Issue(4315)
 def patch_lacking_trailing_eol_on_context(sbox):
   "patch file lacking trailing eol on context"
 

Modified: subversion/branches/addremove/subversion/tests/cmdline/stat_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/stat_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/stat_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/stat_tests.py Tue 
Aug 22 14:19:36 2017
@@ -2224,7 +2224,8 @@ def status_missing_conflicts(sbox):
 
   sbox.simple_rm('A/B/E')
 
-  sbox.simple_update('A/B/E', revision=1)
+  svntest.main.run_svn(False, 'update', sbox.ospath('A/B/E'), '-r', '1',
+    '--accept=postpone')
 
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
   expected_status.tweak('A/B/E', status='D ', treeconflict='C', wc_rev=1)
@@ -2277,7 +2278,8 @@ def status_missing_conflicts(sbox):
   sbox.simple_move('A/B/E/beta', 'beta')
 
   sbox.simple_rm('A/B/E')
-  sbox.simple_update('A/B/E', revision=1)
+  svntest.main.run_svn(False, 'update', sbox.ospath('A/B/E'), '-r', '1',
+    '--accept=postpone')
   svntest.actions.run_and_verify_svn(None, [],
                                      'resolve', '--accept=mine-conflict',
                                      '--depth=empty', sbox.ospath('A/B/E'))

Modified: subversion/branches/addremove/subversion/tests/cmdline/svntest/main.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/svntest/main.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/svntest/main.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/svntest/main.py Tue 
Aug 22 14:19:36 2017
@@ -1043,14 +1043,14 @@ def _post_create_repos(path, minor_versi
         shutil.copy(options.config_file, confpath)
 
       if options.memcached_server is not None or \
-         options.fsfs_compression_level is not None and \
+         options.fsfs_compression is not None and \
          os.path.exists(confpath):
         with open(confpath, 'r') as conffile:
           newlines = []
           for line in conffile.readlines():
-            if line.startswith('# compression-level ') and \
-               options.fsfs_compression_level is not None:
-              line = 'compression-level = %d\n' % 
options.fsfs_compression_level
+            if line.startswith('# compression ') and \
+               options.fsfs_compression is not None:
+              line = 'compression = %s\n' % options.fsfs_compression
             newlines += line
             if options.memcached_server is not None and \
                line == '[memcached-servers]\n':
@@ -1737,8 +1737,8 @@ class TestSpawningThread(threading.Threa
       args.append('--fsfs-version=' + str(options.fsfs_version))
     if options.dump_load_cross_check:
       args.append('--dump-load-cross-check')
-    if options.fsfs_compression_level:
-      args.append('--fsfs-compression=' + str(options.fsfs_compression_level))
+    if options.fsfs_compression:
+      args.append('--fsfs-compression=' + options.fsfs_compression)
 
     result, stdout_lines, stderr_lines = spawn_process(command, 0, False, None,
                                                        *args)
@@ -2151,9 +2151,8 @@ def _create_parser(usage=None):
                     help='Use sqlite exclusive locking for working copies')
   parser.add_option('--memcached-server', action='store',
                     help='Use memcached server at specified URL (FSFS only)')
-  parser.add_option('--fsfs-compression', action='store', type='int',
-                    dest="fsfs_compression_level",
-                    help='Set compression level (for fsfs)')
+  parser.add_option('--fsfs-compression', action='store', type='str',
+                    help='Set compression type (for fsfs)')
 
   # most of the defaults are None, but some are other values, set them here
   parser.set_defaults(
@@ -2203,10 +2202,6 @@ def parse_options(arglist=sys.argv[1:],
   if options.fsfs_packing and not options.fsfs_sharding:
     parser.error("--fsfs-packing requires --fsfs-sharding")
 
-  if options.fsfs_compression_level is not None and\
-     options.fsfs_compression_level not in range(0, 10):
-    parser.error("--fsfs-compression must be between 0 and 9")
-
   if options.server_minor_version not in range(3, SVN_VER_MINOR+1):
     parser.error("test harness only supports server minor versions 3-%d"
                  % SVN_VER_MINOR)

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/svntest/mergetrees.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/svntest/mergetrees.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/cmdline/svntest/mergetrees.py 
(original)
+++ 
subversion/branches/addremove/subversion/tests/cmdline/svntest/mergetrees.py 
Tue Aug 22 14:19:36 2017
@@ -446,7 +446,8 @@ def svn_merge(rev_range, source, target,
                                   prop_resolved=prop_resolved,
                                   tree_resolved=tree_resolved)
   actions.run_and_verify_svn(exp_out, [],
-                                     'merge', rev_arg, source, target, *args)
+                                     'merge', rev_arg, source, target,
+                                     '--accept=postpone', *args)
 
 #----------------------------------------------------------------------
 # Setup helper for issue #4056 and issue #4057 tests.

Modified: 
subversion/branches/addremove/subversion/tests/cmdline/tree_conflict_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/tree_conflict_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/cmdline/tree_conflict_tests.py 
(original)
+++ 
subversion/branches/addremove/subversion/tests/cmdline/tree_conflict_tests.py 
Tue Aug 22 14:19:36 2017
@@ -463,7 +463,7 @@ def ensure_tree_conflict(sbox, operation
       if operation == 'update':
         logger.debug("--- Updating")
         run_and_verify_svn(expected_stdout, [],
-                           'update', target_path)
+                           'update', target_path, '--accept=postpone')
       elif operation == 'switch':
         logger.debug("--- Switching")
         run_and_verify_svn(expected_stdout, [],

Modified: subversion/branches/addremove/subversion/tests/cmdline/update_tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/cmdline/update_tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/cmdline/update_tests.py 
(original)
+++ subversion/branches/addremove/subversion/tests/cmdline/update_tests.py Tue 
Aug 22 14:19:36 2017
@@ -6792,7 +6792,9 @@ def missing_tmp_update(sbox):
   svntest.actions.run_and_verify_svn(None, '.*Unable to create.*',
                                      'up', wc_dir, '--set-depth', 'infinity')
 
-  svntest.actions.run_and_verify_svn(None, [], 'cleanup', wc_dir)
+  # This re-creates .svn/tmp as a side-effect.
+  svntest.actions.run_and_verify_svn(None, [], 'cleanup',
+                                     '--vacuum-pristines', wc_dir)
 
   svntest.actions.run_and_verify_update(wc_dir, None, None, None, [], False,
                                         wc_dir, '--set-depth', 'infinity')

Modified: 
subversion/branches/addremove/subversion/tests/libsvn_client/conflicts-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_client/conflicts-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/libsvn_client/conflicts-test.c 
(original)
+++ 
subversion/branches/addremove/subversion/tests/libsvn_client/conflicts-test.c 
Tue Aug 22 14:19:36 2017
@@ -4578,6 +4578,89 @@ test_update_incoming_added_dir_merge2(co
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_cherry_pick_post_move_edit(const svn_test_opts_t *opts,
+                                apr_pool_t *pool)
+{
+  svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+  const char *trunk_url;
+  svn_opt_revision_t peg_rev;
+  apr_array_header_t *ranges_to_merge;
+  svn_opt_revision_range_t merge_range;
+  svn_client_ctx_t *ctx;
+  svn_client_conflict_t *conflict;
+  svn_boolean_t tree_conflicted;
+
+  SVN_ERR(svn_test__sandbox_create(b,
+                                   "test_cherry_pick_post_move_edit",
+                                   opts, pool));
+
+  SVN_ERR(sbox_add_and_commit_greek_tree(b)); /* r1 */
+  /* Create a copy of node "A". */
+  SVN_ERR(sbox_wc_copy(b, "A", "A1"));
+  SVN_ERR(sbox_wc_commit(b, "")); /* r2 */
+  /* On "trunk", move the file mu. */
+  SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved"));
+  SVN_ERR(sbox_wc_commit(b, "")); /* r3 */
+  /* On "trunk", edit mu-moved. This will be r4, which we'll cherry-pick. */
+  SVN_ERR(sbox_file_write(b, "A/mu-moved", "Modified content.\n"));
+  SVN_ERR(sbox_wc_commit(b, "")); /* r4 */
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+
+  /* Perform a cherry-pick merge of r4 from A to A1. */
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, b->pool));
+  trunk_url = apr_pstrcat(b->pool, b->repos_url, "/A", SVN_VA_NULL);
+  peg_rev.kind = svn_opt_revision_number;
+  peg_rev.value.number = 4;
+  merge_range.start.kind = svn_opt_revision_number;
+  merge_range.start.value.number = 3;
+  merge_range.end.kind = svn_opt_revision_number;
+  merge_range.end.value.number = 4;
+  ranges_to_merge = apr_array_make(b->pool, 1,
+                                   sizeof(svn_opt_revision_range_t *));
+  APR_ARRAY_PUSH(ranges_to_merge, svn_opt_revision_range_t *) = &merge_range;
+  /* This should raise a "local delete or move vs incoming edit" conflict. */
+  SVN_ERR(svn_client_merge_peg5(trunk_url, ranges_to_merge, &peg_rev,
+                                sbox_wc_path(b, "A1"), svn_depth_infinity,
+                                FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+                                NULL, ctx, b->pool));
+
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu-moved"),
+                                  ctx, b->pool, b->pool));
+  SVN_ERR(svn_client_conflict_get_conflicted(NULL, NULL, &tree_conflicted,
+                                             conflict, b->pool, b->pool));
+  SVN_TEST_ASSERT(tree_conflicted);
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts,
+                                         b->pool));
+  }
+
+  SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, b->pool));
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      svn_client_conflict_option_local_move_file_text_merge,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts,
+                                         b->pool));
+  }
+
+  /* Try to resolve the conflict. */
+  SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+            conflict,
+            svn_client_conflict_option_local_move_file_text_merge,
+            ctx, b->pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Regression test for chrash fixed in r1780259. */
 static svn_error_t *
 test_cherry_pick_moved_file_with_propdel(const svn_test_opts_t *opts,
@@ -4682,6 +4765,217 @@ test_cherry_pick_moved_file_with_propdel
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_merge_incoming_move_file_text_merge_crlf(const svn_test_opts_t *opts,
+                                              apr_pool_t *pool)
+{
+  svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+  svn_client_ctx_t *ctx;
+  svn_opt_revision_t opt_rev;
+  svn_client_conflict_t *conflict;
+  svn_boolean_t text_conflicted;
+  apr_array_header_t *props_conflicted;
+  svn_boolean_t tree_conflicted;
+  svn_stringbuf_t *buf;
+
+  SVN_ERR(svn_test__sandbox_create(
+            b, "merge_incoming_move_file_text_merge_crlf", opts, pool));
+
+  SVN_ERR(sbox_add_and_commit_greek_tree(b));
+  /* Edit the file to have CRLF line endings. */
+  SVN_ERR(sbox_file_write(b, "A/mu", "Original content.\r\n"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* Create a copy of node "A". */
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+  SVN_ERR(sbox_wc_copy(b, "A", "A1"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* On "trunk", move the file. */
+  SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* On "branch", edit the file. */
+  SVN_ERR(sbox_file_write(b, "A1/mu", "Modified content.\r\n"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+  opt_rev.kind = svn_opt_revision_head;
+  opt_rev.value.number = SVN_INVALID_REVNUM;
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, pool));
+
+  /* Merge "A" to "A1". */
+  SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A",
+                                                            pool),
+                                NULL, &opt_rev, sbox_wc_path(b, "A1"),
+                                svn_depth_infinity,
+                                FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+                                NULL, ctx, pool));
+
+  /* We should have a tree conflict in the file "mu". */
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu"), ctx,
+                                  pool, pool));
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted,
+                                             &props_conflicted,
+                                             &tree_conflicted,
+                                             conflict, pool, pool));
+  SVN_TEST_ASSERT(!text_conflicted);
+  SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0);
+  SVN_TEST_ASSERT(tree_conflicted);
+
+  /* Check available tree conflict resolution options. */
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      svn_client_conflict_option_incoming_delete_ignore,
+      svn_client_conflict_option_incoming_delete_accept,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool));
+  }
+
+  SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, pool));
+
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      svn_client_conflict_option_incoming_move_file_text_merge,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool));
+  }
+
+  /* Resolve the tree conflict by moving "mu" to "mu-moved". */
+  SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+            conflict, svn_client_conflict_option_incoming_move_file_text_merge,
+            ctx, pool));
+
+  /* The file should no longer be in conflict, and should not have a
+   * text conflict, because the contents are identical in "trunk" and
+   * in the "branch". */
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu-moved"),
+                                  ctx, pool, pool));
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted,
+                                             &props_conflicted,
+                                             &tree_conflicted,
+                                             conflict, pool, pool));
+  SVN_TEST_ASSERT(!text_conflicted);
+  SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0);
+  SVN_TEST_ASSERT(!tree_conflicted);
+
+  /* And it should have expected contents. */
+  SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A1/mu-moved"),
+                                   pool));
+  SVN_TEST_STRING_ASSERT(buf->data, "Modified content.\r\n");
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_merge_incoming_move_file_text_merge_native_eol(const svn_test_opts_t 
*opts,
+                                                    apr_pool_t *pool)
+{
+  svn_test__sandbox_t *b = apr_palloc(pool, sizeof(*b));
+  svn_client_ctx_t *ctx;
+  svn_opt_revision_t opt_rev;
+  svn_client_conflict_t *conflict;
+  svn_boolean_t text_conflicted;
+  apr_array_header_t *props_conflicted;
+  svn_boolean_t tree_conflicted;
+  svn_stringbuf_t *buf;
+
+  SVN_ERR(svn_test__sandbox_create(
+            b, "merge_incoming_move_file_text_merge_native_eol", opts, pool));
+
+  SVN_ERR(sbox_add_and_commit_greek_tree(b));
+  /* Set svn:eol-style on a file and edit it. */
+  SVN_ERR(sbox_wc_propset(b, SVN_PROP_EOL_STYLE, "native", "A/mu"));;
+  SVN_ERR(sbox_file_write(b, "A/mu", "Original content.\n"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* Create a copy of node "A". */
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+  SVN_ERR(sbox_wc_copy(b, "A", "A1"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* On "trunk", move the file. */
+  SVN_ERR(sbox_wc_move(b, "A/mu", "A/mu-moved"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+  /* On "branch", edit the file. */
+  SVN_ERR(sbox_file_write(b, "A1/mu", "Modified content.\n"));
+  SVN_ERR(sbox_wc_commit(b, ""));
+
+  SVN_ERR(sbox_wc_update(b, "", SVN_INVALID_REVNUM));
+  opt_rev.kind = svn_opt_revision_head;
+  opt_rev.value.number = SVN_INVALID_REVNUM;
+  SVN_ERR(svn_test__create_client_ctx(&ctx, b, pool));
+
+  /* Merge "A" to "A1". */
+  SVN_ERR(svn_client_merge_peg5(svn_path_url_add_component2(b->repos_url, "A",
+                                                            pool),
+                                NULL, &opt_rev, sbox_wc_path(b, "A1"),
+                                svn_depth_infinity,
+                                FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,
+                                NULL, ctx, pool));
+
+  /* We should have a tree conflict in the file "mu". */
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu"), ctx,
+                                  pool, pool));
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted,
+                                             &props_conflicted,
+                                             &tree_conflicted,
+                                             conflict, pool, pool));
+  SVN_TEST_ASSERT(!text_conflicted);
+  SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0);
+  SVN_TEST_ASSERT(tree_conflicted);
+
+  /* Check available tree conflict resolution options. */
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      svn_client_conflict_option_incoming_delete_ignore,
+      svn_client_conflict_option_incoming_delete_accept,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool));
+  }
+
+  SVN_ERR(svn_client_conflict_tree_get_details(conflict, ctx, pool));
+
+  {
+    svn_client_conflict_option_id_t expected_opts[] = {
+      svn_client_conflict_option_postpone,
+      svn_client_conflict_option_accept_current_wc_state,
+      svn_client_conflict_option_incoming_move_file_text_merge,
+      -1 /* end of list */
+    };
+    SVN_ERR(assert_tree_conflict_options(conflict, ctx, expected_opts, pool));
+  }
+
+  /* Resolve the tree conflict by moving "mu" to "mu-moved". */
+  SVN_ERR(svn_client_conflict_tree_resolve_by_id(
+            conflict, svn_client_conflict_option_incoming_move_file_text_merge,
+            ctx, pool));
+
+  /* The file should no longer be in conflict, and should not have a
+   * text conflict, because the contents are identical in "trunk" and
+   * in the "branch". */
+  SVN_ERR(svn_client_conflict_get(&conflict, sbox_wc_path(b, "A1/mu-moved"),
+                                  ctx, pool, pool));
+  SVN_ERR(svn_client_conflict_get_conflicted(&text_conflicted,
+                                             &props_conflicted,
+                                             &tree_conflicted,
+                                             conflict, pool, pool));
+  SVN_TEST_ASSERT(!text_conflicted);
+  SVN_TEST_INT_ASSERT(props_conflicted->nelts, 0);
+  SVN_TEST_ASSERT(!tree_conflicted);
+
+  /* And it should have expected contents. */
+  SVN_ERR(svn_stringbuf_from_file2(&buf, sbox_wc_path(b, "A1/mu-moved"),
+                                   pool));
+  SVN_TEST_STRING_ASSERT(buf->data, "Modified content." APR_EOL_STR);
+
+  return SVN_NO_ERROR;
+}
+
 /* ========================================================================== 
*/
 
 
@@ -4764,6 +5058,12 @@ static struct svn_test_descriptor_t test
                        "update incoming add dir merge with obstructions"),
     SVN_TEST_OPTS_PASS(test_cherry_pick_moved_file_with_propdel,
                        "cherry-pick with moved file and propdel"),
+    SVN_TEST_OPTS_PASS(test_merge_incoming_move_file_text_merge_crlf,
+                       "merge incoming move file merge with CRLF eols"),
+    SVN_TEST_OPTS_PASS(test_merge_incoming_move_file_text_merge_native_eol,
+                       "merge incoming move file merge with native eols"),
+    SVN_TEST_OPTS_XFAIL(test_cherry_pick_post_move_edit,
+                        "cherry-pick edit from moved file"),
     SVN_TEST_NULL
   };
 

Modified: 
subversion/branches/addremove/subversion/tests/libsvn_delta/random-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_delta/random-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/libsvn_delta/random-test.c 
(original)
+++ subversion/branches/addremove/subversion/tests/libsvn_delta/random-test.c 
Tue Aug 22 14:19:36 2017
@@ -515,6 +515,96 @@ random_combine_test(apr_pool_t *pool)
 }
 
 
+/* (Note: *LAST_SEED is an output parameter.) */
+static svn_error_t *
+do_random_txdelta_to_svndiff_stream_test(apr_pool_t *pool,
+                                         apr_uint32_t *last_seed)
+{
+  apr_uint32_t seed;
+  apr_uint32_t maxlen;
+  apr_size_t bytes_range;
+  int i;
+  int iterations;
+  int dump_files;
+  int print_windows;
+  const char *random_bytes;
+  apr_pool_t *iterpool;
+
+  /* Initialize parameters and print out the seed in case we dump core
+     or something. */
+  init_params(&seed, &maxlen, &iterations, &dump_files, &print_windows,
+              &random_bytes, &bytes_range, pool);
+
+  iterpool = svn_pool_create(pool);
+  for (i = 0; i < iterations; i++)
+    {
+      apr_uint32_t subseed_base;
+      apr_file_t *source;
+      apr_file_t *target;
+      apr_file_t *source_copy;
+      apr_file_t *new_target;
+      svn_txdelta_stream_t *txstream;
+      svn_stream_t *delta_stream;
+      svn_txdelta_window_handler_t handler;
+      void *handler_baton;
+      svn_stream_t *push_stream;
+
+      svn_pool_clear(iterpool);
+
+      /* Generate source and target for the delta and its application. */
+      *last_seed = seed;
+      subseed_base = svn_test_rand(&seed);
+      source = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      target = generate_random_file(maxlen, subseed_base, &seed,
+                                    random_bytes, bytes_range,
+                                    dump_files, iterpool);
+      source_copy = copy_tempfile(source, iterpool);
+      new_target = open_tempfile(NULL, iterpool);
+
+      /* Create a txdelta stream that turns the source into target;
+         turn it into a generic readable svn_stream_t. */
+      svn_txdelta2(&txstream,
+                   svn_stream_from_aprfile2(source, TRUE, iterpool),
+                   svn_stream_from_aprfile2(target, TRUE, iterpool),
+                   FALSE, iterpool);
+      delta_stream = svn_txdelta_to_svndiff_stream(txstream, i % 3, i % 10,
+                                                   iterpool);
+
+      /* Apply it to a copy of the source file to see if we get the
+         same target back. */
+      svn_txdelta_apply(svn_stream_from_aprfile2(source_copy, TRUE, iterpool),
+                        svn_stream_from_aprfile2(new_target, TRUE, iterpool),
+                        NULL, NULL, iterpool, &handler, &handler_baton);
+      push_stream = svn_txdelta_parse_svndiff(handler, handler_baton, TRUE,
+                                              iterpool);
+      SVN_ERR(svn_stream_copy3(delta_stream, push_stream, NULL, NULL,
+                               iterpool));
+
+      SVN_ERR(compare_files(target, new_target, dump_files));
+
+      apr_file_close(source);
+      apr_file_close(target);
+      apr_file_close(source_copy);
+      apr_file_close(new_target);
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
+/* Implements svn_test_driver_t. */
+static svn_error_t *
+random_txdelta_to_svndiff_stream_test(apr_pool_t *pool)
+{
+  apr_uint32_t seed;
+  svn_error_t *err = do_random_txdelta_to_svndiff_stream_test(pool, &seed);
+  if (err)
+    fprintf(stderr, "SEED: %lu\n", (unsigned long)seed);
+  return err;
+}
+
 /* Change to 1 to enable the unit test for the delta combiner's range index: */
 #if 0
 #include "range-index-test.h"
@@ -533,6 +623,8 @@ static struct svn_test_descriptor_t test
                    "random delta test"),
     SVN_TEST_PASS2(random_combine_test,
                    "random combine delta test"),
+    SVN_TEST_PASS2(random_txdelta_to_svndiff_stream_test,
+                   "random txdelta to svndiff stream test"),
 #ifdef SVN_RANGE_INDEX_TEST_H
     SVN_TEST_PASS2(random_range_index_test,
                    "random range index test"),

Propchange: subversion/branches/addremove/subversion/tests/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Tue Aug 22 14:19:36 2017
@@ -10,6 +10,7 @@ Debug
 Release
 checksum-test
 compat-test
+compress-test
 config-test
 crypto-test
 error-test

Modified: 
subversion/branches/addremove/subversion/tests/libsvn_subr/checksum-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_subr/checksum-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/libsvn_subr/checksum-test.c 
(original)
+++ subversion/branches/addremove/subversion/tests/libsvn_subr/checksum-test.c 
Tue Aug 22 14:19:36 2017
@@ -296,6 +296,74 @@ test_checksum_parse_all_zero(apr_pool_t
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_checksummed_stream_read(apr_pool_t *pool)
+{
+  const svn_string_t *str = svn_string_create("abcde", pool);
+  svn_checksum_kind_t kind;
+
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    {
+      svn_stream_t *stream;
+      svn_checksum_t *expected_checksum;
+      svn_checksum_t *actual_checksum;
+      char buf[64];
+      apr_size_t len;
+
+      stream = svn_stream_from_string(str, pool);
+      stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
+                                       kind, TRUE, pool);
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_close(stream));
+
+      SVN_ERR(svn_checksum(&expected_checksum, kind,
+                           str->data, str->len, pool));
+      SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_checksummed_stream_reset(apr_pool_t *pool)
+{
+  const svn_string_t *str = svn_string_create("abcde", pool);
+  svn_checksum_kind_t kind;
+
+  for (kind = svn_checksum_md5; kind <= svn_checksum_fnv1a_32x4; ++kind)
+    {
+      svn_stream_t *stream;
+      svn_checksum_t *expected_checksum;
+      svn_checksum_t *actual_checksum;
+      char buf[64];
+      apr_size_t len;
+
+      stream = svn_stream_from_string(str, pool);
+      stream = svn_stream_checksummed2(stream, &actual_checksum, NULL,
+                                       kind, TRUE, pool);
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_reset(stream));
+
+      len = str->len;
+      SVN_ERR(svn_stream_read_full(stream, buf, &len));
+      SVN_TEST_INT_ASSERT((int) len, str->len);
+
+      SVN_ERR(svn_stream_close(stream));
+
+      SVN_ERR(svn_checksum(&expected_checksum, kind,
+                           str->data, str->len, pool));
+      SVN_TEST_ASSERT(svn_checksum_match(expected_checksum, actual_checksum));
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* An array of all test functions */
 
 static int max_threads = 1;
@@ -317,6 +385,10 @@ static struct svn_test_descriptor_t test
                    "checksum (de-)serialization"),
     SVN_TEST_PASS2(test_checksum_parse_all_zero,
                    "checksum parse all zero"),
+    SVN_TEST_PASS2(test_checksummed_stream_read,
+                   "read from checksummed stream"),
+    SVN_TEST_PASS2(test_checksummed_stream_reset,
+                   "reset checksummed stream"),
     SVN_TEST_NULL
   };
 

Modified: 
subversion/branches/addremove/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/tests/libsvn_subr/dirent_uri-test.c 
(original)
+++ 
subversion/branches/addremove/subversion/tests/libsvn_subr/dirent_uri-test.c 
Tue Aug 22 14:19:36 2017
@@ -938,6 +938,13 @@ static const testcase_canonicalize_t uri
     /* Hostnames that look like non-canonical paths */
     { "file://./foo",             "file://./foo" },
     { "http://./foo";,             "http://./foo"; },
+    /* Some invalid URLs, these still have a canonical form */
+    { "http://server:81:81/";,  "http://server:81:81"; },
+    { "http://server:81foo/";,  "http://server:81foo"; },
+    { "http://server::/";,      "http://server::"; },
+    { "http://server:-/";,      "http://server:-"; },
+    { "http://hst:1.2.3.4.5/";, "http://hst:1.2.3.4.5"},
+    { "http://hst:1.2.999.4/";, "http://hst:1.2.999.4"},
   /* svn_uri_is_canonical() was a private function in the 1.6 API, and
      has since taken a MAJOR change of direction, namely that only
      absolute URLs are considered canonical uris now. */
@@ -1238,6 +1245,12 @@ test_uri_is_canonical(apr_pool_t *pool)
                                  t->path,
                                  canonical ? "TRUE" : "FALSE",
                                  t->result);
+
+      if (t->result && !svn_uri_is_canonical(t->result, pool))
+        return svn_error_createf(SVN_ERR_TEST_FAILED, NULL,
+                                 "svn_uri_is_canonical(\"%s\") returned "
+                                 "FALSE on canonical form",
+                                 t->result);
     }
 
   return SVN_NO_ERROR;

Modified: 
subversion/branches/addremove/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/libsvn_subr/mergeinfo-test.c 
(original)
+++ subversion/branches/addremove/subversion/tests/libsvn_subr/mergeinfo-test.c 
Tue Aug 22 14:19:36 2017
@@ -1770,10 +1770,96 @@ test_rangelist_merge_overlap(apr_pool_t
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+test_rangelist_loop(apr_pool_t *pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  int x, y;
+
+  for (x = 0; x < 62; x++)
+    for (y = x + 1; y < 63; y++)
+      {
+        svn_rangelist_t *base_list;
+        svn_rangelist_t *change_list;
+        svn_merge_range_t *mrange;
+        svn_pool_clear(iterpool);
+
+        SVN_ERR(svn_rangelist__parse(&base_list,
+                                     "2,4,7-9,12-15,18-20,"
+                                     "22*,25*,28-30*,33-35*,"
+                                     "38-40,43-45*,48-50,52-54,56-59*",
+                                     iterpool));
+
+        change_list = apr_array_make(iterpool, 1, sizeof(mrange));
+
+        mrange = apr_pcalloc(pool, sizeof(*mrange));
+        mrange->start = x;
+        mrange->end = y;
+        APR_ARRAY_PUSH(change_list, svn_merge_range_t *) = mrange;
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          SVN_ERR(svn_rangelist_merge2(bl, cl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_ERR(svn_rangelist_merge2(cl, bl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        mrange->inheritable = TRUE;
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          SVN_ERR(svn_rangelist_merge2(bl, cl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+
+        {
+          svn_rangelist_t *bl = svn_rangelist_dup(base_list, iterpool);
+          svn_rangelist_t *cl = svn_rangelist_dup(change_list, iterpool);
+
+          SVN_ERR(svn_rangelist_merge2(cl, bl, iterpool, iterpool));
+
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(bl));
+          SVN_TEST_ASSERT(svn_rangelist__is_canonical(cl));
+
+          /* TODO: Verify result */
+        }
+      }
+
+  return SVN_NO_ERROR;
+}
 
 /* The test table.  */
 
-static int max_threads = 1;
+static int max_threads = 4;
 
 static struct svn_test_descriptor_t test_funcs[] =
   {
@@ -1816,6 +1902,8 @@ static struct svn_test_descriptor_t test
                    "removal of prefix paths from catalog keys"),
     SVN_TEST_XFAIL2(test_rangelist_merge_overlap,
                    "merge of rangelists with overlaps (issue 4686)"),
+    SVN_TEST_XFAIL2(test_rangelist_loop,
+                    "test rangelist edgecases via loop"),
     SVN_TEST_NULL
   };
 

Modified: subversion/branches/addremove/subversion/tests/libsvn_subr/utf-test.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/tests/libsvn_subr/utf-test.c?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/tests/libsvn_subr/utf-test.c 
(original)
+++ subversion/branches/addremove/subversion/tests/libsvn_subr/utf-test.c Tue 
Aug 22 14:19:36 2017
@@ -664,11 +664,18 @@ test_utf_fuzzy_escape(apr_pool_t *pool)
   SVN_TEST_ASSERT(0 == strcmp(fuzzy, "Subversi{U+03BF}n"));
 
   fuzzy = svn_utf__fuzzy_escape(invalid, sizeof(invalid) - 1, pool);
-  /*fprintf(stderr, "%s\n", fuzzy);*/
+
+  /* utf8proc 1.1.15 produces {U?FDD1} while 2.x produces {U+FDD1} */
   SVN_TEST_ASSERT(0 == strcmp(fuzzy,
                               "Not Unicode: {U?FDD1};"
                               "Out of range: ?\\F4?\\90?\\80?\\81;"
                               "Not UTF-8: ?\\E6;"
+                              "Null byte: \\0;")
+                  ||
+                  0 == strcmp(fuzzy,
+                              "Not Unicode: {U+FDD1};"
+                              "Out of range: ?\\F4?\\90?\\80?\\81;"
+                              "Not UTF-8: ?\\E6;"
                               "Null byte: \\0;"));
 
   return SVN_NO_ERROR;

Modified: 
subversion/branches/addremove/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- 
subversion/branches/addremove/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh 
(original)
+++ 
subversion/branches/addremove/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh 
Tue Aug 22 14:19:36 2017
@@ -71,6 +71,11 @@ if [ ${svnminor} -gt 8 ]; then
   optimizeconfig=' --enable-optimize'
 fi
 
+if [ ${svnminor} -ge 10 ]; then
+  lz4config='--with-lz4=internal'
+  utf8proconfig='--with-utf8proc=internal'
+fi
+
 #
 # Step 3: Configure
 #
@@ -88,6 +93,8 @@ ${abssrc}/configure \
     --with-berkeley-db=db.h:"${SVNBB_BDB}/include":${SVNBB_BDB}/lib:db \
     --enable-javahl \
     --without-jikes \
+    ${lz4config} \
+    ${utf8proconfig} \
     --with-junit="${SVNBB_JUNIT}"
 
 test -f config.log && mv config.log "${abssrc}/.test-logs/config.log"

Modified: subversion/branches/addremove/tools/dev/unix-build/Makefile.svn
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dev/unix-build/Makefile.svn?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/addremove/tools/dev/unix-build/Makefile.svn Tue Aug 22 
14:19:36 2017
@@ -100,6 +100,7 @@ BZ2_VER     = 1.0.6
 PYTHON_VER     = 2.7.13
 JUNIT_VER      = 4.10
 GETTEXT_VER    = 0.19.8.1
+LZ4_VER                = 1.7.5
 
 BDB_DIST       = db-$(BDB_VER).tar.gz
 APR_ICONV_DIST = apr-iconv-$(APR_ICONV_VER).tar.gz
@@ -114,6 +115,7 @@ BZ2_DIST    = bzip2-$(BZ2_VER).tar.gz
 PYTHON_DIST    = Python-$(PYTHON_VER).tgz
 JUNIT_DIST     = junit-${JUNIT_VER}.jar
 GETTEXT_DIST   = gettext-$(GETTEXT_VER).tar.gz
+LZ4_DIST       = lz4-$(LZ4_VER).tar.gz
 
 SHA256_${BDB_DIST} = 
f14fd96dd38915a1d63dcb94a63fbb8092334ceba6b5060760427096f631263e
 SHA256_${APR_ICONV_DIST} = 
19381959d50c4a5f3b9c84d594a5f9ffb3809786919b3058281f4c87e1f4b245
@@ -128,6 +130,7 @@ SHA256_${BZ2_DIST} = a2848f34fcd5d6cf47d
 SHA256_${PYTHON_DIST} = 
a4f05a0720ce0fd92626f0278b6b433eee9a6173ddf2bced7957dfb599a5ece1
 SHA256_${JUNIT_DIST} = 
36a747ca1e0b86f6ea88055b8723bb87030d627766da6288bf077afdeeb0f75a
 SHA256_${GETTEXT_DIST} = 
ff942af0e438ced4a8b0ea4b0b6e0d6d657157c5e2364de57baa279c1c125c43
+SHA256_${LZ4_DIST} = 
0190cacd63022ccb86f44fa5041dc6c3804407ad61550ca21c382827319e7e7e
 
 define do_check_sha256
 if [ -x /bin/sha256 ]; then \
@@ -176,6 +179,7 @@ BZ2_URL             = http://bzip.org/$(BZ2_VER)/$(
 PYTHON_URL     = https://python.org/ftp/python/$(PYTHON_VER)/$(PYTHON_DIST)
 JUNIT_URL      = 
https://downloads.sourceforge.net/project/junit/junit/$(JUNIT_VER)/$(JUNIT_DIST)
 GETTEXT_URL    = https://ftp.gnu.org/pub/gnu/gettext/$(GETTEXT_DIST)
+LZ4_URL                = https://github.com/lz4/lz4/archive/v$(LZ4_VER).tar.gz
 
 
 BDB_SRCDIR     = $(SRCDIR)/db-$(BDB_VER)
@@ -194,6 +198,7 @@ RUBY_SRCDIR = $(SRCDIR)/ruby-$(RUBY_VER)
 BZ2_SRCDIR     = $(SRCDIR)/bzip2-$(BZ2_VER)
 PYTHON_SRCDIR  = $(SRCDIR)/Python-$(PYTHON_VER)
 GETTEXT_SRCDIR = $(SRCDIR)/gettext-$(GETTEXT_VER)
+LZ4_SRCDIR     = ${SRCDIR}/lz4-$(LZ4_VER)
 SVN_SRCDIR     = $(SVN_WC)
 
 BDB_OBJDIR     = $(OBJDIR)/db-$(BDB_VER)
@@ -212,6 +217,7 @@ RUBY_OBJDIR = $(OBJDIR)/ruby-$(RUBY_VER)
 BZ2_OBJDIR     = $(OBJDIR)/bzip2-$(BZ2_VER)
 PYTHON_OBJDIR  = $(OBJDIR)/python-$(PYTHON_VER)
 GETTEXT_OBJDIR = $(OBJDIR)/gettext-$(GETTEXT_VER)
+LZ4_OBJDIR     = ${OBJDIR}/lz4-$(LZ4_VER)
 SVN_OBJDIR     = $(OBJDIR)/$(SVN_REL_WC)
 
 # Tweak this for out-of-tree builds. Note that running individual
@@ -236,18 +242,19 @@ all: dirs-create bdb-install apr-install
        httpd-install neon-install serf-install serf-old-install \
        sqlite-install cyrus-sasl-install libmagic-install \
        ruby-install bz2-install python-install gettext-install \
-       svn-install svn-bindings-install
+       lz4-install svn-install svn-bindings-install
 
 # Use these to start a build from the beginning.
 reset: dirs-reset bdb-reset apr-reset iconv-reset apr-util-reset \
        httpd-reset neon-reset serf-reset serf-old-reset sqlite-reset \
        cyrus-sasl-reset libmagic-reset ruby-reset python-reset \
-       bz2-reset gettext-reset svn-reset
+       bz2-reset gettext-reset lz4-reset svn-reset
 
 # Use to save disk space.
 clean: bdb-clean apr-clean iconv-clean apr-util-clean httpd-clean \
        neon-clean serf-clean serf-old-clean sqlite-clean cyrus-sasl-clean \
-       libmagic-clean ruby-clean bz2-clean python-clean gettext-clean svn-clean
+       libmagic-clean ruby-clean bz2-clean python-clean gettext-clean \
+       lz4-clean svn-clean
 
 # Nukes everything (including installed binaries!)
 # Use this to start ALL OVER AGAIN! Use with caution!
@@ -1319,6 +1326,49 @@ $(GETTEXT_OBJDIR)/.installed: $(GETTEXT_
        touch $@
 
 #######################################################################
+# lz4
+#######################################################################
+
+lz4-retrieve:  $(LZ4_OBJDIR)/.retrieved
+lz4-configure: $(LZ4_OBJDIR)/.configured
+lz4-compile:   $(LZ4_OBJDIR)/.compiled
+lz4-install:   $(LZ4_OBJDIR)/.installed
+lz4-reset:
+       $(foreach f, .retrieved .configured .compiled .installed, \
+               rm -f $(LZ4_OBJDIR)/$(f);)
+
+lz4-clean:
+       -(cd $(LZ4_SRCDIR) && env MAKEFLAGS= $(MAKE) clean)
+
+# fetch distfile for lz4
+$(DISTDIR)/$(LZ4_DIST):
+       cd $(DISTDIR) && $(FETCH_CMD) -O $(LZ4_DIST) $(LZ4_URL)
+
+# retrieve lz4
+$(LZ4_OBJDIR)/.retrieved: $(DISTDIR)/$(LZ4_DIST)
+       $(call do_check_sha256,$(LZ4_DIST))
+       [ -d $(LZ4_OBJDIR) ] || mkdir -p $(LZ4_OBJDIR)
+       tar -C $(SRCDIR) -zxf $(DISTDIR)/$(LZ4_DIST)
+       touch $@
+
+# configure lz4
+$(LZ4_OBJDIR)/.configured: $(LZ4_OBJDIR)/.retrieved
+       touch $@
+
+# compile lz4
+$(LZ4_OBJDIR)/.compiled: $(LZ4_OBJDIR)/.configured
+       (cd $(LZ4_SRCDIR)/lib && \
+               env MAKEFLAGS= $(MAKE) PREFIX=$(PREFIX)/lz4)
+       touch $@
+
+# install lz4
+$(LZ4_OBJDIR)/.installed: $(LZ4_OBJDIR)/.compiled
+       mkdir -p $(PREFIX)/lz4/lib
+       (cd $(LZ4_SRCDIR)/lib && \
+               env MAKEFLAGS= $(MAKE) PREFIX=$(PREFIX)/lz4 install)
+       touch $@
+
+#######################################################################
 # svn
 #######################################################################
 
@@ -1393,7 +1443,7 @@ DISABLE_NEON_VERSION_CHECK=--disable-neo
 W_NO_SYSTEM_HEADERS=-Wno-system-headers
 NEON_FLAG=--with-neon="$(PREFIX)/neon"
 JAVAHL_CHECK_TARGET=check-javahl
-else # 1.8
+else ifeq ($(BRANCH_MAJOR), $(filter $(BRANCH_MAJOR), 1.8 1.9))
 BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
 SERF_FLAG=--with-serf="$(PREFIX)/serf"
 # serf >= 1.3.0 is built with scons and no longer sets up rpath linker flags,
@@ -1404,6 +1454,19 @@ MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_auth
 MOD_DONTDOTHAT=modules/svn-$(WC)/mod_dontdothat.so
 LIBMAGIC_FLAG=--with-libmagic=$(PREFIX)/libmagic
 JAVAHL_CHECK_TARGET=check-all-javahl
+else # 1.10
+BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
+SERF_FLAG=--with-serf="$(PREFIX)/serf"
+# serf >= 1.3.0 is built with scons and no longer sets up rpath linker flags,
+# so we have to do that ourselves :(
+SERF_LDFLAG=-Wl,-rpath,$(PREFIX)/serf/lib -Wl,-rpath,$(PREFIX)/bdb/lib
+MOD_DAV_SVN=modules/svn-$(WC)/mod_dav_svn.so
+MOD_AUTHZ_SVN=modules/svn-$(WC)/mod_authz_svn.so
+MOD_DONTDOTHAT=modules/svn-$(WC)/mod_dontdothat.so
+LIBMAGIC_FLAG=--with-libmagic=$(PREFIX)/libmagic
+JAVAHL_CHECK_TARGET=check-all-javahl
+LZ4_FLAG=--with-lz4=$(PREFIX)/lz4
+UTF8PROC_FLAG=--with-utf8proc=internal
 endif
 
 ifeq ($(ENABLE_JAVA_BINDINGS),yes)
@@ -1454,6 +1517,8 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)
                        --disable-mod-activation \
                        $(JAVAHL_FLAG) \
                        $(LIBMAGIC_FLAG) \
+                       $(LZ4_FLAG) \
+                       $(UTF8PROC_FLAG) \
                        $(SVN_STATIC_FLAG) \
                        $(DISABLE_NEON_VERSION_CHECK)
        touch $@
@@ -2019,6 +2084,9 @@ endif
        @echo "serf:       $(SERF_VER)"
        @echo "cyrus-sasl: $(CYRUS_SASL_VER)"
        @echo "sqlite:     $(SQLITE_VER)"
+ifdef LZ4_FLAG
+       @echo "lz4:        $(LZ4_VER)"
+endif
        @echo "libssl:     `openssl version`"
        @echo "swig:       `swig -version | grep Version | cut -d' ' -f3`"
        @echo "python:     $(PYTHON_VER)"

Modified: subversion/branches/addremove/tools/dist/dist.sh
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dist/dist.sh?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dist/dist.sh (original)
+++ subversion/branches/addremove/tools/dist/dist.sh Tue Aug 22 14:19:36 2017
@@ -57,6 +57,7 @@
 #   To build a Windows zip file package, additionally pass -zip and the
 #   path to apr-iconv with -apri.
 
+set -e
 
 USAGE="USAGE: ./dist.sh -v VERSION -r REVISION -pr REPOS-PATH \
 [-alpha ALPHA_NUM|-beta BETA_NUM|-rc RC_NUM|-pre PRE_NUM] \
@@ -205,7 +206,7 @@ export TZ
 echo "Exporting $REPOS_PATH r$REVISION into sandbox..."
 (cd "$DIST_SANDBOX" && \
  ${SVN:-svn} export -q $EXTRA_EXPORT_OPTIONS \
-     "http://svn.apache.org/repos/asf/subversion/$REPOS_PATH"@"$REVISION"; \
+     "https://svn.apache.org/repos/asf/subversion/$REPOS_PATH"@"$REVISION"; \
      "$DISTNAME" --username none --password none)
 
 rm -f "$DISTPATH/STATUS"
@@ -242,7 +243,7 @@ fi
 # Instead of attempting to deal with various line ending issues, just export
 # the find_python script manually.
 ${svn:-svn} export -q -r "$REVISION"  \
-     
"http://svn.apache.org/repos/asf/subversion/$REPOS_PATH/build/find_python.sh"; \
+     
"https://svn.apache.org/repos/asf/subversion/$REPOS_PATH/build/find_python.sh"; \
      --username none --password none "$DIST_SANDBOX/find_python.sh"
 PYTHON="`$DIST_SANDBOX/find_python.sh`"
 if test -z "$PYTHON"; then
@@ -297,7 +298,7 @@ echo "Running po-update.sh in sandbox, t
 # Can't use the po-update.sh in the packaged export since it might have CRLF
 # line endings, in which case it won't run.  So first we export it again.
 ${svn:-svn} export -q -r "$REVISION"  \
-     
"http://svn.apache.org/repos/asf/subversion/$REPOS_PATH/tools/po/po-update.sh"; \
+     
"https://svn.apache.org/repos/asf/subversion/$REPOS_PATH/tools/po/po-update.sh"; 
\
      --username none --password none "$DIST_SANDBOX/po-update.sh"
 (cd "$DISTPATH" && ../po-update.sh pot) || exit 1
 

Modified: subversion/branches/addremove/tools/dist/release.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dist/release.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dist/release.py (original)
+++ subversion/branches/addremove/tools/dist/release.py Tue Aug 22 14:19:36 2017
@@ -166,6 +166,27 @@ class Version(object):
             else:
                 return 'supported-releases'
 
+    def get_ver_tags(self, revnum):
+        # These get substituted into svn_version.h
+        ver_tag = ''
+        ver_numtag = ''
+        if self.pre == 'alpha':
+            ver_tag = '" (Alpha %d)"' % self.pre_num
+            ver_numtag = '"-alpha%d"' % self.pre_num
+        elif self.pre == 'beta':
+            ver_tag = '" (Beta %d)"' % args.version.pre_num
+            ver_numtag = '"-beta%d"' % self.pre_num
+        elif self.pre == 'rc':
+            ver_tag = '" (Release Candidate %d)"' % self.pre_num
+            ver_numtag = '"-rc%d"' % self.pre_num
+        elif self.pre == 'nightly':
+            ver_tag = '" (Nightly Build r%d)"' % revnum
+            ver_numtag = '"-nightly-r%d"' % revnum
+        else:
+            ver_tag = '" (r%d)"' % revnum 
+            ver_numtag = '""'
+        return (ver_tag, ver_numtag)
+
     def __serialize(self):
         return (self.major, self.minor, self.patch, self.pre, self.pre_num)
 
@@ -199,7 +220,7 @@ class Version(object):
             return self.pre_num < that.pre_num
 
     def __str__(self):
-        "Return an SVN_VER_NUMBER-formattes string, or 'nightly'."
+        "Return an SVN_VER_NUMBER-formatted string, or 'nightly'."
         if self.pre:
             if self.pre == 'nightly':
                 return 'nightly'
@@ -220,6 +241,18 @@ def get_prefix(base_dir):
 def get_tempdir(base_dir):
     return os.path.join(base_dir, 'tempdir')
 
+def get_workdir(base_dir):
+    return os.path.join(get_tempdir(base_dir), 'working')
+
+# The name of this directory is also used to name the tarball and for
+# the root of paths within the tarball, e.g. subversion-1.9.5 or
+# subversion-nightly-r1800000
+def get_exportdir(base_dir, version, revnum):
+    if version.pre != 'nightly':
+        return os.path.join(get_tempdir(base_dir), 'subversion-'+str(version))
+    return os.path.join(get_tempdir(base_dir),
+                        'subversion-%s-r%d' % (version, revnum))
+
 def get_deploydir(base_dir):
     return os.path.join(base_dir, 'deploy')
 
@@ -243,13 +276,14 @@ def get_tmplfile(filename):
 def get_nullfile():
     return open(os.path.devnull, 'w')
 
-def run_script(verbose, script):
+def run_script(verbose, script, hide_stderr=False):
+    stderr = None
     if verbose:
         stdout = None
-        stderr = None
     else:
         stdout = get_nullfile()
-        stderr = subprocess.STDOUT
+        if hide_stderr:
+            stderr = get_nullfile()
 
     for l in script.split('\n'):
         subprocess.check_call(l.split(), stdout=stdout, stderr=stderr)
@@ -484,6 +518,16 @@ def check_copyright_year(repos, branch,
     check_file('NOTICE')
     check_file('subversion/libsvn_subr/version.c')
 
+def replace_lines(path, actions):
+    with open(path, 'r') as old_content:
+        lines = old_content.readlines()
+    with open(path, 'w') as new_content:
+        for line in lines:
+            for start, pattern, repl in actions:
+                if line.startswith(start):
+                    line = re.sub(pattern, repl, line)
+            new_content.write(line)
+
 def roll_tarballs(args):
     'Create the release artifacts.'
 
@@ -524,43 +568,163 @@ def roll_tarballs(args):
 
     os.mkdir(get_deploydir(args.base_dir))
 
-    # For now, just delegate to dist.sh to create the actual artifacts
-    extra_args = ''
-    if args.version.is_prerelease():
-        if args.version.pre == 'nightly':
-            extra_args = '-nightly'
+    logging.info('Preparing working copy source')
+    shutil.rmtree(get_workdir(args.base_dir), True)
+    run_script(args.verbose, 'svn checkout %s %s'
+               % (repos + '/' + branch + '@' + str(args.revnum),
+                  get_workdir(args.base_dir)))
+
+    # Exclude stuff we don't want in the tarball, it will not be present
+    # in the exported tree.
+    exclude = ['contrib', 'notes']
+    if branch != 'trunk':
+        exclude += ['STATUS']
+        if args.version.minor < 7:
+            exclude += ['packages', 'www']
+    cwd = os.getcwd()
+    os.chdir(get_workdir(args.base_dir))
+    run_script(args.verbose,
+               'svn update --set-depth exclude %s' % " ".join(exclude))
+    os.chdir(cwd)
+
+    if args.patches:
+        # Assume patches are independent and can be applied in any
+        # order, no need to sort.
+        majmin = '%d.%d' % (args.version.major, args.version.minor)
+        for name in os.listdir(args.patches):
+            if name.find(majmin) != -1 and name.endswith('patch'):
+                logging.info('Applying patch %s' % name)
+                run_script(args.verbose,
+                           '''svn patch %s %s'''
+                           % (os.path.join(args.patches, name),
+                              get_workdir(args.base_dir)))
+
+    # Massage the new version number into svn_version.h.
+    ver_tag, ver_numtag = args.version.get_ver_tags(args.revnum)
+    replacements = [('#define SVN_VER_TAG',
+                     '".*"', ver_tag),
+                    ('#define SVN_VER_NUMTAG',
+                     '".*"', ver_numtag),
+                    ('#define SVN_VER_REVISION',
+                     '[0-9][0-9]*', str(args.revnum))]
+    if args.version.pre != 'nightly':
+        # SVN_VER_PATCH might change for security releases, e.g., when
+        # releasing 1.9.7 from the magic revision of 1.9.6.
+        #
+        # ### Would SVN_VER_MAJOR / SVN_VER_MINOR ever change?
+        # ### Note that SVN_VER_MINOR is duplicated in some places, see
+        # ### 
<https://subversion.apache.org/docs/community-guide/releasing.html#release-branches>
+        replacements += [('#define SVN_VER_MAJOR',
+                          '[0-9][0-9]*', str(args.version.major)),
+                         ('#define SVN_VER_MINOR',
+                          '[0-9][0-9]*', str(args.version.minor)),
+                         ('#define SVN_VER_PATCH',
+                          '[0-9][0-9]*', str(args.version.patch))]
+    replace_lines(os.path.join(get_workdir(args.base_dir),
+                               'subversion', 'include', 'svn_version.h'),
+                  replacements)
+
+    # Basename for export and tarballs, e.g. subversion-1.9.5 or
+    # subversion-nightly-r1800000
+    exportdir = get_exportdir(args.base_dir, args.version, args.revnum)
+    basename = os.path.basename(exportdir)
+
+    def export(windows):
+        shutil.rmtree(exportdir, True)
+        if windows:
+            eol_style = "--native-eol CRLF"
         else:
-            extra_args = '-%s %d' % (args.version.pre, args.version.pre_num)
-    # Build Unix last to leave Unix-style svn_version.h for tagging
+            eol_style = "--native-eol LF"
+        run_script(args.verbose, "svn export %s %s %s"
+                   % (eol_style, get_workdir(args.base_dir), exportdir))
+
+    def transform_sql():
+        for root, dirs, files in os.walk(exportdir):
+            for fname in files:
+                if fname.endswith('.sql'):
+                    run_script(args.verbose,
+                               'python build/transform_sql.py %s/%s %s/%s'
+                               % (root, fname, root, fname[:-4] + '.h'))
+
+    def clean_autom4te():
+        for root, dirs, files in os.walk(get_workdir(args.base_dir)):
+            for dname in dirs:
+                if dname.startswith('autom4te') and dname.endswith('.cache'):
+                    shutil.rmtree(os.path.join(root, dname))
+
     logging.info('Building Windows tarballs')
-    run_script(args.verbose, '%s/dist.sh -v %s -pr %s -r %d -zip %s'
-                     % (sys.path[0], args.version.base, branch, args.revnum,
-                        extra_args) )
-    logging.info('Building UNIX tarballs')
-    run_script(args.verbose, '%s/dist.sh -v %s -pr %s -r %d %s'
-                     % (sys.path[0], args.version.base, branch, args.revnum,
-                        extra_args) )
+    export(windows=True)
+    os.chdir(exportdir)
+    transform_sql()
+    # Can't use the po-update.sh in the Windows export since it has CRLF
+    # line endings and won't run, so use the one in the working copy.
+    run_script(args.verbose,
+               '%s/tools/po/po-update.sh pot' % get_workdir(args.base_dir))
+    os.chdir(cwd)
+    clean_autom4te() # dist.sh does it but pointless on Windows?
+    os.chdir(get_tempdir(args.base_dir))
+    run_script(args.verbose,
+               'zip -q -r %s %s' % (basename + '.zip', basename))
+    os.chdir(cwd)
+
+    logging.info('Building Unix tarballs')
+    export(windows=False)
+    os.chdir(exportdir)
+    transform_sql()
+    run_script(args.verbose,
+               '''tools/po/po-update.sh pot
+                  ./autogen.sh --release''',
+               hide_stderr=True) # SWIG is noisy
+    os.chdir(cwd)
+    clean_autom4te() # dist.sh does it but probably pointless
+
+    # Do not use tar, it's probably GNU tar which produces tar files
+    # that are not compliant with POSIX.1 when including filenames
+    # longer than 100 chars.  Platforms without a tar that understands
+    # the GNU tar extension will not be able to extract the resulting
+    # tar file.  Use pax to produce POSIX.1 tar files.
+    #
+    # Use the gzip -n flag - this prevents it from storing the
+    # original name of the .tar file, and far more importantly, the
+    # mtime of the .tar file, in the produced .tar.gz file. This is
+    # important, because it makes the gzip encoding reproducable by
+    # anyone else who has an similar version of gzip, and also uses
+    # "gzip -9n". This means that committers who want to GPG-sign both
+    # the .tar.gz and the .tar.bz2 can download the .tar.bz2 (which is
+    # smaller), and locally generate an exact duplicate of the
+    # official .tar.gz file. This metadata is data on the temporary
+    # uncompressed tarball itself, not any of its contents, so there
+    # will be no effect on end-users.
+    os.chdir(get_tempdir(args.base_dir))
+    run_script(args.verbose,
+               '''pax -x ustar -w -f %s %s
+                  bzip2 -9fk %s
+                  gzip -9nf %s'''
+               % (basename + '.tar', basename,
+                  basename + '.tar',
+                  basename + '.tar'))
+    os.chdir(cwd)
 
     # Move the results to the deploy directory
     logging.info('Moving artifacts and calculating checksums')
     for e in extns:
-        if args.version.pre == 'nightly':
-            filename = 'subversion-nightly.%s' % e
-        else:
-            filename = 'subversion-%s.%s' % (args.version, e)
-
-        shutil.move(filename, get_deploydir(args.base_dir))
-        filename = os.path.join(get_deploydir(args.base_dir), filename)
+        filename = basename + '.' + e
+        filepath = os.path.join(get_tempdir(args.base_dir), filename)
+        shutil.move(filepath, get_deploydir(args.base_dir))
+        filepath = os.path.join(get_deploydir(args.base_dir), filename)
         m = hashlib.sha1()
-        m.update(open(filename, 'r').read())
-        open(filename + '.sha1', 'w').write(m.hexdigest())
+        m.update(open(filepath, 'r').read())
+        open(filepath + '.sha1', 'w').write(m.hexdigest())
         m = hashlib.sha512()
-        m.update(open(filename, 'r').read())
-        open(filename + '.sha512', 'w').write(m.hexdigest())
+        m.update(open(filepath, 'r').read())
+        open(filepath + '.sha512', 'w').write(m.hexdigest())
 
-    shutil.move('svn_version.h.dist',
-                get_deploydir(args.base_dir) + '/' + 'svn_version.h.dist'
-                + '-' + str(args.version))
+    # Nightlies do not get tagged so do not need the header
+    if args.version.pre != 'nightly':
+        shutil.copy(os.path.join(get_workdir(args.base_dir),
+                                 'subversion', 'include', 'svn_version.h'),
+                    os.path.join(get_deploydir(args.base_dir),
+                                 'svn_version.h.dist-%s' % str(args.version)))
 
     # And we're done!
 
@@ -710,7 +874,9 @@ def clean_dist(args):
     versions = set(map(Version, filenames))
     minor_lines = set(map(minor, versions))
     to_keep = set()
-    for recent_line in sorted(minor_lines, reverse=True)[:2]:
+    # Keep 3 minor lines: 1.10.0-alpha3, 1.9.7, 1.8.19.
+    # TODO: When we release 1.A.0 GA we'll have to manually remove 1.(A-2).* 
artifacts.
+    for recent_line in sorted(minor_lines, reverse=True)[:3]:
         to_keep.add(max(
             x for x in versions
             if minor(x) == recent_line
@@ -784,7 +950,7 @@ def write_news(args):
     template.generate(sys.stdout, data)
 
 
-def get_sha1info(args, replace=False):
+def get_sha1info(args):
     'Return a list of sha1 info for the release'
 
     target = get_target(args)
@@ -798,12 +964,7 @@ def get_sha1info(args, replace=False):
     for s in sha1s:
         i = info()
         # strip ".sha1"
-        fname = os.path.basename(s)[:-5]
-        if replace:
-            # replace the version number with the [version] reference
-            i.filename = Version.regex.sub('[version]', fname)
-        else:
-            i.filename = fname
+        i.filename = os.path.basename(s)[:-5]
         i.sha1 = open(s, 'r').read()
         sha1info.append(i)
 
@@ -846,7 +1007,7 @@ def write_announcement(args):
 
 def write_downloads(args):
     'Output the download section of the website.'
-    sha1info = get_sha1info(args, replace=True)
+    sha1info = get_sha1info(args)
 
     data = { 'version'              : str(args.version),
              'fileinfo'             : sha1info,
@@ -861,6 +1022,7 @@ def write_downloads(args):
 # Validate the signatures for a release
 
 key_start = '-----BEGIN PGP SIGNATURE-----'
+key_end = '-----END PGP SIGNATURE-----'
 
 PUBLIC_KEY_ALGORITHMS = {
     # These values are taken from the RFC's registry at:
@@ -895,9 +1057,27 @@ def get_siginfo(args, quiet=False):
         text = open(filename).read()
         keys = text.split(key_start)
 
+        # Check the keys file syntax. We've been bitten in the past
+        # with syntax errors in the key delimiters that GPG didn't
+        # catch for us, but the ASF key checker tool did.
+        if keys[0]:
+            sys.stderr.write("SYNTAX ERROR: %s does not start with '%s'\n"
+                             % (filename, key_start))
+            sys.exit(1)
+        keys = keys[1:]
+
         if not quiet:
-            logging.info("Checking %d sig(s) in %s" % (len(keys[1:]), 
filename))
-        for key in keys[1:]:
+            logging.info("Checking %d sig(s) in %s" % (len(keys), filename))
+
+        n = 0
+        for key in keys:
+            n += 1
+            if not key.rstrip().endswith(key_end):
+                sys.stderr.write("SYNTAX ERROR: Key %d in %s"
+                                 " does not end with '%s'\n"
+                                 % (n, filename, key_end))
+                sys.exit(1)
+
             fd, fn = tempfile.mkstemp()
             os.write(fd, key_start + key)
             os.close(fd)
@@ -907,7 +1087,8 @@ def get_siginfo(args, quiet=False):
             if verified.valid:
                 good_sigs[verified.fingerprint] = True
             else:
-                sys.stderr.write("BAD SIGNATURE for %s\n" % filename)
+                sys.stderr.write("BAD SIGNATURE: Key %d in %s\n"
+                                 % (n, filename))
                 if verified.key_id:
                     sys.stderr.write("  key id: %s\n" % verified.key_id)
                 sys.exit(1)
@@ -1038,6 +1219,8 @@ def main():
     subparser.add_argument('--branch',
                     help='''The branch to base the release on,
                             relative to ^/subversion/.''')
+    subparser.add_argument('--patches',
+                    help='''The path to the directory containing patches.''')
 
     # Setup the parser for the sign-candidates subcommand
     subparser = subparsers.add_parser('sign-candidates',
@@ -1173,6 +1356,9 @@ def main():
     os.environ['PATH'] = os.path.join(get_prefix(args.base_dir), 'bin') + ':' \
                                                             + 
os.environ['PATH']
 
+    # Make timestamps in tarballs independent of local timezone
+    os.environ['TZ'] = 'UTC'
+
     # finally, run the subcommand, and give it the parsed arguments
     args.func(args)
 

Modified: subversion/branches/addremove/tools/dist/templates/rc-release-ann.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dist/templates/rc-release-ann.ezt?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dist/templates/rc-release-ann.ezt 
(original)
+++ subversion/branches/addremove/tools/dist/templates/rc-release-ann.ezt Tue 
Aug 22 14:19:36 2017
@@ -31,7 +31,7 @@ Apache Subversion open source version co
 issues, a complete list of [major-minor-patch]-blocking issues can be found
 here:
 
-    
http://subversion.tigris.org/issues/buglist.cgi?component=subversion&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED&target_milestone=[major-minor-patch]
+    
https://issues.apache.org/jira/issues/?jql=project%20%3D%20SVN%20AND%20resolution%20%3D%20Unresolved%20AND%20fixVersion%20%3D%20[major-minor-patch]%20ORDER%20BY%20priority%20DESC%2C%20updated%20DESC
 
 A pre-release means the Subversion developers feel that this release
 is ready for widespread testing by the community.  There are known issues

Modified: subversion/branches/addremove/tools/dist/templates/stable-news.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dist/templates/stable-news.ezt?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dist/templates/stable-news.ezt 
(original)
+++ subversion/branches/addremove/tools/dist/templates/stable-news.ezt Tue Aug 
22 14:19:36 2017
@@ -5,14 +5,11 @@
 </h3> 
  
 <p>We are pleased to announce the release of Apache Subversion [version].
-[if-any is_recommended]
-   This is the most complete Subversion release to date, and we encourage
+[if-any is_recommended]   This is the most complete Subversion release to 
date, and we encourage
    users of Subversion to upgrade as soon as reasonable.
-[else]
-   This is the most complete release of the [major-minor].x line to date,
+[else]   This is the most complete release of the [major-minor].x line to date,
    and we encourage all users to upgrade as soon as reasonable.
-[end]
-   Please see the
+[end]   Please see the
    <a href=""
    >release announcement</a> and the
    <a href="http://svn.apache.org/repos/asf/subversion/tags/[version]/CHANGES";

Modified: 
subversion/branches/addremove/tools/dist/templates/stable-release-ann.ezt
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/tools/dist/templates/stable-release-ann.ezt?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/tools/dist/templates/stable-release-ann.ezt 
(original)
+++ subversion/branches/addremove/tools/dist/templates/stable-release-ann.ezt 
Tue Aug 22 14:19:36 2017
@@ -1,6 +1,6 @@
 From: [email protected]
 To: [email protected], [email protected], 
[email protected], [email protected]
-[if-any security]Cc: [email protected]
+[if-any security]Cc: [email protected], [email protected], 
[email protected]
 [end][if-any security]Subject: [[]SECURITY][[]ANNOUNCE] Apache Subversion 
[version] released
 [else]Subject: [[]ANNOUNCE] Apache Subversion [version] released
 [end]

Modified: subversion/branches/addremove/win-tests.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/win-tests.py?rev=1805769&r1=1805768&r2=1805769&view=diff
==============================================================================
--- subversion/branches/addremove/win-tests.py (original)
+++ subversion/branches/addremove/win-tests.py Tue Aug 22 14:19:36 2017
@@ -113,7 +113,7 @@ def _usage_exit():
   print("  --config-file          : Configuration file for tests")
   print("  --fsfs-sharding        : Specify shard size (for fsfs)")
   print("  --fsfs-packing         : Run 'svnadmin pack' automatically")
-  print("  --fsfs-compression=VAL : Set compression level to VAL (for fsfs)")
+  print("  --fsfs-compression=VAL : Set compression type to VAL (for fsfs)")
   print("  -q, --quiet            : Deprecated; this is the default.")
   print("                           Use --set-log-level instead.")
 
@@ -191,7 +191,7 @@ memcached_server = None
 memcached_dir = None
 skip_c_tests = None
 dump_load_cross_check = None
-fsfs_compression_level = None
+fsfs_compression = None
 
 for opt, val in opts:
   if opt in ('-h', '--help'):
@@ -287,7 +287,7 @@ for opt, val in opts:
     memcached_dir = val
     run_memcached = 1
   elif opt == '--fsfs-compression':
-    fsfs_compression_level = int(val)
+    fsfs_compression = val
 
 # Calculate the source and test directory names
 abs_srcdir = os.path.abspath("")
@@ -1017,6 +1017,7 @@ create_target_dir(CMDLINE_TEST_SCRIPT_NA
 # Ensure the tests directory is correctly cased
 abs_builddir = fix_case(abs_builddir)
 
+failed = None
 daemon = None
 memcached = None
 # Run the tests
@@ -1112,7 +1113,7 @@ if not test_javahl and not test_swig:
   opts.memcached_server = memcached_server
   opts.skip_c_tests = skip_c_tests
   opts.dump_load_cross_check = dump_load_cross_check
-  opts.fsfs_compression_level = fsfs_compression_level
+  opts.fsfs_compression = fsfs_compression
   th = run_tests.TestHarness(abs_srcdir, abs_builddir,
                              log_file, fail_log_file, opts)
   old_cwd = os.getcwd()
@@ -1330,6 +1331,10 @@ elif test_swig == 'ruby':
       print('[Test runner reported failure]')
       failed = True
 
+elif test_swig:
+  print('Unknown Swig binding type: ' + str(test_swig))
+  failed = True
+
 # Stop service daemon, if any
 if daemon:
   del daemon


Reply via email to