Rev 1242: Make editor API more object oriented. in http://people.samba.org/bzr/jelmer/bzr-svn/0.4/

Jelmer Vernooij jelmer at samba.org
Thu Jun 19 14:58:51 BST 2008


At http://people.samba.org/bzr/jelmer/bzr-svn/0.4/

------------------------------------------------------------
revno: 1242
revision-id: jelmer at samba.org-20080619135842-8kg5be1na8cgdptp
parent: jelmer at samba.org-20080618115824-vzo020t2d83ik66x
committer: Jelmer Vernooij <jelmer at samba.org>
branch nick: 0.4
timestamp: Thu 2008-06-19 15:58:42 +0200
message:
  Make editor API more object oriented.
modified:
  __init__.py                    __init__.py-20051008155114-eae558e6cf149e1d
  auth.py                        auth.py-20071209174622-w8d42k6nm5yhxvi8-1
  convert.py                     svn2bzr.py-20051018015439-cb4563bff29e632d
  delta.py                       delta.py-20080617225125-jeg43afui0czkuwk-1
  fetch.py                       fetch.py-20060625004942-x2lfaib8ra707a8p-1
  logwalker.py                   logwalker.py-20060621215743-c13fhfnyzh1xzwh2-1
  ra.py                          ra.py-20080615005305-t5221niknu8rm6bt-1
  revspec.py                     revspec.py-20071106211507-q4fz2en91yrmjjl8-1
  tree.py                        tree.py-20060624222557-dudlwqcmkf22lt2s-1
=== modified file '__init__.py'
--- a/__init__.py	2008-06-10 21:39:41 +0000
+++ b/__init__.py	2008-06-19 13:58:42 +0000
@@ -74,8 +74,8 @@
         warning('No Python bindings for Subversion installed. See the '
                 'bzr-svn README for details.')
         raise bzrlib.errors.BzrError("missing python subversion bindings")
-    if (not hasattr(svn.delta, 'svn_delta_invoke_txdelta_window_handler') and 
-        not hasattr(svn.delta, 'tx_invoke_window_handler')):
+    if (not getattr(svn.delta, 'svn_delta_invoke_txdelta_window_handler', None) and 
+        not getattr(svn.delta, 'tx_invoke_window_handler', None)):
         warning('Installed Subversion version does not have updated Python '
                 'bindings. See the bzr-svn README for details.')
         raise bzrlib.errors.BzrError("incompatible python subversion bindings")

=== modified file 'auth.py'
--- a/auth.py	2008-06-18 11:58:24 +0000
+++ b/auth.py	2008-06-19 13:58:42 +0000
@@ -143,13 +143,13 @@
             ra.get_ssl_server_trust_file_provider(),
             ]
 
-    if hasattr(ra, 'get_windows_simple_provider'):
+    if getattr(ra, 'get_windows_simple_provider', None):
         providers.append(ra.get_windows_simple_provider())
 
-    if hasattr(ra, 'get_keychain_simple_provider'):
+    if getattr(ra, 'get_keychain_simple_provider', None):
         providers.append(ra.get_keychain_simple_provider())
 
-    if hasattr(ra, 'get_windows_ssl_server_trust_provider'):
+    if getattr(ra, 'get_windows_ssl_server_trust_provider', None):
         providers.append(ra.get_windows_ssl_server_trust_provider())
 
     return providers

=== modified file 'convert.py'
--- a/convert.py	2008-06-05 17:54:39 +0000
+++ b/convert.py	2008-06-19 13:58:42 +0000
@@ -141,7 +141,7 @@
         if all:
             inter.fetch()
         elif (target_repos.is_shared() and 
-              hasattr(inter, '_supports_branches') and 
+              getattr(inter, '_supports_branches', None) and 
               inter._supports_branches):
             inter.fetch(branches=[branch.last_revision() for branch in existing_branches])
 

=== modified file 'delta.py'
--- a/delta.py	2008-06-17 22:52:33 +0000
+++ b/delta.py	2008-06-19 13:58:42 +0000
@@ -19,11 +19,11 @@
 from cStringIO import StringIO
 import svn.delta
 
-if hasattr(svn.delta, 'tx_invoke_window_handler'):
+if getattr(svn.delta, 'tx_invoke_window_handler', None):
     def apply_txdelta_handler(sbuf, target_stream):
         src_stream = StringIO(sbuf)
