/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_4.py

  • Committer: Jelmer Vernooij
  • Date: 2012-02-06 11:36:02 UTC
  • mfrom: (6462 +trunk)
  • mto: This revision was merged to the branch mainline in revision 6463.
  • Revision ID: jelmer@samba.org-20120206113602-yu3j0xe7qbk1szw9
Merge bzr.dev.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
22
22
WorkingTree.open(dir).
23
23
"""
24
24
 
 
25
from __future__ import absolute_import
 
26
 
25
27
from cStringIO import StringIO
26
28
import os
27
29
import sys
31
33
import errno
32
34
import stat
33
35
 
34
 
import bzrlib
35
36
from bzrlib import (
36
37
    bzrdir,
37
38
    cache_utf8,
 
39
    config,
 
40
    conflicts as _mod_conflicts,
38
41
    debug,
39
42
    dirstate,
40
43
    errors,
 
44
    filters as _mod_filters,
41
45
    generate_ids,
42
46
    osutils,
43
47
    revision as _mod_revision,
46
50
    transform,
47
51
    views,
48
52
    )
49
 
import bzrlib.branch
50
 
import bzrlib.ui
51
53
""")
52
54
 
53
55
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
 
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
56
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
 
from bzrlib.mutabletree import needs_tree_write_lock
 
57
from bzrlib.lock import LogicalLockResult
 
58
from bzrlib.lockable_files import LockableFiles
 
59
from bzrlib.lockdir import LockDir
 
60
from bzrlib.mutabletree import (
 
61
    MutableTree,
 
62
    needs_tree_write_lock,
 
63
    )
57
64
from bzrlib.osutils import (
58
65
    file_kind,
59
66
    isdir,
61
68
    realpath,
62
69
    safe_unicode,
63
70
    )
64
 
from bzrlib.trace import mutter
65
71
from bzrlib.transport.local import LocalTransport
66
 
from bzrlib.tree import InterTree
67
 
from bzrlib.tree import Tree
68
 
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
69
 
 
70
 
 
71
 
class DirStateWorkingTree(WorkingTree3):
 
72
from bzrlib.tree import (
 
73
    InterTree,
 
74
    InventoryTree,
 
75
    )
 
76
from bzrlib.workingtree import (
 
77
    InventoryWorkingTree,
 
78
    WorkingTree,
 
79
    WorkingTreeFormatMetaDir,
 
80
    )
 
81
 
 
82
 
 
83
class DirStateWorkingTree(InventoryWorkingTree):
 
84
 
