Modified: 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py
 (original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/svn_fs.py
 Sat May 23 14:16:56 2020
@@ -63,7 +63,7 @@ _kindmap = {core.svn_node_dir: Node.DIRE
 
 def _get_history(path, authz, fs_ptr, start, end, limit=None):
     history = []
-    if hasattr(repos, 'svn_repos_history2'):
+    if getattr(repos, 'svn_repos_history2', None) is not None:
         # For Subversion >= 1.1
         def authz_cb(root, path, pool):
             if limit and len(history) >= limit:
@@ -107,17 +107,17 @@ class SubversionRepository(Repository):
             raise TracError("%s does not appear to be a Subversion 
repository." % (path, ))
         if self.path != path:
             self.scope = path[len(self.path):]
-            if not self.scope[-1] == '/':
-                self.scope += '/'
+            if not self.scope[-1:] == b'/':
+                self.scope += b'/'
         else:
-            self.scope = '/'
+            self.scope = b'/'
 
         self.repos = repos.svn_repos_open(self.path)
         self.fs_ptr = repos.svn_repos_fs(self.repos)
         self.rev = fs.youngest_rev(self.fs_ptr)
 
         self.history = None
-        if self.scope != '/':
+        if self.scope != b'/':
             self.history = []
             for path,rev in _get_history(self.scope[1:], self.authz,
                                          self.fs_ptr, 0, self.rev):
@@ -132,7 +132,7 @@ class SubversionRepository(Repository):
         return node_type in _kindmap
 
     def normalize_path(self, path):
-        return path == '/' and path or path and path.strip('/') or ''
+        return path == b'/' and path or path and path.strip(b'/') or b''
 
     def normalize_rev(self, rev):
         try:
@@ -157,7 +157,7 @@ class SubversionRepository(Repository):
 
     def get_node(self, path, rev=None):
         self.authz.assert_permission(self.scope + path)
-        if path and path[-1] == '/':
+        if path and path[-1] == b'/':
             path = path[:-1]
 
         rev = self.normalize_rev(rev)
@@ -166,13 +166,13 @@ class SubversionRepository(Repository):
 
     def get_oldest_rev(self):
         rev = 0
-        if self.scope == '/':
+        if self.scope == b'/':
             return rev
         return self.history[-1]
 
     def get_youngest_rev(self):
         rev = self.rev
-        if self.scope == '/':
+        if self.scope == b'/':
             return rev
         return self.history[0]
 
@@ -180,7 +180,7 @@ class SubversionRepository(Repository):
         rev = int(rev)
         if rev == 0:
             return None
-        if self.scope == '/':
+        if self.scope == b'/':
             return rev - 1
         idx = self.history.index(rev)
         if idx + 1 < len(self.history):
@@ -191,7 +191,7 @@ class SubversionRepository(Repository):
         rev = int(rev)
         if rev == self.rev:
             return None
-        if self.scope == '/':
+        if self.scope == b'/':
             return rev + 1
         if rev == 0:
             return self.oldest_rev
@@ -224,7 +224,7 @@ class SubversionRepository(Repository):
                         else: # the path changed: 'newer' was a copy
                             rev = self.previous_rev(newer[1]) # restart before 
the copy op
                             yield newer[0], newer[1], Changeset.COPY
-                            older = (older[0], older[1], 'unknown')
+                            older = (older[0], older[1], b'unknown')
                             break
                     newer = older
                 if older: # either a real ADD or the source of a COPY
@@ -262,7 +262,7 @@ class SubversionRepository(Repository):
             def authz_cb(root, path, pool): return 1
             text_deltas = 0 # as this is anyway re-done in Diff.py...
             entry_props = 0 # ("... typically used only for working copy 
updates")
-            repos.svn_repos_dir_delta(old_root, old_path, '',
+            repos.svn_repos_dir_delta(old_root, old_path, b'',
                                       new_root, new_path,
                                       e_ptr, e_baton, authz_cb,
                                       text_deltas,
@@ -290,7 +290,7 @@ class SubversionNode(Node):
     def __init__(self, path, rev, authz, scope, fs_ptr):
         self.authz = authz
         self.scope = scope
-        if scope != '/':
+        if scope != b'/':
             self.scoped_path = scope + path
         else:
             self.scoped_path = path
@@ -300,7 +300,8 @@ class SubversionNode(Node):
         self.root = fs.revision_root(fs_ptr, rev)
         node_type = fs.check_path(self.root, self.scoped_path)
         if not node_type in _kindmap:
-            raise TracError("No node at %s in revision %s" % (path, rev))
+            raise TracError("No node at %s in revision %s"
+                            % (path.decode('UTF-8'), rev))
         self.created_rev = fs.node_created_rev(self.root, self.scoped_path)
         self.created_path = fs.node_created_path(self.root, self.scoped_path)
         # Note: 'created_path' differs from 'path' if the last change was a 
copy,
@@ -322,8 +323,8 @@ class SubversionNode(Node):
         if self.isfile:
             return
         entries = fs.dir_entries(self.root, self.scoped_path)
-        for item in entries.keys():
-            path = '/'.join((self.path, item))
+        for item in entries:
+            path = b'/'.join((self.path, item))
             if not self.authz.has_permission(path):
                 continue
             yield SubversionNode(path, self._requested_rev, self.authz,
@@ -349,8 +350,8 @@ class SubversionNode(Node):
 
     def get_properties(self):
         props = fs.node_proplist(self.root, self.scoped_path)
-        for name,value in props.items():
-            props[name] = str(value) # Make sure the value is a proper string
+        for name,value in core._as_list(props.items()):
+            props[name] = value
         return props
 
     def get_content_length(self):
@@ -366,7 +367,7 @@ class SubversionNode(Node):
     def get_last_modified(self):
         date = fs.revision_prop(self.fs_ptr, self.created_rev,
                                 core.SVN_PROP_REVISION_DATE)
-        return core.svn_time_from_cstring(date) / 1000000
+        return core.svn_time_from_cstring(date) // 1000000
 
     def _get_prop(self, name):
         return fs.node_prop(self.root, self.scoped_path, name)
@@ -382,7 +383,7 @@ class SubversionChangeset(Changeset):
         message = self._get_prop(core.SVN_PROP_REVISION_LOG)
         author = self._get_prop(core.SVN_PROP_REVISION_AUTHOR)
         date = self._get_prop(core.SVN_PROP_REVISION_DATE)
-        date = core.svn_time_from_cstring(date) / 1000000
+        date = core.svn_time_from_cstring(date) // 1000000
         Changeset.__init__(self, rev, message, author, date)
 
     def get_changes(self):
@@ -392,9 +393,10 @@ class SubversionChangeset(Changeset):
         repos.svn_repos_replay(root, e_ptr, e_baton)
 
         idx = 0
+        # Variables to record copy/deletes for later move detection
         copies, deletions = {}, {}
         changes = []
-        for path, change in editor.changes.items():
+        for path, change in core._as_list(editor.changes.items()):
             if not self.authz.has_permission(path):
                 # FIXME: what about base_path?
                 continue
@@ -409,10 +411,12 @@ class SubversionChangeset(Changeset):
             action = ''
             if change.action == repos.CHANGE_ACTION_DELETE:
                 action = Changeset.DELETE
+                # Save off the index within changes of this deletion
                 deletions[change.base_path] = idx
             elif change.added:
                 if change.base_path and change.base_rev:
                     action = Changeset.COPY
+                    # Save off the index within changes of this copy
                     copies[change.base_path] = idx
                 else:
                     action = Changeset.ADD
@@ -423,18 +427,19 @@ class SubversionChangeset(Changeset):
             changes.append([path, kind, action, base_path, change.base_rev])
             idx += 1
 
-        moves = []
-        for k,v in copies.items():
+        # Detect moves by checking for copies whose source was deleted in this
+        # change set.
+        moves = set()
+        for k,v in core._as_list(copies.items()):
             if k in deletions:
                 changes[v][2] = Changeset.MOVE
-                moves.append(deletions[k])
-        offset = 0
-        for i in moves:
-            del changes[i - offset]
-            offset += 1
+                # Record the index of the now redundant delete action.
+                moves.add(deletions[k])
 
-        for change in changes:
-            yield tuple(change)
+        for i, change in enumerate(changes):
+            # Do not return the 'delete' changes that were part of moves.
+            if i not in moves:
+                yield tuple(change)
 
     def _get_prop(self, name):
         return fs.revision_prop(self.fs_ptr, self.rev, name)
@@ -457,7 +462,7 @@ class DiffChangeEditor(delta.Editor):
     # -- svn.delta.Editor callbacks
 
     def open_root(self, base_revision, dir_pool):
-        return ('/', Changeset.EDIT)
+        return (b'/', Changeset.EDIT)
 
     def add_directory(self, path, dir_baton, copyfrom_path, copyfrom_rev, 
dir_pool):
         self.deltas.append((path, Node.DIRECTORY, Changeset.ADD))

Modified: 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py
 (original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/python/tests/trac/versioncontrol/tests/svn_fs.py
 Sat May 23 14:16:56 2020
@@ -53,17 +53,14 @@ import shutil
 import sys
 import tempfile
 import unittest
-from urllib import pathname2url
+from io import BytesIO
 
 if sys.version_info[0] >= 3:
   # Python >=3.0
-  from io import StringIO
+  from urllib.request import pathname2url
 else:
   # Python <3.0
-  try:
-    from cStringIO import StringIO
-  except ImportError:
-    from StringIO import StringIO
+  from urllib import pathname2url
 
 from svn import core, repos
 
@@ -72,35 +69,34 @@ from trac.versioncontrol import Changese
 from trac.versioncontrol.svn_fs import SubversionRepository
 
 temp_path = tempfile.mktemp("-trac-svnrepos")
-REPOS_PATH = core.svn_dirent_internal_style(temp_path)
-REPOS_URL = pathname2url(temp_path)
+REPOS_PATH = core.svn_dirent_internal_style(temp_path.encode('UTF-8'))
+REPOS_URL = pathname2url(temp_path).encode('UTF-8')
 del temp_path
 
-if REPOS_URL.startswith("///"):
+if REPOS_URL.startswith(b"///"):
   # Don't add extra slashes if they're already present.
   # (This is important for Windows compatibility).
-  REPOS_URL = "file:" + REPOS_URL
+  REPOS_URL = b"file:" + REPOS_URL
 else:
   # If the URL simply starts with '/', we need to add two
   # extra slashes to make it a valid 'file://' URL
-  REPOS_URL = "file://" + REPOS_URL
+  REPOS_URL = b"file://" + REPOS_URL
 
 REPOS_URL = core.svn_uri_canonicalize(REPOS_URL)
 
 class SubversionRepositoryTestSetup(TestSetup):
 
     def setUp(self):
-        dumpfile = open(os.path.join(os.path.split(__file__)[0],
-                                     'svnrepos.dump'), 'rb')
-
-        # Remove the trac-svnrepos directory, so that we can
-        # ensure a fresh start.
-        self.tearDown()
-
-        r = repos.svn_repos_create(REPOS_PATH, '', '', None, None)
-        repos.svn_repos_load_fs2(r, dumpfile, StringIO(),
-                                repos.svn_repos_load_uuid_ignore, '',
-                                0, 0, None)
+        dump_path = os.path.join(os.path.split(__file__)[0], 'svnrepos.dump')
+        with open(dump_path, 'rb') as dumpfile:
+            # Remove the trac-svnrepos directory, so that we can
+            # ensure a fresh start.
+            self.tearDown()
+
+            r = repos.svn_repos_create(REPOS_PATH, b'', b'', None, None)
+            repos.svn_repos_load_fs2(r, dumpfile, BytesIO(),
+                                    repos.svn_repos_load_uuid_ignore, b'',
+                                    0, 0, None)
 
     def tearDown(self):
         if os.path.exists(REPOS_PATH):
@@ -126,110 +122,111 @@ class SubversionRepositoryTestCase(unitt
         self.assertEqual(None, self.repos.next_rev(12))
 
     def test_get_node(self):
-        node = self.repos.get_node('/trunk')
-        self.assertEqual('trunk', node.name)
-        self.assertEqual('/trunk', node.path)
+        node = self.repos.get_node(b'/trunk')
+        self.assertEqual(b'trunk', node.name)
+        self.assertEqual(b'/trunk', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(6, node.rev)
         self.assertEqual(1112381806, node.last_modified)
-        node = self.repos.get_node('/trunk/README.txt')
-        self.assertEqual('README.txt', node.name)
-        self.assertEqual('/trunk/README.txt', node.path)
+        node = self.repos.get_node(b'/trunk/README.txt')
+        self.assertEqual(b'README.txt', node.name)
+        self.assertEqual(b'/trunk/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(3, node.rev)
         self.assertEqual(1112361898, node.last_modified)
 
     def test_get_node_specific_rev(self):
-        node = self.repos.get_node('/trunk', 1)
-        self.assertEqual('trunk', node.name)
-        self.assertEqual('/trunk', node.path)
+        node = self.repos.get_node(b'/trunk', 1)
+        self.assertEqual(b'trunk', node.name)
+        self.assertEqual(b'/trunk', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(1, node.rev)
         self.assertEqual(1112349652, node.last_modified)
-        node = self.repos.get_node('/trunk/README.txt', 2)
-        self.assertEqual('README.txt', node.name)
-        self.assertEqual('/trunk/README.txt', node.path)
+        node = self.repos.get_node(b'/trunk/README.txt', 2)
+        self.assertEqual(b'README.txt', node.name)
+        self.assertEqual(b'/trunk/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(2, node.rev)
         self.assertEqual(1112361138, node.last_modified)
 
     def test_get_dir_entries(self):
-        node = self.repos.get_node('/trunk')
+        node = self.repos.get_node(b'/trunk')
         entries = node.get_entries()
-        self.assertEqual('README2.txt', entries.next().name)
-        self.assertEqual('dir1', entries.next().name)
-        self.assertEqual('README.txt', entries.next().name)
-        self.assertRaises(StopIteration, entries.next)
+        self.assertSequenceEqual(sorted([entry.name for entry in entries]),
+                                 sorted([b'README2.txt',
+                                  b'dir1',
+                                  b'README.txt']))
 
     def test_get_file_entries(self):
-        node = self.repos.get_node('/trunk/README.txt')
+        node = self.repos.get_node(b'/trunk/README.txt')
         entries = node.get_entries()
-        self.assertRaises(StopIteration, entries.next)
+        self.assertSequenceEqual([entry.name for entry in entries],
+                                 [])
 
     def test_get_dir_content(self):
-        node = self.repos.get_node('/trunk')
+        node = self.repos.get_node(b'/trunk')
         self.assertEqual(None, node.content_length)
         self.assertEqual(None, node.content_type)
         self.assertEqual(None, node.get_content())
 
     def test_get_file_content(self):
-        node = self.repos.get_node('/trunk/README.txt')
+        node = self.repos.get_node(b'/trunk/README.txt')
         self.assertEqual(8, node.content_length)
-        self.assertEqual('text/plain', node.content_type)
-        self.assertEqual('A test.\n', node.get_content().read())
+        self.assertEqual(b'text/plain', node.content_type)
+        self.assertEqual(b'A test.\n', node.get_content().read())
 
     def test_get_dir_properties(self):
-        f = self.repos.get_node('/trunk')
+        f = self.repos.get_node(b'/trunk')
         props = f.get_properties()
         self.assertEqual(0, len(props))
 
     def test_get_file_properties(self):
-        f = self.repos.get_node('/trunk/README.txt')
+        f = self.repos.get_node(b'/trunk/README.txt')
         props = f.get_properties()
-        self.assertEqual('native', props['svn:eol-style'])
-        self.assertEqual('text/plain', props['svn:mime-type'])
+        self.assertEqual(b'native', props[b'svn:eol-style'])
+        self.assertEqual(b'text/plain', props[b'svn:mime-type'])
 
     # Revision Log / node history
 
     def test_get_node_history(self):
-        node = self.repos.get_node('/trunk/README2.txt')
+        node = self.repos.get_node(b'/trunk/README2.txt')
         history = node.get_history()
-        self.assertEqual(('trunk/README2.txt', 6, 'copy'), history.next())
-        self.assertEqual(('trunk/README.txt', 3, 'edit'), history.next())
-        self.assertEqual(('trunk/README.txt', 2, 'add'), history.next())
-        self.assertRaises(StopIteration, history.next)
+        self.assertSequenceEqual([x for x in history],
+                                 [(b'trunk/README2.txt', 6, b'copy'),
+                                  (b'trunk/README.txt', 3, b'edit'),
+                                  (b'trunk/README.txt', 2, b'add')])
 
     def test_get_node_history_follow_copy(self):
-        node = self.repos.get_node('/tags/v1/README.txt')
+        node = self.repos.get_node(b'/tags/v1/README.txt')
         history = node.get_history()
-        self.assertEqual(('tags/v1/README.txt', 7, 'copy'), history.next())
-        self.assertEqual(('trunk/README.txt', 3, 'edit'), history.next())
-        self.assertEqual(('trunk/README.txt', 2, 'add'), history.next())
-        self.assertRaises(StopIteration, history.next)
+        self.assertSequenceEqual([x for x in history],
+                                 [(b'tags/v1/README.txt', 7, b'copy'),
+                                  (b'trunk/README.txt', 3, b'edit'),
+                                  (b'trunk/README.txt', 2, b'add')])
 
     # Revision Log / path history
 
     def test_get_path_history(self):
-        history = self.repos.get_path_history('/trunk/README2.txt', None)
-        self.assertEqual(('trunk/README2.txt', 6, 'copy'), history.next())
-        self.assertEqual(('trunk/README.txt', 3, 'unknown'), history.next())
-        self.assertRaises(StopIteration, history.next)
+        history = self.repos.get_path_history(b'/trunk/README2.txt', None)
+        self.assertSequenceEqual([x for x in history],
+                                 [(b'trunk/README2.txt', 6, b'copy'),
+                                  (b'trunk/README.txt', 3, b'unknown')])
 
     def test_get_path_history_copied_file(self):
-        history = self.repos.get_path_history('/tags/v1/README.txt', None)
-        self.assertEqual(('tags/v1/README.txt', 7, 'copy'), history.next())
-        self.assertEqual(('trunk/README.txt', 3, 'unknown'), history.next())
-        self.assertRaises(StopIteration, history.next)
+        history = self.repos.get_path_history(b'/tags/v1/README.txt', None)
+        self.assertSequenceEqual([x for x in history],
+                                 [(b'tags/v1/README.txt', 7, b'copy'),
+                                  (b'trunk/README.txt', 3, b'unknown')])
 
     def test_get_path_history_copied_dir(self):
-        history = self.repos.get_path_history('/branches/v1x', None)
-        self.assertEqual(('branches/v1x', 12, 'copy'), history.next())
-        self.assertEqual(('tags/v1.1', 10, 'unknown'), history.next())
-        self.assertEqual(('branches/v1x', 11, 'delete'), history.next())
-        self.assertEqual(('branches/v1x', 9, 'edit'), history.next())
-        self.assertEqual(('branches/v1x', 8, 'copy'), history.next())
-        self.assertEqual(('tags/v1', 7, 'unknown'), history.next())
-        self.assertRaises(StopIteration, history.next)
+        history = self.repos.get_path_history(b'/branches/v1x', None)
+        self.assertSequenceEqual([x for x in history],
+                                 [(b'branches/v1x', 12, b'copy'),
+                                  (b'tags/v1.1', 10, b'unknown'),
+                                  (b'branches/v1x', 11, b'delete'),
+                                  (b'branches/v1x', 9, b'edit'),
+                                  (b'branches/v1x', 8, b'copy'),
+                                  (b'tags/v1', 7, b'unknown')])
 
     # Diffs
 
@@ -243,63 +240,63 @@ class SubversionRepositoryTestCase(unitt
         self.assertEqual(expected[2], (got[2], got[3]))
 
     def test_diff_file_different_revs(self):
-        diffs = self.repos.get_deltas('trunk/README.txt', 2, 
'trunk/README.txt', 3)
-        self._cmp_diff((('trunk/README.txt', 2),
-                        ('trunk/README.txt', 3),
-                        (Node.FILE, Changeset.EDIT)), diffs.next())
-        self.assertRaises(StopIteration, diffs.next)
+        diffs = self.repos.get_deltas(b'trunk/README.txt', 2, 
b'trunk/README.txt', 3)
+        self._cmp_diff(((b'trunk/README.txt', 2),
+                        (b'trunk/README.txt', 3),
+                        (Node.FILE, Changeset.EDIT)), next(diffs))
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     def test_diff_file_different_files(self):
-        diffs = self.repos.get_deltas('branches/v1x/README.txt', 12,
-                                      'branches/v1x/README2.txt', 12)
-        self._cmp_diff((('branches/v1x/README.txt', 12),
-                        ('branches/v1x/README2.txt', 12),
-                        (Node.FILE, Changeset.EDIT)), diffs.next())
-        self.assertRaises(StopIteration, diffs.next)
+        diffs = self.repos.get_deltas(b'branches/v1x/README.txt', 12,
+                                      b'branches/v1x/README2.txt', 12)
+        self._cmp_diff(((b'branches/v1x/README.txt', 12),
+                        (b'branches/v1x/README2.txt', 12),
+                        (Node.FILE, Changeset.EDIT)), next(diffs))
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     def test_diff_file_no_change(self):
-        diffs = self.repos.get_deltas('trunk/README.txt', 7,
-                                      'tags/v1/README.txt', 7)
-        self.assertRaises(StopIteration, diffs.next)
+        diffs = self.repos.get_deltas(b'trunk/README.txt', 7,
+                                      b'tags/v1/README.txt', 7)
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     def test_diff_dir_different_revs(self):
-        diffs = self.repos.get_deltas('trunk', 4, 'trunk', 8)
+        diffs = self.repos.get_deltas(b'trunk', 4, b'trunk', 8)
         expected = [
-          (None, ('trunk/README2.txt', 6),
+          (None, (b'trunk/README2.txt', 6),
            (Node.FILE, Changeset.ADD)),
-          (None, ('trunk/dir1/dir2', 8),
+          (None, (b'trunk/dir1/dir2', 8),
            (Node.DIRECTORY, Changeset.ADD)),
-          (None, ('trunk/dir1/dir3', 8),
+          (None, (b'trunk/dir1/dir3', 8),
            (Node.DIRECTORY, Changeset.ADD)),
-          (('trunk/dir2', 4), None,
+          ((b'trunk/dir2', 4), None,
            (Node.DIRECTORY, Changeset.DELETE)),
-          (('trunk/dir3', 4), None,
+          ((b'trunk/dir3', 4), None,
            (Node.DIRECTORY, Changeset.DELETE)),
         ]
-        actual = [diffs.next() for i in range(5)]
+        actual = [next(diffs) for i in range(5)]
         actual = sorted(actual,
                         key=lambda diff: ((diff[0] or diff[1]).path,
                                           (diff[0] or diff[1]).rev))
         self.assertEqual(len(expected), len(actual))
         for e,a in zip(expected, actual):
           self._cmp_diff(e,a)
-        self.assertRaises(StopIteration, diffs.next)
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     def test_diff_dir_different_dirs(self):
-        diffs = self.repos.get_deltas('trunk', 1, 'branches/v1x', 12)
+        diffs = self.repos.get_deltas(b'trunk', 1, b'branches/v1x', 12)
         expected = [
-          (None, ('branches/v1x/README.txt', 12),
+          (None, (b'branches/v1x/README.txt', 12),
            (Node.FILE, Changeset.ADD)),
-          (None, ('branches/v1x/README2.txt', 12),
+          (None, (b'branches/v1x/README2.txt', 12),
            (Node.FILE, Changeset.ADD)),
-          (None, ('branches/v1x/dir1', 12),
+          (None, (b'branches/v1x/dir1', 12),
            (Node.DIRECTORY, Changeset.ADD)),
-          (None, ('branches/v1x/dir1/dir2', 12),
+          (None, (b'branches/v1x/dir1/dir2', 12),
            (Node.DIRECTORY, Changeset.ADD)),
-          (None, ('branches/v1x/dir1/dir3', 12),
+          (None, (b'branches/v1x/dir1/dir3', 12),
            (Node.DIRECTORY, Changeset.ADD)),
         ]
-        actual = [diffs.next() for i in range(5)]
+        actual = [next(diffs) for i in range(5)]
         actual = sorted(actual, key=lambda diff: (diff[1].path, diff[1].rev))
         # for e,a in zip(expected, actual):
         #   t.write("%r\n" % (e,))
@@ -308,12 +305,12 @@ class SubversionRepositoryTestCase(unitt
         self.assertEqual(len(expected), len(actual))
         for e,a in zip(expected, actual):
           self._cmp_diff(e,a)
-        self.assertRaises(StopIteration, diffs.next)
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     def test_diff_dir_no_change(self):
-        diffs = self.repos.get_deltas('trunk', 7,
-                                      'tags/v1', 7)
-        self.assertRaises(StopIteration, diffs.next)
+        diffs = self.repos.get_deltas(b'trunk', 7,
+                                      b'tags/v1', 7)
+        self.assertRaises(StopIteration, lambda: next(diffs))
 
     # Changesets
 
@@ -323,61 +320,57 @@ class SubversionRepositoryTestCase(unitt
         self.assertEqual(None, chgset.message)
         self.assertEqual(None, chgset.author)
         self.assertEqual(1112349461, chgset.date)
-        self.assertRaises(StopIteration, chgset.get_changes().next)
+        self.assertRaises(StopIteration, lambda: next(chgset.get_changes()))
 
     def test_changeset_added_dirs(self):
         chgset = self.repos.get_changeset(1)
         self.assertEqual(1, chgset.rev)
-        self.assertEqual('Initial directory layout.', chgset.message)
-        self.assertEqual('john', chgset.author)
+        self.assertEqual(b'Initial directory layout.', chgset.message)
+        self.assertEqual(b'john', chgset.author)
         self.assertEqual(1112349652, chgset.date)
 
         changes = chgset.get_changes()
-        self.assertEqual(('trunk', Node.DIRECTORY, Changeset.ADD, None, -1),
-                         changes.next())
-        self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None, -1),
-                         changes.next())
-        self.assertEqual(('tags', Node.DIRECTORY, Changeset.ADD, None, -1),
-                         changes.next())
-        self.assertRaises(StopIteration, changes.next)
+        self.assertSequenceEqual(sorted([x for x in changes]),
+          sorted([(b'trunk', Node.DIRECTORY, Changeset.ADD, None, -1),
+                  (b'branches', Node.DIRECTORY, Changeset.ADD, None, -1),
+                  (b'tags', Node.DIRECTORY, Changeset.ADD, None, -1)]))
 
     def test_changeset_file_edit(self):
         chgset = self.repos.get_changeset(3)
         self.assertEqual(3, chgset.rev)
-        self.assertEqual('Fixed README.\n', chgset.message)
-        self.assertEqual('kate', chgset.author)
+        self.assertEqual(b'Fixed README.\n', chgset.message)
+        self.assertEqual(b'kate', chgset.author)
         self.assertEqual(1112361898, chgset.date)
 
         changes = chgset.get_changes()
-        self.assertEqual(('trunk/README.txt', Node.FILE, Changeset.EDIT,
-                          'trunk/README.txt', 2), changes.next())
-        self.assertRaises(StopIteration, changes.next)
+        self.assertSequenceEqual(sorted([x for x in changes]),
+                                 sorted([(b'trunk/README.txt', Node.FILE, 
Changeset.EDIT,
+                                   b'trunk/README.txt', 2)]))
 
     def test_changeset_dir_moves(self):
         chgset = self.repos.get_changeset(5)
         self.assertEqual(5, chgset.rev)
-        self.assertEqual('Moved directories.', chgset.message)
-        self.assertEqual('kate', chgset.author)
+        self.assertEqual(b'Moved directories.', chgset.message)
+        self.assertEqual(b'kate', chgset.author)
         self.assertEqual(1112372739, chgset.date)
 
         changes = chgset.get_changes()
-        self.assertEqual(('trunk/dir1/dir2', Node.DIRECTORY, Changeset.MOVE,
-                          'trunk/dir2', 4), changes.next())
-        self.assertEqual(('trunk/dir1/dir3', Node.DIRECTORY, Changeset.MOVE,
-                          'trunk/dir3', 4), changes.next())
-        self.assertRaises(StopIteration, changes.next)
+        self.assertSequenceEqual(sorted([x for x in changes]),
+          sorted([
+            (b'trunk/dir1/dir2', Node.DIRECTORY, Changeset.MOVE, 
b'trunk/dir2', 4),
+            (b'trunk/dir1/dir3', Node.DIRECTORY, Changeset.MOVE, 
b'trunk/dir3', 4)]))
 
     def test_changeset_file_copy(self):
         chgset = self.repos.get_changeset(6)
         self.assertEqual(6, chgset.rev)
-        self.assertEqual('More things to read', chgset.message)
-        self.assertEqual('john', chgset.author)
+        self.assertEqual(b'More things to read', chgset.message)
+        self.assertEqual(b'john', chgset.author)
         self.assertEqual(1112381806, chgset.date)
 
         changes = chgset.get_changes()
-        self.assertEqual(('trunk/README2.txt', Node.FILE, Changeset.COPY,
-                          'trunk/README.txt', 3), changes.next())
-        self.assertRaises(StopIteration, changes.next)
+        self.assertSequenceEqual(sorted([x for x in changes]),
+          sorted([(b'trunk/README2.txt', Node.FILE, Changeset.COPY,
+                   b'trunk/README.txt', 3)]))
 
 
 def suite():

Modified: 
subversion/branches/addremove/subversion/bindings/swig/python/tests/utils.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/python/tests/utils.py?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/python/tests/utils.py 
(original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/python/tests/utils.py 
Sat May 23 14:16:56 2020
@@ -18,9 +18,15 @@
 # under the License.
 #
 #
-import os.path, sys, tempfile, urllib
+import os.path, sys, tempfile
 from svn import core, repos
-from StringIO import StringIO
+from io import BytesIO
+try:
+  # Python >=3.0
+  from urllib.request import pathname2url
+except ImportError:
+  # Python <3.0
+  from urllib import pathname2url
 
 class Temper(object):
   """Class to simplify allocation and cleanup of dummy Subversion
@@ -41,14 +47,19 @@ class Temper(object):
   def alloc_empty_dir(self, suffix = ""):
     """Create an empty temporary directory. Returns its full path
        in canonical internal form."""
-    temp_dir_name = core.svn_dirent_internal_style(tempfile.mkdtemp(suffix))
+    if isinstance(suffix, bytes):
+      suffix = suffix.decode('UTF-8')
+    temp_dir_name = tempfile.mkdtemp(suffix).encode('UTF-8')
+    temp_dir_name = core.svn_dirent_internal_style(temp_dir_name)
     self._cleanup_list.append((temp_dir_name, core.svn_io_remove_dir))
     return temp_dir_name
 
   def alloc_empty_repo(self, suffix = ""):
     """Create an empty repository. Returns a tuple of its handle, path and
        file: URI in canonical internal form."""
-    temp_path = tempfile.mkdtemp(suffix)
+    if isinstance(suffix, bytes):
+      suffix = suffix.decode('UTF-8')
+    temp_path = tempfile.mkdtemp(suffix).encode('UTF-8')
     repo_path = core.svn_dirent_internal_style(temp_path)
     repo_uri = core.svn_uri_canonicalize(file_uri_for_path(temp_path))
     handle = repos.create(repo_path, None, None, None, None)
@@ -61,15 +72,18 @@ class Temper(object):
        location. Returns the same as alloc_empty_repo."""
     dump_path = os.path.join(os.path.dirname(sys.argv[0]), repo_id)
     (handle, repo_path, repo_uri) = self.alloc_empty_repo(suffix=suffix)
-    repos.svn_repos_load_fs2(handle, open(dump_path, 'rb'), StringIO(),
-                             repos.load_uuid_default, None, False, False, None)
+    with open(dump_path, 'rb') as dump_fp:
+      repos.svn_repos_load_fs2(handle, dump_fp, BytesIO(),
+                               repos.load_uuid_default, None, False, False, 
None)
     return (handle, repo_path, repo_uri)
 
 def file_uri_for_path(path):
   """Return the file: URI corresponding to the given path."""
-  uri_path = urllib.pathname2url(path)
+  if not isinstance(path, str):
+    path = path.decode('UTF-8')
+  uri_path = pathname2url(path).encode('UTF-8')
 
   # pathname2url claims to return the path part of the URI, but on Windows
   # it returns both the authority and path parts for no reason, which
   # means we have to trim the leading slashes to "normalize" the result.
-  return 'file:///' + uri_path.lstrip('/')
+  return b'file:///' + uri_path.lstrip(b'/')

Modified: 
subversion/branches/addremove/subversion/bindings/swig/python/tests/wc.py
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/python/tests/wc.py?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/bindings/swig/python/tests/wc.py 
(original)
+++ subversion/branches/addremove/subversion/bindings/swig/python/tests/wc.py 
Sat May 23 14:16:56 2020
@@ -19,12 +19,7 @@
 #
 #
 from sys import version_info # For Python version check
-if version_info[0] >= 3:
-  # Python >=3.0
-  from io import StringIO
-else:
-  # Python <3.0
-  from cStringIO import StringIO
+from io import BytesIO
 import unittest, os, tempfile, setup_path, binascii
 import svn.diff
 from svn import core, repos, wc, client
@@ -61,10 +56,10 @@ class SubversionWorkingCopyTestCase(unit
       wc.entry(self.path, self.wc, True)
 
   def test_lock(self):
-      readme_path = '%s/trunk/README.txt' % self.path
+      readme_path = b'%s/trunk/README.txt' % self.path
 
       lock = core.svn_lock_create(core.Pool())
-      lock.token = 'http://svnbook.org/nightly/en/svn.advanced.locking.html'
+      lock.token = b'http://svnbook.org/nightly/en/svn.advanced.locking.html'
 
       wc.add_lock(readme_path, lock, self.wc)
       self.assertEqual(True, wc.adm_locked(self.wc))
@@ -78,23 +73,23 @@ class SubversionWorkingCopyTestCase(unit
       self.assertEqual(self.path, wc.adm_access_path(self.wc))
 
   def test_is_adm_dir(self):
-      self.assert_(wc.is_adm_dir(".svn"))
-      self.failIf(wc.is_adm_dir(".foosvn"))
+      self.assertTrue(wc.is_adm_dir(b".svn"))
+      self.assertFalse(wc.is_adm_dir(b".foosvn"))
 
   def test_get_adm_dir(self):
-      self.assert_(isinstance(wc.get_adm_dir(), basestring))
+      self.assertTrue(isinstance(wc.get_adm_dir(), bytes))
 
   def test_set_adm_dir(self):
-      self.assertRaises(SubversionException, wc.set_adm_dir, ".foobar")
-      self.assert_(wc.is_adm_dir(".svn"))
-      self.failIf(wc.is_adm_dir("_svn"))
-      self.failIf(wc.is_adm_dir(".foobar"))
-      wc.set_adm_dir("_svn")
-      self.assert_(wc.is_adm_dir("_svn"))
-      self.assertEqual("_svn", wc.get_adm_dir())
-      wc.set_adm_dir(".svn")
-      self.failIf(wc.is_adm_dir("_svn"))
-      self.assertEqual(".svn", wc.get_adm_dir())
+      self.assertRaises(SubversionException, wc.set_adm_dir, b".foobar")
+      self.assertTrue(wc.is_adm_dir(b".svn"))
+      self.assertFalse(wc.is_adm_dir(b"_svn"))
+      self.assertFalse(wc.is_adm_dir(b".foobar"))
+      wc.set_adm_dir(b"_svn")
+      self.assertTrue(wc.is_adm_dir(b"_svn"))
+      self.assertEqual(b"_svn", wc.get_adm_dir())
+      wc.set_adm_dir(b".svn")
+      self.assertFalse(wc.is_adm_dir(b"_svn"))
+      self.assertEqual(b".svn", wc.get_adm_dir())
 
   def test_init_traversal_info(self):
       wc.init_traversal_info()
@@ -127,8 +122,8 @@ class SubversionWorkingCopyTestCase(unit
               pass
 
       # Remove trunk/README.txt
-      readme_path = '%s/trunk/README.txt' % self.path
-      self.assert_(os.path.exists(readme_path))
+      readme_path = b'%s/trunk/README.txt' % self.path
+      self.assertTrue(os.path.exists(readme_path))
       os.remove(readme_path)
 
       # Restore trunk/README.txt using crawl_revision2
@@ -138,8 +133,8 @@ class SubversionWorkingCopyTestCase(unit
                           True, True, False, notify, info)
 
       # Check that the report finished
-      self.assert_(reporter.finished_report)
-      self.assertEqual([''], set_paths)
+      self.assertTrue(reporter.finished_report)
+      self.assertEqual([b''], set_paths)
       self.assertEqual(1, len(infos))
 
       # Check content of infos object
@@ -152,7 +147,7 @@ class SubversionWorkingCopyTestCase(unit
       wc.create_notify(self.path, wc.notify_add)
 
   def test_check_wc(self):
-      self.assert_(wc.check_wc(self.path) > 0)
+      self.assertTrue(wc.check_wc(self.path) > 0)
 
   def test_get_ancestry(self):
       self.assertEqual([self.repos_uri, 12],
@@ -164,7 +159,6 @@ class SubversionWorkingCopyTestCase(unit
   def test_status_editor(self):
       paths = []
       def status_func(target, status):
-        self.assert_(target.startswith(self.path))
         paths.append(target)
 
       (anchor_access, target_access,
@@ -181,54 +175,79 @@ class SubversionWorkingCopyTestCase(unit
                                               None,  # traversal_info
                                               )
       editor.close_edit(edit_baton)
-      self.assert_(len(paths) > 0)
+      self.assertTrue(len(paths) > 0)
+      for target in paths:
+        self.assertTrue(target.startswith(self.path))
+
+  def test_status_editor_callback_exception(self):
+      """test case for status_editor call back not to be crashed by Python 
exception"""
+      def status_func(target, status):
+        # Note: exception with in this call back doesn't propagate to
+        # the caller
+        raise AssertionError('intentional exception')
+
+      (anchor_access, target_access,
+       target) = wc.adm_open_anchor(self.path, False, -1, None)
+      (editor, edit_baton, set_locks_baton,
+       edit_revision) = wc.get_status_editor2(anchor_access,
+                                              target,
+                                              None,  # SvnConfig
+                                              True,  # recursive
+                                              True, # get_all
+                                              False, # no_ignore
+                                              status_func,
+                                              None,  # cancel_func
+                                              None,  # traversal_info
+                                              )
+      editor.close_edit(edit_baton)
 
   def test_is_normal_prop(self):
-      self.failIf(wc.is_normal_prop('svn:wc:foo:bar'))
-      self.failIf(wc.is_normal_prop('svn:entry:foo:bar'))
-      self.assert_(wc.is_normal_prop('svn:foo:bar'))
-      self.assert_(wc.is_normal_prop('foreign:foo:bar'))
+      self.assertFalse(wc.is_normal_prop(b'svn:wc:foo:bar'))
+      self.assertFalse(wc.is_normal_prop(b'svn:entry:foo:bar'))
+      self.assertTrue(wc.is_normal_prop(b'svn:foo:bar'))
+      self.assertTrue(wc.is_normal_prop(b'foreign:foo:bar'))
 
   def test_is_wc_prop(self):
-      self.assert_(wc.is_wc_prop('svn:wc:foo:bar'))
-      self.failIf(wc.is_wc_prop('svn:entry:foo:bar'))
-      self.failIf(wc.is_wc_prop('svn:foo:bar'))
-      self.failIf(wc.is_wc_prop('foreign:foo:bar'))
+      self.assertTrue(wc.is_wc_prop(b'svn:wc:foo:bar'))
+      self.assertFalse(wc.is_wc_prop(b'svn:entry:foo:bar'))
+      self.assertFalse(wc.is_wc_prop(b'svn:foo:bar'))
+      self.assertFalse(wc.is_wc_prop(b'foreign:foo:bar'))
 
   def test_is_entry_prop(self):
-      self.assert_(wc.is_entry_prop('svn:entry:foo:bar'))
-      self.failIf(wc.is_entry_prop('svn:wc:foo:bar'))
-      self.failIf(wc.is_entry_prop('svn:foo:bar'))
-      self.failIf(wc.is_entry_prop('foreign:foo:bar'))
+      self.assertTrue(wc.is_entry_prop(b'svn:entry:foo:bar'))
+      self.assertFalse(wc.is_entry_prop(b'svn:wc:foo:bar'))
+      self.assertFalse(wc.is_entry_prop(b'svn:foo:bar'))
+      self.assertFalse(wc.is_entry_prop(b'foreign:foo:bar'))
 
   def test_get_prop_diffs(self):
-      wc.prop_set("foreign:foo", "bla", self.path, self.wc)
-      self.assertEquals([{"foreign:foo": "bla"}, {}],
+      wc.prop_set(b"foreign:foo", b"bla", self.path, self.wc)
+      self.assertEqual([{b"foreign:foo": b"bla"}, {}],
               wc.get_prop_diffs(self.path, self.wc))
 
   def test_get_pristine_copy_path(self):
-      path_to_file = '%s/trunk/README.txt' % self.path
+      path_to_file = b'%s/trunk/README.txt' % self.path
       path_to_text_base = wc.get_pristine_copy_path(path_to_file)
-      text_base = open(path_to_text_base).read()
+      with open(path_to_text_base, 'rb') as fp:
+          text_base = fp.read()
       # TODO: This test should modify the working file first, to ensure the
       # path isn't just the path to the working file.
-      self.assertEqual(text_base, 'A test.\n')
+      self.assertEqual(text_base, b'A test.\n')
 
   def test_entries_read(self):
       entries = wc.entries_read(self.wc, True)
-      keys = list(entries.keys())
+      keys = core._as_list(entries.keys())
       keys.sort()
-      self.assertEqual(['', 'branches', 'tags', 'trunk'], keys)
+      self.assertEqual([b'', b'branches', b'tags', b'trunk'], keys)
 
   def test_get_ignores(self):
-      self.assert_(isinstance(wc.get_ignores(None, self.wc), list))
+      self.assertTrue(isinstance(wc.get_ignores(None, self.wc), list))
 
   def test_commit(self):
     # Replace README.txt's contents, using binary mode so we know the
     # exact contents even on Windows, and therefore the MD5 checksum.
-    readme_path = '%s/trunk/README.txt' % self.path
+    readme_path = b'%s/trunk/README.txt' % self.path
     fp = open(readme_path, 'wb')
-    fp.write('hello\n')
+    fp.write(b'hello\n')
     fp.close()
 
     # Setup ra_ctx.
@@ -240,7 +259,7 @@ class SubversionWorkingCopyTestCase(unit
     commit_info = [None]
     def commit_cb(_commit_info, pool):
       commit_info[0] = _commit_info
-    (editor, edit_baton) = ra.get_commit_editor2(ra_ctx, 'log message',
+    (editor, edit_baton) = ra.get_commit_editor2(ra_ctx, b'log message',
                                                  commit_cb,
                                                  None,
                                                  False)
@@ -254,7 +273,7 @@ class SubversionWorkingCopyTestCase(unit
                                                   False, editor, baton, pool)
       return baton
     try:
-      delta.path_driver(editor, edit_baton, -1, ['trunk/README.txt'],
+      delta.path_driver(editor, edit_baton, -1, [b'trunk/README.txt'],
                         driver_cb)
       editor.close_edit(edit_baton)
     except:
@@ -269,9 +288,9 @@ class SubversionWorkingCopyTestCase(unit
     (commit_info,) = commit_info
 
     # Assert the commit.
-    self.assertEquals(binascii.b2a_hex(checksum),
-                      'b1946ac92492d2347c6235b4d2611184')
-    self.assertEquals(commit_info.revision, 13)
+    self.assertEqual(binascii.b2a_hex(checksum),
+                      b'b1946ac92492d2347c6235b4d2611184')
+    self.assertEqual(commit_info.revision, 13)
 
     # Bump working copy state.
     wc.process_committed4(readme_path,
@@ -282,10 +301,10 @@ class SubversionWorkingCopyTestCase(unit
 
     # Assert bumped state.
     entry = wc.entry(readme_path, self.wc, False)
-    self.assertEquals(entry.revision, commit_info.revision)
-    self.assertEquals(entry.schedule, wc.schedule_normal)
-    self.assertEquals(entry.cmt_rev, commit_info.revision)
-    self.assertEquals(entry.cmt_date,
+    self.assertEqual(entry.revision, commit_info.revision)
+    self.assertEqual(entry.schedule, wc.schedule_normal)
+    self.assertEqual(entry.cmt_rev, commit_info.revision)
+    self.assertEqual(entry.cmt_date,
                       core.svn_time_from_cstring(commit_info.date))
 
   def test_diff_editor4(self):
@@ -294,14 +313,14 @@ class SubversionWorkingCopyTestCase(unit
     url = self.repos_uri
 
     # cause file_changed: Replace README.txt's contents.
-    readme_path = '%s/trunk/README.txt' % self.path
-    fp = open(readme_path, 'w')
-    fp.write('hello\n')
+    readme_path = b'%s/trunk/README.txt' % self.path
+    fp = open(readme_path, 'wb')
+    fp.write(b'hello\n')
     fp.close()
     # cause file_added: Create readme3.
-    readme3_path = '%s/trunk/readme3' % self.path
-    fp = open(readme3_path, 'w')
-    fp.write('hello\n')
+    readme3_path = b'%s/trunk/readme3' % self.path
+    fp = open(readme3_path, 'wb')
+    fp.write(b'hello\n')
     fp.close()
     wc.add2(readme3_path,
             wc.adm_probe_retrieve(self.wc,
@@ -311,7 +330,7 @@ class SubversionWorkingCopyTestCase(unit
             None,                     # notify_func
             pool)
     # cause file_deleted: Delete README2.txt.
-    readme2_path = '%s/trunk/README2.txt' % self.path
+    readme2_path = b'%s/trunk/README2.txt' % self.path
     wc.delete3(readme2_path,
                wc.adm_probe_retrieve(self.wc,
                                      os.path.dirname(readme2_path), pool),
@@ -320,8 +339,8 @@ class SubversionWorkingCopyTestCase(unit
                False,                 # keep_local
                pool)
     # cause dir_props_changed: ps testprop testval dir1/dir2
-    dir2_path = '%s/trunk/dir1/dir2' % self.path
-    wc.prop_set2('testprop', 'testval', dir2_path,
+    dir2_path = b'%s/trunk/dir1/dir2' % self.path
+    wc.prop_set2(b'testprop', b'testval', dir2_path,
                  wc.adm_probe_retrieve(self.wc,
                                        os.path.dirname(dir2_path), pool),
                  False,               # skip_checks
@@ -331,7 +350,7 @@ class SubversionWorkingCopyTestCase(unit
     # Save prop changes.
     got_prop_changes = []
     def props_changed(path, propchanges):
-      for (name, value) in propchanges.items():
+      for (name, value) in core._as_list(propchanges.items()):
         (kind, _) = core.svn_property_kind(name)
         if kind != core.svn_prop_regular_kind:
           continue
@@ -342,16 +361,16 @@ class SubversionWorkingCopyTestCase(unit
     def write_diff(path, left, right):
       options = svn.diff.file_options_create()
       diff = svn.diff.file_diff_2(left, right, options, pool)
-      original_header = modified_header = ''
-      encoding = 'utf8'
+      original_header = modified_header = b''
+      encoding = b'utf8'
       relative_to_dir = None
-      sio = StringIO()
-      svn.diff.file_output_unified3(sio, diff,
+      bio = BytesIO()
+      svn.diff.file_output_unified3(bio, diff,
                                     left, right,
                                     original_header, modified_header,
                                     encoding, relative_to_dir,
                                     options.show_c_function, pool)
-      got_diffs[path[len(self.path) + 1:]] = sio.getvalue().splitlines()
+      got_diffs[path[len(self.path) + 1:]] = bio.getvalue().splitlines()
 
     # Diff callbacks that call props_changed and write_diff.
     contentstate = propstate = state = wc.notify_state_unknown
@@ -383,7 +402,7 @@ class SubversionWorkingCopyTestCase(unit
 
     # Setup wc diff editor.
     (editor, edit_baton) = wc.get_diff_editor4(
-      self.wc, '', diff_callbacks, depth,
+      self.wc, b'', diff_callbacks, depth,
       False,                    # ignore_ancestry
       False,                    # use_text_base
       False,                    # reverse_order
@@ -400,39 +419,39 @@ class SubversionWorkingCopyTestCase(unit
     (reporter, report_baton) = ra.do_diff3(
       ra_ctx,
       head,                     # versus_url revision
-      '',                       # diff_target
+      b'',                       # diff_target
       depth,
       False,                    # ignore_ancestry
       True,                     # text_deltas
       url,                      # versus_url
       editor, edit_baton, pool)
     # Report wc state (pretty plain).
-    reporter.set_path(report_baton, '', head, depth,
+    reporter.set_path(report_baton, b'', head, depth,
                       False,    # start_empty
                       None,     # lock_token
                       pool)
     reporter.finish_report(report_baton, pool)
 
     # Assert we got the right diff.
-    expected_prop_changes = [('trunk/dir1/dir2',
-                              'testprop', 'testval')]
+    expected_prop_changes = [(b'trunk/dir1/dir2',
+                              b'testprop', b'testval')]
     expected_diffs = {
-      'trunk/readme3':
-        ['--- ',
-         '+++ ',
-         '@@ -0,0 +1 @@',
-         '+hello'],
-      'trunk/README.txt':
-        ['--- ',
-         '+++ ',
-         '@@ -1 +1 @@',
-         '-A test.',
-         '+hello'],
-      'trunk/README2.txt':
-        ['--- ',
-         '+++ ',
-         '@@ -1 +0,0 @@',
-         '-A test.'],
+      b'trunk/readme3':
+        [b'--- ',
+         b'+++ ',
+         b'@@ -0,0 +1 @@',
+         b'+hello'],
+      b'trunk/README.txt':
+        [b'--- ',
+         b'+++ ',
+         b'@@ -1 +1 @@',
+         b'-A test.',
+         b'+hello'],
+      b'trunk/README2.txt':
+        [b'--- ',
+         b'+++ ',
+         b'@@ -1 +0,0 @@',
+         b'-A test.'],
       }
     self.assertEqual(got_prop_changes, expected_prop_changes)
     self.assertEqual(got_diffs, expected_diffs)

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/svn/client.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/svn/client.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/bindings/swig/ruby/svn/client.rb 
(original)
+++ subversion/branches/addremove/subversion/bindings/swig/ruby/svn/client.rb 
Sat May 23 14:16:56 2020
@@ -637,25 +637,25 @@ module Svn
                        ignore_externals, allow_unver_obstruction, self)
       end
 
-      def set_log_msg_func(callback=Proc.new)
+      def set_log_msg_func(&callback)
         callback_wrapper = Proc.new do |items|
           items = items.collect do |item|
             item_wrapper = CommitItemWrapper.new(item)
           end
           callback.call(items)
         end
-        set_log_msg_func2(callback_wrapper)
+        set_log_msg_func2(&callback_wrapper)
       end
 
-      def set_log_msg_func2(callback=Proc.new)
+      def set_log_msg_func2(&callback)
         @log_msg_baton = Client.set_log_msg_func3(self, callback)
       end
 
-      def set_notify_func(callback=Proc.new)
+      def set_notify_func(&callback)
         @notify_baton = Client.set_notify_func2(self, callback)
       end
 
-      def set_cancel_func(callback=Proc.new)
+      def set_cancel_func(&callback)
         @cancel_baton = Client.set_cancel_func(self, callback)
       end
 
@@ -707,9 +707,9 @@ module Svn
 
       private
       def init_callbacks
-        set_log_msg_func(nil)
-        set_notify_func(nil)
-        set_cancel_func(nil)
+        set_log_msg_func
+        set_notify_func
+        set_cancel_func
       end
       %w(log_msg notify cancel).each do |type|
         private "#{type}_func", "#{type}_baton"

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/svn/core.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/svn/core.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/bindings/swig/ruby/svn/core.rb 
(original)
+++ subversion/branches/addremove/subversion/bindings/swig/ruby/svn/core.rb Sat 
May 23 14:16:56 2020
@@ -249,31 +249,31 @@ module Svn
         end
       end
 
-      def add_simple_prompt_provider(retry_limit, prompt=Proc.new)
+      def add_simple_prompt_provider(retry_limit, &prompt)
         args = [retry_limit]
         klass = AuthCredSimple
         add_prompt_provider("simple", args, prompt, klass)
       end
 
-      def add_username_prompt_provider(retry_limit, prompt=Proc.new)
+      def add_username_prompt_provider(retry_limit, &prompt)
         args = [retry_limit]
         klass = AuthCredUsername
         add_prompt_provider("username", args, prompt, klass)
       end
 
-      def add_ssl_server_trust_prompt_provider(prompt=Proc.new)
+      def add_ssl_server_trust_prompt_provider(&prompt)
         args = []
         klass = AuthCredSSLServerTrust
         add_prompt_provider("ssl_server_trust", args, prompt, klass)
       end
 
-      def add_ssl_client_cert_prompt_provider(retry_limit, prompt=Proc.new)
+      def add_ssl_client_cert_prompt_provider(retry_limit, &prompt)
         args = [retry_limit]
         klass = AuthCredSSLClientCert
         add_prompt_provider("ssl_client_cert", args, prompt, klass)
       end
 
-      def add_ssl_client_cert_pw_prompt_provider(retry_limit, prompt=Proc.new)
+      def add_ssl_client_cert_pw_prompt_provider(retry_limit, &prompt)
         args = [retry_limit]
         klass = AuthCredSSLClientCertPw
         add_prompt_provider("ssl_client_cert_pw", args, prompt, klass)

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/svn/util.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/svn/util.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/bindings/swig/ruby/svn/util.rb 
(original)
+++ subversion/branches/addremove/subversion/bindings/swig/ruby/svn/util.rb Sat 
May 23 14:16:56 2020
@@ -36,8 +36,13 @@ module Svn
   module Util #:nodoc:
     module_function
     def to_ruby_class_name(name)
+      # Convert to CamelCase with 'X' for a leading/double/trailing underscore.
       name.to_s.split("_").collect do |x|
-        "#{x[0,1].upcase}#{x[1..-1].downcase}"
+        if x.empty?
+          "X"
+        else
+          x.capitalize
+        end
       end.join("")
     end
 
@@ -70,6 +75,8 @@ module Svn
           target_name = $POSTMATCH
         when /^SWIG_SVN_/
           target_name = $POSTMATCH
+        when /^Svn_(?:#{target_mod.name.split("::").last.downcase}_)?_(.+)_t$/
+          # ignore private types
         when /^Svn_(?:#{target_mod.name.split("::").last.downcase}_)?(.+)_t$/
           target_name = to_ruby_class_name($1)
         when /^Svn_(?:#{target_mod.name.split("::").last.downcase}_)?/

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_client.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_client.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_client.rb 
(original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_client.rb 
Sat May 23 14:16:56 2020
@@ -1087,7 +1087,7 @@ class SvnClientTest < Test::Unit::TestCa
   We haven't yet figured out what to expect in the case of an obstruction,
   but it is no longer an error.  Commenting out this test until that
   decision is made (see issue #3680:
-  http://subversion.tigris.org/issues/show_bug.cgi?id=3680)
+  https://issues.apache.org/jira/browse/SVN-3680)
 
   def test_cleanup
     log = "sample log"

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_delta.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_delta.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_delta.rb 
(original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_delta.rb 
Sat May 23 14:16:56 2020
@@ -211,29 +211,32 @@ class SvnDeltaTest < Test::Unit::TestCas
     assert_equal(target_text, data)
   end
 
-  def test_path_driver
-    editor = Svn::Delta::BaseEditor.new
-    sorted_paths = []
-    callback = Proc.new do |parent_baton, path|
-      sorted_paths << path
-    end
-
-    targets = [
-      "/",
-      "/file1",
-      "/dir1",
-      "/dir2/file2",
-      "/dir2/dir3/file3",
-      "/dir2/dir3/file4"
-    ]
-    10.times do
-      x = rand(targets.size)
-      y = rand(targets.size)
-      targets[x], targets[y] = targets[y], targets[x]
-    end
-    Svn::Delta.path_driver(editor, 0, targets, &callback)
-    assert_equal(targets.sort, sorted_paths)
-  end
+# Fails since r1852536: "delta path editor binding broken for root path"
+#   https://issues.apache.org/jira/browse/SVN-4805
+#
+#  def test_path_driver
+#    editor = Svn::Delta::BaseEditor.new
+#    sorted_paths = []
+#    callback = Proc.new do |parent_baton, path|
+#      sorted_paths << path
+#    end
+#
+#    targets = [
+#      "/",
+#      "/file1",
+#      "/dir1",
+#      "/dir2/file2",
+#      "/dir2/dir3/file3",
+#      "/dir2/dir3/file4"
+#    ]
+#    10.times do
+#      x = rand(targets.size)
+#      y = rand(targets.size)
+#      targets[x], targets[y] = targets[y], targets[x]
+#    end
+#    Svn::Delta.path_driver(editor, 0, targets, &callback)
+#    assert_equal(targets.sort, sorted_paths)
+#  end
 
   def test_changed
     dir = "changed_dir"

Modified: 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_util.rb
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_util.rb?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_util.rb 
(original)
+++ 
subversion/branches/addremove/subversion/bindings/swig/ruby/test/test_util.rb 
Sat May 23 14:16:56 2020
@@ -33,5 +33,6 @@ class SvnUtilTest < Test::Unit::TestCase
     assert_equal("Abc", Svn::Util.to_ruby_class_name("abc"))
     assert_equal("AbcDef", Svn::Util.to_ruby_class_name("abc_def"))
     assert_equal("AbcDef", Svn::Util.to_ruby_class_name("ABC_DEF"))
+    assert_equal("XFoo", Svn::Util.to_ruby_class_name("_foo"))
   end
 end

Modified: subversion/branches/addremove/subversion/bindings/swig/svn_client.i
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/bindings/swig/svn_client.i?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/bindings/swig/svn_client.i 
(original)
+++ subversion/branches/addremove/subversion/bindings/swig/svn_client.i Sat May 
23 14:16:56 2020
@@ -119,7 +119,7 @@
     ppitem = (svn_client_proplist_item_t **)(*$1)->elts;
     for (i = 0; i < nelts; ++i, ++ppitem) {
         PyObject *item = PyTuple_New(2);
-        PyObject *name = PyString_FromStringAndSize((*ppitem)->node_name->data,
+        PyObject *name = PyBytes_FromStringAndSize((*ppitem)->node_name->data,
                                                     (*ppitem)->node_name->len);
         PyObject *hash = svn_swig_py_prophash_to_dict((*ppitem)->prop_hash);
 
@@ -239,6 +239,33 @@ Callback: svn_client_diff_summarize_func
                   svn_swig_rb_changelist_receiver)
 #endif
 
+ /* -----------------------------------------------------------------------
+    Callback: svn_client_status_func_t
+    svn_client_status*()
+    svn_client__shelf_save_new_version3()
+ */
+
+#ifdef SWIGPYTHON
+%callback_typemap(svn_client_status_func_t status_func,
+                  void *status_baton,
+                  svn_swig_py_client_status_func,
+                  ,
+                  )
+
+%callback_typemap_maybenull(svn_client_status_func_t shelved_func,
+                            void *shelved_baton,
+                            svn_swig_py_client_status_func,
+                            ,
+                            )
+
+%callback_typemap_maybenull(svn_client_status_func_t not_shelved_func,
+                            void *not_shelved_baton,
+                            svn_swig_py_client_status_func,
+                            ,
+                            )
+#endif
+
+
 /* -----------------------------------------------------------------------
    We use 'svn_wc_status_t *' in some custom code, but it isn't in the
    API anywhere. Thus, SWIG doesn't generate a typemap entry for it. by

Modified: 
subversion/branches/addremove/subversion/include/private/svn_auth_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_auth_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_auth_private.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_auth_private.h 
Sat May 23 14:16:56 2020
@@ -39,7 +39,7 @@ extern "C" {
 
 /** SSL server authority verification credential type.
  *
- * The followin auth parameters are available to the providers:
+ * The following auth parameters are available to the providers:
  *
  * - @c SVN_AUTH_PARAM_SSL_SERVER_FAILURES (@c apr_uint32_t*)
  * - @c SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO

Modified: subversion/branches/addremove/subversion/include/private/svn_branch.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_branch.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_branch.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_branch.h Sat 
May 23 14:16:56 2020
@@ -98,7 +98,7 @@ extern "C" {
  *
  * An element may appear in any or all branches, and its EID is the same in
  * each branch in which the element appears.
- * 
+ *
  * By definition, an element keeps the same EID for its whole lifetime, even
  * if deleted from all branches and later 'resurrected'.
  *

Modified: 
subversion/branches/addremove/subversion/include/private/svn_branch_impl.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_branch_impl.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_branch_impl.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_branch_impl.h 
Sat May 23 14:16:56 2020
@@ -21,7 +21,7 @@
  * @endcopyright
  *
  * @file svn_branch_impl.h
- * @brief Declarations needed by implementators of branch classes
+ * @brief Declarations needed by implementors of branch classes
  *
  * @since New in ???.
  */
@@ -36,7 +36,7 @@ extern "C" {
 #endif
 
 
-/* Common aspects od a txn/branch 'editor' class (derived from Ev2) */
+/* Common aspects of a txn/branch 'editor' class (derived from Ev2) */
 typedef struct svn_branch__vtable_priv_t
 {
   /* Standard cancellation function. Called before each callback.  */

Modified: 
subversion/branches/addremove/subversion/include/private/svn_client_mtcc.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_client_mtcc.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_client_mtcc.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_client_mtcc.h 
Sat May 23 14:16:56 2020
@@ -207,6 +207,17 @@ svn_client__mtcc_check_path(svn_node_kin
 /** Commits all operations stored in @a mtcc as a new revision and destroys
  * @a mtcc.
  *
+ * A log message is obtained from the log message callback in the client
+ * context in @a mtcc.
+ *
+ * @a revprop_table (if non-NULL) supplies additional revision properties;
+ * it may not supply any "svn:*" revision properties.
+ *
+ * As with svn_ra_get_commit_editor3(), after the commit has succeeded,
+ * it will invoke @a commit_callback (if non-NULL) with filled-in
+ * #svn_commit_info_t *, @a commit_baton, and @a scratch_pool or some subpool
+ * thereof as arguments.
+ *
  * @since New in 1.9.
  */
 svn_error_t *

Modified: 
subversion/branches/addremove/subversion/include/private/svn_client_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_client_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_client_private.h 
(original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_client_private.h 
Sat May 23 14:16:56 2020
@@ -281,26 +281,6 @@ svn_client__wc_node_get_origin(svn_clien
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
-/* Copy the file or directory on URL in some repository to DST_ABSPATH,
- * copying node information and properties. Resolve URL using PEG_REV and
- * REVISION.
- *
- * If URL specifies a directory, create the copy using depth DEPTH.
- *
- * If MAKE_PARENTS is TRUE and DST_ABSPATH doesn't have an added parent
- * create missing parent directories
- */
-svn_error_t *
-svn_client__copy_foreign(const char *url,
-                         const char *dst_abspath,
-                         svn_opt_revision_t *peg_revision,
-                         svn_opt_revision_t *revision,
-                         svn_depth_t depth,
-                         svn_boolean_t make_parents,
-                         svn_boolean_t already_locked,
-                         svn_client_ctx_t *ctx,
-                         apr_pool_t *scratch_pool);
-
 /* Same as the public svn_client_mergeinfo_log2 API, except for the addition
  * of the TARGET_MERGEINFO_CATALOG and RESULT_POOL parameters.
  *
@@ -341,6 +321,220 @@ svn_client__mergeinfo_log(svn_boolean_t
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool);
 
+/** Return a diff processor that will print a Subversion-style
+ * (not git-style) diff.
+ *
+ * @a anchor is optional (may be null), and is the 'anchor' path to prefix
+ * to the diff-processor paths before displaying.
+ *
+ * @a orig_path_1 and @a orig_path_2 are the two main root paths to be
+ * diffed; each may be a URL, a local WC path or a local unversioned path.
+ *
+ * Other arguments are as for svn_client_diff7() etc.
+ */
+svn_error_t *
+svn_client__get_diff_writer_svn(
+                svn_diff_tree_processor_t **diff_processor,
+                const char *anchor,
+                const char *orig_path_1,
+                const char *orig_path_2,
+                const apr_array_header_t *options,
+                const char *relative_to_dir,
+                svn_boolean_t no_diff_added,
+                svn_boolean_t no_diff_deleted,
+                svn_boolean_t show_copies_as_adds,
+                svn_boolean_t ignore_content_type,
+                svn_boolean_t ignore_properties,
+                svn_boolean_t properties_only,
+                svn_boolean_t pretty_print_mergeinfo,
+                const char *header_encoding,
+                svn_stream_t *outstream,
+                svn_stream_t *errstream,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *pool);
+
+/*** Editor for diff summary ***/
+
+/* Set *DIFF_PROCESSOR to a diff processor that will report a diff summary
+   to SUMMARIZE_FUNC.
+
+   SUMMARIZE_FUNC is called with SUMMARIZE_BATON as parameter by the
+   created callbacks for each changed item.
+*/
+svn_error_t *
+svn_client__get_diff_summarize_callbacks(
+                        svn_diff_tree_processor_t **diff_processor,
+                        svn_client_diff_summarize_func_t summarize_func,
+                        void *summarize_baton,
+                        apr_pool_t *result_pool,
+                        apr_pool_t *scratch_pool);
+
+/** Copy a directory tree or a file (according to @a kind) from @a src_url at
+ * @a src_rev, to @a dst_abspath in a WC.
+ *
+ * The caller should be holding a WC write lock that allows @a dst_abspath to
+ * be created, such as on the parent of @a dst_abspath.
+ *
+ * If not same repositories, then remove any svn:mergeinfo property.
+ *
+ * Use @a ra_session to fetch the data. The session may point to any URL
+ * within the source repository.
+ *
+ * This API does not process any externals definitions that may be present
+ * on copied directories.
+ */
+svn_error_t *
+svn_client__repos_to_wc_copy_internal(svn_boolean_t *timestamp_sleep,
+                             svn_node_kind_t kind,
+                             const char *src_url,
+                             svn_revnum_t src_rev,
+                             const char *dst_abspath,
+                             svn_ra_session_t *ra_session,
+                             svn_client_ctx_t *ctx,
+                             apr_pool_t *scratch_pool);
+
+/** Copy a directory tree or a file (according to @a kind) from @a src_url at
+ * @a src_rev, to @a dst_abspath in a WC.
+ *
+ * The caller should be holding a WC write lock that allows @a dst_abspath to
+ * be created, such as on the parent of @a dst_abspath.
+ *
+ * If not same repositories, then remove any svn:mergeinfo property.
+ *
+ * Use @a ra_session to fetch the data. The session may point to a different
+ * URL after returning.
+ *
+ * This API does not process any externals definitions that may be present
+ * on copied directories.
+ */
+svn_error_t *
+svn_client__repos_to_wc_copy_by_editor(svn_boolean_t *timestamp_sleep,
+                svn_node_kind_t kind,
+                const char *src_url,
+                svn_revnum_t src_rev,
+                const char *dst_abspath,
+                svn_ra_session_t *ra_session,
+                svn_client_ctx_t *ctx,
+                apr_pool_t *scratch_pool);
+
+/** Return an editor for applying local modifications to a WC.
+ *
+ * Return an editor in @a *editor_p, @a *edit_baton_p that will apply
+ * local modifications to the WC subdirectory at @a dst_abspath.
+ *
+ * The @a path arguments to the editor methods shall be local WC paths,
+ * relative to @a dst_abspath. The @a copyfrom_path arguments to the
+ * editor methods shall be URLs.
+ *
+ * Send notifications via @a notify_func / @a notify_baton.
+ * ### INCOMPLETE
+ *
+ * @a ra_session is used to fetch the original content for copies.
+ *
+ * Ignore changes to non-regular property (entry-props, DAV/WC-props).
+ *
+ * Acquire the WC write lock in 'open_root' and release it in
+ * 'close_edit', in 'abort_edit', or when @a result_pool is cleared.
+ */
+svn_error_t *
+svn_client__wc_editor(const svn_delta_editor_t **editor_p,
+                      void **edit_baton_p,
+                      const char *dst_abspath,
+                      svn_wc_notify_func2_t notify_func,
+                      void *notify_baton,
+                      svn_ra_session_t *ra_session,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *result_pool);
+
+/* Return an editor for applying local modifications to a WC.
+ *
+ * Like svn_client__wc_editor() but with additional options.
+ *
+ * If @a root_dir_add is true, then create and schedule for addition
+ * the root directory of this edit, else assume it is already a versioned,
+ * existing directory.
+ *
+ * If @a ignore_mergeinfo_changes is true, ignore any incoming changes
+ * to the 'svn:mergeinfo' property.
+ *
+ * If @a manage_wc_write_lock is true, acquire the WC write lock in
+ * 'open_root' and release it in 'close_edit', in 'abort_edit', or
+ * when @a result_pool is cleared.
+ */
+svn_error_t *
+svn_client__wc_editor_internal(const svn_delta_editor_t **editor_p,
+                               void **edit_baton_p,
+                               const char *dst_abspath,
+                               svn_boolean_t root_dir_add,
+                               svn_boolean_t ignore_mergeinfo_changes,
+                               svn_boolean_t manage_wc_write_lock,
+                               svn_wc_notify_func2_t notify_func,
+                               void *notify_baton,
+                               svn_ra_session_t *ra_session,
+                               svn_client_ctx_t *ctx,
+                               apr_pool_t *result_pool);
+
+/** Send committable changes found in the WC to a delta-editor.
+ *
+ * Committable changes are found in TARGETS:DEPTH:CHANGELISTS.
+ *
+ * Send the changes to @a editor:@a edit_baton. The @a path arguments
+ * to the editor methods are URL-paths relative to the URL of
+ * @a src_wc_abspath.
+ *
+ *    ### We will presumably need to change this so that the @a path
+ *        arguments to the editor will be local WC relpaths, in order
+ *        to handle switched paths.
+ *
+ * The @a copyfrom_path arguments to the editor methods are URLs. As the
+ * WC does not store copied-from-foreign-repository metadata, the URL will
+ * be in the same repository as the URL of its parent path.
+ *
+ * Compared with svn_client__do_commit(), this (like svn_client_commit6)
+ * handles:
+ *  - condense targets and find committable paths
+ *  - checking only one repository is involved
+ *
+ * Compared with svn_client_commit6(), this does not handle:
+ *  - externals
+ *  - log message
+ *  - revprops
+ *  - checking the commit includes both halves of each local move
+ *  - changing the copy revision of each local move to ~HEAD
+ *  - WC write locks
+ *  - bumping revisions in WC
+ *  - removing locks and changelists in WC
+ */
+svn_error_t *
+svn_client__wc_replay(const char *src_wc_abspath,
+                      const apr_array_header_t *targets,
+                      svn_depth_t depth,
+                      const apr_array_header_t *changelists,
+                      const svn_delta_editor_t *editor,
+                      void *edit_baton,
+                      svn_wc_notify_func2_t notify_func,
+                      void *notify_baton,
+                      svn_client_ctx_t *ctx,
+                      apr_pool_t *scratch_pool);
+
+/** Copy local modifications from one WC subtree to another.
+ *
+ * Find local modifications under @a src_wc_abspath, in the same way as
+ * for a commit.
+ *
+ * Edit the WC at @a dst_wc_abspath, applying those modifications to the
+ * current working state to produce a new working state.
+ *
+ * The source and destination may be in the same WC or in different WCs.
+ */
+svn_error_t *
+svn_client__wc_copy_mods(const char *src_wc_abspath,
+                         const char *dst_wc_abspath,
+                         svn_wc_notify_func2_t notify_func,
+                         void *notify_baton,
+                         svn_client_ctx_t *ctx,
+                         apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: 
subversion/branches/addremove/subversion/include/private/svn_cmdline_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_cmdline_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_cmdline_private.h 
(original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_cmdline_private.h 
Sat May 23 14:16:56 2020
@@ -269,6 +269,15 @@ svn_cmdline__disable_cancellation_handle
 void
 svn_cmdline__cancellation_exit(void);
 
+/** Reads a string from stdin until a newline or EOF is found
+ *
+ * @since New in 1.10.
+ */
+svn_error_t *
+svn_cmdline__stdin_readline(const char **result,
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: 
subversion/branches/addremove/subversion/include/private/svn_config_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_config_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_config_private.h 
(original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_config_private.h 
Sat May 23 14:16:56 2020
@@ -77,7 +77,7 @@ typedef svn_error_t *(*svn_config__add_v
 
 
 /*
- * Create a new constuctor allocated from RESULT_POOL.
+ * Create a new constructor allocated from RESULT_POOL.
  * Any of the callback functions may be NULL.
  * The constructor implementation is responsible for implementing any
  * case-insensitivity, value expansion, or other features on top of
@@ -98,9 +98,9 @@ svn_config__constructor_create(
  * passed to the callback in the same order as they're defined in
  * STREAM.
  *
- * The lifetome of section names, option names and values passed to
+ * The lifetime of section names, option names and values passed to
  * the constructor does not extend past the invocation of each
- * callback; see calback docs, above.
+ * callback; see callback docs, above.
  *
  * The parser will use SCRATCH_POOL for its own allocations.
  */

Modified: 
subversion/branches/addremove/subversion/include/private/svn_dep_compat.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_dep_compat.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_dep_compat.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_dep_compat.h 
Sat May 23 14:16:56 2020
@@ -108,12 +108,6 @@ extern "C" {
 #define APR_OPENINFO  0x00100000
 #endif
 
-#if !APR_VERSION_AT_LEAST(1,4,0)
-#ifndef apr_time_from_msec
-#define apr_time_from_msec(msec) ((apr_time_t)(msec) * 1000)
-#endif
-#endif
-
 /**
  * APR 1 has volatile qualifier bugs in some atomic prototypes that
  * are fixed in APR 2:

Modified: 
subversion/branches/addremove/subversion/include/private/svn_diff_tree.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_diff_tree.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_diff_tree.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_diff_tree.h 
Sat May 23 14:16:56 2020
@@ -74,14 +74,14 @@ extern "C" {
  * To cleanup the implementation and make it easier on diff processors to
  * handle the results I also added the following constraints.
  *
- *   * Diffs should be fully reversable: anything that is deleted should be
+ *   * Diffs should be fully reversible: anything that is deleted should be
  *     available, just like something that is added.
  *     (Proven via svn_diff__tree_processor_reverse_create)
  *     ### Still in doubt if *_deleted() needs a copy_to argument, for the
  *     ### 99% -> 100%.
  *
  *   * Diff processors should have an easy way to communicate that they are
- *     not interrested in certain expensive to obtain results.
+ *     not interested in certain expensive to obtain results.
  *
  *   * Directories should have clear open and close events to allow adding them
  *     before their children, but still allowing property changes to have
@@ -321,7 +321,6 @@ svn_diff__tree_processor_create(void *ba
  */ /* Used by libsvn clients repository diff */
 const svn_diff_tree_processor_t *
 svn_diff__tree_processor_reverse_create(const svn_diff_tree_processor_t * 
processor,
-                                        const char *prefix_relpath,
                                         apr_pool_t *result_pool);
 
 /**

Modified: subversion/branches/addremove/subversion/include/private/svn_element.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_element.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_element.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_element.h Sat 
May 23 14:16:56 2020
@@ -348,7 +348,7 @@ svn_element__content_t *
 svn_element__tree_get(const svn_element__tree_t *tree,
                       int eid);
 
-svn_error_t *
+void
 svn_element__tree_set(svn_element__tree_t *tree,
                       int eid,
                       const svn_element__content_t *element);

Modified: 
subversion/branches/addremove/subversion/include/private/svn_fs_fs_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_fs_fs_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_fs_fs_private.h 
(original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_fs_fs_private.h 
Sat May 23 14:16:56 2020
@@ -255,22 +255,6 @@ typedef struct svn_fs_fs__stats_t
   apr_hash_t *by_extension;
 } svn_fs_fs__stats_t;
 
-
-/* Scan all contents of the repository FS and return statistics in *STATS,
- * allocated in RESULT_POOL.  Report progress through PROGRESS_FUNC with
- * PROGRESS_BATON, if PROGRESS_FUNC is not NULL.
- * Use SCRATCH_POOL for temporary allocations.
- */
-svn_error_t *
-svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats,
-                     svn_fs_t *fs,
-                     svn_fs_progress_notify_func_t progress_func,
-                     void *progress_baton,
-                     svn_cancel_func_t cancel_func,
-                     void *cancel_baton,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool);
-
 /* A node-revision ID in FSFS consists of 3 sub-IDs ("parts") that consist
  * of a creation REVISION number and some revision- / transaction-local
  * counter value (NUMBER).  Old-style ID parts use global counter values.
@@ -325,33 +309,60 @@ typedef svn_error_t *
                                 void *baton,
                                 apr_pool_t *scratch_pool);
 
-/* Read the P2L index for the rev / pack file containing REVISION in FS.
- * For each index entry, invoke CALLBACK_FUNC with CALLBACK_BATON.
- * If not NULL, call CANCEL_FUNC with CANCEL_BATON from time to time.
- * Use SCRATCH_POOL for temporary allocations.
- */
-svn_error_t *
-svn_fs_fs__dump_index(svn_fs_t *fs,
-                      svn_revnum_t revision,
-                      svn_fs_fs__dump_index_func_t callback_func,
-                      void *callback_baton,
-                      svn_cancel_func_t cancel_func,
-                      void *cancel_baton,
-                      apr_pool_t *scratch_pool);
+typedef struct svn_fs_fs__ioctl_get_stats_input_t
+{
+  svn_fs_progress_notify_func_t progress_func;
+  void *progress_baton;
+} svn_fs_fs__ioctl_get_stats_input_t;
 
+typedef struct svn_fs_fs__ioctl_get_stats_output_t
+{
+  svn_fs_fs__stats_t *stats;
+} svn_fs_fs__ioctl_get_stats_output_t;
 
-/* Rewrite the respective index information of the rev / pack file in FS
- * containing REVISION and use the svn_fs_fs__p2l_entry_t * array ENTRIES
- * as the new index contents.  Allocate temporaries from SCRATCH_POOL.
- *
- * Note that this becomes a no-op if ENTRIES is empty.  You may use a zero-
- * sized empty entry instead.
- */
-svn_error_t *
-svn_fs_fs__load_index(svn_fs_t *fs,
-                      svn_revnum_t revision,
-                      apr_array_header_t *entries,
-                      apr_pool_t *scratch_pool);
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_GET_STATS, SVN_FS_TYPE_FSFS, 1000);
+
+typedef struct svn_fs_fs__ioctl_dump_index_input_t
+{
+  svn_revnum_t revision;
+  svn_fs_fs__dump_index_func_t callback_func;
+  void *callback_baton;
+} svn_fs_fs__ioctl_dump_index_input_t;
+
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_DUMP_INDEX, SVN_FS_TYPE_FSFS, 1001);
+
+typedef struct svn_fs_fs__ioctl_load_index_input_t
+{
+  svn_revnum_t revision;
+  /* Array of svn_fs_fs__p2l_entry_t * entries. */
+  apr_array_header_t *entries;
+} svn_fs_fs__ioctl_load_index_input_t;
+
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_LOAD_INDEX, SVN_FS_TYPE_FSFS, 1002);
+
+typedef struct svn_fs_fs__ioctl_revision_size_input_t
+{
+  svn_revnum_t revision;
+} svn_fs_fs__ioctl_revision_size_input_t;
+
+typedef struct svn_fs_fs__ioctl_revision_size_output_t
+{
+  apr_off_t rev_size;
+} svn_fs_fs__ioctl_revision_size_output_t;
+
+/* See svn_fs_fs__revision_size(). */
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_REVISION_SIZE, SVN_FS_TYPE_FSFS, 
1003);
+
+typedef struct svn_fs_fs__ioctl_build_rep_cache_input_t
+{
+  svn_revnum_t start_rev;
+  svn_revnum_t end_rev;
+  svn_fs_progress_notify_func_t progress_func;
+  void *progress_baton;
+} svn_fs_fs__ioctl_build_rep_cache_input_t;
+
+/* See svn_fs_fs__build_rep_cache(). */
+SVN_FS_DECLARE_IOCTL_CODE(SVN_FS_FS__IOCTL_BUILD_REP_CACHE, SVN_FS_TYPE_FSFS, 
1004);
 
 #ifdef __cplusplus
 }

Modified: 
subversion/branches/addremove/subversion/include/private/svn_mergeinfo_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_mergeinfo_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_mergeinfo_private.h
 (original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_mergeinfo_private.h
 Sat May 23 14:16:56 2020
@@ -62,7 +62,7 @@ svn_rangelist__parse(svn_rangelist_t **r
 /* Return TRUE, if all ranges in RANGELIST are in ascending order and do
 * not overlap and are not adjacent.
 *
-* If this returns FALSE, you probaly want to call
+* If this returns FALSE, you probably want to call
 * svn_rangelist__canonicalize().
 */
 svn_boolean_t

Modified: 
subversion/branches/addremove/subversion/include/private/svn_object_pool.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_object_pool.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- subversion/branches/addremove/subversion/include/private/svn_object_pool.h 
(original)
+++ subversion/branches/addremove/subversion/include/private/svn_object_pool.h 
Sat May 23 14:16:56 2020
@@ -67,7 +67,7 @@ typedef struct svn_object_pool__t svn_ob
 
 /* Create a new object pool in POOL and return it in *OBJECT_POOL.
  * Objects are reference-counted and stored as opaque pointers.  Each
- * must be allocated in a separate pool ceated by
+ * must be allocated in a separate pool created by
  * svn_object_pool__new_item_pool.  Unused objects get destroyed at
  * the object pool's discretion.
  *

Modified: 
subversion/branches/addremove/subversion/include/private/svn_ra_svn_private.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/addremove/subversion/include/private/svn_ra_svn_private.h?rev=1878061&r1=1878060&r2=1878061&view=diff
==============================================================================
--- 
subversion/branches/addremove/subversion/include/private/svn_ra_svn_private.h 
(original)
+++ 
subversion/branches/addremove/subversion/include/private/svn_ra_svn_private.h 
Sat May 23 14:16:56 2020
@@ -127,6 +127,11 @@ svn_error_t *
 svn_ra_svn__set_capabilities(svn_ra_svn_conn_t *conn,
                              const svn_ra_svn__list_t *list);
 
+/** Returns the preferred svndiff version to be used with connection @a conn.
+ */
+int
+svn_ra_svn__svndiff_version(svn_ra_svn_conn_t *conn);
+
 
 /**
  * Set the shim callbacks to be used by @a conn to @a shim_callbacks.


Reply via email to