-        assert hasattr(src_stream, 'read')
-        assert hasattr(target_stream, 'write')
+        assert getattr(src_stream, 'read', None) is not None
+        assert getattr(target_stream, 'write', None) is not None
         window_handler, baton = svn.delta.tx_apply(src_stream, target_stream, 
                                                    None)
 
@@ -34,8 +34,8 @@
 else:
     def apply_txdelta_handler(sbuf, target_stream):
         src_stream = StringIO(sbuf)
-        assert hasattr(src_stream, 'read')
-        assert hasattr(target_stream, 'write')
+        assert getattr(src_stream, 'read', None) is not None
+        assert getattr(target_stream, 'write', None) is not None
         ret = svn.delta.svn_txdelta_apply(src_stream, target_stream, None)
 
         def wrapper(window):

=== modified file 'fetch.py'
--- a/fetch.py	2008-06-18 11:58:24 +0000
+++ b/fetch.py	2008-06-19 13:58:42 +0000
@@ -135,17 +135,17 @@
 
         return (rev, signature)
 
-    def open_root(self, base_revnum, baton):
+    def open_root(self, base_revnum):
         if self.old_inventory.root is None:
             # First time the root is set
             old_file_id = None
             file_id = self.mapping.generate_file_id(self.source.uuid, self.revnum, self.branch_path, u"")
-            self.dir_baserev[file_id] = []
+            file_parents = []
         else:
             assert self.old_inventory.root.revision is not None
             old_file_id = self.old_inventory.root.file_id
             file_id = self._get_id_map().get("", old_file_id)
-            self.dir_baserev[file_id] = [self.old_inventory.root.revision]
+            file_parents = [self.old_inventory.root.revision]
 
         if self.inventory.root is not None and \
                 file_id == self.inventory.root.file_id:
@@ -153,7 +153,28 @@
         else:
             ie = self.inventory.add_path("", 'directory', file_id)
         ie.revision = self.revid
-        return (old_file_id, file_id)
+        return DirectoryBuildEditor(self, old_file_id, file_id, file_parents)
+
+    def close(self):
+        pass
+
+    def _store_directory(self, file_id, parents):
+        raise NotImplementedError(self._store_directory)
+
+    def _get_file_data(self, file_id, revid):
+        raise NotImplementedError(self._get_file_data)
+
+    def _finish_commit(self):
+        raise NotImplementedError(self._finish_commit)
+
+    def abort(self):
+        pass
+
+    def _start_revision(self):
+        pass
+
+    def _store_file(self, file_id, lines, parents):
+        raise NotImplementedError(self._store_file)
 
     def _get_existing_id(self, old_parent_id, new_parent_id, path):
         assert isinstance(path, unicode)
@@ -187,82 +208,81 @@
             return
         self.inventory.rename(file_id, parent_id, urlutils.basename(path))
 
-    def delete_entry(self, path, revnum, (old_parent_id, new_parent_id), pool):
-        assert isinstance(path, str)
-        path = path.decode("utf-8")
-        if path in self._premature_deletes:
-            # Delete recursively
-            self._premature_deletes.remove(path)
-            for p in self._premature_deletes.copy():
-                if p.startswith("%s/" % path):
-                    self._premature_deletes.remove(p)
-        else:
-            self.inventory.remove_recursive_id(self._get_old_id(old_parent_id, path))
-
-    def close_directory(self, (old_id, new_id)):
-        self.inventory[new_id].revision = self.revid
+
+class DirectoryBuildEditor:
+    def __init__(self, editor, old_id, new_id, parent_revids=[]):
+        self.editor = editor
+        self.old_id = old_id
+        self.new_id = new_id
+        self.parent_revids = parent_revids
+
+    def close(self):
+        self.editor.inventory[self.new_id].revision = self.editor.revid
 
         # Only record root if the target repository supports it
-        self._store_directory(new_id, self.dir_baserev[new_id])
-
-    def add_directory(self, path, (old_parent_id, new_parent_id), copyfrom_path, copyfrom_revnum, 
-                      pool):
+        self.editor._store_directory(self.new_id, self.parent_revids)
+
+        if self.new_id == self.editor.inventory.root.file_id:
+            assert len(self.editor._premature_deletes) == 0
+            self.editor._finish_commit()
+
+    def add_directory(self, path, copyfrom_path=None, copyfrom_revnum=-1):
         assert isinstance(path, str)
         path = path.decode("utf-8")
         check_filename(path)
-        file_id = self._get_new_id(new_parent_id, path)
+        file_id = self.editor._get_new_id(self.new_id, path)
 