72
85
    def __init__(self, basedir,
73
86
                 branch,
74
87
                 _control_files=None,
84
97
        self._format = _format
85
98
        self.bzrdir = _bzrdir
86
99
        basedir = safe_unicode(basedir)
87
 
        mutter("opening working tree %r", basedir)
 
100
        trace.mutter("opening working tree %r", basedir)
88
101
        self._branch = branch
89
102
        self.basedir = realpath(basedir)
90
103
        # if branch is at our basedir and is a format 6 or less
124
137
            state.add(f, file_id, kind, None, '')
125
138
        self._make_dirty(reset_inventory=True)
126
139
 
 
140
    def _get_check_refs(self):
 
141
        """Return the references needed to perform a check of this tree."""
 
142
        return [('trees', self.last_revision())]
 
143
 
127
144
    def _make_dirty(self, reset_inventory):
128
145
        """Make the tree state dirty.
129
146
 
181
198
 
182
199
    def _comparison_data(self, entry, path):
183
200
        kind, executable, stat_value = \
184
 
            WorkingTree3._comparison_data(self, entry, path)
 
201
            WorkingTree._comparison_data(self, entry, path)
185
202
        # it looks like a plain directory, but it's really a reference -- see
186
203
        # also kind()
187
204
        if (self._repo_supports_tree_reference and kind == 'directory'
193
210
    def commit(self, message=None, revprops=None, *args, **kwargs):
194
211
        # mark the tree as dirty post commit - commit
195
212
        # can change the current versioned list by doing deletes.
196
 
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
 
213
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
197
214
        self._make_dirty(reset_inventory=True)
198
215
        return result
199
216
 
218
235
        local_path = self.bzrdir.get_workingtree_transport(None
219
236
            ).local_abspath('dirstate')
220
237
        self._dirstate = dirstate.DirState.on_file(local_path,
221
 
            self._sha1_provider())
 
238
            self._sha1_provider(), self._worth_saving_limit())
222
239
        return self._dirstate
223
240
 
224
241
    def _sha1_provider(self):
233
250
        else:
234
251
            return None
235
252
 
 
253
    def _worth_saving_limit(self):
 
254
        """How many hash changes are ok before we must save the dirstate.
 
255
 
 
256
        :return: an integer. -1 means never save.
 
257
        """
 
258
        conf = self.get_config_stack()
 
259
        return conf.get('bzr.workingtree.worth_saving_limit')
 
260
 
236
261
    def filter_unversioned_files(self, paths):
237
262
        """Filter out paths that are versioned.
238
263
 
368
393
        state = self.current_dirstate()
369
394
        if stat_value is None:
370
395
            try:
371
 
                stat_value = os.lstat(file_abspath)
 
396
                stat_value = osutils.lstat(file_abspath)
372
397
            except OSError, e:
373
398
                if e.errno == errno.ENOENT:
374
399
                    return None
455
480
            return False # Missing entries are not executable
456
481
        return entry[1][0][3] # Executable?
457
482
 
458
 
    if not osutils.supports_executable():
459
 
        def is_executable(self, file_id, path=None):
460
 
            """Test if a file is executable or not.
 
483
    def is_executable(self, file_id, path=None):
 
484
        """Test if a file is executable or not.
461
485
 
462
 
            Note: The caller is expected to take a read-lock before calling this.
463
 
            """
 
486
        Note: The caller is expected to take a read-lock before calling this.
 
487
        """
 
488
        if not self._supports_executable():
464
489
            entry = self._get_entry(file_id=file_id, path=path)
465
490
            if entry == (None, None):
466
491
                return False
467
492
            return entry[1][0][3]
468
 
 
469
 
        _is_executable_from_path_and_stat = \
470
 
            _is_executable_from_path_and_stat_from_basis
471
 
    else:
472
 
        def is_executable(self, file_id, path=None):
473
 
            """Test if a file is executable or not.
474
 
 
475
 
            Note: The caller is expected to take a read-lock before calling this.
476
 
            """
 
493
        else:
477
494
            self._must_be_locked()
478
495
            if not path:
479
496
                path = self.id2path(file_id)
480
 
            mode = os.lstat(self.abspath(path)).st_mode
 
497
            mode = osutils.lstat(self.abspath(path)).st_mode
481
498
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
482
499
 
483
500
    def all_file_ids(self):
567
584
            return _mod_revision.NULL_REVISION
568
585
 
569
586
    def lock_read(self):
570
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
587
        """See Branch.lock_read, and WorkingTree.unlock.
 
588
 
 
589
        :return: A bzrlib.lock.LogicalLockResult.
 
590
        """
571
591
        self.branch.lock_read()
572
592
        try:
573
593
            self._control_files.lock_read()
586
606
        except:
587
607
            self.branch.unlock()
588
608
            raise
 
609
        return LogicalLockResult(self.unlock)
589
610
 
590
611
    def _lock_self_write(self):
591
612
        """This should be called after the branch is locked."""
606
627
        except:
607
628
            self.branch.unlock()
608
629
            raise
 
630
        return LogicalLockResult(self.unlock)
609
631
 
610
632
    def lock_tree_write(self):
611
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
633
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
634
 
 
635
        :return: A bzrlib.lock.LogicalLockResult.
 
636
        """
612
637
        self.branch.lock_read()
613
 
        self._lock_self_write()
 
638
        return self._lock_self_write()
614
639
 
615
640
    def lock_write(self):
616
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
641
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
642
 
 
643
        :return: A bzrlib.lock.LogicalLockResult.
 
644
        """
617
645
        self.branch.lock_write()
618
 
        self._lock_self_write()
 
646
        return self._lock_self_write()
619
647
 
620
648
    @needs_tree_write_lock
621
649
    def move(self, from_paths, to_dir, after=False):
838
866
                rollback_rename()
839
867
                raise
840
868
            result.append((from_rel, to_rel))
841
 
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
 
869
            state._mark_modified()
842
870
            self._make_dirty(reset_inventory=False)
843
871
 
844
872
        return result
937
965
                    all_versioned = False
938
966
                    break
939
967
            if not all_versioned:
940
 
                raise errors.PathsNotVersionedError(paths)
 
968
                raise errors.PathsNotVersionedError(
 
969
                    [p.decode('utf-8') for p in paths])
941
970
        # -- remove redundancy in supplied paths to prevent over-scanning --
942
971
        search_paths = osutils.minimum_path_selection(paths)
943
972
        # sketch:
992
1021
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
993
1022
            for dir_name in split_paths:
994
1023
                if dir_name not in found_dir_names:
995
 
                    raise errors.PathsNotVersionedError(paths)
 
1024
                    raise errors.PathsNotVersionedError(
 
1025
                        [p.decode('utf-8') for p in paths])
996
1026
 
997
1027
        for dir_name_id, trees_info in found.iteritems():
998
1028
            for index in search_indexes:
1101
1131
                        _mod_revision.NULL_REVISION)))
