Merge upstream.
authorJelmer Vernooij <jelmer@samba.org>
Thu, 19 Jun 2008 15:45:18 +0000 (17:45 +0200)
committerJelmer Vernooij <jelmer@samba.org>
Thu, 19 Jun 2008 15:45:18 +0000 (17:45 +0200)
1  2 
tests/__init__.py
tree.py
workingtree.py

diff --combined tests/__init__.py
index b8ba3d30011a9d95f26adbaf04e8427aa8e9f63a,9b6877d57d2359f0c7f1dc3c0312cb9b48ff6010..48204ad958cbe80e7d4c29870d0d19d61551b4fa
@@@ -26,10 -26,11 +26,10 @@@ from bzrlib import osutils, urlutil
  from bzrlib.bzrdir import BzrDir
  from bzrlib.tests import TestCaseInTempDir, TestSkipped
  from bzrlib.trace import mutter
 -from bzrlib.urlutils import local_path_to_url
  from bzrlib.workingtree import WorkingTree
  
 -import svn.core, svn.repos
 -from bzrlib.plugins.svn.ra import RemoteAccess
 +from bzrlib.plugins.svn import repos, wc, client, ra, properties
 +from bzrlib.plugins.svn.ra import RemoteAccess, txdelta_send_stream
  
  class TestCaseWithSubversionRepository(TestCaseInTempDir):
      """A test case that provides the ability to build Subversion 
  
      def setUp(self):
          super(TestCaseWithSubversionRepository, self).setUp()
 -        self.client_ctx = svn.client.create_context()
 -        self.client_ctx.log_msg_func2 = svn.client.svn_swig_py_get_commit_log_func
 -        self.client_ctx.log_msg_baton2 = self.log_message_func
 +        self.client_ctx = client.Client()
 +        self.client_ctx.log_msg_func = self.log_message_func
  
 -    def log_message_func(self, items, pool):
 -        return self.next_message
 +    def log_message_func(self, items):
 +        return (self.next_message, None)
  
      def make_repository(self, relpath, allow_revprop_changes=True):
          """Create a repository.