-        self.dir_baserev[file_id] = []
-        if file_id in self.inventory:
+        if file_id in self.editor.inventory:
             # This directory was moved here from somewhere else, but the 
             # other location hasn't been removed yet. 
             if copyfrom_path is None:
                 # This should ideally never happen!
-                copyfrom_path = self.old_inventory.id2path(file_id)
+                copyfrom_path = self.editor.old_inventory.id2path(file_id)
                 mutter('no copyfrom path set, assuming %r', copyfrom_path)
-            assert copyfrom_path == self.old_inventory.id2path(file_id)
-            assert copyfrom_path not in self._premature_deletes
-            self._premature_deletes.add(copyfrom_path)
-            self._rename(file_id, new_parent_id, path)
-            ie = self.inventory[file_id]
+            assert copyfrom_path == self.editor.old_inventory.id2path(file_id)
+            assert copyfrom_path not in self.editor._premature_deletes
+            self.editor._premature_deletes.add(copyfrom_path)
+            self.editor._rename(file_id, self.new_id, path)
+            ie = self.editor.inventory[file_id]
             old_file_id = file_id
         else:
             old_file_id = None
-            ie = self.inventory.add_path(path, 'directory', file_id)
-        ie.revision = self.revid
-
-        return (old_file_id, file_id)
-
-    def open_directory(self, path, (old_parent_id, new_parent_id), base_revnum, pool):
+            ie = self.editor.inventory.add_path(path, 'directory', file_id)
+        ie.revision = self.editor.revid
+
+        return DirectoryBuildEditor(self.editor, old_file_id, file_id)
+
+    def open_directory(self, path, base_revnum):
         assert isinstance(path, str)
         path = path.decode("utf-8")
         assert base_revnum >= 0
-        base_file_id = self._get_old_id(old_parent_id, path)
-        base_revid = self.old_inventory[base_file_id].revision
-        file_id = self._get_existing_id(old_parent_id, new_parent_id, path)
+        base_file_id = self.editor._get_old_id(self.old_id, path)
+        base_revid = self.editor.old_inventory[base_file_id].revision
+        file_id = self.editor._get_existing_id(self.old_id, self.new_id, path)
         if file_id == base_file_id:
-            self.dir_baserev[file_id] = [base_revid]
-            ie = self.inventory[file_id]
+            file_parents = [base_revid]
+            ie = self.editor.inventory[file_id]
         else:
             # Replace if original was inside this branch
             # change id of base_file_id to file_id
-            ie = self.inventory[base_file_id]
+            ie = self.editor.inventory[base_file_id]
             for name in ie.children:
                 ie.children[name].parent_id = file_id
             # FIXME: Don't touch inventory internals
-            del self.inventory._byid[base_file_id]
-            self.inventory._byid[file_id] = ie
+            del self.editor.inventory._byid[base_file_id]
+            self.editor.inventory._byid[file_id] = ie
             ie.file_id = file_id
-            self.dir_baserev[file_id] = []
-        ie.revision = self.revid
-        return (base_file_id, file_id)
+            file_parents = []
+        ie.revision = self.editor.revid
+        return DirectoryBuildEditor(self.editor, base_file_id, file_id, 
+                                    file_parents)
 
-    def change_dir_prop(self, (old_id, new_id), name, value, pool):
-        if new_id == self.inventory.root.file_id:
+    def change_prop(self, name, value):
+        if self.new_id == self.editor.inventory.root.file_id:
             # Replay lazy_dict, since it may be more expensive
