Merge property changes from 0.4.
authorJelmer Vernooij <jelmer@samba.org>
Thu, 5 Jun 2008 17:34:37 +0000 (19:34 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Thu, 5 Jun 2008 17:34:37 +0000 (19:34 +0200)
1  2 
commit.py
config.py
constants.py
fetch.py
mapping.py
mapping3/__init__.py
transport.py
tree.py
workingtree.py

diff --cc commit.py
index c6f5b064072528602bf394ee6b301f2a02777499,6dd1863b9beb84d5718af1f26b6ce1d09e66dfff..916be849836b977495c0981794f23178934a39f6
+++ b/commit.py
@@@ -28,11 -28,9 +28,11 @@@ from bzrlib.repository import RootCommi
  from bzrlib.revision import NULL_REVISION
  from bzrlib.trace import mutter, warning
  
- from bzrlib.plugins.svn import util
+ from bzrlib.plugins.svn import properties
  
  from cStringIO import StringIO
 +
 +from bzrlib.plugins.svn import constants
  from bzrlib.plugins.svn.errors import ChangesRootLHSHistory, MissingPrefix, RevpropChangeFailed
  from bzrlib.plugins.svn.svk import (generate_svk_feature, serialize_svk_features, 
                   parse_svk_features, SVN_PROP_SVK_MERGE)
@@@ -277,13 -277,14 +277,13 @@@ class SvnCommitBuilder(RootCommitBuilde
                  old_special = False
                  old_executable = False
  
 -            if child_baton is not None:
 +            if child_editor is not None:
                  if old_executable != child_ie.executable:
                      if child_ie.executable:
-                         value = constants.PROP_EXECUTABLE_VALUE
+                         value = properties.PROP_EXECUTABLE_VALUE
                      else:
                          value = None
-                     child_editor.change_prop(constants.PROP_EXECUTABLE, value)
 -                    self.editor.change_file_prop(child_baton, 
 -                            properties.PROP_EXECUTABLE, value, self.pool)
++                    child_editor.change_prop(properties.PROP_EXECUTABLE, value)
  
                  if old_special != (child_ie.kind == 'symlink'):
                      if child_ie.kind == 'symlink':
                      else:
                          value = None
  
-                     child_editor.change_prop(constants.PROP_SPECIAL, value)
 -                    self.editor.change_file_prop(child_baton, 
 -                            properties.PROP_SPECIAL, value, self.pool)
++                    child_editor.change_prop(properties.PROP_SPECIAL, value)
  
              # handle the file
              if child_ie.file_id in self.modified_files:
          try:
              existing_bp_parts = _check_dirs_exist(self.repository.transport, 
                                                bp_parts, -1)
 -            self.revision_metadata = None
              for prop in self._svn_revprops:
-                 if not util.is_valid_property_name(prop):
+                 if not properties.is_valid_property_name(prop):
                      warning("Setting property %r with invalid characters in name" % prop)
 +            conn = self.repository.transport.get_connection()
              try:
 -                self.editor = self.repository.transport.get_commit_editor(
 -                        self._svn_revprops, done, None, False)
 -                self._svn_revprops = {}
 -            except NotImplementedError:
 -                if set_revprops:
 -                    raise
 -                # Try without bzr: revprops
 -                self.editor = self.repository.transport.get_commit_editor({
 -                    properties.PROP_REVISION_LOG: self._svn_revprops[properties.PROP_REVISION_LOG]},
 -                    done, None, False)
 -                del self._svn_revprops[properties.PROP_REVISION_LOG]
 -
 -            root = self.editor.open_root(self.base_revnum)
 -
 -            replace_existing = False
 -            # See whether the base of the commit matches the lhs parent
 -            # if not, we need to replace the existing directory
 -            if len(bp_parts) == len(existing_bp_parts):
 -                if self.base_path.strip("/") != "/".join(bp_parts).strip("/"):
 -                    replace_existing = True
 -                elif self.base_revnum < self.repository._log.find_latest_change(self.branch.get_branch_path(), repository_latest_revnum):
 -                    replace_existing = True
 -
 -            if replace_existing and self.branch._get_append_revisions_only():
 -                raise AppendRevisionsOnlyViolation(self.branch.base)
 -
 -            # TODO: Accept create_prefix argument (#118787)
 -            branch_batons = self.open_branch_batons(root, bp_parts,
 -                existing_bp_parts, self.base_path, self.base_revnum, 
 -                replace_existing)
 -
 -            self._dir_process("", self.new_inventory.root.file_id, 
 -                branch_batons[-1])
 -
 -            # Set all the revprops
 -            for prop, value in self._svnprops.items():
 -                if not properties.is_valid_property_name(prop):
 -                    warning("Setting property %r with invalid characters in name" % prop)
 -                if value is not None:
 -                    value = value.encode('utf-8')
 -                self.editor.change_dir_prop(branch_batons[-1], prop, value, 
 -                                            self.pool)
 -                self.mutter("Setting root file property %r -> %r" % (prop, value))
 -
 -            for baton in reversed(branch_batons):
 -                self.editor.close_directory(baton, self.pool)
 -
 -            self.editor.close()
 +                try:
 +                    self.editor = conn.get_commit_editor(
 +                            self._svn_revprops, done, None, False)
 +                    self._svn_revprops = {}
 +                except NotImplementedError:
 +                    if set_revprops:
 +                        raise
 +                    # Try without bzr: revprops
 +                    self.editor = conn.get_commit_editor({
-                         constants.PROP_REVISION_LOG: self._svn_revprops[constants.PROP_REVISION_LOG]},
++                        properties.PROP_REVISION_LOG: self._svn_revprops[properties.PROP_REVISION_LOG]},
 +                        done, None, False)
-                     del self._svn_revprops[constants.PROP_REVISION_LOG]
++                    del self._svn_revprops[properties.PROP_REVISION_LOG]
 +
 +                root = self.editor.open_root(self.base_revnum)
 +
 +                replace_existing = False
 +                # See whether the base of the commit matches the lhs parent
 +                # if not, we need to replace the existing directory
 +                if len(bp_parts) == len(existing_bp_parts):
 +                    if self.base_path.strip("/") != "/".join(bp_parts).strip("/"):
 +                        replace_existing = True
 +                    elif self.base_revnum < self.repository._log.find_latest_change(self.branch.get_branch_path(), repository_latest_revnum):
 +                        replace_existing = True
 +
 +                if replace_existing and self.branch._get_append_revisions_only():
 +                    raise AppendRevisionsOnlyViolation(self.branch.base)
 +
 +                # TODO: Accept create_prefix argument (#118787)
 +                branch_editors = self.open_branch_editors(root, bp_parts,
 +                    existing_bp_parts, self.base_path, self.base_revnum, 
 +                    replace_existing)
 +
 +                self._dir_process("", self.new_inventory.root.file_id, 
 +                    branch_editors[-1])
 +
 +                # Set all the revprops
 +                for prop, value in self._svnprops.items():
 +                    if not util.is_valid_property_name(prop):
 +                        warning("Setting property %r with invalid characters in name" % prop)
 +                    if value is not None:
 +                        value = value.encode('utf-8')
 +                    branch_editors[-1].change_prop(prop, value)
 +                    self.mutter("Setting root file property %r -> %r" % (prop, value))
 +
 +                for dir_editor in reversed(branch_editors):
 +                    dir_editor.close()
 +
 +                self.editor.close()
 +            finally:
 +                self.repository.transport.add_connection(conn)
          finally:
              lock.unlock()
  
          override_svn_revprops = self._config.get_override_svn_revprops()
          if override_svn_revprops is not None:
              new_revprops = {}
-             if constants.PROP_REVISION_AUTHOR in override_svn_revprops:
-                 new_revprops[constants.PROP_REVISION_AUTHOR] = self._committer.encode("utf-8")
-             if constants.PROP_REVISION_DATE in override_svn_revprops:
-                 new_revprops[constants.PROP_REVISION_DATE] = time_to_cstring(1000000*self._timestamp)
+             if properties.PROP_REVISION_AUTHOR in override_svn_revprops:
+                 new_revprops[properties.PROP_REVISION_AUTHOR] = self._committer.encode("utf-8")
+             if properties.PROP_REVISION_DATE in override_svn_revprops:
 -                new_revprops[properties.PROP_REVISION_DATE] = svn_time_to_cstring(1000000*self._timestamp)
++                new_revprops[properties.PROP_REVISION_DATE] = time_to_cstring(1000000*self._timestamp)
              set_svn_revprops(self.repository.transport, self.revision_metadata.revision, new_revprops)
  
          try:
diff --cc config.py
index 51a632a60b37a6b485548392c28a73d745dd5f33,7285d4b0d88825cb546c7e861484a90e172de06d..090e6e178d570bbd60634833fd34c1c82d29857b
+++ b/config.py
  from bzrlib import osutils, urlutils, trace
  from bzrlib.config import IniBasedConfig, config_dir, ensure_config_dir_exists, GlobalConfig, LocationConfig, Config, STORE_BRANCH, STORE_GLOBAL, STORE_LOCATION
  
 +from bzrlib.plugins.svn.core import SubversionException
 +
  import os
  
 -import svn.core
 -
+ from bzrlib.plugins.svn import properties
  # Settings are stored by UUID. 
  # Data stored includes default branching scheme and locations the repository 
  # was seen at.
diff --cc constants.py
index 1e0df8eac5d7c39b24caa92baecba8bbe4058f8e,0000000000000000000000000000000000000000..5b63af18f58332eefe577e89937d18ba6853c155
mode 100644,000000..100644
--- /dev/null
@@@ -1,67 -1,0 +1,45 @@@
- PROP_EXECUTABLE = 'svn:executable'
- PROP_EXECUTABLE_VALUE = '*'
- PROP_EXTERNALS = 'svn:externals'
- PROP_IGNORE = 'svn:ignore'
- PROP_KEYWORDS = 'svn:keywords'
- PROP_MIME_TYPE = 'svn:mime-type'
- PROP_NEEDS_LOCK = 'svn:needs-lock'
- PROP_NEEDS_LOCK_VALUE = '*'
- PROP_PREFIX = 'svn:'
- PROP_SPECIAL = 'svn:special'
- PROP_SPECIAL_VALUE = '*'
- PROP_WC_PREFIX = 'svn:wc:'
- PROP_ENTRY_COMMITTED_DATE = 'svn:entry:committed-date'
- PROP_ENTRY_COMMITTED_REV = 'svn:entry:committed-rev'
- PROP_ENTRY_LAST_AUTHOR = 'svn:entry:last-author'
- PROP_ENTRY_LOCK_TOKEN = 'svn:entry:lock-token'
- PROP_ENTRY_UUID = 'svn:entry:uuid'
- PROP_REVISION_LOG = "svn:log"
- PROP_REVISION_AUTHOR = "svn:author"
- PROP_REVISION_DATE = "svn:date"
 +# Copyright (C) 2005-2008 Jelmer Vernooij <jelmer@samba.org>
 + 
 +# This program is free software; you can redistribute it and/or modify
 +# it under the terms of the GNU General Public License as published by
 +# the Free Software Foundation; either version 3 of the License, or
 +# (at your option) any later version.
 +
 +# This program is distributed in the hope that it will be useful,
 +# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +# GNU General Public License for more details.
 +
 +# You should have received a copy of the GNU General Public License
 +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +
 +ERR_UNKNOWN_HOSTNAME = 670002
 +ERR_RA_SVN_CONNECTION_CLOSED = 210002
 +ERR_WC_LOCKED = 155004
 +ERR_RA_NOT_AUTHORIZED = 170001
 +ERR_INCOMPLETE_DATA = 200003
 +ERR_RA_SVN_MALFORMED_DATA = 210004
 +ERR_RA_NOT_IMPLEMENTED = 170003
 +ERR_FS_NO_SUCH_REVISION = 160006
 +ERR_FS_TXN_OUT_OF_DATE = 160028
 +ERR_REPOS_DISABLED_FEATURE = 165006
 +ERR_STREAM_MALFORMED_DATA = 140001
 +ERR_RA_ILLEGAL_URL = 170000
 +ERR_RA_LOCAL_REPOS_OPEN_FAILED = 180001
 +ERR_BAD_URL = 125002
 +ERR_RA_DAV_REQUEST_FAILED = 175002
 +ERR_FS_NOT_DIRECTORY = 160016
 +ERR_FS_NOT_FOUND = 160013
 +ERR_FS_ALREADY_EXISTS = 160020
 +ERR_RA_SVN_REPOS_NOT_FOUND = 210005
 +ERR_WC_NOT_DIRECTORY = 155007
 +ERR_ENTRY_EXISTS = 150002
 +ERR_WC_PATH_NOT_FOUND = 155010
 +ERR_CANCELLED = 200015
 +ERR_WC_UNSUPPORTED_FORMAT = 155021
 +
 +AUTH_SSL_NOTYETVALID = 0x00000001
 +AUTH_SSL_EXPIRED     = 0x00000002
 +AUTH_SSL_CNMISMATCH  = 0x00000004
 +AUTH_SSL_UNKNOWNCA   = 0x00000008
 +AUTH_SSL_OTHER       = 0x40000000
diff --cc fetch.py
index 16f17f34b03eb57b54fa7246615282061bf306ae,fc91a59c3b077aff790d8dfae7a57cce188f9b8b..720df1a28b693c996d228ab1bd4e6c9d35536ec8
+++ b/fetch.py
@@@ -25,9 -25,10 +25,10 @@@ from bzrlib.trace import mutte
  from cStringIO import StringIO
  import md5
  
 -from svn.core import Pool
 -import svn.core
 +import constants
  
 +from bzrlib.plugins.svn.delta import apply_txdelta_handler
+ from bzrlib.plugins.svn import properties
  from bzrlib.plugins.svn.errors import InvalidFileName
  from bzrlib.plugins.svn.logwalker import lazy_dict
  from bzrlib.plugins.svn.mapping import (SVN_PROP_BZR_MERGE, 
@@@ -266,123 -249,54 +267,123 @@@ class DirectoryBuildEditor
              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 (constants.PROP_ENTRY_COMMITTED_DATE,
-                     constants.PROP_ENTRY_COMMITTED_REV,
-                     constants.PROP_ENTRY_LAST_AUTHOR,
-                     constants.PROP_ENTRY_LOCK_TOKEN,
-                     constants.PROP_ENTRY_UUID,
-                     constants.PROP_EXECUTABLE):
+         if name in (properties.PROP_ENTRY_COMMITTED_DATE,
+                     properties.PROP_ENTRY_COMMITTED_REV,
+                     properties.PROP_ENTRY_LAST_AUTHOR,
+                     properties.PROP_ENTRY_LOCK_TOKEN,
+                     properties.PROP_ENTRY_UUID,
+                     properties.PROP_EXECUTABLE):
              pass
-         elif (name.startswith(constants.PROP_WC_PREFIX)):
+         elif (name.startswith(properties.PROP_WC_PREFIX)):
              pass
-         elif name.startswith(constants.PROP_PREFIX):
+         elif name.startswith(properties.PROP_PREFIX):
              mutter('unsupported dir property %r' % name)
  
 -    def change_file_prop(self, id, name, value, pool):
 -        if name == properties.PROP_EXECUTABLE: 
 +    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 == constants.PROP_EXECUTABLE: 
              # You'd expect executable to match 
 -            # properties.PROP_EXECUTABLE_VALUE, but that's not 
 +            # constants.PROP_EXECUTABLE_VALUE, but that's not 
              # how SVN behaves. It appears to consider the presence 
              # of the property sufficient to mark it executable.
              self.is_executable = (value != None)
-         elif (name == constants.PROP_SPECIAL):
+         elif (name == properties.PROP_SPECIAL):
              self.is_symlink = (value != None)
-         elif name == constants.PROP_ENTRY_COMMITTED_REV:
+         elif name == properties.PROP_ENTRY_COMMITTED_REV:
              self.last_file_rev = int(value)
-         elif name in (constants.PROP_ENTRY_COMMITTED_DATE,
-                       constants.PROP_ENTRY_LAST_AUTHOR,
-                       constants.PROP_ENTRY_LOCK_TOKEN,
-                       constants.PROP_ENTRY_UUID,
-                       constants.PROP_MIME_TYPE):
 -        elif name == properties.PROP_EXTERNALS:
 -            mutter('svn:externals property on file!')
+         elif name in (properties.PROP_ENTRY_COMMITTED_DATE,
+                       properties.PROP_ENTRY_LAST_AUTHOR,
+                       properties.PROP_ENTRY_LOCK_TOKEN,
+                       properties.PROP_ENTRY_UUID,
+                       properties.PROP_MIME_TYPE):
              pass
-         elif name.startswith(constants.PROP_WC_PREFIX):
+         elif name.startswith(properties.PROP_WC_PREFIX):
              pass
-         elif name == constants.PROP_EXTERNALS:
++        elif name == properties.PROP_EXTERNALS:
 +            mutter('svn:externals property on file!')
-         elif (name.startswith(constants.PROP_PREFIX) or
+         elif (name.startswith(properties.PROP_PREFIX) or
                name.startswith(SVN_PROP_BZR_PREFIX)):
              mutter('unsupported file property %r' % name)
  
diff --cc mapping.py
index f2e502af7811606f4926d04b05b1c8540e2b883e,4ef06563538e0b0914bcd7814b9a7530979fd3e9..8705cd294be16d993e3cd3e3c5508f301b1a67f9
@@@ -19,9 -19,9 +19,9 @@@ from bzrlib import osutils, registr
  from bzrlib.errors import InvalidRevisionId
  from bzrlib.trace import mutter
  
- from bzrlib.plugins.svn import core, constants, version_info, constants, errors
 -from bzrlib.plugins.svn import version_info, errors, properties
++from bzrlib.plugins.svn import core, constants, version_info, constants, errors, properties
  import calendar
 -import svn
 +import sha
  import time
  import urllib
  
@@@ -150,8 -150,8 +150,8 @@@ def parse_svn_revprops(svn_revprops, re
          except UnicodeDecodeError:
              pass
  
-     if svn_revprops.has_key(constants.PROP_REVISION_DATE):
-         rev.timestamp = core.time_from_cstring(svn_revprops[constants.PROP_REVISION_DATE]) / 1000000.0
+     if svn_revprops.has_key(properties.PROP_REVISION_DATE):
 -        rev.timestamp = 1.0 * svn.core.secs_from_timestr(svn_revprops[properties.PROP_REVISION_DATE], None)
++        rev.timestamp = core.time_from_cstring(svn_revprops[properties.PROP_REVISION_DATE]) / 1000000.0
      else:
          rev.timestamp = 0.0 # FIXME: Obtain repository creation time
      rev.timezone = None
index 881ca7f1cca22bb3ee22892ece62554cd37709f1,623ca019b01a217871697355e966489819f857d8..08393a851c38468e18b16eeb4364a01c46e730e0
@@@ -16,7 -16,7 +16,7 @@@
  from bzrlib import osutils, ui
  from bzrlib.errors import InvalidRevisionId
  from bzrlib.trace import mutter
- from bzrlib.plugins.svn import core, constants, mapping
 -from bzrlib.plugins.svn import mapping, properties
++from bzrlib.plugins.svn import core, constants, mapping, properties
  from bzrlib.plugins.svn.layout import RepositoryLayout
  from bzrlib.plugins.svn.mapping3.scheme import (BranchingScheme, guess_scheme_from_branch_path, 
                               guess_scheme_from_history, ListBranchingScheme, 
diff --cc transport.py
index 95c7c2f33633901d3c44b281837c079152625848,bb46ab6ce78be8d1bd7c55607fa8756e88ee0396..c6b71ab5314bae60fc58942f1344f24a19cc0bd2
@@@ -21,12 -21,12 +21,13 @@@ from bzrlib.errors import (NoSuchFile, 
  from bzrlib.trace import mutter
  from bzrlib.transport import Transport
  
 -from svn.core import SubversionException, Pool
 -import svn.ra
 -import svn.core
 -import svn.client
 +from core import SubversionException
 +from auth import create_auth_baton
 +import ra
 +import core
 +import constants
  
+ from bzrlib.plugins.svn import properties
  from bzrlib.plugins.svn.errors import convert_svn_error, NoSvnRepositoryPresent
  import urlparse
  import urllib
diff --cc tree.py
index fc917edaddb738f2721487eb9102d1dbb26967dd,c1ac846b96411aaeb870fa5a9f321eb66f841ece..e1f57ca1605d31075f90ae958c0a623c6de38b93
+++ b/tree.py
@@@ -28,8 -28,10 +28,8 @@@ import md
  from cStringIO import StringIO
  import urllib
  
 -import svn.core, svn.wc, svn.delta
 -from svn.core import Pool
 -
 -from bzrlib.plugins.svn import errors, properties
 +from bzrlib.plugins.svn.delta import apply_txdelta_handler
- from bzrlib.plugins.svn import core, constants, errors, wc
++from bzrlib.plugins.svn import core, constants, errors, wc, properties
  
  def parse_externals_description(base_url, val):
      """Parse an svn:externals property value.
@@@ -154,66 -173,60 +154,66 @@@ class DirectoryTreeEditor
          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):
 -        if name == properties.PROP_ENTRY_COMMITTED_REV:
 -            self.dir_revnum[id] = int(value)
 -        elif name == properties.PROP_IGNORE:
 -            self.dir_ignores[id] = value
 -        elif name in (properties.PROP_ENTRY_COMMITTED_DATE,
 +    def change_prop(self, name, value):
-         if name in (constants.PROP_ENTRY_COMMITTED_DATE,
-                       constants.PROP_ENTRY_COMMITTED_REV,
-                       constants.PROP_ENTRY_LAST_AUTHOR,
-                       constants.PROP_ENTRY_LOCK_TOKEN,
-                       constants.PROP_ENTRY_UUID,
-                       constants.PROP_EXECUTABLE,
-                       constants.PROP_IGNORE):
++        if name in (properties.PROP_ENTRY_COMMITTED_DATE,
++                      properties.PROP_ENTRY_COMMITTED_REV,
+                       properties.PROP_ENTRY_LAST_AUTHOR,
+                       properties.PROP_ENTRY_LOCK_TOKEN,
+                       properties.PROP_ENTRY_UUID,
 -                      properties.PROP_EXECUTABLE):
++                      properties.PROP_EXECUTABLE,
++                      properties.PROP_IGNORE):
              pass
-         elif name.startswith(constants.PROP_WC_PREFIX):
+         elif name.startswith(properties.PROP_WC_PREFIX):
              pass
-         elif name.startswith(constants.PROP_PREFIX):
+         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")
 +        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):
 +        from mapping import SVN_PROP_BZR_PREFIX
 +
-         if name == constants.PROP_EXECUTABLE:
+         if name == properties.PROP_EXECUTABLE:
              self.is_executable = (value != None)
-         elif name == constants.PROP_SPECIAL:
+         elif name == properties.PROP_SPECIAL:
              self.is_symlink = (value != None)
-         elif name == constants.PROP_EXTERNALS:
+         elif name == properties.PROP_EXTERNALS:
              mutter('%r property on file!' % name)
-         elif name == constants.PROP_ENTRY_COMMITTED_REV:
+         elif name == properties.PROP_ENTRY_COMMITTED_REV:
              self.last_file_rev = int(value)
-         elif name in (constants.PROP_ENTRY_COMMITTED_DATE,
-                       constants.PROP_ENTRY_LAST_AUTHOR,
-                       constants.PROP_ENTRY_LOCK_TOKEN,
-                       constants.PROP_ENTRY_UUID,
-                       constants.PROP_MIME_TYPE):
+         elif name in (properties.PROP_ENTRY_COMMITTED_DATE,
+                       properties.PROP_ENTRY_LAST_AUTHOR,
+                       properties.PROP_ENTRY_LOCK_TOKEN,
+                       properties.PROP_ENTRY_UUID,
+                       properties.PROP_MIME_TYPE):
              pass
-         elif name.startswith(constants.PROP_WC_PREFIX):
+         elif name.startswith(properties.PROP_WC_PREFIX):
              pass
-         elif name.startswith(constants.SVN_PROP_PREFIX):
 -        elif name.startswith(properties.PROP_PREFIX):
++        elif name.startswith(properties.SVN_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_dir(self, id):
 -        if id in self.tree._inventory and self.dir_ignores.has_key(id):
 -            self.tree._inventory[id].ignores = self.dir_ignores[id]
 -
 -    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:
@@@ -258,9 -277,11 +258,9 @@@ class SvnBasisTree(RevisionTree)
          self._inventory = Inventory(root_id=None)
          self._repository = workingtree.branch.repository
  
 -        def add_file_to_inv(relpath, id, revid, wc):
 -            props = svn.wc.get_prop_diffs(self.workingtree.abspath(relpath).encode("utf-8"), wc)
 -            if isinstance(props, list): # Subversion 1.5
 -                props = props[1]
 +        def add_file_to_inv(relpath, id, revid, adm):
 +            (delta_props, props) = adm.get_prop_diffs(self.workingtree.abspath(relpath))
-             if props.has_key(constants.PROP_SPECIAL):
+             if props.has_key(properties.PROP_SPECIAL):
                  ie = self._inventory.add_path(relpath, 'symlink', id)
                  ie.symlink_target = open(self._abspath(relpath)).read()[len("link "):]
                  ie.text_sha1 = None
diff --cc workingtree.py
index c9fdb83028d51d36d1c2b70487932862ea4d7eff,7b3f60252e8c203a570e0a2f75b64b1e350694ef..0f51f1c1fbd4ad7b44a950d2b487a65a74abc407
@@@ -31,7 -32,7 +31,7 @@@ from bzrlib.revisiontree import Revisio
  from bzrlib.transport.local import LocalTransport
  from bzrlib.workingtree import WorkingTree, WorkingTreeFormat
  
- from bzrlib.plugins.svn import constants
 -from bzrlib.plugins.svn import properties
++from bzrlib.plugins.svn import constants, properties
  from bzrlib.plugins.svn.branch import SvnBranch
  from bzrlib.plugins.svn.commit import _revision_id_to_svk_feature
  from bzrlib.plugins.svn.convert import SvnConverter
@@@ -96,18 -104,17 +96,18 @@@ class SvnWorkingTree(WorkingTree)
          self._control_files = LockableFiles(control_transport, 'lock', LockDir)
  
      def get_ignore_list(self):
 -        ignores = set([svn.wc.get_adm_dir()])
 -        ignores.update(svn.wc.get_default_ignores(svn_config))
 +        ignore_globs = set([wc.get_adm_dir()])
 +        ignore_globs.update(ignores.get_runtime_ignores())
 +        ignore_globs.update(ignores.get_user_ignores())
  
 -        def dir_add(wc, prefix, patprefix):
 -            ignorestr = svn.wc.prop_get(properties.PROP_IGNORE, 
 -                                        self.abspath(prefix).rstrip("/"), wc)
 +        def dir_add(adm, prefix, patprefix):
-             ignorestr = adm.prop_get(constants.PROP_IGNORE, 
++            ignorestr = adm.prop_get(properties.PROP_IGNORE, 
 +                                    self.abspath(prefix).rstrip("/"))
              if ignorestr is not None:
                  for pat in ignorestr.splitlines():
 -                    ignores.add(urlutils.joinpath(patprefix, pat))
 +                    ignore_globs.add(urlutils.joinpath(patprefix, pat))
  
 -            entries = svn.wc.entries_read(wc, False)
 +            entries = adm.entries_read(False)
              for entry in entries:
                  if entry == "":
                      continue