1102
1132
                ghosts.append(rev_id)
1103
1133
            accepted_revisions.add(rev_id)
1104
 
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1134
        updated = False
 
1135
        if (len(real_trees) == 1
 
1136
            and not ghosts
 
1137
            and self.branch.repository._format.fast_deltas
 
1138
            and isinstance(real_trees[0][1],
 
1139
                revisiontree.InventoryRevisionTree)
 
1140
            and self.get_parent_ids()):
 
1141
            rev_id, rev_tree = real_trees[0]
 
1142
            basis_id = self.get_parent_ids()[0]
 
1143
            # There are times when basis_tree won't be in
 
1144
            # self.branch.repository, (switch, for example)
 
1145
            try:
 
1146
                basis_tree = self.branch.repository.revision_tree(basis_id)
 
1147
            except errors.NoSuchRevision:
 
1148
                # Fall back to the set_parent_trees(), since we can't use
 
1149
                # _make_delta if we can't get the RevisionTree
 
1150
                pass
 
1151
            else:
 
1152
                delta = rev_tree.inventory._make_delta(
 
1153
                    basis_tree.inventory)
 
1154
                dirstate.update_basis_by_delta(delta, rev_id)
 
1155
                updated = True
 
1156
        if not updated:
 
1157
            dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1105
1158
        self._make_dirty(reset_inventory=False)
1106
1159
 
1107
1160
    def _set_root_id(self, file_id):
1127
1180
 
1128
1181
    def unlock(self):
1129
1182
        """Unlock in format 4 trees needs to write the entire dirstate."""
1130
 
        # do non-implementation specific cleanup
1131
 
        self._cleanup()
1132
 
 
1133
1183
        if self._control_files._lock_count == 1:
 
1184
            # do non-implementation specific cleanup
 
1185
            self._cleanup()
 
1186
 
1134
1187
            # eventually we should do signature checking during read locks for
1135
1188
            # dirstate updates.
1136
1189
            if self._control_files._lock_mode == 'w':
1235
1288
        # have to change the legacy inventory too.
1236
1289
        if self._inventory is not None:
1237
1290
            for file_id in file_ids:
1238
 
                self._inventory.remove_recursive_id(file_id)
 
1291
                if self._inventory.has_id(file_id):
 
1292
                    self._inventory.remove_recursive_id(file_id)
1239
1293
 
1240
1294
    @needs_tree_write_lock