-            if type(self.revmeta.fileprops) != dict:
-                self.revmeta.fileprops = {}
-            self.revmeta.fileprops[name] = value
+            if type(self.editor.revmeta.fileprops) != dict:
+                self.editor.revmeta.fileprops = {}
+            self.editor.revmeta.fileprops[name] = value
 
         if name in (properties.PROP_ENTRY_COMMITTED_DATE,
                     properties.PROP_ENTRY_COMMITTED_REV,
@@ -276,7 +296,76 @@
         elif name.startswith(properties.PROP_PREFIX):
             mutter('unsupported dir property %r', name)
 
-    def change_file_prop(self, id, name, value, pool):
+    def add_file(self, path, copyfrom_path=None, copyfrom_revnum=-1):
+        assert isinstance(path, str)
+        path = path.decode("utf-8")
+        check_filename(path)
+        file_id = self.editor._get_new_id(self.new_id, path)
+        if file_id in self.editor.inventory:
+            # This file was moved here from somewhere else, but the 
+            # other location hasn't been removed yet. 
+            if copyfrom_path is None:
+                # This should ideally never happen
+                copyfrom_path = self.editor.old_inventory.id2path(file_id)
+                mutter('no copyfrom path set, assuming %r', copyfrom_path)
+            assert copyfrom_path == self.editor.old_inventory.id2path(file_id)
+            assert copyfrom_path not in self.editor._premature_deletes
+            self.editor._premature_deletes.add(copyfrom_path)
+            # No need to rename if it's already in the right spot
+            self.editor._rename(file_id, self.new_id, path)
+        return FileBuildEditor(self.editor, path, file_id)
+
+    def open_file(self, path, base_revnum):
+        assert isinstance(path, str)
+        path = path.decode("utf-8")
+        base_file_id = self.editor._get_old_id(self.old_id, path)
+        base_revid = self.editor.old_inventory[base_file_id].revision
+        file_id = self.editor._get_existing_id(self.old_id, self.new_id, path)
+        is_symlink = (self.editor.inventory[base_file_id].kind == 'symlink')
+        file_data = self.editor._get_file_data(base_file_id, base_revid)
+        if file_id == base_file_id:
+            file_parents = [base_revid]
+        else:
+            # Replace
+            del self.editor.inventory[base_file_id]
+            file_parents = []
+        return FileBuildEditor(self.editor, path, file_id, 
+                               file_parents, file_data, is_symlink=is_symlink)
+
+    def delete_entry(self, path, revnum):
+        assert isinstance(path, str)
+        path = path.decode("utf-8")
+        if path in self.editor._premature_deletes:
+            # Delete recursively
+            self.editor._premature_deletes.remove(path)
+            for p in self.editor._premature_deletes.copy():
+                if p.startswith("%s/" % path):
+                    self.editor._premature_deletes.remove(p)
+        else:
+            self.editor.inventory.remove_recursive_id(self.editor._get_old_id(self.old_id, path))
+
+
+class FileBuildEditor:
+    def __init__(self, editor, path, file_id, file_parents=[], data="", 
+                 is_symlink=False):
+        self.path = path
+        self.editor = editor
+        self.file_id = file_id
+        self.file_data = data
+        self.is_symlink = is_symlink
+        self.file_parents = file_parents
+        self.is_executable = None
+        self.file_stream = None
+
+    def apply_textdelta(self, base_checksum=None):
+        actual_checksum = md5.new(self.file_data).hexdigest()
+        assert (base_checksum is None or base_checksum == actual_checksum,
+            "base checksum mismatch: %r != %r" % (base_checksum, 
+                                                  actual_checksum))
+        self.file_stream = StringIO()
+        return apply_txdelta_handler(self.file_data, self.file_stream)
+
+    def change_prop(self, name, value):
         if name == properties.PROP_EXECUTABLE: 
             # You'd expect executable to match 
             # properties.PROP_EXECUTABLE_VALUE, but that's not 
@@ -301,50 +390,8 @@
               name.startswith(SVN_PROP_BZR_PREFIX)):
             mutter('unsupported file property %r', name)
 
-    def add_file(self, path, (old_parent_id, new_parent_id), copyfrom_path, copyfrom_revnum, baton):
-        assert isinstance(path, str)
-        path = path.decode("utf-8")
-        check_filename(path)
-        self.is_symlink = False
-        self.is_executable = None
-        self.file_data = ""
-        self.file_parents = []
-        self.file_stream = None
-        self.file_id = self._get_new_id(new_parent_id, path)
-        if self.file_id in self.inventory:
-            # This file was moved here from somewhere else, but the 
-            # other location hasn't been removed yet. 
-            if copyfrom_path is None:
-                # This should ideally never happen
-                copyfrom_path = self.old_inventory.id2path(self.file_id)
-                mutter('no copyfrom path set, assuming %r', copyfrom_path)
-            assert copyfrom_path == self.old_inventory.id2path(self.file_id)
-            assert copyfrom_path not in self._premature_deletes
-            self._premature_deletes.add(copyfrom_path)
-            # No need to rename if it's already in the right spot
-            self._rename(self.file_id, new_parent_id, path)
-        return path
-
-    def open_file(self, path, (old_parent_id, new_parent_id), base_revnum, pool):
-        assert isinstance(path, str)
-        path = path.decode("utf-8")
-        base_file_id = self._get_old_id(old_parent_id, path)
-        base_revid = self.old_inventory[base_file_id].revision
-        self.file_id = self._get_existing_id(old_parent_id, new_parent_id, path)
-        self.is_executable = None
-        self.is_symlink = (self.inventory[base_file_id].kind == 'symlink')
-        self.file_data = self._get_file_data(base_file_id, base_revid)
-        self.file_stream = None
-        if self.file_id == base_file_id:
-            self.file_parents = [base_revid]
-        else:
-            # Replace
-            del self.inventory[base_file_id]
-            self.file_parents = []
-        return path
-
-    def close_file(self, path, checksum):
-        assert isinstance(path, unicode)
+    def close(self, checksum=None):
+        assert isinstance(self.path, unicode)
         if self.file_stream is not None:
             self.file_stream.seek(0)
             lines = osutils.split_lines(self.file_stream.read())
