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/10/31 09:29:47 UTC

svn commit: r1813857 - in /subversion/branches/shelve: ./ build/ build/generator/ notes/commit-access-templates/ subversion/bindings/javahl/native/ subversion/bindings/swig/include/ subversion/include/ subversion/libsvn_client/ subversion/libsvn_repos/...

Author: julianfoad
Date: Tue Oct 31 09:29:47 2017
New Revision: 1813857

URL: http://svn.apache.org/viewvc?rev=1813857&view=rev
Log:
On the 'shelve' branch: Catch up with trunk@1813856.

Removed:
    subversion/branches/shelve/notes/commit-access-templates/contrib-committer.tmpl
Modified:
    subversion/branches/shelve/   (props changed)
    subversion/branches/shelve/CHANGES
    subversion/branches/shelve/COMMITTERS
    subversion/branches/shelve/build/generator/gen_win_dependencies.py
    subversion/branches/shelve/build/run_tests.py
    subversion/branches/shelve/notes/commit-access-templates/partial-committer.tmpl
    subversion/branches/shelve/subversion/bindings/javahl/native/SVNRepos.cpp
    subversion/branches/shelve/subversion/bindings/swig/include/svn_types.swg
    subversion/branches/shelve/subversion/include/svn_repos.h
    subversion/branches/shelve/subversion/libsvn_client/diff.c
    subversion/branches/shelve/subversion/libsvn_repos/deprecated.c
    subversion/branches/shelve/subversion/libsvn_repos/dump.c
    subversion/branches/shelve/subversion/libsvn_repos/reporter.c
    subversion/branches/shelve/subversion/libsvn_subr/mergeinfo.c
    subversion/branches/shelve/subversion/svnadmin/svnadmin.c
    subversion/branches/shelve/subversion/svndumpfilter/svndumpfilter.c
    subversion/branches/shelve/subversion/tests/cmdline/basic_tests.py
    subversion/branches/shelve/subversion/tests/cmdline/diff_tests.py
    subversion/branches/shelve/subversion/tests/cmdline/svnadmin_tests.py
    subversion/branches/shelve/subversion/tests/cmdline/svntest/verify.py
    subversion/branches/shelve/subversion/tests/libsvn_repos/dump-load-test.c
    subversion/branches/shelve/tools/client-side/bash_completion
    subversion/branches/shelve/tools/dev/unix-build/Makefile.svn

Propchange: subversion/branches/shelve/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Oct 31 09:29:47 2017
@@ -98,4 +98,4 @@
 /subversion/branches/verify-at-commit:1462039-1462408
 /subversion/branches/verify-keep-going:1439280-1546110
 /subversion/branches/wc-collate-path:1402685-1480384
-/subversion/trunk:1801593-1811551
+/subversion/trunk:1801593-1813856

Modified: subversion/branches/shelve/CHANGES
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/CHANGES?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/CHANGES (original)
+++ subversion/branches/shelve/CHANGES Tue Oct 31 09:29:47 2017
@@ -13,6 +13,7 @@ the 1.9 release:  https://subversion.apa
     * svnbench: Show wall-clock time when done (r1703383)
     * svnbench: Show number of bytes transferred across the network (r1710586)
     * svnbench: Actually evaluate the '--with-no-revprops' option (r1709593)
+    * New 'svnadmin dump' options to include/exclude paths (r1811992)
     * New 'svnadmin load-revprops' subcommand (r1694191)
     * New 'svnadmin dump-revprops' subcommand (r1694225)
     * New '--no-flush-to-disk' option for 'svnadmin load' (r1736357, -7357)

Modified: subversion/branches/shelve/COMMITTERS
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/COMMITTERS?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/COMMITTERS [UTF-8] (original)
+++ subversion/branches/shelve/COMMITTERS [UTF-8] Tue Oct 31 09:29:47 2017
@@ -103,6 +103,7 @@ Commit access for specific areas:
        rschupp   Roderich Schupp <ro...@gmail.com> (Swig bindings)
         stilor   Alexey Neyman <st...@att.net>              (Python bindings,
                                                              svn-vendor.py)
+  troycurtisjr   Troy Curtis, Jr <tr...@gmail.com>    (Swig bindings)
 
   Packages:
 
@@ -168,6 +169,7 @@ Commit access for specific areas:
       prabhugs   Prabhu Gnana Sundar <pp...@gmail.com>   (verify-keep-going)
         schabi   Markus Schaber <sc...@apache.org>          (testsuite)
            gbg   Gabriela Gibson <ga...@gmail.com> (gtest)
+     lyalyakin   Pavel Lyalyakin <pa...@visualsvn.com> (site)
 
   Translation of message files:
 