1241
1295
    def rename_one(self, from_rel, to_rel, after=False):
1242
1296
        """See WorkingTree.rename_one"""
1243
1297
        self.flush()
1244
 
        WorkingTree.rename_one(self, from_rel, to_rel, after)
 
1298
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1245
1299
 
1246
1300
    @needs_tree_write_lock
1247
1301
    def apply_inventory_delta(self, changes):
1280
1334
            self._inventory = inv
1281
1335
        self.flush()
1282
1336
 
 
1337
    @needs_tree_write_lock
 
1338
    def reset_state(self, revision_ids=None):
 
1339
        """Reset the state of the working tree.
 
1340
 
 
1341
        This does a hard-reset to a last-known-good state. This is a way to
 
1342
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
 
1343
        """
 
1344
        if revision_ids is None:
 
1345
            revision_ids = self.get_parent_ids()
 
1346
        if not revision_ids:
 
1347
            base_tree = self.branch.repository.revision_tree(
 
1348
                _mod_revision.NULL_REVISION)
 
1349
            trees = []
 
1350
        else:
 
1351
            trees = zip(revision_ids,
 
1352
                        self.branch.repository.revision_trees(revision_ids))
 
1353
            base_tree = trees[0][1]
 
1354
        state = self.current_dirstate()
 
1355
        # We don't support ghosts yet
 
1356
        state.set_state_from_scratch(base_tree.inventory, trees, [])
 
1357
 
1283
1358
 
1284
1359
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1285
1360
 
1290
1365
        """See dirstate.SHA1Provider.sha1()."""
1291
1366
        filters = self.tree._content_filter_stack(
1292
1367
            self.tree.relpath(osutils.safe_unicode(abspath)))
1293
 
        return internal_size_sha_file_byname(abspath, filters)[1]
 
1368
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1294
1369
 
1295
1370
    def stat_and_sha1(self, abspath):
1296
1371
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1300
1375
        try:
1301
1376
            statvalue = os.fstat(file_obj.fileno())
1302
1377
            if filters:
1303
 
                file_obj = filtered_input_file(file_obj, filters)
 
1378
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1304
1379
            sha1 = osutils.size_sha_file(file_obj)[1]
1305
1380
        finally:
1306
1381
            file_obj.close()
1317
1392
    def _file_content_summary(self, path, stat_result):
1318
1393
        # This is to support the somewhat obsolete path_content_summary method
1319
1394
        # with content filtering: see
1320
 
        # <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
 
1395
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
1321
1396
        #
1322
1397
        # If the dirstate cache is up to date and knows the hash and size,
1323
1398
        # return that.
1336
1411
class WorkingTree4(DirStateWorkingTree):
1337
1412
    """This is the Format 4 working tree.
1338
1413
 
1339
 
    This differs from WorkingTree3 by:
 
1414
    This differs from WorkingTree by:
1340
1415
     - Having a consolidated internal dirstate, stored in a
1341
1416
       randomly-accessible sorted file on disk.
1342
1417
     - Not having a regular inventory attribute.  One can be synthesized
1370
1445
        return views.PathBasedViews(self)
1371
1446
 
1372
1447
 
1373
 
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
 
1448
class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
 
1449
 
 
1450
    missing_parent_conflicts = True
 
1451
 
 
1452
    supports_versioned_directories = True
 
1453
 
 
1454
    _lock_class = LockDir
 
1455
    _lock_file_name = 'lock'
 
1456
 
 
1457
    def _open_control_files(self, a_bzrdir):
 
1458
        transport = a_bzrdir.get_workingtree_transport(None)
 
1459
        return LockableFiles(transport, self._lock_file_name,
 
1460
                             self._lock_class)
1374
1461
 
1375
1462
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1376
1463
                   accelerator_tree=None, hardlink=False):
1377
1464
        """See WorkingTreeFormat.initialize().
1378
1465
 
1379
1466
        :param revision_id: allows creating a working tree at a different
