You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2017/08/24 08:39:33 UTC

svn commit: r1806005 [4/4] - in /subversion/branches/shelve: ./ build/ build/ac-macros/ build/generator/ notes/ notes/api-errata/1.10/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion/libsvn_...

Modified: subversion/branches/shelve/subversion/tests/libsvn_client/conflicts-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_client/conflicts-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_client/conflicts-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_client/conflicts-test.c Thu Aug 24 08:39:31 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/shelve/subversion/tests/libsvn_delta/random-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_delta/random-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_delta/random-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_delta/random-test.c Thu Aug 24 08:39:31 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"),

Modified: subversion/branches/shelve/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_fs_fs/fs-fs-private-test.c Thu Aug 24 08:39:31 2017
@@ -85,8 +85,10 @@ verify_representation_stats(const svn_fs
   SVN_TEST_ASSERT(stats->total.count == expected_count);
   SVN_TEST_ASSERT(   stats->total.packed_size >= 10 * expected_count
                   && stats->total.packed_size <= 1000 * expected_count);
-  SVN_TEST_ASSERT(   stats->total.packed_size >= stats->total.expanded_size
-                  && stats->total.packed_size <= 2 * stats->total.expanded_size);
+  /* Expect the packed size to be sane, keeping in mind that it might
+   * be less or more than the expanded size due differences in the
+   * compression algorithms or options such as directory deltification. */
+  SVN_TEST_ASSERT(stats->total.packed_size <= 2 * stats->total.expanded_size);
   SVN_TEST_ASSERT(   stats->total.overhead_size >= 5 * expected_count
                   && stats->total.overhead_size <= 100 * expected_count);
 

Propchange: subversion/branches/shelve/subversion/tests/libsvn_subr/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Thu Aug 24 08:39:31 2017
@@ -10,6 +10,7 @@ Debug
 Release
 checksum-test
 compat-test
+compress-test
 config-test
 crypto-test
 error-test

Modified: subversion/branches/shelve/subversion/tests/libsvn_subr/checksum-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_subr/checksum-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_subr/checksum-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_subr/checksum-test.c Thu Aug 24 08:39:31 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/shelve/subversion/tests/libsvn_subr/dirent_uri-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_subr/dirent_uri-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_subr/dirent_uri-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_subr/dirent_uri-test.c Thu Aug 24 08:39:31 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/shelve/subversion/tests/libsvn_subr/mergeinfo-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_subr/mergeinfo-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_subr/mergeinfo-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_subr/mergeinfo-test.c Thu Aug 24 08:39:31 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/shelve/subversion/tests/libsvn_subr/utf-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_subr/utf-test.c?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_subr/utf-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_subr/utf-test.c Thu Aug 24 08:39:31 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/shelve/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh (original)
+++ subversion/branches/shelve/tools/buildbot/slaves/svn-x64-macosx/svnbuild.sh Thu Aug 24 08:39:31 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/shelve/tools/client-side/bash_completion
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/client-side/bash_completion?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/client-side/bash_completion (original)
+++ subversion/branches/shelve/tools/client-side/bash_completion Thu Aug 24 08:39:31 2017
@@ -925,11 +925,12 @@ _svn()
 		;;
 	list|ls)
 		cmdOpts="$rOpts -v --verbose -R --recursive $pOpts \
-                         --incremental --xml --depth --include-externals"
+		         --incremental --search --xml --depth \
+		         --include-externals"
 		;;
 	lock)
 		cmdOpts="-m --message -F --file --encoding --force-log \
-                         --targets --force $pOpts"
+                         $qOpts --targets --force $pOpts"
 		;;
 	log)
 		cmdOpts="$rOpts -v --verbose --targets $pOpts --stop-on-copy \
@@ -1010,12 +1011,13 @@ _svn()
 		         --ignore-ancestry"
 		;;
 	unlock)
-		cmdOpts="--targets --force $pOpts"
+		cmdOpts="$qOpts --targets --force $pOpts"
 		;;
 	update|up)
 		cmdOpts="$rOpts $nOpts $qOpts $pOpts --diff3-cmd \
                          --ignore-externals --force --accept $cOpts \
-                         --parents --editor-cmd --set-depth"
+                         --parents --editor-cmd --set-depth \
+		         --adds-as-modification"
 		;;
 	upgrade)
 		cmdOpts="$qOpts $pOpts"

Modified: subversion/branches/shelve/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dev/unix-build/Makefile.svn?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/shelve/tools/dev/unix-build/Makefile.svn Thu Aug 24 08:39:31 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/shelve/tools/dist/checksums.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/checksums.py?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/checksums.py (original)
+++ subversion/branches/shelve/tools/dist/checksums.py Thu Aug 24 08:39:31 2017
@@ -19,12 +19,14 @@
 # under the License.
 #
 #