@@@ -50,7 -52,7 +50,7 @@@
          """
          abspath = os.path.join(self.test_dir, relpath)
  
 -        svn.repos.create(abspath, '', '', None, None)
 +        repos.create(abspath)
  
          if allow_revprop_changes:
              if sys.platform == 'win32':
@@@ -61,7 -63,7 +61,7 @@@
                  open(revprop_hook, 'w').write("#!/bin/sh\n")
                  os.chmod(revprop_hook, os.stat(revprop_hook).st_mode | 0111)
  
 -        return local_path_to_url(abspath)
 +        return urlutils.local_path_to_url(abspath)
  
      def make_remote_bzrdir(self, relpath):
          """Create a repository."""
  
          return self.open_local_bzrdir(repos_url, relpath)
  
      def make_checkout(self, repos_url, relpath):
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_head
 -
 -        svn.client.checkout2(repos_url, relpath, 
 -                rev, rev, True, False, self.client_ctx)
 +        self.client_ctx.checkout(repos_url, relpath, "HEAD", "HEAD", 
 +                                 True, False)
  
      @staticmethod
      def create_checkout(branch, path, revision_id=None, lightweight=False):
      def client_set_prop(self, path, name, value):
          if value is None:
              value = ""
 -        svn.client.propset2(name, value, path, False, True, self.client_ctx)
 +        self.client_ctx.propset(name, value, path, False, True)
  
      def client_get_prop(self, path, name, revnum=None, recursive=False):
 -        rev = svn.core.svn_opt_revision_t()
 -
          if revnum is None:
 -            rev.kind = svn.core.svn_opt_revision_working
 -        else:
 -            rev.kind = svn.core.svn_opt_revision_number
 -            rev.value.number = revnum
 -        ret = svn.client.propget2(name, path, rev, rev, recursive, 
 -                                  self.client_ctx)
 +            revnum = "WORKING"
 +        ret = self.client_ctx.propget(name, path, revnum, revnum, recursive)
          if recursive:
              return ret
          else:
              return ret.values()[0]
  
      def client_get_revprop(self, url, revnum, name):
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_number
 -        rev.value.number = revnum
 -        return svn.client.revprop_get(name, url, rev, self.client_ctx)[0]
 +        return self.client_ctx.revprop_get(name, url, revnum)[0]
  
      def client_set_revprop(self, url, revnum, name, value):
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_number
 -        rev.value.number = revnum
 -        svn.client.revprop_set(name, value, url, rev, True, self.client_ctx)
 +        return self.client_ctx.revprop_set(name, value, url, revnum)
          
      def client_commit(self, dir, message=None, recursive=True):
          """Commit current changes in specified working copy.
          """
          olddir = os.path.abspath('.')
          self.next_message = message
 -        os.chdir(dir)
 -        info = svn.client.commit2(["."], recursive, False, self.client_ctx)
 -        os.chdir(olddir)
 +        info = self.client_ctx.commit([dir], recursive, False)
          assert info is not None
 -        return (info.revision, info.date, info.author)
 +        return info
  
      def client_add(self, relpath, recursive=True):
          """Add specified files to working copy.
          
          :param relpath: Path to the files to add.
          """
 -        svn.client.add3(relpath, recursive, False, False, self.client_ctx)
 +        self.client_ctx.add(relpath, recursive, False, False)
  
 -    def revnum_to_opt_rev(self, revnum):
 -        rev = svn.core.svn_opt_revision_t()
 -        if revnum is None:
 -            rev.kind = svn.core.svn_opt_revision_head
 -        else:
 -            assert isinstance(revnum, int)
 -            rev.kind = svn.core.svn_opt_revision_number
 -            rev.value.number = revnum
 -        return rev
 -
 -    def client_log(self, path, start_revnum=None, stop_revnum=None):
 -        assert isinstance(path, str)
 +    def client_log(self, url, start_revnum=0, stop_revnum=-1):
 +        ra = RemoteAccess(url.encode("utf-8"))
          ret = {}
 -        def rcvr(orig_paths, rev, author, date, message, pool):
 -            ret[rev] = (orig_paths, author, date, message)
 -        svn.client.log([path], self.revnum_to_opt_rev(start_revnum),
 -                       self.revnum_to_opt_rev(stop_revnum),
 -                       True,
 -                       True,
 -                       rcvr,
 -                       self.client_ctx)
 +        def rcvr(orig_paths, rev, revprops):
 +            ret[rev] = (orig_paths, 
 +                        revprops.get(properties.PROP_REVISION_AUTHOR),
 +                        revprops.get(properties.PROP_REVISION_DATE),
 +                        revprops.get(properties.PROP_REVISION_LOG))
 +        if stop_revnum == -1:
 +            stop_revnum = ra.get_latest_revnum()
 +        ra.get_log(rcvr, None, start_revnum, stop_revnum, 0, True, True)
          return ret
  
      def client_delete(self, relpath):
  
          :param relpath: Path to the files to remove.
          """
 -        svn.client.delete2([relpath], True, self.client_ctx)
 +        self.client_ctx.delete([relpath], True)
  
      def client_copy(self, oldpath, newpath, revnum=None):
          """Copy file in working copy.
          :param oldpath: Relative path to original file.
          :param newpath: Relative path to new file.
          """
 -        rev = svn.core.svn_opt_revision_t()
 -        if revnum is None:
 -            rev.kind = svn.core.svn_opt_revision_head
 -        else:
 -            rev.kind = svn.core.svn_opt_revision_number
 -            rev.value.number = revnum
 -        svn.client.copy2(oldpath, rev, newpath, self.client_ctx)
 +        self.client_ctx.copy(oldpath, newpath, revnum)
  
      def client_update(self, path):
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_head
 -        svn.client.update(path, rev, True, self.client_ctx)
 +        self.client_ctx.update([path], None, True)
  
      def build_tree(self, files):
          """Create a directory tree.
  
          :return: FS.
          """
 -        repos = svn.repos.open(relpath)
 -
 -        return svn.repos.fs(repos)
 +        return repos.Repository(relpath).fs()
  
      def commit_editor(self, url, message="Test commit"):
          ra = RemoteAccess(url.encode('utf8'))
                          else:
                              child_baton = dir_baton.open_file(subpath)
                          if isinstance(contents, str):
 -                            (txdelta, txbaton) = child_baton.apply_textdelta()
 -                            svn.delta.svn_txdelta_send_stream(StringIO(contents), txdelta, txbaton)
 +                            txdelta = child_baton.apply_textdelta(None)
 +                            txdelta_send_stream(StringIO(contents), txdelta)
                          if subpath in self.props:
                              for k, v in self.props[subpath].items():
                                  child_baton.change_prop(k, v)
@@@ -352,8 -390,6 +351,8 @@@ def test_suite()
              'test_branchprops', 
              'test_changes',
              'test_checkout',
 +            'test_client',
 +            'test_core',
              'test_commit',
              'test_config',
              'test_convert',
              'test_logwalker',
              'test_mapping',
              'test_push',
 +            'test_ra',
              'test_radir',
              'test_repos', 
 +            'test_repository', 
              'test_revids',
              'test_revspec',
              'test_scheme', 
              'test_transport',
              'test_tree',
              'test_upgrade',
 +            'test_wc',
              'test_workingtree',
              'test_blackbox']
      suite.addTest(loader.loadTestsFromModuleNames(["%s.%s" % (__name__, i) for i in testmod_names]))
