/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/workingtree.py

  • Committer: Matthieu Moy
  • Date: 2006-07-08 19:32:30 UTC
  • mfrom: (1845 +trunk)
  • mto: This revision was merged to the branch mainline in revision 1857.
  • Revision ID: Matthieu.Moy@imag.fr-20060708193230-3eb72d871471bd5b
merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
40
40
# memory.  (Now done? -- mbp 20060309)
41
41
 
42
42
from binascii import hexlify
 
43
import collections
43
44
from copy import deepcopy
44
45
from cStringIO import StringIO
45
46
import errno
48
49
import re
49
50
import stat
50
51
from time import time
 
52
import warnings
51
53
 
52
54
from bzrlib.atomicfile import AtomicFile
53
 
from bzrlib.branch import (Branch,
54
 
                           quotefn)
55
55
from bzrlib.conflicts import Conflict, ConflictList, CONFLICT_SUFFIXES
56
56
import bzrlib.bzrdir as bzrdir
57
57
from bzrlib.decorators import needs_read_lock, needs_write_lock
59
59
from bzrlib.errors import (BzrCheckError,
60
60
                           BzrError,
61
61
                           ConflictFormatError,
62
 
                           DivergedBranches,
63
62
                           WeaveRevisionNotPresent,
64
63
                           NotBranchError,
65
64
                           NoSuchFile,
73
72
from bzrlib.merge import merge_inner, transform_tree
74
73
from bzrlib.osutils import (
75
74
                            abspath,
76
 
                            appendpath,
77
75
                            compact_date,
78
76
                            file_kind,
79
77
                            isdir,
92
90
from bzrlib.progress import DummyProgress, ProgressPhase
93
91
from bzrlib.revision import NULL_REVISION
94
92
from bzrlib.rio import RioReader, rio_file, Stanza
95
 
from bzrlib.symbol_versioning import *
 
93
from bzrlib.symbol_versioning import (deprecated_passed,
 
94
        deprecated_method,
 
95
        deprecated_function,
 
96
        DEPRECATED_PARAMETER,
 
97
        zero_eight,
 
98
        )
 
99
 
96
100
from bzrlib.textui import show_status
97
101
import bzrlib.tree
98
102
from bzrlib.transform import build_tree
99
103
from bzrlib.trace import mutter, note
100
104
from bzrlib.transport import get_transport
101
105
from bzrlib.transport.local import LocalTransport
 
106
import bzrlib.urlutils as urlutils
102
107
import bzrlib.ui
103
108
import bzrlib.xml5
104
109
 
148
153
 
149
154
 
150
155
class TreeEntry(object):
151
 
    """An entry that implements the minium interface used by commands.
 
156
    """An entry that implements the minimum interface used by commands.
152
157
 
153
158
    This needs further inspection, it may be better to have 
154
159
    InventoryEntries without ids - though that seems wrong. For now,
230
235
        self.bzrdir = _bzrdir
231
236
        if not _internal:
232
237
            # not created via open etc.
233
 
            warn("WorkingTree() is deprecated as of bzr version 0.8. "
 
238
            warnings.warn("WorkingTree() is deprecated as of bzr version 0.8. "
234
239
                 "Please use bzrdir.open_workingtree or WorkingTree.open().",
235
240
                 DeprecationWarning,
236
241
                 stacklevel=2)
250
255
        mutter("opening working tree %r", basedir)
251
256
        if deprecated_passed(branch):
252
257
            if not _internal:
253
 
                warn("WorkingTree(..., branch=XXX) is deprecated as of bzr 0.8."
 
258
                warnings.warn("WorkingTree(..., branch=XXX) is deprecated as of bzr 0.8."
254
259
                     " Please use bzrdir.open_workingtree() or"
255
260
                     " WorkingTree.open().",
256
261
                     DeprecationWarning,
259
264
            self._branch = branch
260
265
        else:
261
266
            self._branch = self.bzrdir.open_branch()
262
 
        assert isinstance(self.branch, Branch), \
263
 
            "branch %r is not a Branch" % self.branch
264
267
        self.basedir = realpath(basedir)
265
268
        # if branch is at our basedir and is a format 6 or less
266
269
        if isinstance(self._format, WorkingTreeFormat2):
279
282
        # if needed, or, when the cache sees a change, append it to the hash
280
283
        # cache file, and have the parser take the most recent entry for a
281
284
        # given path only.
282
 
        cache_filename = self.bzrdir.get_workingtree_transport(None).abspath('stat-cache')
 
285
        cache_filename = self.bzrdir.get_workingtree_transport(None).local_abspath('stat-cache')
283
286
        hc = self._hashcache = HashCache(basedir, cache_filename, self._control_files._file_mode)
284
287
        hc.read()
285
288
        # is this scan needed ? it makes things kinda slow.
286
 
        hc.scan()
 
289
        #hc.scan()
287
290
 
288
291
        if hc.needs_write:
289
292
            mutter("write hc")
349
352
        run into /.  If there isn't one, raises NotBranchError.
350
353
        TODO: give this a new exception.
351
354
        If there is one, it is returned, along with the unused portion of path.
 
355
 
 
356
        :return: The WorkingTree that contains 'path', and the rest of path
352
357
        """
353
358
        if path is None:
354
359
            path = os.getcwdu()
355
360
        control, relpath = bzrdir.BzrDir.open_containing(path)
 
361
 
356
362
        return control.open_workingtree(), relpath
357
363
 
358
364
    @staticmethod
413
419
        XXX: When BzrDir is present, these should be created through that 
414
420
        interface instead.
415
421
        """
416
 
        warn('delete WorkingTree.create', stacklevel=3)
 
422
        warnings.warn('delete WorkingTree.create', stacklevel=3)
417
423
        transport = get_transport(directory)
418
424
        if branch.bzrdir.root_transport.base == transport.base:
419
425
            # same dir 
451
457
    def get_file_byname(self, filename):
452
458
        return file(self.abspath(filename), 'rb')
453
459
 
 
460
    def get_parent_ids(self):
 
461
        """See Tree.get_parent_ids.
 
462
        
 
463
        This implementation reads the pending merges list and last_revision
 
464
        value and uses that to decide what the parents list should be.
 
465
        """
 
466
        last_rev = self.last_revision()
 
467
        if last_rev is None:
 
468
            parents = []
 
469
        else:
 
470
            parents = [last_rev]
 
471
        other_parents = self.pending_merges()
 
472
        return parents + other_parents
 
473
 
454
474
    def get_root_id(self):
455
475
        """Return the id of this trees root"""
456
476
        inv = self.read_working_inventory()
505
525
        # but with branch a kwarg now, passing in args as is results in the
506
526
        #message being used for the branch
507
527
        args = (DEPRECATED_PARAMETER, message, ) + args
508
 
        Commit().commit(working_tree=self, revprops=revprops, *args, **kwargs)
 
528
        committed_id = Commit().commit( working_tree=self, revprops=revprops,
 
529
            *args, **kwargs)
509
530
        self._set_inventory(self.read_working_inventory())
 
531
        return committed_id
510
532
 
511
533
    def id2abspath(self, file_id):
512
534
        return self.abspath(self.id2path(file_id))
530
552
        return os.path.getsize(self.id2abspath(file_id))
531
553
 
532
554
    @needs_read_lock
533
 
    def get_file_sha1(self, file_id):
534
 
        path = self._inventory.id2path(file_id)
 
555
    def get_file_sha1(self, file_id, path=None):
 
556
        if not path:
 
557
            path = self._inventory.id2path(file_id)
535
558
        return self._hashcache.get_sha1(path)
536
559
 
537
 
    def is_executable(self, file_id):
538
 
        if not supports_executable():
 
560
    def get_file_mtime(self, file_id, path=None):
 
561
        if not path:
 
562
            path = self._inventory.id2path(file_id)
 
563
        return os.lstat(self.abspath(path)).st_mtime
 
564
 
 
565
    if not supports_executable():
 
566
        def is_executable(self, file_id, path=None):
539
567
            return self._inventory[file_id].executable
540
 
        else:
541
 
            path = self._inventory.id2path(file_id)
 
568
    else:
 
569
        def is_executable(self, file_id, path=None):
 
570
            if not path:
 
571
                path = self._inventory.id2path(file_id)
542
572
            mode = os.lstat(self.abspath(path)).st_mode
543
 
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC&mode)
 
573
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
544
574
 
545
575
    @needs_write_lock
546
576
    def add(self, files, ids=None):
581
611
        inv = self.read_working_inventory()
582
612
        for f,file_id in zip(files, ids):
583
613
            if self.is_control_filename(f):
584
 
                raise BzrError("cannot add control file %s" % quotefn(f))
 
614
                raise errors.ForbiddenControlFileError(filename=f)
585
615
 
586
616
            fp = splitpath(f)
587
617
 
589
619
                raise BzrError("cannot add top-level %r" % f)
590
620
 
591
621
            fullpath = normpath(self.abspath(f))
592
 
 
593
622
            try:
594
623
                kind = file_kind(fullpath)
595
624
            except OSError, e:
596
625
                if e.errno == errno.ENOENT:
597
626
                    raise NoSuchFile(fullpath)
598
 
                # maybe something better?
599
 
                raise BzrError('cannot add: not a regular file, symlink or directory: %s' % quotefn(f))
600
 
 
601
627
            if not InventoryEntry.versionable_kind(kind):
602
 
                raise BzrError('cannot add: not a versionable file ('
603
 
                               'i.e. regular file, symlink or directory): %s' % quotefn(f))
604
 
 
 
628
                raise errors.BadFileKindError(filename=f, kind=kind)
605
629
            if file_id is None:
606
630
                inv.add_path(f, kind=kind)
607
631
            else:
632
656
        """
633
657
        try:
634
658
            merges_file = self._control_files.get_utf8('pending-merges')
635
 
        except OSError, e:
636
 
            if e.errno != errno.ENOENT:
637
 
                raise
 
659
        except NoSuchFile:
638
660
            return []
639
661
        p = []
640
662
        for l in merges_file.readlines():
690
712
            return '?'
691
713
 
692
714
    def list_files(self):
693
 
        """Recursively list all files as (path, class, kind, id).
 
715
        """Recursively list all files as (path, class, kind, id, entry).
694
716
 
695
717
        Lists, but does not descend into unversioned directories.
696
718
 
700
722
        Skips the control directory.
701
723
        """
702
724
        inv = self._inventory
703
 
 
704
 
        def descend(from_dir_relpath, from_dir_id, dp):
705
 
            ls = os.listdir(dp)
706
 
            ls.sort()
707
 
            for f in ls:
 
725
        # Convert these into local objects to save lookup times
 
726
        pathjoin = bzrlib.osutils.pathjoin
 
727
        file_kind = bzrlib.osutils.file_kind
 
728
 
 
729
        # transport.base ends in a slash, we want the piece
 
730
        # between the last two slashes
 
731
        transport_base_dir = self.bzrdir.transport.base.rsplit('/', 2)[1]
 
732
 
 
733
        fk_entries = {'directory':TreeDirectory, 'file':TreeFile, 'symlink':TreeLink}
 
734
 
 
735
        # directory file_id, relative path, absolute path, reverse sorted children
 
736
        children = os.listdir(self.basedir)
 
737
        children.sort()
 
738
        # jam 20060527 The kernel sized tree seems equivalent whether we 
 
739
        # use a deque and popleft to keep them sorted, or if we use a plain
 
740
        # list and just reverse() them.
 
741
        children = collections.deque(children)
 
742
        stack = [(inv.root.file_id, u'', self.basedir, children)]
 
743
        while stack:
 
744
            from_dir_id, from_dir_relpath, from_dir_abspath, children = stack[-1]
 
745
 
 
746
            while children:
 
747
                f = children.popleft()
708
748
                ## TODO: If we find a subdirectory with its own .bzr
709
749
                ## directory, then that is a separate tree and we
710
750
                ## should exclude it.
711
751
 
712
752
                # the bzrdir for this tree
713
 
                if self.bzrdir.transport.base.endswith(f + '/'):
 
753
                if transport_base_dir == f:
714
754
                    continue
715
755
 
716
 
                # path within tree
717
 
                fp = appendpath(from_dir_relpath, f)
 
756
                # we know that from_dir_relpath and from_dir_abspath never end in a slash
 
757
                # and 'f' doesn't begin with one, we can do a string op, rather
 
758
                # than the checks of pathjoin(), all relative paths will have an extra slash
 
759
                # at the beginning
 
760
                fp = from_dir_relpath + '/' + f
718
761
 
719
762
                # absolute path
720
 
                fap = appendpath(dp, f)
 
763
                fap = from_dir_abspath + '/' + f
721
764
                
722
765
                f_ie = inv.get_child(from_dir_id, f)
723
766
                if f_ie:
724
767
                    c = 'V'
725
 
                elif self.is_ignored(fp):
 
768
                elif self.is_ignored(fp[1:]):
726
769
                    c = 'I'
727
770
                else:
728
771
                    c = '?'
737
780
 
738
781
                # make a last minute entry
739
782
                if f_ie:
740
 
                    entry = f_ie
 
783
                    yield fp[1:], c, fk, f_ie.file_id, f_ie
741
784
                else:
742
 
                    if fk == 'directory':
743
 
                        entry = TreeDirectory()
744
 
                    elif fk == 'file':
745
 
                        entry = TreeFile()
746
 
                    elif fk == 'symlink':
747
 
                        entry = TreeLink()
748
 
                    else:
749
 
                        entry = TreeEntry()
 
785
                    try:
 
786
                        yield fp[1:], c, fk, None, fk_entries[fk]()
 
787
                    except KeyError:
 
788
                        yield fp[1:], c, fk, None, TreeEntry()
 
789
                    continue
750
790
                
751
 
                yield fp, c, fk, (f_ie and f_ie.file_id), entry
752
 
 
753
791
                if fk != 'directory':
754
792
                    continue
755
793
 
756
 
                if c != 'V':
757
 
                    # don't descend unversioned directories
758
 
                    continue
759
 
                
760
 
                for ff in descend(fp, f_ie.file_id, fap):
761
 
                    yield ff
 
794
                # But do this child first
 
795
                new_children = os.listdir(fap)
 
796
                new_children.sort()
 
797
                new_children = collections.deque(new_children)
 
798
                stack.append((f_ie.file_id, fp, fap, new_children))
 
799
                # Break out of inner loop, so that we start outer loop with child
 
800
                break
 
801
            else:
 
802
                # if we finished all children, pop it off the stack
 
803
                stack.pop()
762
804
 
763
 
        for f in descend(u'', inv.root.file_id, self.basedir):
764
 
            yield f
765
805
 
766
806
    @needs_write_lock
767
807
    def move(self, from_paths, to_name):
803
843
            if f_id == None:
804
844
                raise BzrError("%r is not versioned" % f)
805
845
            name_tail = splitpath(f)[-1]
806
 
            dest_path = appendpath(to_name, name_tail)
 
846
            dest_path = pathjoin(to_name, name_tail)
807
847
            if self.has_filename(dest_path):
808
848
                raise BzrError("destination %r already exists" % dest_path)
809
849
            if f_id in to_idpath:
816
856
        try:
817
857
            for f in from_paths:
818
858
                name_tail = splitpath(f)[-1]
819
 
                dest_path = appendpath(to_name, name_tail)
 
859
                dest_path = pathjoin(to_name, name_tail)
820
860
                result.append((f, dest_path))
821
861
                inv.rename(inv.path2id(f), to_dir_id, name_tail)
822
862
                try:
886
926
 
887
927
        These are files in the working directory that are not versioned or
888
928
        control files or ignored.
889
 
        
890
 
        >>> from bzrlib.bzrdir import ScratchDir
891
 
        >>> d = ScratchDir(files=['foo', 'foo~'])
892
 
        >>> b = d.open_branch()
893
 
        >>> tree = d.open_workingtree()
894
 
        >>> map(str, tree.unknowns())
895
 
        ['foo']
896
 
        >>> tree.add('foo')
897
 
        >>> list(b.unknowns())
898
 
        []
899
 
        >>> tree.remove('foo')
900
 
        >>> list(b.unknowns())
901
 
        [u'foo']
902
929
        """
903
930
        for subp in self.extras():
904
931
            if not self.is_ignored(subp):
912
939
 
913
940
    def _iter_conflicts(self):
914
941
        conflicted = set()
915
 
        for path in (s[0] for s in self.list_files()):
 
942
        for info in self.list_files():
 
943
            path = info[0]
916
944
            stem = get_conflicted_stem(path)
917
945
            if stem is None:
918
946
                continue
978
1006
            
979
1007
            fl.sort()
980
1008
            for subf in fl:
981
 
                subp = appendpath(path, subf)
 
1009
                subp = pathjoin(path, subf)
982
1010
                yield subp
983
1011
 
984
1012
    def _translate_ignore_rule(self, rule):
1051
1079
        if hasattr(self, '_ignorelist'):
1052
1080
            return self._ignorelist
1053
1081
 
1054
 
        l = bzrlib.DEFAULT_IGNORE[:]
 
1082
        l = []
1055
1083
        if self.has_filename(bzrlib.IGNORE_FILENAME):
1056
1084
            f = self.get_file_byname(bzrlib.IGNORE_FILENAME)
1057
 
            l.extend([line.rstrip("\n\r") for line in f.readlines()])
 
1085
            l.extend([line.rstrip("\n\r").decode('utf-8') 
 
1086
                      for line in f.readlines()])
1058
1087
        self._ignorelist = l
1059
1088
        self._ignore_regex = self._combine_ignore_rules(l)
1060
1089
        return l
1166
1195
 
1167
1196
    def _cache_basis_inventory(self, new_revision):
1168
1197
        """Cache new_revision as the basis inventory."""
 
1198
        # TODO: this should allow the ready-to-use inventory to be passed in,
 
1199
        # as commit already has that ready-to-use [while the format is the
 
1200
        # same, that is].
1169
1201
        try:
1170
1202
            # this double handles the inventory - unpack and repack - 
1171
1203
            # but is easier to understand. We can/should put a conditional
1172
1204
            # in here based on whether the inventory is in the latest format
1173
1205
            # - perhaps we should repack all inventories on a repository
1174
1206
            # upgrade ?
1175
 
            inv = self.branch.repository.get_inventory(new_revision)
1176
 
            inv.revision_id = new_revision
1177
 
            xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
1178
 
 
 
1207
            # the fast path is to copy the raw xml from the repository. If the
 
1208
            # xml contains 'revision_id="', then we assume the right 
 
1209
            # revision_id is set. We must check for this full string, because a
 
1210
            # root node id can legitimately look like 'revision_id' but cannot
 
1211
            # contain a '"'.
 
1212
            xml = self.branch.repository.get_inventory_xml(new_revision)
 
1213
            if not 'revision_id="' in xml.split('\n', 1)[0]:
 
1214
                inv = self.branch.repository.deserialise_inventory(
 
1215
                    new_revision, xml)
 
1216
                inv.revision_id = new_revision
 
1217
                xml = bzrlib.xml5.serializer_v5.write_inventory_to_string(inv)
 
1218
            assert isinstance(xml, str), 'serialised xml must be bytestring.'
1179
1219
            path = self._basis_inventory_name()
1180
 
            self._control_files.put_utf8(path, xml)
 
1220
            sio = StringIO(xml)
 
1221
            self._control_files.put(path, sio)
1181
1222
        except WeaveRevisionNotPresent:
1182
1223
            pass
1183
1224
 
1184
1225
    def read_basis_inventory(self):
1185
1226
        """Read the cached basis inventory."""
1186
1227
        path = self._basis_inventory_name()
1187
 
        return self._control_files.get_utf8(path).read()
 
1228
        return self._control_files.get(path).read()
1188
1229
        
1189
1230
    @needs_read_lock
1190
1231
    def read_working_inventory(self):
1197
1238
        return result
1198
1239
 
1199
1240
    @needs_write_lock
1200
 
    def remove(self, files, verbose=False):
 
1241
    def remove(self, files, verbose=False, to_file=None):
1201
1242
        """Remove nominated files from the working inventory..
1202
1243
 
1203
1244
        This does not remove their text.  This does not run on XXX on what? RBC
1225
1266
                # TODO: Perhaps make this just a warning, and continue?
1226
1267
                # This tends to happen when 
1227
1268
                raise NotVersionedError(path=f)
1228
 
            mutter("remove inventory entry %s {%s}", quotefn(f), fid)
1229
1269
            if verbose:
1230
1270
                # having remove it, it must be either ignored or unknown
1231
1271
                if self.is_ignored(f):
1232
1272
                    new_status = 'I'
1233
1273
                else:
1234
1274
                    new_status = '?'
1235
 
                show_status(new_status, inv[fid].kind, quotefn(f))
 
1275
                show_status(new_status, inv[fid].kind, f, to_file=to_file)
1236
1276
            del inv[fid]
1237
1277
 
1238
1278
        self._write_inventory(inv)
1305
1345
        # of a nasty hack; probably it's better to have a transaction object,
1306
1346
        # which can do some finalization when it's either successfully or
1307
1347
        # unsuccessfully completed.  (Denys's original patch did that.)
1308
 
        # RBC 20060206 hookinhg into transaction will couple lock and transaction
1309
 
        # wrongly. Hookinh into unllock on the control files object is fine though.
 
1348
        # RBC 20060206 hooking into transaction will couple lock and transaction
 
1349
        # wrongly. Hooking into unlock on the control files object is fine though.
1310
1350
        
1311
1351
        # TODO: split this per format so there is no ugly if block
1312
1352
        if self._hashcache.needs_write and (
1358
1398
                                      this_tree=self)
1359
1399
                self.set_last_revision(self.branch.last_revision())
1360
1400
            if old_tip and old_tip != self.last_revision():
1361
 
                # our last revision was not the prior branch last reivison
 
1401
                # our last revision was not the prior branch last revision
1362
1402
                # and we have converted that last revision to a pending merge.
1363
1403
                # base is somewhere between the branch tip now
1364
1404
                # and the now pending merge
1392
1432
    def set_conflicts(self, arg):
1393
1433
        raise UnsupportedOperation(self.set_conflicts, self)
1394
1434
 
 
1435
    def add_conflicts(self, arg):
 
1436
        raise UnsupportedOperation(self.add_conflicts, self)
 
1437
 
1395
1438
    @needs_read_lock
1396
1439
    def conflicts(self):
1397
1440
        conflicts = ConflictList()
1400
1443
            try:
1401
1444
                if file_kind(self.abspath(conflicted)) != "file":
1402
1445
                    text = False
1403
 
            except OSError, e:
1404
 
                if e.errno == errno.ENOENT:
1405
 
                    text = False
1406
 
                else:
1407
 
                    raise
 
1446
            except errors.NoSuchFile:
 
1447
                text = False
1408
1448
            if text is True:
1409
1449
                for suffix in ('.THIS', '.OTHER'):
1410
1450
                    try:
1411
1451
                        kind = file_kind(self.abspath(conflicted+suffix))
1412
 
                    except OSError, e:
1413
 
                        if e.errno == errno.ENOENT:
 
1452
                        if kind != "file":
1414
1453
                            text = False
1415
 
                            break
1416
 
                        else:
1417
 
                            raise
1418
 
                    if kind != "file":
 
1454
                    except errors.NoSuchFile:
1419
1455
                        text = False
 
1456
                    if text == False:
1420
1457
                        break
1421
1458
            ctype = {True: 'text conflict', False: 'contents conflict'}[text]
1422
1459
            conflicts.append(Conflict.factory(ctype, path=conflicted,
1463
1500
        self._put_rio('conflicts', conflicts.to_stanzas(), 
1464
1501
                      CONFLICT_HEADER_1)
1465
1502
 
 
1503
    @needs_write_lock
 
1504
    def add_conflicts(self, new_conflicts):
 
1505
        conflict_set = set(self.conflicts())
 
1506
        conflict_set.update(set(list(new_conflicts)))
 
1507
        self.set_conflicts(ConflictList(sorted(conflict_set,
 
1508
                                               key=Conflict.sort_key)))
 
1509
 
1466
1510
    @needs_read_lock
1467
1511
    def conflicts(self):
1468
1512
        try:
1532
1576
        except NoSuchFile:
1533
1577
            raise errors.NoWorkingTree(base=transport.base)
1534
1578
        except KeyError:
1535
 
            raise errors.UnknownFormatError(format_string)
 
1579
            raise errors.UnknownFormatError(format=format_string)
1536
1580
 
1537
1581
    @classmethod
1538
1582
    def get_default_format(klass):
1615
1659
                branch.unlock()
1616
1660
        revision = branch.last_revision()
1617
1661
        inv = Inventory() 
1618
 
        wt = WorkingTree(a_bzrdir.root_transport.base,
 
1662
        wt = WorkingTree(a_bzrdir.root_transport.local_abspath('.'),
1619
1663
                         branch,
1620
1664
                         inv,
1621
1665
                         _internal=True,
1643
1687
            raise NotImplementedError
1644
1688
        if not isinstance(a_bzrdir.transport, LocalTransport):
1645
1689
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1646
 
        return WorkingTree(a_bzrdir.root_transport.base,
 
1690
        return WorkingTree(a_bzrdir.root_transport.local_abspath('.'),
1647
1691
                           _internal=True,
1648
1692
                           _format=self,
1649
1693
                           _bzrdir=a_bzrdir)
1680
1724
    def initialize(self, a_bzrdir, revision_id=None):
1681
1725
        """See WorkingTreeFormat.initialize().
1682
1726
        
1683
 
        revision_id allows creating a working tree at a differnet
 
1727
        revision_id allows creating a working tree at a different
1684
1728
        revision than the branch is at.
1685
1729
        """
1686
1730
        if not isinstance(a_bzrdir.transport, LocalTransport):
1694
1738
        if revision_id is None:
1695
1739
            revision_id = branch.last_revision()
1696
1740
        inv = Inventory() 
1697
 
        wt = WorkingTree3(a_bzrdir.root_transport.base,
 
1741
        wt = WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
1698
1742
                         branch,
1699
1743
                         inv,
1700
1744
                         _internal=True,
1729
1773
        if not isinstance(a_bzrdir.transport, LocalTransport):
1730
1774
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1731
1775
        control_files = self._open_control_files(a_bzrdir)
1732
 
        return WorkingTree3(a_bzrdir.root_transport.base,
 
1776
        return WorkingTree3(a_bzrdir.root_transport.local_abspath('.'),
1733
1777
                           _internal=True,
1734
1778
                           _format=self,
1735
1779
                           _bzrdir=a_bzrdir,