1380
 
        revision than the branch is at.
 
1467
            revision than the branch is at.
1381
1468
        :param accelerator_tree: A tree which can be used for retrieving file
1382
1469
            contents more quickly than the revision tree, i.e. a workingtree.
1383
1470
            The revision tree will be used for cases where accelerator_tree's
1394
1481
        control_files = self._open_control_files(a_bzrdir)
1395
1482
        control_files.create_lock()
1396
1483
        control_files.lock_write()
1397
 
        transport.put_bytes('format', self.get_format_string(),
 
1484
        transport.put_bytes('format', self.as_string(),
1398
1485
            mode=a_bzrdir._get_file_mode())
1399
1486
        if from_branch is not None:
1400
1487
            branch = from_branch
1460
1547
                transform.build_tree(basis, wt, accelerator_tree,
1461
1548
                                     hardlink=hardlink,
1462
1549
                                     delta_from_tree=delta_from_tree)
 
1550
                for hook in MutableTree.hooks['post_build_tree']:
 
1551
                    hook(wt)
1463
1552
            finally:
1464
1553
                basis.unlock()
1465
1554
        finally:
1476
1565
        :param wt: the WorkingTree object
1477
1566
        """
1478
1567
 
 
1568
    def open(self, a_bzrdir, _found=False):
 
1569
        """Return the WorkingTree object for a_bzrdir
 
1570
 
 
1571
        _found is a private parameter, do not use it. It is used to indicate
 
1572
               if format probing has already been done.
 
1573
        """
 
1574
        if not _found:
 
1575
            # we are being called directly and must probe.
 
1576
            raise NotImplementedError
 
1577
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
1578
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
1579
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
1580
        return wt
 
1581
 
1479
1582
    def _open(self, a_bzrdir, control_files):
1480
1583
        """Open the tree itself.
1481
1584
 
1495
1598
        """Overrideable method to get a bzrdir for testing."""
1496
1599
        # please test against something that will let us do tree references
1497
1600
        return bzrdir.format_registry.make_bzrdir(
1498
 
            'dirstate-with-subtree')
 
1601
            'development-subtree')
1499
1602
 
1500
1603
    _matchingbzrdir = property(__get_matchingbzrdir)
1501
1604
 
1506
1609
    This format:
1507
1610
        - exists within a metadir controlling .bzr
1508
1611
        - includes an explicit version marker for the workingtree control
1509
 
          files, separate from the BzrDir format
 
1612
          files, separate from the ControlDir format
1510
1613
        - modifies the hash cache format
1511
1614
        - is new in bzr 0.15
1512
1615
        - uses a LockDir to guard access to it.
1516
1619
 
1517
1620
    _tree_class = WorkingTree4
1518
1621
 
1519
 
    def get_format_string(self):
 
1622
    @classmethod
 
1623
    def get_format_string(cls):
1520
1624
        """See WorkingTreeFormat.get_format_string()."""
1521
1625
        return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1522
1626
 
1533
1637
 
1534
1638
    _tree_class = WorkingTree5
1535
1639
 
1536
 
    def get_format_string(self):
 
1640
    @classmethod
 
1641
    def get_format_string(cls):
1537
1642
        """See WorkingTreeFormat.get_format_string()."""
1538
1643
        return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1539
1644
 
1553
1658
 
1554
1659
    _tree_class = WorkingTree6
1555
1660
 
1556
 
    def get_format_string(self):
 
1661
    @classmethod
 
1662
    def get_format_string(cls):
1557
1663
        """See WorkingTreeFormat.get_format_string()."""
1558
1664
        return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1559
1665
 
1572
1678
        return True
1573
1679
 
1574
1680
 
1575
 
class DirStateRevisionTree(Tree):
 