-# Check MD5 and SHA1 signatures of files, using md5sums and/or
-# sha1sums as manifests.  Replaces the 'md5sum' and 'sha1sum' commands
+# Check MD5 and SHA-1 and SHA-2 signatures of files, using 
+# md5sums, sha1sums, and/or sha512sums as manifests
+# Replaces the 'md5sum', 'sha1sum', and 'sha512sums' commands
 # on systems that do not have them, such as Mac OS X or Windows.
 #
 # Usage: checksums.py [manifest]
-#   where "os.path.basename(manifest)" is either "md5sums" or "sha1sums"
+#   where "os.path.basename(manifest)" is either "md5sums", "sha1sums",
+#   "sha512sums"
 #
 # Tested with the following Python versions:
 #        2.4   2.5   2.6   2.7   3.2
@@ -37,6 +39,7 @@ import sys
 try:
     from hashlib import md5
     from hashlib import sha1
+    from hashlib import sha512
 except ImportError:
     from md5 import md5
     from sha import sha as sha1
@@ -67,9 +70,11 @@ def main(manipath):
         sink = Digester(md5)
     elif manifest == 'sha1sums':
         sink = Digester(sha1)
+    elif manifest == 'sha512sums':
+        sink = Digester(sha512)
     else:
         raise ValueError('The name of the digest manifest must be '
-                         "'md5sums' or 'sha1sums', not '%s'" % manifest)
+                         "'md5sums', 'sha1sums', or 'sha512sums', not '%s'" % manifest)
 
     # No 'with' statement in Python 2.4 ...
     stream = None

Modified: subversion/branches/shelve/tools/dist/dist.sh
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/dist.sh?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/dist.sh (original)
+++ subversion/branches/shelve/tools/dist/dist.sh Thu Aug 24 08:39:31 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
 
@@ -369,9 +370,10 @@ sign_file()
   fi
 }
 
-# allow md5sum and sha1sum tool names to be overridden
+# allow md5sum, sha1sum, and sha512sum tool names to be overridden
 [ -n "$MD5SUM" ] || MD5SUM=md5sum
 [ -n "$SHA1SUM" ] || SHA1SUM=sha1sum
+[ -n "$SHA512SUM" ] || SHA512SUM=sha512sum
 
 echo ""
 echo "Done:"
@@ -387,6 +389,12 @@ if [ -z "$ZIP" ]; then
     echo "sha1sums:"
     $SHA1SUM "$DISTNAME.tar.bz2" "$DISTNAME.tar.gz"
   fi
+  type $SHA512SUM > /dev/null 2>&1
+  if [ $? -eq 0 ]; then
+    echo ""
+    echo "sha512sums:"
+    $SHA512SUM "$DISTNAME.tar.bz2" "$DISTNAME.tar.gz"
+  fi
 else
   ls -l "$DISTNAME.zip"
   sign_file $DISTNAME.zip
@@ -399,4 +407,10 @@ else
     echo "sha1sum:"
     $SHA1SUM "$DISTNAME.zip"
   fi
+  type $SHA512SUM > /dev/null 2>&1
+  if [ $? -eq 0 ]; then
+    echo ""
+    echo "sha512sum:"
+    $SHA512SUM "$DISTNAME.zip"
+  fi
 fi

Modified: subversion/branches/shelve/tools/dist/release.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/release.py?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/release.py (original)
+++ subversion/branches/shelve/tools/dist/release.py Thu Aug 24 08:39:31 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,6 +220,7 @@ class Version(object):
             return self.pre_num < that.pre_num
 
     def __str__(self):
+        "Return an SVN_VER_NUMBER-formatted string, or 'nightly'."
         if self.pre:
             if self.pre == 'nightly':
                 return 'nightly'
@@ -219,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')
 
@@ -242,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)
@@ -483,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.'
 
@@ -490,6 +535,7 @@ def roll_tarballs(args):
         args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor)
 
     branch = args.branch # shorthand
+    branch = branch.rstrip('/') # canonicalize for later comparisons
 
     logging.info('Rolling release %s from branch %s@%d' % (args.version,
                                                            branch, args.revnum))
@@ -522,40 +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())
-
-    shutil.move('svn_version.h.dist',
-                get_deploydir(args.base_dir) + '/' + 'svn_version.h.dist'
-                + '-' + str(args.version))
+        m.update(open(filepath, 'r').read())
+        open(filepath + '.sha1', 'w').write(m.hexdigest())
+        m = hashlib.sha512()
+        m.update(open(filepath, 'r').read())
+        open(filepath + '.sha512', 'w').write(m.hexdigest())
+
+    # 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!
 