diff --combined tree.py
index 9b39c6edbe70eb5c8ba5bdbe7a8ea53187769e66,9306195ec8eb25d9a7c4cee324c81ad960d74871..e74d8589bbf0bf7f44e644992116b70e10271fde
+++ b/tree.py
@@@ -29,8 -29,7 +29,8 @@@ import md
  from cStringIO import StringIO
  import urllib
  
 -from bzrlib.plugins.svn import errors, properties, core, wc
 +from bzrlib.plugins.svn import core, errors, properties, wc
 +from bzrlib.plugins.svn.delta import apply_txdelta_handler
  
  def parse_externals_description(base_url, val):
      """Parse an svn:externals property value.
@@@ -112,11 -111,8 +112,11 @@@ class SvnRevisionTree(RevisionTree)
          reporter = conn.do_switch(
                  self.revnum, "", True, 
                  urlutils.join(root_repos, self.branch_path), editor)
 -        reporter.set_path("", 0, True, None)
 -        reporter.finish()
 +        try:
 +            reporter.set_path("", 0, True)
 +            reporter.finish()
 +        finally:
 +            repository.transport.add_connection(conn)
  
      def get_file_lines(self, file_id):
          return osutils.split_lines(self.file_data[file_id])
@@@ -261,7 -257,7 +261,7 @@@ class SvnBasisTree(RevisionTree)
          self._repository = workingtree.branch.repository
  
          def add_file_to_inv(relpath, id, revid, adm):
-             (delta_props, props) = adm.get_prop_diffs(self.workingtree.abspath(relpath))
+             (propchanges, props) = adm.get_prop_diffs(self.workingtree.abspath(relpath).encode("utf-8"))
              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 "):]
                  
                  if entry.kind == core.NODE_DIR:
                      subwc = wc.WorkingCopy(adm, 
-                             self.workingtree.abspath(subrelpath), 
-                                              False, 0, None)
+                             self.workingtree.abspath(subrelpath))
                      try:
                          add_dir_to_inv(subrelpath, subwc, id)
                      finally:
diff --combined workingtree.py
index fd53dceb82a4a1bd9d9f50c5007617d9e6a2b3c0,06b6823f3905040b1e61b2841cdb0da0084db1c1..acbfcf6e375a61c22f9936f1eb3a80b038e859d4
  """Checkouts and working trees (working copies)."""
  
  import bzrlib, bzrlib.add
 -from bzrlib import osutils, urlutils
 +from bzrlib import osutils, urlutils, ignores
  from bzrlib.branch import PullResult
  from bzrlib.bzrdir import BzrDirFormat, BzrDir
  from bzrlib.errors import (InvalidRevisionId, NotBranchError, NoSuchFile,
                             NoRepositoryPresent, BzrError, UninitializableFormat,
 -                           OutOfDateTree)
 +                           OutOfDateTree, UnsupportedFormatError)
  from bzrlib.inventory import Inventory, InventoryFile, InventoryLink
  from bzrlib.lockable_files import TransportLock, LockableFiles
  from bzrlib.lockdir import LockDir
@@@ -31,37 -31,30 +31,38 @@@ from bzrlib.revisiontree import Revisio
  from bzrlib.transport.local import LocalTransport
  from bzrlib.workingtree import WorkingTree, WorkingTreeFormat
  
- from bzrlib.plugins.svn import core, properties, wc
+ from bzrlib.plugins.svn import core, 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
  from bzrlib.plugins.svn.core import SubversionException, time_to_cstring
 -from bzrlib.plugins.svn.errors import LocalCommitsUnsupported, NoSvnRepositoryPresent, ERR_FS_TXN_OUT_OF_DATE, ERR_ENTRY_EXISTS, ERR_WC_PATH_NOT_FOUND, ERR_WC_NOT_DIRECTORY
 +from bzrlib.plugins.svn.errors import NoSvnRepositoryPresent, ERR_FS_TXN_OUT_OF_DATE, ERR_ENTRY_EXISTS, ERR_WC_PATH_NOT_FOUND, ERR_WC_NOT_DIRECTORY, ERR_WC_UNSUPPORTED_FORMAT
 +from bzrlib.plugins.svn.format import get_rich_root_format
  from bzrlib.plugins.svn.mapping import (SVN_PROP_BZR_ANCESTRY, SVN_PROP_BZR_FILEIDS, 
                       SVN_PROP_BZR_REVISION_ID, SVN_PROP_BZR_REVISION_INFO,
                       escape_svn_path, generate_revision_metadata)
 -from bzrlib.plugins.svn.ra import create_svn_client
  from bzrlib.plugins.svn.remote import SvnRemoteAccess
  from bzrlib.plugins.svn.repository import SvnRepository
  from bzrlib.plugins.svn.svk import SVN_PROP_SVK_MERGE, parse_svk_features, serialize_svk_features
  from bzrlib.plugins.svn.transport import (SvnRaTransport, bzr_to_svn_url, 
                         svn_config) 
  from bzrlib.plugins.svn.tree import SvnBasisTree
+ from bzrlib.plugins.svn.wc import *
  
  import os
  import urllib
  
 -import svn.core
 +def update_wc(adm, basedir, conn, revnum):
 +    # FIXME: honor SVN_CONFIG_SECTION_HELPERS:SVN_CONFIG_OPTION_DIFF3_CMD
 +    # FIXME: honor SVN_CONFIG_SECTION_MISCELLANY:SVN_CONFIG_OPTION_USE_COMMIT_TIMES
 +    # FIXME: honor SVN_CONFIG_SECTION_MISCELLANY:SVN_CONFIG_OPTION_PRESERVED_CF_EXTS
 +    editor = adm.get_update_editor(basedir, False, True)
 +    assert editor is not None
 +    reporter = conn.do_update(revnum, "", True, editor)
 +    adm.crawl_revisions(basedir, reporter, restore_files=False, 
 +                        recurse=True, use_commit_times=False)
 +    # FIXME: handle externals
  
 -from bzrlib.plugins.svn.format import get_rich_root_format
  
  def generate_ignore_list(ignore_map):
      """Create a list of ignores, ordered by directory.
  class SvnWorkingTree(WorkingTree):
      """WorkingTree implementation that uses a Subversion Working Copy for storage."""
      def __init__(self, bzrdir, local_path, branch):