1681
class DirStateRevisionTree(InventoryTree):
1576
1682
    """A revision tree pulling the inventory from a dirstate.
1577
1683
    
1578
1684
    Note that this is one of the historical (ie revision) trees cached in the
1597
1703
    def annotate_iter(self, file_id,
1598
1704
                      default_revision=_mod_revision.CURRENT_REVISION):
1599
1705
        """See Tree.annotate_iter"""
1600
 
        text_key = (file_id, self.inventory[file_id].revision)
 
1706
        text_key = (file_id, self.get_file_revision(file_id))
1601
1707
        annotations = self._repository.texts.annotate(text_key)
1602
1708
        return [(key[-1], line) for (key, line) in annotations]
1603
1709
 
1604
 
    def _get_ancestors(self, default_revision):
1605
 
        return set(self._repository.get_ancestry(self._revision_id,
1606
 
                                                 topo_sorted=False))
1607
1710
    def _comparison_data(self, entry, path):
1608
1711
        """See Tree._comparison_data."""
1609
1712
        if entry is None:
1725
1828
                elif kind == 'directory':
1726
1829
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1727
1830
                elif kind == 'symlink':
1728
 
                    inv_entry.executable = False
1729
 
                    inv_entry.text_size = None
1730
1831
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1731
1832
                elif kind == 'tree-reference':
1732
1833
                    inv_entry.reference_revision = fingerprint or None
1752
1853
        # Make sure the file exists
1753
1854
        entry = self._get_entry(file_id, path=path)
1754
1855
        if entry == (None, None): # do we raise?
1755
 
            return None
 
1856
            raise errors.NoSuchId(self, file_id)
1756
1857
        parent_index = self._get_parent_index()
1757
1858
        last_changed_revision = entry[1][parent_index][4]
1758
1859
        try:
1769
1870
            return parent_details[1]
1770
1871
        return None
1771
1872
 
 
1873
    @needs_read_lock
 
1874
    def get_file_revision(self, file_id):
 
1875
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1876
        return inv[inv_file_id].revision
 
1877
 
1772
1878
    def get_file(self, file_id, path=None):
1773
1879
        return StringIO(self.get_file_text(file_id))
1774
1880
 
1775
1881
    def get_file_size(self, file_id):
1776
1882
        """See Tree.get_file_size"""
1777
 
        return self.inventory[file_id].text_size
 
1883
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1884
        return inv[inv_file_id].text_size
1778
1885
 
1779
1886
    def get_file_text(self, file_id, path=None):
1780
1887
        _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
1781
1888
        return ''.join(content)
1782
1889
 
1783
1890
    def get_reference_revision(self, file_id, path=None):
1784
 
        return self.inventory[file_id].reference_revision
 
1891
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1892
        return inv[inv_file_id].reference_revision
1785
1893
 
1786
1894
    def iter_files_bytes(self, desired_files):
1787
1895
        """See Tree.iter_files_bytes.
1797
1905
                                       identifier))
1798
1906
        return self._repository.iter_files_bytes(repo_desired_files)
1799
1907
 
1800
 
    def get_symlink_target(self, file_id):
 
1908
    def get_symlink_target(self, file_id, path=None):
1801
1909
        entry = self._get_entry(file_id=file_id)
1802
1910
        parent_index = self._get_parent_index()
1803
1911
        if entry[1][parent_index][0] != 'l':
1841
1949
 
1842
1950
    def path_content_summary(self, path):
1843
1951
        """See Tree.path_content_summary."""
1844
 
        id = self.inventory.path2id(path)
1845
 
        if id is None:
 
1952
        inv, inv_file_id = self._path2inv_file_id(path)
 
1953
        if inv_file_id is None:
1846
1954
            return ('missing', None, None, None)
1847
 
        entry = self._inventory[id]
 
1955
        entry = inv[inv_file_id]
1848
1956
        kind = entry.kind
1849
1957
        if kind == 'file':
1850
1958
            return (kind, entry.text_size, entry.executable, entry.text_sha1)
1854
1962
            return (kind, None, None, None)
1855
1963
 
1856
1964
    def is_executable(self, file_id, path=None):
1857
 
        ie = self.inventory[file_id]
 