Modified: subversion/branches/shelve/build/generator/gen_win_dependencies.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/build/generator/gen_win_dependencies.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/build/generator/gen_win_dependencies.py (original)
+++ subversion/branches/shelve/build/generator/gen_win_dependencies.py Tue Oct 31 09:29:47 2017
@@ -263,7 +263,7 @@ class GenDependenciesBase(gen_base.Gener
         elif val == '2017' or val == '15':
           self.vs_version = '2017'
           self.sln_version = '12.00'
-          self.vcproj_version = '15.0'
+          self.vcproj_version = '14.1'
           self.vcproj_extension = '.vcxproj'
         elif re.match('^20\d+$', val):
           print('WARNING: Unknown VS.NET version "%s",'

Modified: subversion/branches/shelve/build/run_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/build/run_tests.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/build/run_tests.py (original)
+++ subversion/branches/shelve/build/run_tests.py Tue Oct 31 09:29:47 2017
@@ -424,7 +424,7 @@ class TestHarness:
           os.write(sys.stdout.fileno(), b'.' * job.test_count())
 
 
-  def _run_global_sheduler(self, testlist, has_py_tests):
+  def _run_global_scheduler(self, testlist, has_py_tests):
     # Collect all tests to execute (separate jobs for each test in python
     # test cases, one job for each c test case).  Do that concurrently to
     # mask latency.  This takes .5s instead of about 3s.
@@ -576,7 +576,7 @@ class TestHarness:
     if self.opts.global_scheduler is None:
       failed = self._run_local_schedulers(testlist)
     else:
-      failed = self._run_global_sheduler(testlist, len(py_tests) > 0)
+      failed = self._run_global_scheduler(testlist, len(py_tests) > 0)
 
     # Open the log again to for filtering.
     if self.logfile:
@@ -1036,7 +1036,9 @@ def main():
   (opts, args) = create_parser().parse_args(sys.argv[1:])
 
   if len(args) < 3:
-    print(__doc__)
+    print("{}: at least three positional arguments required; got {!r}".format(
+      os.path.basename(sys.argv[0]), args
+    ))
     sys.exit(2)
 
   if opts.log_to_stdout:

Modified: subversion/branches/shelve/notes/commit-access-templates/partial-committer.tmpl
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/notes/commit-access-templates/partial-committer.tmpl?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/notes/commit-access-templates/partial-committer.tmpl (original)
+++ subversion/branches/shelve/notes/commit-access-templates/partial-committer.tmpl Tue Oct 31 09:29:47 2017
@@ -15,18 +15,20 @@ Hi New Partial Committer,
 The other committers and I would like to offer you partial commit
 access for maintenance of the Subversion FROBLINGS area.
 
-If you already have partial commit access to another area, you can
+#ifdef THE_INVITEE_ALREADY_HAS_PARTIAL_COMMIT_ACCESS_TO_ANOTHER_AREA
+Since you already have partial commit access to another area, you can
 accept this offer by simply replying to this mail.  We'll update the
 COMMITTERS file (or you can do it yourself, that's fine too).
 
-If you do not already have partial commit access, you can accept this
-offer by replying to this mail and following the instructions at
-<http://www.apache.org/dev/new-committers-guide.html#cla>.  You will
-receive an email with details on how to access your account.  Once you
-have access to your account, you are encouraged to modify the COMMITTERS
-file appropriately, which also serves as a test of your new username and
-password.
+#else
+You can accept this offer by replying to this mail and following the
+instructions at <http://www.apache.org/dev/new-committers-guide.html#cla>.
+You will receive an email with details on how to access your account.
+Once you have access to your account, you are encouraged to modify the
+COMMITTERS file appropriately, which also serves as a test of your new
+username and password.
 
+#endif
 Remember that you can still post patches for review before committing,
 when you want to.  Commit access just means that you can rely on your
 own judgment to decide when something is ready for commit.  Also, if

Modified: subversion/branches/shelve/subversion/bindings/javahl/native/SVNRepos.cpp
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/bindings/javahl/native/SVNRepos.cpp?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/bindings/javahl/native/SVNRepos.cpp (original)
+++ subversion/branches/shelve/subversion/bindings/javahl/native/SVNRepos.cpp Tue Oct 31 09:29:47 2017
@@ -247,6 +247,7 @@ void SVNRepos::dump(File &path, OutputSt
                                     ? ReposNotifyCallback::notify
                                     : NULL,
                                  notifyCallback,
+                                 NULL, NULL,
                                  checkCancel, this, requestPool.getPool()), );
 }
 

Modified: subversion/branches/shelve/subversion/bindings/swig/include/svn_types.swg
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/bindings/swig/include/svn_types.swg?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/bindings/swig/include/svn_types.swg (original)
+++ subversion/branches/shelve/subversion/bindings/swig/include/svn_types.swg Tue Oct 31 09:29:47 2017
@@ -1107,7 +1107,7 @@ svn_ ## TYPE ## _swig_rb_closed(VALUE se
 #ifdef SWIGRUBY
 %typemap(argout) unsigned char digest[ANY] {
   char *digest_string = (char *)svn_md5_digest_to_cstring($1, _global_pool);
-  %append_output(rb_str_new2(digest_string));
+  %append_output(rb_str_new2(digest_string ? digest_string : ""));
 }
 #endif
 

Modified: subversion/branches/shelve/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/include/svn_repos.h?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/include/svn_repos.h (original)
+++ subversion/branches/shelve/subversion/include/svn_repos.h Tue Oct 31 09:29:47 2017
@@ -375,6 +375,24 @@ typedef void (*svn_repos_notify_func_t)(
                                         const svn_repos_notify_t *notify,
                                         apr_pool_t *scratch_pool);
 
+/** Callback for filtering repository contents during dump.
+ *
+ * Set @a *include to TRUE to indicate that node, identified by path
+ * @a path in @a root should be included in dump, or set it to @c FALSE
+ * to indicate that node should be excluded (presumably according to state
+ * stored in @a baton).
+ *
+ * Do not assume @a scratch_pool has any lifetime beyond this call.
+ *
+ * @since New in 1.10.
+ */
+typedef svn_error_t * (*svn_repos_dump_filter_func_t)(
+  svn_boolean_t *include,
+  svn_fs_root_t *root,
+  const char *path,
+  void *baton,
+  apr_pool_t *scratch_pool);
+
 /**
  * Allocate an #svn_repos_notify_t structure in @a result_pool, initialize
  * and return it.
@@ -3310,6 +3328,9 @@ svn_repos_verify_fs(svn_repos_t *repos,
  *            reiterating the existence of previous warnings
  *        ### This is a presentation issue. Caller could do this itself.
  *
+ * If @a filter_func is not @c NULL, it is called for each node being
+ * dumped, allowing the caller to exclude it from dump.
+ *
  * If @a cancel_func is not @c NULL, it is called periodically with
  * @a cancel_baton as argument to see if the client wishes to cancel
  * the dump.
@@ -3329,13 +3350,16 @@ svn_repos_dump_fs4(svn_repos_t *repos,
                    svn_boolean_t include_changes,
                    svn_repos_notify_func_t notify_func,
                    void *notify_baton,
+                   svn_repos_dump_filter_func_t filter_func,
+                   void *filter_baton,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    apr_pool_t *pool);
 
 /**
  * Similar to svn_repos_dump_fs4(), but with @a include_revprops and 
- * @a include_changes both set to @c TRUE.
+ * @a include_changes both set to @c TRUE and @a filter_func and
+ * @a filter_baton set to @c NULL.
  *
  * @since New in 1.7.
  * @deprecated Provided for backward compatibility with the 1.9 API.

Modified: subversion/branches/shelve/subversion/libsvn_client/diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/libsvn_client/diff.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/libsvn_client/diff.c (original)
+++ subversion/branches/shelve/subversion/libsvn_client/diff.c Tue Oct 31 09:29:47 2017
@@ -422,7 +422,8 @@ print_git_diff_header(svn_stream_t *os,
                                             scratch_pool));
       *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1),
                            rev1, scratch_pool);
-      *label2 = diff_label("/dev/null", rev2, scratch_pool);
+      *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
+                           rev2, scratch_pool);
 
     }
   else if (operation == svn_diff_op_copied)
@@ -447,7 +448,8 @@ print_git_diff_header(svn_stream_t *os,
                                           repos_relpath1, repos_relpath2,
                                           exec_bit2, symlink_bit2,
                                           scratch_pool));
-      *label1 = diff_label("/dev/null", rev1, scratch_pool);
+      *label1 = diff_label(apr_psprintf(scratch_pool, "a/%s", repos_relpath1),
+                           rev1, scratch_pool);
       *label2 = diff_label(apr_psprintf(scratch_pool, "b/%s", repos_relpath2),
                            rev2, scratch_pool);
     }

Modified: subversion/branches/shelve/subversion/libsvn_repos/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/libsvn_repos/deprecated.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/libsvn_repos/deprecated.c (original)
+++ subversion/branches/shelve/subversion/libsvn_repos/deprecated.c Tue Oct 31 09:29:47 2017
@@ -822,6 +822,7 @@ svn_repos_dump_fs3(svn_repos_t *repos,
                                             TRUE,
                                             notify_func,
                                             notify_baton,
+                                            NULL, NULL,
                                             cancel_func,
                                             cancel_baton,
                                             pool));

Modified: subversion/branches/shelve/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/libsvn_repos/dump.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/shelve/subversion/libsvn_repos/dump.c Tue Oct 31 09:29:47 2017
@@ -1922,14 +1922,17 @@ get_dump_editor(const svn_delta_editor_t
 
 /* Helper for svn_repos_dump_fs.
 
-   Write a revision record of REV in FS to writable STREAM, using POOL.
+   Write a revision record of REV in REPOS to writable STREAM, using POOL.
    Dump revision properties as well if INCLUDE_REVPROPS has been set.
+   AUTHZ_FUNC and AUTHZ_BATON are passed directly to the repos layer.
  */
 static svn_error_t *
 write_revision_record(svn_stream_t *stream,
-                      svn_fs_t *fs,
+                      svn_repos_t *repos,
                       svn_revnum_t rev,
                       svn_boolean_t include_revprops,
+                      svn_repos_authz_func_t authz_func,
+                      void *authz_baton,
                       apr_pool_t *pool)
 {
   apr_hash_t *props;
@@ -1938,7 +1941,8 @@ write_revision_record(svn_stream_t *stre
 
   if (include_revprops)
     {
-      SVN_ERR(svn_fs_revision_proplist2(&props, fs, rev, FALSE, pool, pool));
+      SVN_ERR(svn_repos_fs_revision_proplist(&props, repos, rev,
+                                             authz_func, authz_baton, pool));
 
       /* Run revision date properties through the time conversion to
         canonicalize them. */
@@ -1965,6 +1969,27 @@ write_revision_record(svn_stream_t *stre
   return SVN_NO_ERROR;
 }
 
+/* Baton for dump_filter_authz_func(). */
+typedef struct dump_filter_baton_t
+{
+  svn_repos_dump_filter_func_t filter_func;
+  void *filter_baton;
+} dump_filter_baton_t;
+
+/* Implements svn_repos_authz_func_t. */
+static svn_error_t *
+dump_filter_authz_func(svn_boolean_t *allowed,
+                       svn_fs_root_t *root,
+                       const char *path,
+                       void *baton,
+                       apr_pool_t *pool)
+{
+  dump_filter_baton_t *b = baton;
+
+  return svn_error_trace(b->filter_func(allowed, root, path, b->filter_baton,
+                                        pool));
+}
+
 
 
 /* The main dumper. */
@@ -1979,6 +2004,8 @@ svn_repos_dump_fs4(svn_repos_t *repos,
                    svn_boolean_t include_changes,
                    svn_repos_notify_func_t notify_func,
                    void *notify_baton,
+                   svn_repos_dump_filter_func_t filter_func,
+                   void *filter_baton,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    apr_pool_t *pool)
@@ -1994,6 +2021,8 @@ svn_repos_dump_fs4(svn_repos_t *repos,
   svn_boolean_t found_old_reference = FALSE;
   svn_boolean_t found_old_mergeinfo = FALSE;
   svn_repos_notify_t *notify;
+  svn_repos_authz_func_t authz_func;
+  dump_filter_baton_t authz_baton = {0};
 
   /* Make sure we catch up on the latest revprop changes.  This is the only
    * time we will refresh the revprop data in this query. */
@@ -2022,6 +2051,20 @@ svn_repos_dump_fs4(svn_repos_t *repos,
                                "(youngest revision is %ld)"),
                              end_rev, youngest);
 
+  /* We use read authz callback to implement dump filtering. If there is no
+   * read access for some node, it will be excluded from dump as well as
+   * references to it (e.g. copy source). */
+  if (filter_func)
+    {
+      authz_func = dump_filter_authz_func;
+      authz_baton.filter_func = filter_func;
+      authz_baton.filter_baton = filter_baton;
+    }
+  else
+    {
+      authz_func = NULL;
+    }
+
   /* Write out the UUID. */
   SVN_ERR(svn_fs_get_uuid(fs, &uuid, pool));
 
@@ -2057,8 +2100,8 @@ svn_repos_dump_fs4(svn_repos_t *repos,
         SVN_ERR(cancel_func(cancel_baton));
 
       /* Write the revision record. */
-      SVN_ERR(write_revision_record(stream, fs, rev, include_revprops,
-                                    iterpool));
+      SVN_ERR(write_revision_record(stream, repos, rev, include_revprops,
+                                    authz_func, &authz_baton, iterpool));
 
       /* When dumping revision 0, we just write out the revision record.
          The parser might want to use its properties.
@@ -2091,8 +2134,7 @@ svn_repos_dump_fs4(svn_repos_t *repos,
           SVN_ERR(svn_repos_dir_delta2(from_root, "", "",
                                        to_root, "",
                                        dump_editor, dump_edit_baton,
-                                       NULL,
-                                       NULL,
+                                       authz_func, &authz_baton,
                                        FALSE, /* don't send text-deltas */
                                        svn_depth_infinity,
                                        FALSE, /* don't send entry props */
@@ -2104,7 +2146,7 @@ svn_repos_dump_fs4(svn_repos_t *repos,
           /* The normal case: compare consecutive revs. */
           SVN_ERR(svn_repos_replay2(to_root, "", SVN_INVALID_REVNUM, FALSE,
                                     dump_editor, dump_edit_baton,
-                                    NULL, NULL, iterpool));
+                                    authz_func, &authz_baton, iterpool));
 
           /* While our editor close_edit implementation is a no-op, we still
              do this for completeness. */

Modified: subversion/branches/shelve/subversion/libsvn_repos/reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/libsvn_repos/reporter.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/libsvn_repos/reporter.c (original)
+++ subversion/branches/shelve/subversion/libsvn_repos/reporter.c Tue Oct 31 09:29:47 2017
@@ -976,8 +976,8 @@ update_entry(report_baton_t *b, svn_revn
           SVN_ERR(svn_fs_props_different(&changed, s_root, s_path,
                                          b->t_root, t_path, pool));
           if (!changed)
-            SVN_ERR(svn_fs_contents_different(&changed, s_root, s_path,
-                                              b->t_root, t_path, pool));
+            SVN_ERR(svn_fs_contents_changed(&changed, s_root, s_path,
+                                            b->t_root, t_path, pool));
         }
 
       if ((distance == 0 || !changed) && !any_path_info(b, e_path)

Modified: subversion/branches/shelve/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/libsvn_subr/mergeinfo.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/shelve/subversion/libsvn_subr/mergeinfo.c Tue Oct 31 09:29:47 2017
@@ -271,197 +271,186 @@ combine_with_lastrange(const svn_merge_r
       APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
         svn_merge_range_dup(new_range, result_pool);
     }
+  else if (combine_ranges(&combined_range, lastrange, new_range,
+                     consider_inheritance))
+    {
+      *lastrange = combined_range;
+    }
   else if (!consider_inheritance)
     {
       /* We are not considering inheritance so we can merge intersecting
          ranges of different inheritability.  Of course if the ranges
          don't intersect at all we simply push NEW_RANGE onto RANGELIST. */
-      if (combine_ranges(&combined_range, lastrange, new_range, FALSE))
-        {
-          *lastrange = combined_range;
-        }
-      else
-        {
-          APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
+      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
             svn_merge_range_dup(new_range, result_pool);
-        }
     }
   else /* Considering inheritance */
     {
-      if (combine_ranges(&combined_range, lastrange, new_range, TRUE))
-        {
-          /* Even when considering inheritance two intersection ranges
-             of the same inheritability can simply be combined. */
-          *lastrange = combined_range;
-        }
-      else
-        {
-          /* If we are here then the ranges either don't intersect or do
-             intersect but have differing inheritability.  Check for the
-             first case as that is easy to handle. */
-          intersection_type_t intersection_type;
-          svn_boolean_t sorted = FALSE;
+      /* If we are here then the ranges either don't intersect or do
+          intersect but have differing inheritability.  Check for the
+          first case as that is easy to handle. */
+      intersection_type_t intersection_type;
+      svn_boolean_t sorted = FALSE;
 
-          SVN_ERR(get_type_of_intersection(new_range, lastrange,
-                                           &intersection_type));
+      SVN_ERR(get_type_of_intersection(new_range, lastrange,
+                                        &intersection_type));
 
-          switch (intersection_type)
+      switch (intersection_type)
+        {
+          case svn__no_intersection:
+            /* NEW_RANGE and *LASTRANGE *really* don't intersect so
+                just push NEW_RANGE onto RANGELIST. */
+            APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
+              svn_merge_range_dup(new_range, result_pool);
+            sorted = (svn_sort_compare_ranges(&lastrange,
+                                              &new_range) < 0);
+            break;
+
+          case svn__equal_intersection:
+            /* They range are equal so all we do is force the
+                inheritability of lastrange to true. */
+            lastrange->inheritable = TRUE;
+            sorted = TRUE;
+            break;
+
+          case svn__adjoining_intersection:
+            /* They adjoin but don't overlap so just push NEW_RANGE
+                onto RANGELIST. */
+            APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
+              svn_merge_range_dup(new_range, result_pool);
+            sorted = (svn_sort_compare_ranges(&lastrange,
+                                              &new_range) < 0);
+            break;
+
+          case svn__overlapping_intersection:
+            /* They ranges overlap but neither is a proper subset of
+                the other.  We'll end up pusing two new ranges onto
+                RANGELIST, the intersecting part and the part unique to
+                NEW_RANGE.*/
             {
-              case svn__no_intersection:
-                /* NEW_RANGE and *LASTRANGE *really* don't intersect so
-                   just push NEW_RANGE onto RANGELIST. */
-                APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
-                  svn_merge_range_dup(new_range, result_pool);
-                sorted = (svn_sort_compare_ranges(&lastrange,
-                                                  &new_range) < 0);
-                break;
-
-              case svn__equal_intersection:
-                /* They range are equal so all we do is force the
-                   inheritability of lastrange to true. */
-                lastrange->inheritable = TRUE;
-                sorted = TRUE;
-                break;
-
-              case svn__adjoining_intersection:
-                /* They adjoin but don't overlap so just push NEW_RANGE
-                   onto RANGELIST. */
-                APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) =
-                  svn_merge_range_dup(new_range, result_pool);
-                sorted = (svn_sort_compare_ranges(&lastrange,
-                                                  &new_range) < 0);
-                break;
-
-              case svn__overlapping_intersection:
-                /* They ranges overlap but neither is a proper subset of
-                   the other.  We'll end up pusing two new ranges onto
-                   RANGELIST, the intersecting part and the part unique to
-                   NEW_RANGE.*/
-                {
-                  svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
-                                                              result_pool);
-                  svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
-                                                              result_pool);
-
-                  /* Pop off *LASTRANGE to make our manipulations
-                     easier. */
-                  apr_array_pop(rangelist);
-
-                  /* Ensure R1 is the older range. */
-                  if (r2->start < r1->start)
-                    {
-                      /* Swap R1 and R2. */
-                      *r2 = *r1;
-                      *r1 = *new_range;
-                    }
+              svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
+                                                          result_pool);
+              svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+                                                          result_pool);
+
+              /* Pop off *LASTRANGE to make our manipulations
+                  easier. */
+              apr_array_pop(rangelist);
 
-                  /* Absorb the intersecting ranges into the
-                     inheritable range. */
-                  if (r1->inheritable)
-                    r2->start = r1->end;
-                  else
-                    r1->end = r2->start;
-
-                  /* Push everything back onto RANGELIST. */
-                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
-                  sorted = (svn_sort_compare_ranges(&lastrange,
-                                                    &r1) < 0);
-                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
-                  if (sorted)
-                    sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
-                  break;
+              /* Ensure R1 is the older range. */
+              if (r2->start < r1->start)
+                {
+                  /* Swap R1 and R2. */
+                  *r2 = *r1;
+                  *r1 = *new_range;
                 }
 
-              default: /* svn__proper_subset_intersection */
-                {
-                  /* One range is a proper subset of the other. */
-                  svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
-                                                              result_pool);
-                  svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
-                                                              result_pool);
-                  svn_merge_range_t *r3 = NULL;
+              /* Absorb the intersecting ranges into the
+                  inheritable range. */
+              if (r1->inheritable)
+                r2->start = r1->end;
+              else
+                r1->end = r2->start;
+
+              /* Push everything back onto RANGELIST. */
+              APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
+              sorted = (svn_sort_compare_ranges(&lastrange,
+                                                &r1) < 0);
+              APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
+              if (sorted)
+                sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
+              break;
+            }
 
-                  /* Pop off *LASTRANGE to make our manipulations
-                     easier. */
-                  apr_array_pop(rangelist);
+          default: /* svn__proper_subset_intersection */
+            {
+              /* One range is a proper subset of the other. */
+              svn_merge_range_t *r1 = svn_merge_range_dup(lastrange,
+                                                          result_pool);
+              svn_merge_range_t *r2 = svn_merge_range_dup(new_range,
+                                                          result_pool);
+              svn_merge_range_t *r3 = NULL;
+
+              /* Pop off *LASTRANGE to make our manipulations
+                  easier. */
+              apr_array_pop(rangelist);
 
-                  /* Ensure R1 is the superset. */
-                  if (r2->start < r1->start || r2->end > r1->end)
-                    {
-                      /* Swap R1 and R2. */
-                      *r2 = *r1;
-                      *r1 = *new_range;
-                    }
+              /* Ensure R1 is the superset. */
+              if (r2->start < r1->start || r2->end > r1->end)
+                {
+                  /* Swap R1 and R2. */
+                  *r2 = *r1;
+                  *r1 = *new_range;
+                }
 
-                  if (r1->inheritable)
-                    {
-                      /* The simple case: The superset is inheritable, so
-                         just combine r1 and r2. */
-                      r1->start = MIN(r1->start, r2->start);
-                      r1->end = MAX(r1->end, r2->end);
-                      r2 = NULL;
-                    }
-                  else if (r1->start == r2->start)
-                    {
-                      svn_revnum_t tmp_revnum;
+              if (r1->inheritable)
+                {
+                  /* The simple case: The superset is inheritable, so
+                      just combine r1 and r2. */
+                  r1->start = MIN(r1->start, r2->start);
+                  r1->end = MAX(r1->end, r2->end);
+                  r2 = NULL;
+                }
+              else if (r1->start == r2->start)
+                {
+                  svn_revnum_t tmp_revnum;
 
-                      /* *LASTRANGE and NEW_RANGE share an end point. */
-                      tmp_revnum = r1->end;
-                      r1->end = r2->end;
-                      r2->inheritable = r1->inheritable;
-                      r1->inheritable = TRUE;
-                      r2->start = r1->end;
-                      r2->end = tmp_revnum;
-                    }
-                  else if (r1->end == r2->end)
-                    {
-                      /* *LASTRANGE and NEW_RANGE share an end point. */
-                      r1->end = r2->start;
-                      r2->inheritable = TRUE;
-                    }
-                  else
-                    {
-                      /* NEW_RANGE and *LASTRANGE share neither start
-                         nor end points. */
-                      r3 = apr_pcalloc(result_pool, sizeof(*r3));
-                      r3->start = r2->end;
-                      r3->end = r1->end;
-                      r3->inheritable = r1->inheritable;
-                      r2->inheritable = TRUE;
-                      r1->end = r2->start;
-                    }
+                  /* *LASTRANGE and NEW_RANGE share an end point. */
+                  tmp_revnum = r1->end;
+                  r1->end = r2->end;
+                  r2->inheritable = r1->inheritable;
+                  r1->inheritable = TRUE;
+                  r2->start = r1->end;
+                  r2->end = tmp_revnum;
+                }
+              else if (r1->end == r2->end)
+                {
+                  /* *LASTRANGE and NEW_RANGE share an end point. */
+                  r1->end = r2->start;
+                  r2->inheritable = TRUE;
+                }
+              else
+                {
+                  /* NEW_RANGE and *LASTRANGE share neither start
+                      nor end points. */
+                  r3 = apr_pcalloc(result_pool, sizeof(*r3));
+                  r3->start = r2->end;
+                  r3->end = r1->end;
+                  r3->inheritable = r1->inheritable;
+                  r2->inheritable = TRUE;
+                  r1->end = r2->start;
+                }
 
-                  /* Push everything back onto RANGELIST. */
-                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
-                  sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
-                  if (r2)
-                    {
-                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
-                      if (sorted)
-                        sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
-                    }
-                  if (r3)
+              /* Push everything back onto RANGELIST. */
+              APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r1;
+              sorted = (svn_sort_compare_ranges(&lastrange, &r1) < 0);
+              if (r2)
+                {
+                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r2;
+                  if (sorted)
+                    sorted = (svn_sort_compare_ranges(&r1, &r2) < 0);
+                }
+              if (r3)
+                {
+                  APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
+                  if (sorted)
                     {
-                      APR_ARRAY_PUSH(rangelist, svn_merge_range_t *) = r3;
-                      if (sorted)
-                        {
-                          if (r2)
-                            sorted = (svn_sort_compare_ranges(&r2,
-                                                              &r3) < 0);
-                          else
-                            sorted = (svn_sort_compare_ranges(&r1,
-                                                              &r3) < 0);
-                        }
+                      if (r2)
+                        sorted = (svn_sort_compare_ranges(&r2,
+                                                          &r3) < 0);
+                      else
+                        sorted = (svn_sort_compare_ranges(&r1,
+                                                          &r3) < 0);
                     }
-                  break;
                 }
+              break;
             }
-
-          /* Some of the above cases might have put *RANGELIST out of
-             order, so re-sort.*/
-          if (!sorted)
-            svn_sort__array(rangelist, svn_sort_compare_ranges);
         }
+
+      /* Some of the above cases might have put *RANGELIST out of
+          order, so re-sort.*/
+      if (!sorted)
+        svn_sort__array(rangelist, svn_sort_compare_ranges);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/shelve/subversion/svnadmin/svnadmin.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/svnadmin/svnadmin.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/svnadmin/svnadmin.c (original)
+++ subversion/branches/shelve/subversion/svnadmin/svnadmin.c Tue Oct 31 09:29:47 2017
@@ -152,7 +152,10 @@ enum svnadmin__cmdline_options_t
     svnadmin__check_normalization,
     svnadmin__metadata_only,
     svnadmin__no_flush_to_disk,
-    svnadmin__normalize_props
+    svnadmin__normalize_props,
+    svnadmin__exclude,
+    svnadmin__include,
+    svnadmin__glob
   };
 
 /* Option codes and descriptions.
@@ -279,6 +282,18 @@ static const apr_getopt_option_t options
      N_("normalize property values found in the dumpstream\n"
         "                             (currently, only translates non-LF line endings)")},
 
+    {"exclude", svnadmin__exclude, 1,
+     N_("filter out nodes with given prefix(es) from dump")},
+
+    {"include", svnadmin__include, 1,
+     N_("filter out nodes without given prefix(es) from dump")},
+
+    {"pattern", svnadmin__glob, 0,
+     N_("treat the path prefixes as file glob patterns.\n"
+        "                             Glob special characters are '*' '?' '[]' and '\\'.\n"
+        "                             Character '/' is not treated specially, so\n"
+        "                             pattern /*/foo matches paths /a/foo and /a/b/foo.") },
+
     {NULL}
   };
 