@@ -592,9 +761,7 @@ def post_candidates(args):
     target = get_target(args)
 
     logging.info('Importing tarballs to %s' % dist_dev_url)
-    ver = args.version.base
-    if args.version.pre:
-        ver = "%s-%s%d" % (ver, args.version.pre, args.version.pre_num)
+    ver = str(args.version)
     svn_cmd = ['svn', 'import', '-m',
                'Add Subversion %s candidate release artifacts' % ver,
                '--auto-props', '--config-option',
@@ -617,7 +784,7 @@ def create_tag(args):
     if not args.branch:
         args.branch = 'branches/%d.%d.x' % (args.version.major, args.version.minor)
 
-    branch = secure_repos + '/' + args.branch
+    branch = secure_repos + '/' + args.branch.rstrip('/')
 
     tag = secure_repos + '/tags/' + str(args.version)
 
@@ -631,7 +798,12 @@ def create_tag(args):
                     tag + '/subversion/include/svn_version.h']
 
     # don't redirect stdout/stderr since svnmucc might ask for a password
-    subprocess.check_call(svnmucc_cmd)
+    try:
+        subprocess.check_call(svnmucc_cmd)
+    except subprocess.CalledProcessError:
+        if args.version.is_prerelease():
+            logging.error("Do you need to pass --branch=trunk?")
+        raise
 
     if not args.version.is_prerelease():
         logging.info('Bumping revisions on the branch')
@@ -702,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
@@ -763,6 +937,7 @@ def write_news(args):
              'version' : str(args.version),
              'version_base' : args.version.base,
              'anchor': args.version.get_download_anchor(),
+             'is_recommended': ezt_bool(args.version.is_recommended()),
            }
 
     if args.version.is_prerelease():
@@ -775,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)
@@ -789,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)
 
@@ -837,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,
@@ -852,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:
@@ -886,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)
@@ -898,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)
@@ -1027,7 +1217,10 @@ def main():
     subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')),
                     help='''The revision number to base the release on.''')
     subparser.add_argument('--branch',
-                    help='''The branch to base the release on.''')
+                    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',
@@ -1061,7 +1254,8 @@ def main():
     subparser.add_argument('revnum', type=lambda arg: int(arg.lstrip('r')),
                     help='''The revision number to base the release on.''')
     subparser.add_argument('--branch',
-                    help='''The branch to base the release on.''')
+                    help='''The branch to base the release on,
+                            relative to ^/subversion/.''')
     subparser.add_argument('--username',
                     help='''Username for ''' + secure_repos + '''.''')
     subparser.add_argument('--target',
@@ -1162,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/shelve/tools/dist/templates/rc-release-ann.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/templates/rc-release-ann.ezt?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/templates/rc-release-ann.ezt (original)
+++ subversion/branches/shelve/tools/dist/templates/rc-release-ann.ezt Thu Aug 24 08:39:31 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/shelve/tools/dist/templates/stable-news.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/templates/stable-news.ezt?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/templates/stable-news.ezt (original)
+++ subversion/branches/shelve/tools/dist/templates/stable-news.ezt Thu Aug 24 08:39:31 2017
@@ -5,8 +5,11 @@
 </h3> 
  
 <p>We are pleased to announce the release of Apache Subversion [version].
-   This is the most complete Subversion release to date, and we encourage
-   users of Subversion to upgrade as soon as reasonable.  Please see the
+[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,
+   and we encourage all users to upgrade as soon as reasonable.
+[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/shelve/tools/dist/templates/stable-release-ann.ezt
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/dist/templates/stable-release-ann.ezt?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dist/templates/stable-release-ann.ezt (original)
+++ subversion/branches/shelve/tools/dist/templates/stable-release-ann.ezt Thu Aug 24 08:39:31 2017
@@ -1,6 +1,6 @@
 From: ...@apache.org
 To: announce@subversion.apache.org, users@subversion.apache.org, dev@subversion.apache.org, announce@apache.org
-[if-any security]Cc: security@apache.org
+[if-any security]Cc: security@apache.org, oss-security@lists.openwall.com, bugtraq@securityfocus.com
 [end][if-any security]Subject: [[]SECURITY][[]ANNOUNCE] Apache Subversion [version] released
 [else]Subject: [[]ANNOUNCE] Apache Subversion [version] released
 [end]

Modified: subversion/branches/shelve/win-tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/win-tests.py?rev=1806005&r1=1806004&r2=1806005&view=diff
==============================================================================
--- subversion/branches/shelve/win-tests.py (original)
+++ subversion/branches/shelve/win-tests.py Thu Aug 24 08:39:31 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