-         version = wc.check_wc(local_path)
+         version = check_wc(local_path)
          self._format = SvnWorkingTreeFormat(version)
          self.basedir = local_path
          assert isinstance(self.basedir, unicode)
          self.bzrdir = bzrdir
          self._branch = branch
 -        self.base_revnum = 0
 -        self.client_ctx = create_svn_client(bzrdir.svn_url)
 -        self.client_ctx.log_msg_func2 = \
 -                svn.client.svn_swig_py_get_commit_log_func
 -
          self._get_wc()
-         (min_rev, max_rev, switch, modified) = wc.revision_status(self.basedir, None, True, None)
 -        max_rev = revision_status(self.basedir, None, True)[1]
++        (min_rev, max_rev, switch, modified) = revision_status(self.basedir, None, True, None)
 +        assert min_rev >= 0 and max_rev >= 0, "min rev: (%d, %d)" % (min_rev, max_rev)
          self.base_revnum = max_rev
          self.base_tree = SvnBasisTree(self)
          self.base_revid = branch.generate_revision_id(self.base_revnum)
  
          self.read_working_inventory()
  
-         self.controldir = os.path.join(self.basedir, wc.get_adm_dir(), 'bzr')
+         self.controldir = os.path.join(self.basedir, get_adm_dir(), 
+                                        'bzr')
          try:
              os.makedirs(self.controldir)
              os.makedirs(os.path.join(self.controldir, 'lock'))
          except OSError:
              pass
          control_transport = bzrdir.transport.clone(urlutils.join(
-                                                    wc.get_adm_dir(), 'bzr'))
+                                                    get_adm_dir(), 'bzr'))
          self._control_files = LockableFiles(control_transport, 'lock', LockDir)
  
      def get_ignore_list(self):
-         ignore_globs = set([wc.get_adm_dir()])
 -        ignores = set([get_adm_dir()])
 -        ignores.update(get_default_ignores(svn_config))
++        ignore_globs = set([get_adm_dir()])
 +        ignore_globs.update(ignores.get_runtime_ignores())
 +        ignore_globs.update(ignores.get_user_ignores())
  