@@ -335,8 +350,13 @@ static const svn_opt_subcommand_desc2_t
     "only the paths changed in that revision; otherwise it will describe\n"
     "every path present in the repository as of that revision.  (In either\n"
     "case, the second and subsequent revisions, if any, describe only paths\n"
-    "changed in those revisions.)\n"),
-  {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M', 'F'},
+    "changed in those revisions.)\n"
+    "\n"
+    "Using --exclude or --include gives results equivalent to authz-based\n"
+    "path exclusions. In particular, when the source of a copy is\n"
+    "excluded, the copy is transformed into an add (unlike in 'svndumpfilter').\n"),
+  {'r', svnadmin__incremental, svnadmin__deltas, 'q', 'M', 'F',
+   svnadmin__exclude, svnadmin__include, svnadmin__glob },
   {{'F', N_("write to file ARG instead of stdout")}} },
 
   {"dump-revprops", subcommand_dump_revprops, {0}, N_
@@ -559,6 +579,9 @@ struct svnadmin_opt_state
   apr_uint64_t memory_cache_size;                   /* --memory-cache-size M */
   const char *parent_dir;                           /* --parent-dir */
   const char *file;                                 /* --file */
+  apr_array_header_t *exclude;                      /* --exclude */
+  apr_array_header_t *include;                      /* --include */
+  svn_boolean_t glob;                               /* --pattern */
 
   const char *config_dir;    /* Overriding Configuration Directory */
 };