@@ -355,23 +402,23 @@
         actual_checksum = md5_strings(lines)
         assert checksum is None or checksum == actual_checksum
 
-        self._store_file(self.file_id, lines, self.file_parents)
+        self.editor._store_file(self.file_id, lines, self.file_parents)
 
         assert self.is_symlink in (True, False)
 
-        if self.file_id in self.inventory:
-            del self.inventory[self.file_id]
+        if self.file_id in self.editor.inventory:
+            del self.editor.inventory[self.file_id]
 
         if self.is_symlink:
-            ie = self.inventory.add_path(path, 'symlink', self.file_id)
+            ie = self.editor.inventory.add_path(self.path, 'symlink', self.file_id)
             ie.symlink_target = lines[0][len("link "):]
             ie.text_sha1 = None
             ie.text_size = None
             ie.executable = False
-            ie.revision = self.revid
+            ie.revision = self.editor.revid
         else:
-            ie = self.inventory.add_path(path, 'file', self.file_id)
-            ie.revision = self.revid
+            ie = self.editor.inventory.add_path(self.path, 'file', self.file_id)
+            ie.revision = self.editor.revid
             ie.kind = 'file'
             ie.symlink_target = None
             ie.text_sha1 = osutils.sha_strings(lines)
@@ -380,40 +427,8 @@
             if self.is_executable is not None:
                 ie.executable = self.is_executable
 
-
         self.file_stream = None
 
-    def close_edit(self):
-        assert len(self._premature_deletes) == 0
-        self._finish_commit()
-
-    def apply_textdelta(self, file_id, base_checksum):
-        actual_checksum = md5.new(self.file_data).hexdigest(),
-        assert (base_checksum is None or base_checksum == actual_checksum,
-            "base checksum mismatch: %r != %r" % (base_checksum, 
-                                                  actual_checksum))
-        self.file_stream = StringIO()
-        return apply_txdelta_handler(self.file_data, self.file_stream)
-
-    def _store_file(self, file_id, lines, parents):
-        raise NotImplementedError(self._store_file)
-
-    def _store_directory(self, file_id, parents):
-        raise NotImplementedError(self._store_directory)
-
-    def _get_file_data(self, file_id, revid):
-        raise NotImplementedError(self._get_file_data)
-
-    def _finish_commit(self):
-        raise NotImplementedError(self._finish_commit)
-
-    def abort_edit(self):
-        pass
-
-    def _start_revision(self):
-        pass
-
-
 class WeaveRevisionBuildEditor(RevisionBuildEditor):
     """Subversion commit editor that can write to a weave-based repository.
     """
@@ -451,7 +466,7 @@
         self.target.commit_write_group()
         self._write_group_active = False
 
-    def abort_edit(self):
+    def abort(self):
         if self._write_group_active:
             self.target.abort_write_group()
             self._write_group_active = False