1965
        inv, inv_file_id = self._unpack_file_id(file_id)
 
1966
        ie = inv[inv_file_id]
1858
1967
        if ie.kind != "file":
1859
 
            return None
 
1968
            return False
1860
1969
        return ie.executable
1861
1970
 
 
1971
    def is_locked(self):
 
1972
        return self._locked
 
1973
 
1862
1974
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1863
1975
        # We use a standard implementation, because DirStateRevisionTree is
1864
1976
        # dealing with one of the parents of the current state
1865
 
        inv = self._get_inventory()
1866
1977
        if from_dir is None:
 
1978
            inv = self.inventory
1867
1979
            from_dir_id = None
1868
1980
        else:
1869
 
            from_dir_id = inv.path2id(from_dir)
 
1981
            inv, from_dir_id = self._path2inv_file_id(from_dir)
1870
1982
            if from_dir_id is None:
1871
1983
                # Directory not versioned
1872
1984
                return
1877
1989
            yield path, 'V', entry.kind, entry.file_id, entry
1878
1990
 
1879
1991
    def lock_read(self):
1880
 
        """Lock the tree for a set of operations."""
 
1992
        """Lock the tree for a set of operations.
 
1993
 
 
1994
        :return: A bzrlib.lock.LogicalLockResult.
 
1995
        """
1881
1996
        if not self._locked:
1882
1997
            self._repository.lock_read()
1883
1998
            if self._dirstate._lock_token is None:
1884
1999
                self._dirstate.lock_read()
1885
2000
                self._dirstate_locked = True
1886
2001
        self._locked += 1
 
2002
        return LogicalLockResult(self.unlock)
1887
2003
 
1888
2004
    def _must_be_locked(self):
1889
2005
        if not self._locked:
1968
2084
    def make_source_parent_tree(source, target):
1969
2085
        """Change the source tree into a parent of the target."""
1970
2086
        revid = source.commit('record tree')
1971
 
        target.branch.repository.fetch(source.branch.repository, revid)
 
2087
        target.branch.fetch(source.branch, revid)
1972
2088
        target.set_parent_ids([revid])
1973
2089
        return target.basis_tree(), target
1974
2090
 
2066
2182
                path_entries = state._entries_for_path(path)
2067
2183
                if not path_entries:
2068
2184
                    # this specified path is not present at all: error
2069
 
                    not_versioned.append(path)
 
2185
                    not_versioned.append(path.decode('utf-8'))
2070
2186
                    continue
2071
2187
                found_versioned = False
2072
2188
                # for each id at this path
2080
2196
                if not found_versioned:
2081
2197
                    # none of the indexes was not 'absent' at all ids for this
2082
2198
                    # path.
2083
 
                    not_versioned.append(path)
 
2199
                    not_versioned.append(path.decode('utf-8'))
2084
2200
            if len(not_versioned) > 0:
2085
2201
                raise errors.PathsNotVersionedError(not_versioned)
2086
2202
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
2153
2269
    def update_format(self, tree):
2154
2270
        """Change the format marker."""
2155
2271
        tree._transport.put_bytes('format',
2156
 
            self.target_format.get_format_string(),
 
2272
            self.target_format.as_string(),
2157
2273
            mode=tree.bzrdir._get_file_mode())
2158
2274
 
2159
2275
 
2176
2292
    def update_format(self, tree):
2177
2293
        """Change the format marker."""
2178
2294
        tree._transport.put_bytes('format',
2179
 
            self.target_format.get_format_string(),
 
2295
            self.target_format.as_string(),
2180
2296
            mode=tree.bzrdir._get_file_mode())
2181
2297
 
2182
2298
 
2205
2321
    def update_format(self, tree):
2206
2322
        """Change the format marker."""
2207
2323
        tree._transport.put_bytes('format',
2208
 
            self.target_format.get_format_string(),
 
2324
            self.target_format.as_string(),
2209
2325
            mode=tree.bzrdir._get_file_mode())