@@ -1255,6 +1278,58 @@ get_dump_range(svn_revnum_t *lower,
   return SVN_NO_ERROR;
 }
 
+/* Compare the node-path PATH with the (const char *) prefixes in PFXLIST.
+ * Return TRUE if any prefix is a prefix of PATH (matching whole path
+ * components); FALSE otherwise.
+ * PATH starts with a '/', as do the (const char *) paths in PREFIXES. */
+/* This function is a duplicate of svndumpfilter.c:ary_prefix_match(). */
+static svn_boolean_t
+ary_prefix_match(const apr_array_header_t *pfxlist, const char *path)
+{
+  int i;
+  size_t path_len = strlen(path);
+
+  for (i = 0; i < pfxlist->nelts; i++)
+    {
+      const char *pfx = APR_ARRAY_IDX(pfxlist, i, const char *);
+      size_t pfx_len = strlen(pfx);
+
+      if (path_len < pfx_len)
+        continue;
+      if (strncmp(path, pfx, pfx_len) == 0
+          && (pfx_len == 1 || path[pfx_len] == '\0' || path[pfx_len] == '/'))
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
+/* Baton for dump_filter_func(). */
+struct dump_filter_baton_t
+{
+  apr_array_header_t *prefixes;
+  svn_boolean_t glob;
+  svn_boolean_t do_exclude;
+};
+
+/* Implements svn_repos_dump_filter_func_t. */
+static svn_error_t *
+dump_filter_func(svn_boolean_t *include,
+                 svn_fs_root_t *root,
+                 const char *path,
+                 void *baton,
+                 apr_pool_t *scratch_pool)
+{
+  struct dump_filter_baton_t *b = baton;
+  const svn_boolean_t matches =
+    (b->glob
+     ? svn_cstring_match_glob_list(path, b->prefixes)
+     : ary_prefix_match(b->prefixes, path));
+
+  *include = b->do_exclude ? !matches : matches;
+  return SVN_NO_ERROR;
+}
+
 /* This implements `svn_opt_subcommand_t'. */
 static svn_error_t *
 subcommand_dump(apr_getopt_t *os, void *baton, apr_pool_t *pool)
@@ -1264,6 +1339,7 @@ subcommand_dump(apr_getopt_t *os, void *
   svn_stream_t *out_stream;
   svn_revnum_t lower, upper;
   svn_stream_t *feedback_stream = NULL;
+  struct dump_filter_baton_t filter_baton = {0};
 
   /* Expect no more arguments. */
   SVN_ERR(parse_args(NULL, os, 0, 0, pool));
@@ -1289,11 +1365,34 @@ subcommand_dump(apr_getopt_t *os, void *
   if (! opt_state->quiet)
     feedback_stream = recode_stream_create(stderr, pool);
 
+  /* Initialize the filter baton. */
+  filter_baton.glob = opt_state->glob;
+
+  if (opt_state->exclude && !opt_state->include)
+    {
+      filter_baton.prefixes = opt_state->exclude;
+      filter_baton.do_exclude = TRUE;
+    }
+  else if (opt_state->include && !opt_state->exclude)
+    {
+      filter_baton.prefixes = opt_state->include;
+      filter_baton.do_exclude = FALSE;
+    }
+  else if (opt_state->include && opt_state->exclude)
+    {
+      return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                               _("'--exclude' and '--include' options "
+                                 "cannot be used simultaneously"));
+    }
+
   SVN_ERR(svn_repos_dump_fs4(repos, out_stream, lower, upper,
                              opt_state->incremental, opt_state->use_deltas,
                              TRUE, TRUE,
                              !opt_state->quiet ? repos_notify_handler : NULL,
-                             feedback_stream, check_cancel, NULL, pool));
+                             feedback_stream,
+                             filter_baton.prefixes ? dump_filter_func : NULL,
+                             &filter_baton,
+                             check_cancel, NULL, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1335,7 +1434,8 @@ subcommand_dump_revprops(apr_getopt_t *o
   SVN_ERR(svn_repos_dump_fs4(repos, out_stream, lower, upper,
                              FALSE, FALSE, TRUE, FALSE,
                              !opt_state->quiet ? repos_notify_handler : NULL,
-                             feedback_stream, check_cancel, NULL, pool));
+                             feedback_stream, NULL, NULL,
+                             check_cancel, NULL, pool));
 
   return SVN_NO_ERROR;
 }
@@ -2918,6 +3018,23 @@ sub_main(int *exit_code, int argc, const
       case svnadmin__normalize_props:
         opt_state.normalize_props = TRUE;
         break;
+      case svnadmin__exclude:
+        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+
+        if (! opt_state.exclude)
+          opt_state.exclude = apr_array_make(pool, 1, sizeof(const char *));
+        APR_ARRAY_PUSH(opt_state.exclude, const char *) = utf8_opt_arg;
+        break;
+      case svnadmin__include:
+        SVN_ERR(svn_utf_cstring_to_utf8(&utf8_opt_arg, opt_arg, pool));
+
+        if (! opt_state.include)
+          opt_state.include = apr_array_make(pool, 1, sizeof(const char *));
+        APR_ARRAY_PUSH(opt_state.include, const char *) = utf8_opt_arg;
+        break;
+      case svnadmin__glob:
+        opt_state.glob = TRUE;
+        break;
       default:
         {
           SVN_ERR(subcommand_help(NULL, NULL, pool));

Modified: subversion/branches/shelve/subversion/svndumpfilter/svndumpfilter.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/svndumpfilter/svndumpfilter.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/svndumpfilter/svndumpfilter.c (original)
+++ subversion/branches/shelve/subversion/svndumpfilter/svndumpfilter.c Tue Oct 31 09:29:47 2017
@@ -109,6 +109,7 @@ write_propdel_to_stringbuf(svn_stringbuf
  * Return TRUE if any prefix is a prefix of PATH (matching whole path
  * components); FALSE otherwise.
  * PATH starts with a '/', as do the (const char *) paths in PREFIXES. */
+/* This function is a duplicate of svnadmin.c:ary_prefix_match(). */
 static svn_boolean_t
 ary_prefix_match(const apr_array_header_t *pfxlist, const char *path)
 {

Modified: subversion/branches/shelve/subversion/tests/cmdline/basic_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/cmdline/basic_tests.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/cmdline/basic_tests.py (original)
+++ subversion/branches/shelve/subversion/tests/cmdline/basic_tests.py Tue Oct 31 09:29:47 2017
@@ -3140,6 +3140,62 @@ def filtered_ls(sbox):
   exit_code, output, error = svntest.actions.run_and_verify_svn(
     [], [], 'ls', path, '--depth=infinity', '--search=*/*')
 
+@Issue(4700)
+def null_update_last_changed_revision(sbox):
+  "null 'update' updates last changed rev"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  # r2: Random text change.
+  old_contents = open(sbox.path("iota")).read()
+  sbox.simple_append("iota", "Line 2.\n")
+  sbox.simple_commit(message='r2')
+  sbox.simple_update()
+
+  # r3: Revert r2.
+  sbox.simple_append("iota", old_contents, truncate=True)
+  sbox.simple_commit(message='r3')
+  sbox.simple_update()
+
+  # Perform a null update.
+  #
+  # This used to say '3'; probably because iota@3 and iota@1 were textually
+  # identical. It seems this problem was introduced in r1760570.
+  sbox.simple_update(revision='1')
+  svntest.actions.run_and_verify_svn(["1\n"], [],
+                                     'info', sbox.path('iota'),
+                                     '--show-item', 'last-changed-revision')
+
+@Issue(4700)
+@XFail()
+def null_prop_update_last_changed_revision(sbox):
+  "null 'property update' updates last changed rev"
+
+  sbox.build()
+  wc_dir = sbox.wc_dir
+
+  sbox.simple_propset("prop", "value", "iota")
+  sbox.simple_commit(message='r2')
+  sbox.simple_update()
+
+  # r3: change the property
+  sbox.simple_propset("prop", "changed", "iota")
+  sbox.simple_commit(message='r3')
+  sbox.simple_update()
+
+  # r4: Revert r3.
+  sbox.simple_propset("prop", "value", "iota")
+  sbox.simple_commit(message='r4')
+  sbox.simple_update()
+
+  # Perform a null update.
+  sbox.simple_update(revision='2')
+  svntest.actions.run_and_verify_svn(["2\n"], [],
+                                     'info', sbox.path('iota'),
+                                     '--show-item', 'last-changed-revision')
+
+
 ########################################################################
 # Run the tests
 
@@ -3211,6 +3267,8 @@ test_list = [ None,
               mkdir_parents_target_exists_on_disk,
               plaintext_password_storage_disabled,
               filtered_ls,
+              null_update_last_changed_revision,
+              null_prop_update_last_changed_revision,
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/shelve/subversion/tests/cmdline/diff_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/cmdline/diff_tests.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/cmdline/diff_tests.py (original)
+++ subversion/branches/shelve/subversion/tests/cmdline/diff_tests.py Tue Oct 31 09:29:47 2017
@@ -3531,7 +3531,7 @@ def diff_git_empty_files(sbox):
   expected_output = make_git_diff_header(new_path, "new", "nonexistent",
                                          "working copy",
                                          add=True, text_changes=False) + [
-  ] + make_git_diff_header(iota_path, "iota", "revision 2", "working copy",
+  ] + make_git_diff_header(iota_path, "iota", "revision 2", "nonexistent",
                            delete=True, text_changes=False)
 
   # Two files in diff may be in any order.
@@ -5043,7 +5043,7 @@ def diff_symlinks(sbox):
     '===================================================================\n',
     'diff --git a/to-iota b/to-iota\n',
     'new file mode 120644\n',
-    '--- /dev/null\t(nonexistent)\n',
+    '--- a/to-iota\t(nonexistent)\n',
     '+++ b/to-iota\t(working copy)\n',
     '@@ -0,0 +1 @@\n',
     '+iota\n',

Modified: subversion/branches/shelve/subversion/tests/cmdline/svnadmin_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/cmdline/svnadmin_tests.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/branches/shelve/subversion/tests/cmdline/svnadmin_tests.py Tue Oct 31 09:29:47 2017
@@ -3456,6 +3456,336 @@ def load_from_file(sbox):
                                      'update', sbox.wc_dir)
   svntest.actions.verify_disk(sbox.wc_dir, expected_tree, check_props=True)
 
+def dump_exclude(sbox):
+  "svnadmin dump with excluded paths"
+
+  sbox.build(create_wc=False)
+
+  # Dump repository with /A/D/H and /A/B/E paths excluded.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--exclude', '/A/D/H',
+                                                       '--exclude', '/A/B/E',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r1\ .*\n',
+    # '/A/D/H' and '/A/B/E' is not added.
+    re.escape('Changed paths:\n'),
+    re.escape('   A /A\n'),
+    re.escape('   A /A/B\n'),
+    re.escape('   A /A/B/F\n'),
+    re.escape('   A /A/B/lambda\n'),
+    re.escape('   A /A/C\n'),
+    re.escape('   A /A/D\n'),
+    re.escape('   A /A/D/G\n'),
+    re.escape('   A /A/D/G/pi\n'),
+    re.escape('   A /A/D/G/rho\n'),
+    re.escape('   A /A/D/G/tau\n'),
+    re.escape('   A /A/D/gamma\n'),
+    re.escape('   A /A/mu\n'),
+    re.escape('   A /iota\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_exclude_copysource(sbox):
+  "svnadmin dump with excluded copysource"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create default repository structure.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/trunk',
+                                     sbox.repo_url + '/branches',
+                                     sbox.repo_url + '/tags',
+                                     "-m", "Create repository structure.")
+
+  # Create a branch.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "copy",
+                                     sbox.repo_url + '/trunk',
+                                     sbox.repo_url + '/branches/branch1',
+                                     "-m", "Create branch.")
+
+  # Dump repository with /trunk excluded.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--exclude', '/trunk',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r2\ .*\n',
+    re.escape('Changed paths:\n'),
+    # Simple add, not copy.
+    re.escape('   A /branches/branch1\n'),
+    '-+\\n',
+    'r1\ .*\n',
+    # '/trunk' is not added.
+    re.escape('Changed paths:\n'),
+    re.escape('   A /branches\n'),
+    re.escape('   A /tags\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_include(sbox):
+  "svnadmin dump with included paths"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create a couple of directories.
+  # Note that we can't use greek tree as it contains only two top-level
+  # nodes. Including non top-level nodes (e.g. '--include /A/B/E') will
+  # produce unloadable dump for now.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/A',
+                                     sbox.repo_url + '/B',
+                                     sbox.repo_url + '/C',
+                                     "-m", "Create folder.")
+
+  # Dump repository with /A and /C paths included.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--include', '/A',
+                                                       '--include', '/C',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r1\ .*\n',
+    # '/B' is not added.
+    re.escape('Changed paths:\n'),
+    re.escape('   A /A\n'),
+    re.escape('   A /C\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_not_include_copysource(sbox):
+  "svnadmin dump with not included copysource"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create default repository structure.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/trunk',
+                                     sbox.repo_url + '/branches',
+                                     sbox.repo_url + '/tags',
+                                     "-m", "Create repository structure.")
+
+  # Create a branch.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "copy",
+                                     sbox.repo_url + '/trunk',
+                                     sbox.repo_url + '/branches/branch1',
+                                     "-m", "Create branch.")
+
+  # Dump repository with only /branches included.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--include', '/branches',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r2\ .*\n',
+    re.escape('Changed paths:\n'),
+    # Simple add, not copy.
+    re.escape('   A /branches/branch1\n'),
+    '-+\\n',
+    'r1\ .*\n',
+    # Only '/branches' is added in r1.
+    re.escape('Changed paths:\n'),
+    re.escape('   A /branches\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_exclude_by_pattern(sbox):
+  "svnadmin dump with paths excluded by pattern"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create a couple of directories.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/aaa',
+                                     sbox.repo_url + '/aab',
+                                     sbox.repo_url + '/aac',
+                                     sbox.repo_url + '/bbc',
+                                     "-m", "Create repository structure.")
+
+  # Dump with paths excluded by pattern.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--exclude', '/aa?',
+                                                       '--pattern',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r1\ .*\n',
+    re.escape('Changed paths:\n'),
+    # Only '/bbc' is added in r1.
+    re.escape('   A /bbc\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_include_by_pattern(sbox):
+  "svnadmin dump with paths included by pattern"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create a couple of directories.
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/aaa',
+                                     sbox.repo_url + '/aab',
+                                     sbox.repo_url + '/aac',
+                                     sbox.repo_url + '/bbc',
+                                     "-m", "Create repository structure.")
+
+  # Dump with paths included by pattern.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--include', '/aa?',
+                                                       '--pattern',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r1\ .*\n',
+    # '/bbc' is not added.
+    re.escape('Changed paths:\n'),
+    re.escape('   A /aaa\n'),
+    re.escape('   A /aab\n'),
+    re.escape('   A /aac\n'),
+    '-+\\n'
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v', '-q', sbox2.repo_url)
+
+def dump_exclude_all_rev_changes(sbox):
+  "svnadmin dump with all revision changes excluded"
+
+  sbox.build(create_wc=False, empty=True)
+
+  # Create a couple of directories (r1).
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/r1a',
+                                     sbox.repo_url + '/r1b',
+                                     sbox.repo_url + '/r1c',
+                                     "-m", "Revision 1.")
+
+  # Create a couple of directories (r2).
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/r2a',
+                                     sbox.repo_url + '/r2b',
+                                     sbox.repo_url + '/r2c',
+                                     "-m", "Revision 2.")
+
+  # Create a couple of directories (r3).
+  svntest.actions.run_and_verify_svn(svntest.verify.AnyOutput, [], "mkdir",
+                                     sbox.repo_url + '/r3a',
+                                     sbox.repo_url + '/r3b',
+                                     sbox.repo_url + '/r3c',
+                                     "-m", "Revision 3.")
+
+  # Dump with paths excluded by pattern.
+  _, dump, _ = svntest.actions.run_and_verify_svnadmin(None, [],
+                                                       'dump', '-q',
+                                                       '--exclude', '/r2?',
+                                                       '--pattern',
+                                                       sbox.repo_dir)
+
+  # Load repository from dump.
+  sbox2 = sbox.clone_dependent()
+  sbox2.build(create_wc=False, empty=True)
+  load_and_verify_dumpstream(sbox2, None, [], None, False, dump)
+
+  # Check log. Revision properties ('svn:log' etc.) should be empty for r2.
+  expected_output = svntest.verify.RegexListOutput([
+    '-+\\n',
+    'r3\ |\ jrandom\ |\ .*\ |\ 1\ line\\n',
+    re.escape('Changed paths:'),
+    re.escape('   A /r3a'),
+    re.escape('   A /r3b'),
+    re.escape('   A /r3c'),
+    '',
+    re.escape('Revision 3.'),
+    '-+\\n',
+    re.escape('r2 | (no author) | (no date) | 1 line'),
+    '',
+    '',
+    '-+\\n',
+    'r1\ |\ jrandom\ |\ .*\ |\ 1\ line\\n',
+    re.escape('Changed paths:'),
+    re.escape('   A /r1a'),
+    re.escape('   A /r1b'),
+    re.escape('   A /r1c'),
+    '',
+    re.escape('Revision 1.'),
+    '-+\\n',
+  ])
+  svntest.actions.run_and_verify_svn(expected_output, [],
+                                     'log', '-v',  sbox2.repo_url)
+
+def dump_invalid_filtering_option(sbox):
+  "dump with --include and --exclude simultaneously"
+
+  sbox.build(create_wc=False, empty=False)
+
+  # Attempt to dump repository with '--include' and '--exclude' options
+  # specified simultaneously.
+  expected_error = ".*: '--exclude' and '--include' options cannot be used " \
+                   "simultaneously"
+  svntest.actions.run_and_verify_svnadmin(None, expected_error,
+                                          'dump', '-q',
+                                          '--exclude', '/A/D/H',
+                                          '--include', '/A/B/E',
+                                          sbox.repo_dir)
+
 ########################################################################
 # Run the tests
 
@@ -3520,7 +3850,15 @@ test_list = [ None,
               dump_no_op_prop_change,
               load_no_flush_to_disk,
               dump_to_file,
-              load_from_file
+              load_from_file,
+              dump_exclude,
+              dump_exclude_copysource,
+              dump_include,
+              dump_not_include_copysource,
+              dump_exclude_by_pattern,
+              dump_include_by_pattern,
+              dump_exclude_all_rev_changes,
+              dump_invalid_filtering_option
              ]
 
 if __name__ == '__main__':

Modified: subversion/branches/shelve/subversion/tests/cmdline/svntest/verify.py
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/cmdline/svntest/verify.py?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/cmdline/svntest/verify.py (original)
+++ subversion/branches/shelve/subversion/tests/cmdline/svntest/verify.py Tue Oct 31 09:29:47 2017
@@ -860,7 +860,7 @@ def make_git_diff_header(target_path, re
     ])
     if text_changes:
       output.extend([
-        "--- /dev/null\t(" + old_tag + ")\n",
+        "--- a/" + repos_relpath + src_label + "\t(" + old_tag + ")\n",
         "+++ b/" + repos_relpath + dst_label + "\t(" + new_tag + ")\n"
       ])
   elif delete:
@@ -871,7 +871,7 @@ def make_git_diff_header(target_path, re
     if text_changes:
       output.extend([
         "--- a/" + repos_relpath + src_label + "\t(" + old_tag + ")\n",
-        "+++ /dev/null\t(" + new_tag + ")\n"
+        "+++ b/" + repos_relpath + dst_label + "\t(" + new_tag + ")\n"
       ])
   elif cp:
     if copyfrom_rev:

Modified: subversion/branches/shelve/subversion/tests/libsvn_repos/dump-load-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/subversion/tests/libsvn_repos/dump-load-test.c?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/subversion/tests/libsvn_repos/dump-load-test.c (original)
+++ subversion/branches/shelve/subversion/tests/libsvn_repos/dump-load-test.c Tue Oct 31 09:29:47 2017
@@ -79,7 +79,7 @@ test_dump_bad_props(svn_stringbuf_t **du
   SVN_ERR(svn_repos_dump_fs4(repos, stream, start_rev, end_rev,
                              FALSE, FALSE, TRUE, TRUE,
                              notify_func, notify_baton,
-                             NULL, NULL,
+                             NULL, NULL, NULL, NULL,
                              pool));
   svn_stream_close(stream);
 

Modified: subversion/branches/shelve/tools/client-side/bash_completion
URL: http://svn.apache.org/viewvc/subversion/branches/shelve/tools/client-side/bash_completion?rev=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/tools/client-side/bash_completion (original)
+++ subversion/branches/shelve/tools/client-side/bash_completion Tue Oct 31 09:29:47 2017
@@ -1113,9 +1113,9 @@ _svnadmin ()
 	cur=${COMP_WORDS[COMP_CWORD]}
 
 	# Possible expansions, without pure-prefix abbreviations such as "h".
-	cmds='crashtest create delrevprop deltify dump freeze help hotcopy \
-	      info list-dblogs \
-	      list-unused-dblogs load lock lslocks lstxns pack recover rmlocks \
+	cmds='crashtest create delrevprop deltify dump dump-revprops freeze \
+	      help hotcopy info list-dblogs list-unused-dblogs \
+	      load load-revprops lock lslocks lstxns pack recover rmlocks \
 	      rmtxns setlog setrevprop setuuid unlock upgrade verify --version'
 
 	if [[ $COMP_CWORD -eq 1 ]] ; then
@@ -1126,7 +1126,7 @@ _svnadmin ()
 	# options that require a parameter
 	# note: continued lines must end '|' continuing lines must start '|'
 	optsParam="-r|--revision|--parent-dir|--fs-type|-M|--memory-cache-size"
-	optsParam="$optsParam|-F|--file"
+	optsParam="$optsParam|-F|--file|--exclude|--include"
 
 	# if not typing an option, or if the previous option required a
 	# parameter, then fallback on ordinary filename expansion
@@ -1149,7 +1149,8 @@ _svnadmin ()
 		;;
 	dump)
 		cmdOpts="-r --revision --incremental -q --quiet --deltas \
-		         -M --memory-cache-size -F --file"
+		         -M --memory-cache-size -F --file \
+		         --exclude --include --pattern"
 		;;
 	freeze)
 		cmdOpts="-F --file"