@@ -489,7 +504,7 @@
     :param repository: Repository to obtain the buildeditor for.
     :return: Class object of class descending from RevisionBuildEditor
     """
-    if hasattr(repository, '_packs'):
+    if getattr(repository, '_packs', None):
         return PackRevisionBuildEditor
     return WeaveRevisionBuildEditor
 
@@ -671,7 +686,7 @@
                             if not conn.is_busy():
                                 self.source.transport.add_connection(conn)
                 except:
-                    editor.abort_edit()
+                    editor.abort()
                     raise
 
                 prev_inv = editor.inventory

=== modified file 'logwalker.py'
--- a/logwalker.py	2008-06-17 21:03:10 +0000
+++ b/logwalker.py	2008-06-19 13:58:42 +0000
@@ -403,47 +403,42 @@
         finally:
             self._transport.connections.add(conn)
 
-        class TreeLister(svn.delta.Editor):
+        class DirTreeLister:
+            def __init__(self, tree, path):
+                self.tree = tree
+                self.path = path
+
+            def change_prop(self, name, value):
+                pass
+
+            def close(self):
+                pass
+
+            def add_directory(self, path, copyfrom_path=None, copyfrom_revnum=-1):
+                """See Editor.add_directory()."""
+                self.tree.files.append(urlutils.join(self.tree.base, path))
+                return DirTreeLister(self.tree, path)
+
+            def add_file(self, path, copyfrom_path=None, copyfrom_revnum=-1):
+                self.tree.files.append(urlutils.join(self.tree.base, path))
+                return None
+
+        class TreeLister:
             def __init__(self, base):
                 self.files = []
                 self.base = base
 
-            def set_target_revision(self, revnum):
-                """See Editor.set_target_revision()."""
+            def set_target_revision(self, rev):
                 pass
 
-            def open_root(self, revnum, baton):
+            def open_root(self, revnum):
                 """See Editor.open_root()."""
-                return path
-
-            def add_directory(self, path, parent_baton, copyfrom_path, copyfrom_revnum, pool):
-                """See Editor.add_directory()."""
-                self.files.append(urlutils.join(self.base, path))
-                return path
-
-            def change_dir_prop(self, id, name, value, pool):
-                pass
-
-            def change_file_prop(self, id, name, value, pool):
-                pass
-
-            def add_file(self, path, parent_id, copyfrom_path, copyfrom_revnum, baton):
-                self.files.append(urlutils.join(self.base, path))
-                return path
-
-            def close_dir(self, id):
-                pass
-
-            def close_file(self, path, checksum):
-                pass
-
-            def close_edit(self):
-                pass
-
-            def abort_edit(self):
-                pass
-
-            def apply_textdelta(self, file_id, base_checksum):
+                return DirTreeLister(self, path)
+
+            def close(self):
+                pass
+
+            def abort(self):
                 pass
 
         editor = TreeLister(path)

=== modified file 'ra.py'
--- a/ra.py	2008-06-18 11:58:24 +0000
+++ b/ra.py	2008-06-19 13:58:42 +0000
@@ -58,11 +58,11 @@
 get_ssl_client_cert_file_provider = svn.client.get_ssl_client_cert_file_provider
 get_ssl_client_cert_pw_file_provider = svn.client.get_ssl_client_cert_pw_file_provider
 get_ssl_server_trust_file_provider = svn.client.get_ssl_server_trust_file_provider
-if hasattr(svn.client, 'get_windows_simple_provider'):
+if getattr(svn.client, 'get_windows_simple_provider', None):
     get_windows_simple_provider = svn.client.get_windows_simple_provider
-if hasattr(svn.client, 'get_keychain_simple_provider'):
+if getattr(svn.client, 'get_keychain_simple_provider', None):
     get_keychain_simple_provider = svn.client.get_keychain_simple_provider
-if hasattr(svn.client, 'get_windows_ssl_server_trust_provider'):
+if getattr(svn.client, 'get_windows_ssl_server_trust_provider', None):
     get_windows_ssl_server_trust_provider = svn.client.get_windows_ssl_server_trust_provider
 
 txdelta_send_stream = svn.delta.svn_txdelta_send_stream
@@ -117,8 +117,7 @@
 
     def open_file(self, path, base_revision=-1):
         assert self.base_editor.recent_baton[-1] == self.baton
-        baton = svn.delta.editor_invoke_open_file(self.base_editor.editor, path, self.baton,
-                                                 base_revision)
+        baton = svn.delta.editor_invoke_open_file(self.base_editor.editor, path, self.baton, base_revision)
         self.base_editor.recent_baton.append(baton)
         return FileEditor(self.base_editor, baton)
 
@@ -204,52 +203,61 @@
         self.actual = actual
 
     def set_target_revision(self, revision):
-        if getattr(self.actual, "set_target_revision", None) is not None:
-            self.actual.set_target_revision(revision)
-
-    def open_root(self, base_revision):
-        if getattr(self.actual, "open_root", None) is not None:
-            return self.actual.open_root(base_revision)
-        return None
-
-    def add_directory(self, path, baton, copyfrom_path, copyfrom_rev):
-        if baton is not None and getattr(baton, "add_directory", None) is not None:
+        self.actual.set_target_revision(revision)
+
+    def open_root(self, base_revision, pool):
+        return self.actual.open_root(base_revision)
+
+    def add_directory(self, path, baton, copyfrom_path, copyfrom_rev, pool):
+        if baton is not None:
             return baton.add_directory(path, copyfrom_path, copyfrom_rev)
         return None
 
-    def open_directory(self, path, baton, base_rev):
-        if baton is not None and getattr(baton, "open_directory", None) is not None:
+    def add_file(self, path, baton, copyfrom_path, copyfrom_rev, pool):
+        if baton is not None:
+            return baton.add_file(path, copyfrom_path, copyfrom_rev)
+        return None
+
+    def delete_entry(self, path, revnum, baton, pool):
+        if baton is not None:
+            return baton.delete_entry(path, revnum)
+        return None
+
+    def open_directory(self, path, baton, base_rev, pool):
+        if baton is not None:
             return baton.open_directory(path, base_rev)
         return None
 
     def close_directory(self, baton):
-        if baton is not None and getattr(baton, "close", None) is not None:
+        if baton is not None:
             return baton.close()
 
-    def change_file_prop(self, baton, name, value):
-        if baton is not None and getattr(baton, "change_prop", None) is not None:
+    def change_file_prop(self, baton, name, value, pool):
+        if baton is not None:
             return baton.change_prop(name, value)
 
-    def change_dir_prop(self, baton, name, value):
-        if baton is not None and getattr(baton, "change_prop", None) is not None:
+    def change_dir_prop(self, baton, name, value, pool):
+        if baton is not None:
             return baton.change_prop(name, value)
 
     def apply_textdelta(self, baton, checksum):
-        if baton is not None and getattr(baton, "apply_textdelta", None) is not None:
+        if baton is not None:
             return baton.apply_textdelta(checksum)
 
     def close_file(self, baton, checksum):
-        if baton is not None and getattr(baton, "close", None) is not None:
+        if baton is not None:
             return baton.close(checksum)
 
-    def open_file(self, path, baton, base_rev):
-        if baton is not None and getattr(self.actual, "open_file", None) is not None:
+    def open_file(self, path, baton, base_rev, pool):
+        if baton is not None:
             return baton.open_file(path, base_rev)
         return None
 
     def close_edit(self):
-        if getattr(self.actual, "close_edit", None) is not None:
-            self.actual.close_edit()
+        self.actual.close()
+
+    def abort_edit(self):
+        self.actual.abort()
 
 
 class RemoteAccess(object):
@@ -344,7 +352,9 @@
         return svn.ra.get_latest_revnum(self._ra)
 
     def _make_editor(self, editor):
-        edit, edit_baton = svn.delta.make_editor(editor, None)
+        global cureditor # svn.delta.make_editor() doesn't increment the reference counter
+        cureditor = WrappedEditor(editor)
+        edit, edit_baton = svn.delta.make_editor(cureditor, None)
         self._edit = edit
         self._edit_baton = edit_baton
         return self._edit, self._edit_baton
@@ -376,7 +386,7 @@
         assert len(path) == 0 or path[0] != "/"
         # ra_dav backends fail with strange errors if the path starts with a 
         # slash while other backends don't.
-        if hasattr(svn.ra, 'get_dir2'):
+        if getattr(svn.ra, 'get_dir2', None):
             fields = 0
             if kind:
                 fields += DIRENT_KIND
@@ -427,7 +437,7 @@
     def get_commit_editor(self, revprops, done_cb=None, lock_token=None, keep_locks=False):
         self._mark_busy()
         try:
-            if hasattr(svn.ra, 'get_commit_editor3'):
+            if getattr(svn.ra, 'get_commit_editor3', None):
                 editor = svn.ra.get_commit_editor3(self._ra, revprops, done_cb, 
                                                   lock_token, keep_locks)
             elif revprops.keys() != [properties.PROP_REVISION_LOG]:
@@ -468,7 +478,7 @@
              svn.core.SVN_VER_REVISION < 31470 and svn.core.SVN_VER_REVISION != 0))):
             paths = ["/"]
         self.mutter('svn log %r:%r %r (limit: %r)', from_revnum, to_revnum, paths, limit)
-        if hasattr(svn.ra, 'get_log2'):
+        if getattr(svn.ra, 'get_log2', None):
             return svn.ra.get_log2(self._ra, paths, 
                            from_revnum, to_revnum, limit, 
                            discover_changed_paths, strict_node_history, False, 
@@ -500,7 +510,7 @@
     def reparent(self, url):
         if self.url == url:
             return
-        if hasattr(svn.ra, 'reparent'):
+        if getattr(svn.ra, 'reparent', None):
             self.mutter('svn reparent %r', url)
             svn.ra.reparent(self._ra, url)
             self.url = url

=== modified file 'revspec.py'
--- a/revspec.py	2008-03-24 04:52:30 +0000
+++ b/revspec.py	2008-06-19 13:58:42 +0000
@@ -34,7 +34,7 @@
 
     def _match_on(self, branch, revs):
         loc = self.spec.find(':')
-        if not hasattr(branch.repository, 'uuid'):
+        if not getattr(branch.repository, 'uuid', None):
             raise BzrError("the svn: revisionspec can only be used with Subversion branches")
         try:
             return RevisionInfo.from_revision_id(branch, branch.generate_revision_id(int(self.spec[loc+1:])), branch.revision_history())

=== modified file 'tree.py'
--- a/tree.py	2008-06-18 11:58:24 +0000
+++ b/tree.py	2008-06-19 13:58:42 +0000
@@ -130,21 +130,33 @@
     def set_target_revision(self, revnum):
         self.revnum = revnum
 
-    def open_root(self, revnum, baton):
+    def open_root(self, revnum):
         file_id, revision_id = self.tree.id_map[""]
         ie = self.tree._inventory.add_path("", 'directory', file_id)
         ie.revision = revision_id
         self.tree._inventory.revision_id = revision_id
-        return file_id
-
-    def add_directory(self, path, parent_baton, copyfrom_path, copyfrom_revnum, pool):
+        return DirectoryTreeEditor(self.tree, file_id)
+
+    def close(self):
+        pass
+
+    def abort(self):
+        pass
+
+
+class DirectoryTreeEditor:
+    def __init__(self, tree, file_id):
+        self.tree = tree
+        self.file_id = file_id
+
+    def add_directory(self, path, copyfrom_path=None, copyfrom_revnum=-1):
         path = path.decode("utf-8")
         file_id, revision_id = self.tree.id_map[path]
         ie = self.tree._inventory.add_path(path, 'directory', file_id)
         ie.revision = revision_id
-        return file_id
+        return DirectoryTreeEditor(self.tree, file_id)
 
-    def change_dir_prop(self, id, name, value, pool):
+    def change_prop(self, name, value):
         if name in (properties.PROP_ENTRY_COMMITTED_DATE,
                     properties.PROP_ENTRY_LAST_AUTHOR,
                     properties.PROP_ENTRY_LOCK_TOKEN,
@@ -158,7 +170,25 @@
         elif name.startswith(properties.PROP_PREFIX):
             mutter('unsupported dir property %r', name)
 
-    def change_file_prop(self, id, name, value, pool):
+    def add_file(self, path, copyfrom_path=None, copyfrom_revnum=-1):
+        path = path.decode("utf-8")
+        self.is_symlink = False
+        self.is_executable = False
+        return FileTreeEditor(self.tree, path)
+
+    def close(self):
+        pass
+
+
+class FileTreeEditor:
+    def __init__(self, tree, path):
+        self.tree = tree
+        self.path = path
+        self.is_executable = False
+        self.is_symlink = False
+        self.last_file_rev = None
+
+    def change_prop(self, name, value):
         if name == properties.PROP_EXECUTABLE:
             self.is_executable = (value != None)
         elif name == properties.PROP_SPECIAL:
@@ -178,21 +208,12 @@
         elif name.startswith(properties.PROP_PREFIX):
             mutter('unsupported file property %r', name)
 
-    def add_file(self, path, parent_id, copyfrom_path, copyfrom_revnum, baton):
-        path = path.decode("utf-8")
-        self.is_symlink = False
-        self.is_executable = False
-        return path
-
-    def close_directory(self, id):
-        pass
-
-    def close_file(self, path, checksum):
-        file_id, revision_id = self.tree.id_map[path]
+    def close(self, checksum=None):
+        file_id, revision_id = self.tree.id_map[self.path]
         if self.is_symlink:
-            ie = self.tree._inventory.add_path(path, 'symlink', file_id)
+            ie = self.tree._inventory.add_path(self.path, 'symlink', file_id)
         else:
-            ie = self.tree._inventory.add_path(path, 'file', file_id)
+            ie = self.tree._inventory.add_path(self.path, 'file', file_id)
         ie.revision = revision_id
 
         if self.file_stream:
@@ -219,13 +240,7 @@
 
         self.file_stream = None
 
-    def close_edit(self):
-        pass
-
-    def abort_edit(self):
-        pass
-
-    def apply_textdelta(self, file_id, base_checksum):
+    def apply_textdelta(self, base_checksum):
         self.file_stream = StringIO()
         return apply_txdelta_handler("", self.file_stream)
 




More information about the bazaar-commits mailing list