-         def dir_add(adm, prefix, patprefix):
-             ignorestr = adm.prop_get(properties.PROP_IGNORE, 
+         def dir_add(wc, prefix, patprefix):
+             ignorestr = wc.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 = adm.entries_read(False)
+             entries = wc.entries_read(False)
              for entry in entries:
                  if entry == "":
                      continue
  
                  subprefix = os.path.join(prefix, entry)
  
-                 subwc = wc.WorkingCopy(adm, self.abspath(subprefix))
+                 subwc = WorkingCopy(wc, self.abspath(subprefix))
                  try:
                      dir_add(subwc, subprefix, urlutils.joinpath(patprefix, entry))
                  finally:
                      subwc.close()
  
 -        wc = self._get_wc()
 +        adm = self._get_wc()
          try:
 -            dir_add(wc, "", ".")
 +            dir_add(adm, "", ".")
          finally:
-             adm.close()
+             wc.close()
  
 -        return ignores
 +        return ignore_globs
  
      def is_control_filename(self, path):
-         return wc.is_adm_dir(path)
+         return is_adm_dir(path)
  
      def apply_inventory_delta(self, changes):
          raise NotImplementedError(self.apply_inventory_delta)
  
 -    def update(self, change_reporter=None):
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_head
 -        svn.client.update(self.basedir, rev, True, self.client_ctx)
 +    def _update(self, revnum=None):
 +        if revnum is None:
 +            # FIXME: should be able to use -1 here
 +            revnum = self.branch.get_revnum()
 +        adm = self._get_wc()
 +        try:
 +            conn = self.branch.repository.transport.get_connection()
 +            try:
 +                update_wc(adm, self.basedir, conn, revnum)
 +            finally:
 +                self.branch.repository.transport.add_connection(conn)
 +        finally:
 +            adm.close()
 +        return revnum
 +
 +    def update(self, change_reporter=None, possible_transports=None, revnum=None):
 +        orig_revnum = self.base_revnum
 +        self.base_revnum = self._update(revnum)
 +        self.base_revid = self.branch.generate_revision_id(self.base_revnum)
 +        self.base_tree = None
 +        self.read_working_inventory()
 +        return self.base_revnum - orig_revnum
  
      def remove(self, files, verbose=False, to_file=None):
          # FIXME: Use to_file argument
          # FIXME: Use verbose argument
          assert isinstance(files, list)
-         adm = self._get_wc(write_lock=True)
+         wc = self._get_wc(write_lock=True)
          try:
              for file in files:
-                 adm.delete(self.abspath(file))
+                 wc.delete(self.abspath(file))
          finally:
-             adm.close()
+             wc.close()
  
          for file in files:
              self._change_fileid_mapping(None, file)
          self.read_working_inventory()
  
      def _get_wc(self, relpath="", write_lock=False):
-         return wc.WorkingCopy(None, self.abspath(relpath).rstrip("/"), write_lock)
+         return WorkingCopy(None, self.abspath(relpath).rstrip("/"), 
+                                 write_lock)
  
      def _get_rel_wc(self, relpath, write_lock=False):
          dir = os.path.dirname(relpath)
      def move(self, from_paths, to_dir=None, after=False, **kwargs):
          # FIXME: Use after argument
          assert after != True
 -        revt = svn.core.svn_opt_revision_t()
 -        revt.kind = svn.core.svn_opt_revision_working
          for entry in from_paths:
              try:
                  to_wc = self._get_wc(to_dir, write_lock=True)
-                 to_wc.copy(self.abspath(entry), 
-                             os.path.basename(entry), None, None)
+                 to_wc.copy(self.abspath(entry), os.path.basename(entry))
              finally:
                  to_wc.close()
              try:
      def rename_one(self, from_rel, to_rel, after=False):
          # FIXME: Use after
          assert after != True
 -        revt = svn.core.svn_opt_revision_t()
 -        revt.kind = svn.core.svn_opt_revision_unspecified
          (to_wc, to_file) = self._get_rel_wc(to_rel, write_lock=True)
          if os.path.dirname(from_rel) == os.path.dirname(to_rel):
              # Prevent lock contention
          assert isinstance(path, str)
  
          rp = self.branch.unprefix(path)
 -        entry = self.base_tree.id_map[rp]
 +        entry = self.basis_tree().id_map[rp]
          assert entry[0] is not None
          assert isinstance(entry[0], str), "fileid %r for %r is not a string" % (entry[0], path)
          return entry
                      pass
  
          def find_copies(url, relpath=""):
-             adm = self._get_wc(relpath)
-             entries = adm.entries_read(False)
+             wc = self._get_wc(relpath)
+             entries = wc.entries_read(False)
              for entry in entries.values():
                  subrelpath = os.path.join(relpath, entry.name)
                  if entry.name == "" or entry.kind != 'directory':
                      if ((entry.copyfrom_url == url or entry.url == url) and 
-                         not (entry.schedule in (wc.SCHEDULE_DELETE,
-                                                 wc.SCHEDULE_REPLACE))):
+                         not (entry.schedule in (SCHEDULE_DELETE,
+                                                 SCHEDULE_REPLACE))):
                          yield os.path.join(
                                  self.branch.get_branch_path().strip("/"), 
                                  subrelpath)
                  else:
                      find_copies(subrelpath)
-             adm.close()
+             wc.close()
  
          def find_ids(entry, rootwc):
              relpath = urllib.unquote(entry.url[len(entry.repos):].strip("/"))
-             assert entry.schedule in (wc.SCHEDULE_NORMAL, 
-                                       wc.SCHEDULE_DELETE,
-                                       wc.SCHEDULE_ADD,
-                                       wc.SCHEDULE_REPLACE)
-             if entry.schedule == wc.SCHEDULE_NORMAL:
+             assert entry.schedule in (SCHEDULE_NORMAL, 
+                                       SCHEDULE_DELETE,
+                                       SCHEDULE_ADD,
+                                       SCHEDULE_REPLACE)
+             if entry.schedule == SCHEDULE_NORMAL:
                  assert entry.revision >= 0
                  # Keep old id
                  return self.path_to_file_id(entry.cmt_rev, entry.revision, 
                          relpath)
-             elif entry.schedule == wc.SCHEDULE_DELETE:
+             elif entry.schedule == SCHEDULE_DELETE:
                  return (None, None)