@@ -1266,9 +1267,9 @@ _svndumpfilter ()
 	cmdOpts=
 	case ${COMP_WORDS[1]} in
 	exclude|include)
-		cmdOpts="--drop-empty-revs --renumber-revs
+		cmdOpts="--drop-empty-revs --drop-all-empty-revs --renumber-revs
 		         --skip-missing-merge-sources --targets
-		         --preserve-revprops --quiet"
+		         --preserve-revprops --quiet --pattern"
 		;;
 	help|h|\?)
 		cmdOpts="$cmds"

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=1813857&r1=1813856&r2=1813857&view=diff
==============================================================================
--- subversion/branches/shelve/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/shelve/tools/dev/unix-build/Makefile.svn Tue Oct 31 09:29:47 2017
@@ -50,6 +50,10 @@ PWD		= $(shell pwd)
 UNAME		= $(shell uname)
 RUBY		= $(shell which ruby 2>/dev/null)
 ifeq ($(RUBY),)
+RUBY		= $(shell which ruby24 2>/dev/null)
+ifeq ($(RUBY),)
+RUBY		= $(shell which ruby23 2>/dev/null)
+ifeq ($(RUBY),)
 RUBY		= $(shell which ruby22 2>/dev/null)
 ifeq ($(RUBY),)
 RUBY		= $(shell which ruby21 2>/dev/null)
@@ -64,6 +68,8 @@ endif # 1.9
 endif # 2.0
 endif # 2.1
 endif # 2.2
+endif # 2.3
+endif # 2.4
 
 TAG		?= none
 ifeq ($(TAG),none)
@@ -95,7 +101,7 @@ SERF_OLD_VER	= 0.3.1
 CYRUS_SASL_VER	= 2.1.25
 SQLITE_VER	= 3160200
 LIBMAGIC_VER	= 5.30
-RUBY_VER	= 2.1.10
+RUBY_VER	= 2.4.2
 BZ2_VER	= 1.0.6
 PYTHON_VER	= 2.7.13
 JUNIT_VER	= 4.10
@@ -125,7 +131,7 @@ SHA256_${NEON_DIST} = db0bd8cdec329b48f5
 SHA256_${CYRUS_SASL_DIST} = 418c16e6240a4f9b637cbe3d62937b9675627bad27c622191d47de8686fe24fe
 SHA256_${SQLITE_DIST} = 65cc0c3e9366f50c0679c5ccd31432cea894bc4a3e8947dabab88c8693263615
 SHA256_${LIBMAGIC_DIST} = 694c2432e5240187524c9e7cf1ec6acc77b47a0e19554d34c14773e43dbbf214
-SHA256_${RUBY_DIST} = fb2e454d7a5e5a39eb54db0ec666f53eeb6edc593d1d2b970ae4d150b831dd20
+SHA256_${RUBY_DIST} = 93b9e75e00b262bc4def6b26b7ae8717efc252c47154abb7392e54357e6c8c9c
 SHA256_${BZ2_DIST} = a2848f34fcd5d6cf47def00461fcb528a0484d8edef8208d6d2e2909dc61d9cd
 SHA256_${PYTHON_DIST} = a4f05a0720ce0fd92626f0278b6b433eee9a6173ddf2bced7957dfb599a5ece1
 SHA256_${JUNIT_DIST} = 36a747ca1e0b86f6ea88055b8723bb87030d627766da6288bf077afdeeb0f75a