-             elif (entry.schedule == wc.SCHEDULE_ADD or 
-                   entry.schedule == wc.SCHEDULE_REPLACE):
+             elif (entry.schedule == SCHEDULE_ADD or 
+                   entry.schedule == SCHEDULE_REPLACE):
                  # See if the file this file was copied from disappeared
                  # and has no other copies -> in that case, take id of other file
                  if (entry.copyfrom_url and 
                  # FIXME: Generate more random file ids
                  return ("NEW-" + escape_svn_path(entry.url[len(entry.repos):].strip("/")), None)
  
 -        def add_dir_to_inv(relpath, wc, parent_id):
 +        def add_dir_to_inv(relpath, adm, parent_id):
              assert isinstance(relpath, unicode)
-             entries = adm.entries_read(False)
+             entries = wc.entries_read(False)
              entry = entries[""]
              assert parent_id is None or isinstance(parent_id, str), \
                      "%r is not a string" % parent_id
                  assert entry
                  
                  if entry.kind == core.NODE_DIR:
-                     subwc = wc.WorkingCopy(adm, self.abspath(subrelpath))
+                     subwc = WorkingCopy(wc, self.abspath(subrelpath))
                      try:
                          add_dir_to_inv(subrelpath, subwc, id)
                      finally:
          if revid is None or revid == NULL_REVISION:
              self.base_revid = revid
              self.base_revnum = 0
 -            self.base_tree = RevisionTree(self, Inventory(), revid)
 +            self.base_tree = None
              return
  
          rev = self.branch.lookup_revision_id(revid)
          self.base_revnum = rev
          self.base_revid = revid
 -        self.base_tree = SvnBasisTree(self)
 +        self.base_tree = None
  
          # TODO: Implement more efficient version
          newrev = self.branch.repository.get_revision(revid)
          newrevtree = self.branch.repository.revision_tree(revid)
  
 -        def update_settings(wc, path):
 +        def update_settings(adm, path):
              id = newrevtree.inventory.path2id(path)
              mutter("Updating settings for %r", id)
              revnum = self.branch.lookup_revision_id(
                      newrevtree.inventory[id].revision)
  
-             adm.process_committed(self.abspath(path).rstrip("/"), 
+             wc.process_committed(self.abspath(path).rstrip("/"), 
                            False, revnum, 
                            time_to_cstring(newrev.timestamp), 
                            newrev.committer)
              if newrevtree.inventory[id].kind != 'directory':
                  return
  
-             entries = adm.entries_read(True)
+             entries = wc.entries_read(True)
              for entry in entries:
                  if entry == "":
                      continue
  
-                 subwc = wc.WorkingCopy(adm, os.path.join(self.basedir, path, entry), write_lock=True)
+                 subwc = WorkingCopy(wc, os.path.join(self.basedir, path, entry))
                  try:
                      update_settings(subwc, os.path.join(path, entry))
                  finally:
                      subwc.close()
  
          # Set proper version for all files in the wc
-         adm = self._get_wc(write_lock=True)
+         wc = self._get_wc(write_lock=True)
          try:
-             update_settings(adm, "")
+             update_settings(wc, "")
          finally:
-             adm.close()
+             wc.close()
          self.base_revid = revid
  
 -    def commit(self, message=None, message_callback=None, revprops=None, 
 -               timestamp=None, timezone=None, committer=None, rev_id=None, 
 -               allow_pointless=True, strict=False, verbose=False, local=False, 
 -               reporter=None, config=None, specific_files=None, author=None):
 -        if author is not None:
 -            revprops['author'] = author
 -        # FIXME: Use allow_pointless
 -        # FIXME: Use verbose
 -        # FIXME: Use reporter
 -        # FIXME: Use strict
 -        if local:
 -            raise LocalCommitsUnsupported()
 -
 -        if specific_files:
 -            specific_files = [self.abspath(x).encode('utf8') for x in specific_files]
 -        else:
 -            specific_files = [self.basedir.encode('utf8')]
 -
 -        if message_callback is not None:
 -            def log_message_func(items, pool):
 -                """ Simple log message provider for unit tests. """
 -                return message_callback(self).encode("utf-8")
 -        else:
 -            assert isinstance(message, basestring)
 -            def log_message_func(items, pool):
 -                """ Simple log message provider for unit tests. """
 -                return message.encode("utf-8")
 -
 -        self.client_ctx.log_msg_baton2 = log_message_func
 -        if rev_id is not None:
 -            extra = "%d %s\n" % (self.branch.revno()+1, rev_id)
 -        else:
 -            extra = ""
 -        wc = self._get_wc(write_lock=True)
 -        try:
 -            wc.prop_set(SVN_PROP_BZR_REVISION_ID+str(self.branch.mapping.scheme), 
 -                             self._get_bzr_revids(self._get_base_branch_props()) + extra,
 -                             self.basedir)
 -            wc.prop_set(SVN_PROP_BZR_REVISION_INFO, 
 -                             generate_revision_metadata(timestamp, 
 -                                                        timezone, 
 -                                                        committer,
 -                                                        revprops),
 -                             self.basedir)
 -        finally:
 -            wc.close()
 -
 -        try:
 -            try:
 -                commit_info = svn.client.commit3(specific_files, True, False, 
 -                                                 self.client_ctx)
 -            except SubversionException, (_, num):
 -                if num == ERR_FS_TXN_OUT_OF_DATE:
 -                    raise OutOfDateTree(self)
 -                raise
 -        except:
 -            # Reset properties so the next subversion commit won't 
 -            # accidently set these properties.
 -            wc = self._get_wc(write_lock=True)
 -            base_branch_props = self._get_base_branch_props()
 -            wc.prop_set(SVN_PROP_BZR_REVISION_ID+str(self.branch.mapping.scheme), 
 -                             self._get_bzr_revids(base_branch_props), self.basedir)
 -            wc.prop_set(SVN_PROP_BZR_REVISION_INFO, 
 -                              base_branch_props.get(SVN_PROP_BZR_REVISION_INFO, ""),
 -                              self.basedir)
 -            wc.close()
 -            raise
 -
 -        self.client_ctx.log_msg_baton2 = None
 -
 -        revid = self.branch.generate_revision_id(commit_info.revision)
 -
 -        self.base_revid = revid
 -        self.base_revnum = commit_info.revision
 -        self.base_tree = SvnBasisTree(self)
 -
 -        return revid
 -
      def smart_add(self, file_list, recurse=True, action=None, save=True):
          assert isinstance(recurse, bool)
          if action is None:
              todo = []
              file_path = os.path.abspath(file_path)
              f = self.relpath(file_path)
 -            wc = self._get_wc(os.path.dirname(f), write_lock=True)
 +            adm = self._get_wc(os.path.dirname(f), write_lock=True)
              try:
                  if not self.inventory.has_filename(f):
                      if save:
                          mutter('adding %r', file_path)
-                         adm.add(file_path, None, 0, None, None, None)
+                         wc.add(file_path)
                      added.append(file_path)
                  if recurse and osutils.file_kind(file_path) == 'directory':
                      # Filter out ignored files and update ignored
                              ignored.setdefault(ignore_glob, []).append(c_path)
                          todo.append(c_path)
              finally:
-                 adm.close()
+                 wc.close()
              if todo != []:
                  cadded, cignored = self.smart_add(todo, recurse, action, save)
                  added.extend(cadded)
              ids = iter(ids)
          assert isinstance(files, list)
          for f in files:
 -            wc = self._get_wc(os.path.dirname(f), write_lock=True)
 +            adm = self._get_wc(os.path.dirname(f), write_lock=True)
              try:
                  try:
-                     adm.add(os.path.join(self.basedir, f))
+                     wc.add(os.path.join(self.basedir, f))
                      if ids is not None:
 -                        self._change_fileid_mapping(ids.next(), f, wc)
 +                        self._change_fileid_mapping(ids.next(), f, adm)
                  except SubversionException, (_, num):
                      if num == ERR_ENTRY_EXISTS:
                          continue
                          raise NoSuchFile(path=f)
                      raise
              finally:
-                 adm.close()
+                 wc.close()
          self.read_working_inventory()
  
      def basis_tree(self):
          if self.base_revid is None or self.base_revid == NULL_REVISION:
              return self.branch.repository.revision_tree(self.base_revid)
  
 +        if self.base_tree is None:
 +            self.base_tree = SvnBasisTree(self)
 +
          return self.base_tree
  
      def pull(self, source, overwrite=False, stop_revision=None, 
               delta_reporter=None, possible_transports=None):
          # FIXME: Use delta_reporter
 +        # FIXME: Use source
          # FIXME: Use overwrite
          result = PullResult()
          result.source_branch = source
          (result.old_revno, result.old_revid) = self.branch.last_revision_info()
          if stop_revision is None:
              stop_revision = self.branch.last_revision()
 -        rev = svn.core.svn_opt_revision_t()
 -        rev.kind = svn.core.svn_opt_revision_number
 -        rev.value.number = self.branch.lookup_revision_id(stop_revision)
 -        fetched = svn.client.update(self.basedir, rev, True, self.client_ctx)
 +        revnumber = self.branch.lookup_revision_id(stop_revision)
 +        fetched = self._update(revnum)
 +        self.base_revnum = fetched
          self.base_revid = self.branch.generate_revision_id(fetched)
 +        self.base_tree = None
 +        self.read_working_inventory()
          result.new_revid = self.base_revid
          result.new_revno = self.branch.revision_id_to_revno(result.new_revid)
          return result
              path = self._inventory.id2path(file_id)
          return osutils.fingerprint_file(open(self.abspath(path)))['sha1']
  
 -    def _change_fileid_mapping(self, id, path, wc=None):
 -        if wc is None:
 +    def _change_fileid_mapping(self, id, path, adm=None):
 +        if adm is None:
              subwc = self._get_wc(write_lock=True)
          else:
 -            subwc = wc
 +            subwc = adm 
          new_entries = self._get_new_file_ids(subwc)
          if id is None:
              if new_entries.has_key(path):
          existing = "".join(map(lambda (path, id): "%s\t%s\n" % (path, id), new_entries.items()))
          if existing != "":
              subwc.prop_set(SVN_PROP_BZR_FILEIDS, existing.encode("utf-8"), self.basedir)
-         if adm is None:
+         if wc is None:
              subwc.close()
  
      def _get_base_branch_props(self):
          return self.branch.repository.branchprop_list.get_properties(
                  self.branch.get_branch_path(self.base_revnum), self.base_revnum)
  
 -    def _get_new_file_ids(self, wc):
 +    def _get_new_file_ids(self, adm):
          committed = self._get_base_branch_props().get(SVN_PROP_BZR_FILEIDS, "")
-         existing = adm.prop_get(SVN_PROP_BZR_FILEIDS, self.basedir)
+         existing = wc.prop_get(SVN_PROP_BZR_FILEIDS, self.basedir)
          if existing is None or committed == existing:
              return {}
          return dict(map(lambda x: str(x).split("\t"), 
  
      def set_pending_merges(self, merges):
          """See MutableTree.set_pending_merges()."""
 -        wc = self._get_wc(write_lock=True)
 +        adm = self._get_wc(write_lock=True)
          try:
              # Set bzr:merge
              if len(merges) > 0:
              else:
                  bzr_merge = ""
  
-             adm.prop_set(SVN_PROP_BZR_ANCESTRY+str(self.branch.mapping.scheme), 
+             wc.prop_set(SVN_PROP_BZR_ANCESTRY+str(self.branch.mapping.scheme), 
                                   self._get_bzr_merges(self._get_base_branch_props()) + bzr_merge, 
                                   self.basedir)
              
                  except InvalidRevisionId:
                      pass
  
-             adm.prop_set(SVN_PROP_SVK_MERGE, 
-                              serialize_svk_features(svk_merges), self.basedir, 
-                              False)
+             wc.prop_set(SVN_PROP_SVK_MERGE, 
+                              serialize_svk_features(svk_merges), self.basedir)
          finally:
-             adm.close()
+             wc.close()
  
      def add_pending_merge(self, revid):
          merges = self.pending_merges()
  
      def pending_merges(self):
          merged = self._get_bzr_merges(self._get_base_branch_props()).splitlines()
 -        wc = self._get_wc()
 +        adm = self._get_wc()
          try:
-             merged_data = adm.prop_get(
+             merged_data = wc.prop_get(
                  SVN_PROP_BZR_ANCESTRY+str(self.branch.mapping.scheme), self.basedir)
              if merged_data is None:
                  set_merged = []
              else:
                  set_merged = merged_data.splitlines()
          finally:
-             adm.close()
+             wc.close()
  
          assert (len(merged) == len(set_merged) or 
                 len(merged)+1 == len(set_merged))
  
          return []
  
 +    def path_content_summary(self, path, _lstat=os.lstat,
 +        _mapper=osutils.file_kind_from_stat_mode):
 +        """See Tree.path_content_summary."""
 +        abspath = self.abspath(path)
 +        try:
 +            stat_result = _lstat(abspath)
 +        except OSError, e:
 +            if getattr(e, 'errno', None) == errno.ENOENT:
 +                # no file.
 +                return ('missing', None, None, None)
 +            # propagate other errors
 +            raise
 +        kind = _mapper(stat_result.st_mode)
 +        if kind == 'file':
 +            size = stat_result.st_size
 +            # try for a stat cache lookup
 +            executable = self._is_executable_from_path_and_stat(path, stat_result)
 +            return (kind, size, executable, self._sha_from_stat(
 +                path, stat_result))
 +        elif kind == 'directory':
 +            return kind, None, None, None
 +        elif kind == 'symlink':
 +            return ('symlink', None, None, os.readlink(abspath))
 +        else:
 +            return (kind, None, None, None)
 +
      def _reset_data(self):
          pass
  
@@@ -697,14 -726,11 +698,14 @@@ class SvnCheckout(BzrDir)
          self.local_path = transport.local_abspath(".")
          
          # Open related remote repository + branch
 -        wc = WorkingCopy(None, self.local_path)
          try:
-             adm = wc.WorkingCopy(None, self.local_path)
 -            self.svn_url = wc.entry(self.local_path, True).url
++            wc = WorkingCopy(None, self.local_path)
 +        except SubversionException, (msg, ERR_WC_UNSUPPORTED_FORMAT):
 +            raise UnsupportedFormatError(msg, kind='workingtree')
 +        try:
 +            self.svn_url = adm.entry(self.local_path, True).url
          finally:
-             adm.close()
+             wc.close()
  
          self.remote_transport = SvnRaTransport(self.svn_url)
          self.remote_bzrdir = SvnRemoteAccess(self.remote_transport)