@@ -174,7 +180,7 @@ SERF_OLD_URL	= https://svn.apache.org/re
 SQLITE_URL	= https://www.sqlite.org/2017/$(SQLITE_DIST)
 CYRUS_SASL_URL	= ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/$(CYRUS_SASL_DIST)
 LIBMAGIC_URL	= ftp://ftp.astron.com/pub/file/$(LIBMAGIC_DIST)
-RUBY_URL	= https://cache.ruby-lang.org/pub/ruby/2.1/$(RUBY_DIST)
+RUBY_URL	= https://cache.ruby-lang.org/pub/ruby/2.4/$(RUBY_DIST)
 BZ2_URL		= http://bzip.org/$(BZ2_VER)/$(BZ2_DIST)
 PYTHON_URL	= https://python.org/ftp/python/$(PYTHON_VER)/$(PYTHON_DIST)
 JUNIT_URL	= https://downloads.sourceforge.net/project/junit/junit/$(JUNIT_VER)/$(JUNIT_DIST)
@@ -1111,6 +1117,7 @@ $(RUBY_OBJDIR)/.retrieved: $(DISTDIR)/$(
 	$(call do_check_sha256,$(RUBY_DIST))
 	[ -d $(RUBY_OBJDIR) ] || mkdir -p $(RUBY_OBJDIR)
 	tar -C $(SRCDIR) -zxf $(DISTDIR)/$(RUBY_DIST)
+	-which ghead && sed -i -e "s/head -c/ghead -c/" $(RUBY_SRCDIR)/configure
 	touch $@
 
 ifeq ($(THREADING),yes)