~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Andrew Bennetts
  • Date: 2010-10-08 08:15:14 UTC
  • mto: This revision was merged to the branch mainline in revision 5498.
  • Revision ID: andrew.bennetts@canonical.com-20101008081514-dviqzrdfwyzsqbz2
Split NEWS into per-release doc/en/release-notes/bzr-*.txt

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2012 Canonical Ltd
 
1
# Copyright (C) 2007-2010 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
 
 
27
25
from cStringIO import StringIO
28
26
import os
29
27
import sys
33
31
import errno
34
32
import stat
35
33
 
 
34
import bzrlib
36
35
from bzrlib import (
37
36
    bzrdir,
38
37
    cache_utf8,
39
 
    config,
40
 
    conflicts as _mod_conflicts,
41
 
    controldir,
42
38
    debug,
43
39
    dirstate,
44
40
    errors,
45
 
    filters as _mod_filters,
46
41
    generate_ids,
47
42
    osutils,
48
43
    revision as _mod_revision,
51
46
    transform,
52
47
    views,
53
48
    )
 
49
import bzrlib.branch
 
50
import bzrlib.ui
54
51
""")
55
52
 
56
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
57
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
58
56
from bzrlib.lock import LogicalLockResult
59
 
from bzrlib.lockable_files import LockableFiles
60
 
from bzrlib.lockdir import LockDir
61
 
from bzrlib.mutabletree import (
62
 
    MutableTree,
63
 
    needs_tree_write_lock,
64
 
    )
 
57
from bzrlib.mutabletree import needs_tree_write_lock
65
58
from bzrlib.osutils import (
66
59
    file_kind,
67
60
    isdir,
69
62
    realpath,
70
63
    safe_unicode,
71
64
    )
72
 
from bzrlib.symbol_versioning import (
73
 
    deprecated_in,
74
 
    deprecated_method,
75
 
    )
 
65
from bzrlib.trace import mutter
76
66
from bzrlib.transport.local import LocalTransport
77
 
from bzrlib.tree import (
78
 
    InterTree,
79
 
    InventoryTree,
80
 
    )
81
 
from bzrlib.workingtree import (
82
 
    InventoryWorkingTree,
83
 
    WorkingTree,
84
 
    WorkingTreeFormatMetaDir,
85
 
    )
86
 
 
87
 
 
88
 
class DirStateWorkingTree(InventoryWorkingTree):
89
 
 
 
67
from bzrlib.tree import InterTree
 
68
from bzrlib.tree import Tree
 
69
from bzrlib.workingtree import WorkingTree, WorkingTree3, WorkingTreeFormat3
 
70
 
 
71
 
 
72
class DirStateWorkingTree(WorkingTree3):
90
73
    def __init__(self, basedir,
91
74
                 branch,
92
75
                 _control_files=None,
102
85
        self._format = _format
103
86
        self.bzrdir = _bzrdir
104
87
        basedir = safe_unicode(basedir)
105
 
        trace.mutter("opening working tree %r", basedir)
 
88
        mutter("opening working tree %r", basedir)
106
89
        self._branch = branch
107
90
        self.basedir = realpath(basedir)
108
91
        # if branch is at our basedir and is a format 6 or less
142
125
            state.add(f, file_id, kind, None, '')
143
126
        self._make_dirty(reset_inventory=True)
144
127
 
145
 
    def _get_check_refs(self):
146
 
        """Return the references needed to perform a check of this tree."""
147
 
        return [('trees', self.last_revision())]
148
 
 
149
128
    def _make_dirty(self, reset_inventory):
150
129
        """Make the tree state dirty.
151
130
 
203
182
 
204
183
    def _comparison_data(self, entry, path):
205
184
        kind, executable, stat_value = \
206
 
            WorkingTree._comparison_data(self, entry, path)
 
185
            WorkingTree3._comparison_data(self, entry, path)
207
186
        # it looks like a plain directory, but it's really a reference -- see
208
187
        # also kind()
209
188
        if (self._repo_supports_tree_reference and kind == 'directory'
215
194
    def commit(self, message=None, revprops=None, *args, **kwargs):
216
195
        # mark the tree as dirty post commit - commit
217
196
        # can change the current versioned list by doing deletes.
218
 
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
 
197
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
219
198
        self._make_dirty(reset_inventory=True)
220
199
        return result
221
200
 
240
219
        local_path = self.bzrdir.get_workingtree_transport(None
241
220
            ).local_abspath('dirstate')
242
221
        self._dirstate = dirstate.DirState.on_file(local_path,
243
 
            self._sha1_provider(), self._worth_saving_limit())
 
222
            self._sha1_provider())
244
223
        return self._dirstate
245
224
 
246
225
    def _sha1_provider(self):
255
234
        else:
256
235
            return None
257
236
 
258
 
    def _worth_saving_limit(self):
259
 
        """How many hash changes are ok before we must save the dirstate.
260
 
 
261
 
        :return: an integer. -1 means never save.
262
 
        """
263
 
        conf = self.get_config_stack()
264
 
        return conf.get('bzr.workingtree.worth_saving_limit')
265
 
 
266
237
    def filter_unversioned_files(self, paths):
267
238
        """Filter out paths that are versioned.
268
239
 
398
369
        state = self.current_dirstate()
399
370
        if stat_value is None:
400
371
            try:
401
 
                stat_value = osutils.lstat(file_abspath)
 
372
                stat_value = os.lstat(file_abspath)
402
373
            except OSError, e:
403
374
                if e.errno == errno.ENOENT:
404
375
                    return None
419
390
                return link_or_sha1
420
391
        return None
421
392
 
422
 
    def _get_root_inventory(self):
 
393
    def _get_inventory(self):
423
394
        """Get the inventory for the tree. This is only valid within a lock."""
424
395
        if 'evil' in debug.debug_flags:
425
396
            trace.mutter_callsite(2,
430
401
        self._generate_inventory()
431
402
        return self._inventory
432
403
 
433
 
    @deprecated_method(deprecated_in((2, 5, 0)))
434
 
    def _get_inventory(self):
435
 
        return self.root_inventory
436
 
 
437
404
    inventory = property(_get_inventory,
438
405
                         doc="Inventory of this Tree")
439
406
 
440
 
    root_inventory = property(_get_root_inventory,
441
 
        "Root inventory of this tree")
442
 
 
443
407
    @needs_read_lock
444
408
    def get_parent_ids(self):
445
409
        """See Tree.get_parent_ids.
492
456
            return False # Missing entries are not executable
493
457
        return entry[1][0][3] # Executable?
494
458
 
495
 
    def is_executable(self, file_id, path=None):
496
 
        """Test if a file is executable or not.
 
459
    if not osutils.supports_executable():
 
460
        def is_executable(self, file_id, path=None):
 
461
            """Test if a file is executable or not.
497
462
 
498
 
        Note: The caller is expected to take a read-lock before calling this.
499
 
        """
500
 
        if not self._supports_executable():
 
463
            Note: The caller is expected to take a read-lock before calling this.
 
464
            """
501
465
            entry = self._get_entry(file_id=file_id, path=path)
502
466
            if entry == (None, None):
503
467
                return False
504
468
            return entry[1][0][3]
505
 
        else:
 
469
 
 
470
        _is_executable_from_path_and_stat = \
 
471
            _is_executable_from_path_and_stat_from_basis
 
472
    else:
 
473
        def is_executable(self, file_id, path=None):
 
474
            """Test if a file is executable or not.
 
475
 
 
476
            Note: The caller is expected to take a read-lock before calling this.
 
477
            """
506
478
            self._must_be_locked()
507
479
            if not path:
508
480
                path = self.id2path(file_id)
509
 
            mode = osutils.lstat(self.abspath(path)).st_mode
 
481
            mode = os.lstat(self.abspath(path)).st_mode
510
482
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
511
483
 
512
484
    def all_file_ids(self):
692
664
 
693
665
        if self._inventory is not None:
694
666
            update_inventory = True
695
 
            inv = self.root_inventory
 
667
            inv = self.inventory
696
668
            to_dir_id = to_entry[0][2]
697
669
            to_dir_ie = inv[to_dir_id]
698
670
        else:
878
850
                rollback_rename()
879
851
                raise
880
852
            result.append((from_rel, to_rel))
881
 
            state._mark_modified()
 
853
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
882
854
            self._make_dirty(reset_inventory=False)
883
855
 
884
856
        return result
894
866
    @needs_read_lock
895
867
    def path2id(self, path):
896
868
        """Return the id for path in this tree."""
897
 
        if isinstance(path, list):
898
 
            if path == []:
899
 
                path = [""]
900
 
            path = osutils.pathjoin(*path)
901
869
        path = path.strip('/')
902
870
        entry = self._get_entry(path=path)
903
871
        if entry == (None, None):
981
949
                    all_versioned = False
982
950
                    break
983
951
            if not all_versioned:
984
 
                raise errors.PathsNotVersionedError(
985
 
                    [p.decode('utf-8') for p in paths])
 
952
                raise errors.PathsNotVersionedError(paths)
986
953
        # -- remove redundancy in supplied paths to prevent over-scanning --
987
954
        search_paths = osutils.minimum_path_selection(paths)
988
955
        # sketch:
1037
1004
            found_dir_names = set(dir_name_id[:2] for dir_name_id in found)
1038
1005
            for dir_name in split_paths:
1039
1006
                if dir_name not in found_dir_names:
1040
 
                    raise errors.PathsNotVersionedError(
1041
 
                        [p.decode('utf-8') for p in paths])
 
1007
                    raise errors.PathsNotVersionedError(paths)
1042
1008
 
1043
1009
        for dir_name_id, trees_info in found.iteritems():
1044
1010
            for index in search_indexes:
1051
1017
 
1052
1018
        This is a meaningless operation for dirstate, but we obey it anyhow.
1053
1019
        """
1054
 
        return self.root_inventory
 
1020
        return self.inventory
1055
1021
 
1056
1022
    @needs_read_lock
1057
1023
    def revision_tree(self, revision_id):
1147
1113
                        _mod_revision.NULL_REVISION)))
1148
1114
                ghosts.append(rev_id)
1149
1115
            accepted_revisions.add(rev_id)
1150
 
        updated = False
1151
 
        if (len(real_trees) == 1
1152
 
            and not ghosts
1153
 
            and self.branch.repository._format.fast_deltas
1154
 
            and isinstance(real_trees[0][1],
1155
 
                revisiontree.InventoryRevisionTree)
1156
 
            and self.get_parent_ids()):
1157
 
            rev_id, rev_tree = real_trees[0]
1158
 
            basis_id = self.get_parent_ids()[0]
1159
 
            # There are times when basis_tree won't be in
1160
 
            # self.branch.repository, (switch, for example)
1161
 
            try:
1162
 
                basis_tree = self.branch.repository.revision_tree(basis_id)
1163
 
            except errors.NoSuchRevision:
1164
 
                # Fall back to the set_parent_trees(), since we can't use
1165
 
                # _make_delta if we can't get the RevisionTree
1166
 
                pass
1167
 
            else:
1168
 
                delta = rev_tree.root_inventory._make_delta(
1169
 
                    basis_tree.root_inventory)
1170
 
                dirstate.update_basis_by_delta(delta, rev_id)
1171
 
                updated = True
1172
 
        if not updated:
1173
 
            dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1116
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1174
1117
        self._make_dirty(reset_inventory=False)
1175
1118
 
1176
1119
    def _set_root_id(self, file_id):
1196
1139
 
1197
1140
    def unlock(self):
1198
1141
        """Unlock in format 4 trees needs to write the entire dirstate."""
 
1142
        # do non-implementation specific cleanup
 
1143
        self._cleanup()
 
1144
 
1199
1145
        if self._control_files._lock_count == 1:
1200
 
            # do non-implementation specific cleanup
1201
 
            self._cleanup()
1202
 
 
1203
1146
            # eventually we should do signature checking during read locks for
1204
1147
            # dirstate updates.
1205
1148
            if self._control_files._lock_mode == 'w':
1311
1254
    def rename_one(self, from_rel, to_rel, after=False):
1312
1255
        """See WorkingTree.rename_one"""
1313
1256
        self.flush()
1314
 
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
 
1257
        WorkingTree.rename_one(self, from_rel, to_rel, after)
1315
1258
 
1316
1259
    @needs_tree_write_lock
1317
1260
    def apply_inventory_delta(self, changes):
1343
1286
        # being created.
1344
1287
        self._inventory = None
1345
1288
        # generate a delta,
1346
 
        delta = inv._make_delta(self.root_inventory)
 
1289
        delta = inv._make_delta(self.inventory)
1347
1290
        # and apply it.
1348
1291
        self.apply_inventory_delta(delta)
1349
1292
        if had_inventory:
1350
1293
            self._inventory = inv
1351
1294
        self.flush()
1352
1295
 
1353
 
    @needs_tree_write_lock
1354
 
    def reset_state(self, revision_ids=None):
1355
 
        """Reset the state of the working tree.
1356
 
 
1357
 
        This does a hard-reset to a last-known-good state. This is a way to
1358
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
1359
 
        """
1360
 
        if revision_ids is None:
1361
 
            revision_ids = self.get_parent_ids()
1362
 
        if not revision_ids:
1363
 
            base_tree = self.branch.repository.revision_tree(
1364
 
                _mod_revision.NULL_REVISION)
1365
 
            trees = []
1366
 
        else:
1367
 
            trees = zip(revision_ids,
1368
 
                        self.branch.repository.revision_trees(revision_ids))
1369
 
            base_tree = trees[0][1]
1370
 
        state = self.current_dirstate()
1371
 
        # We don't support ghosts yet
1372
 
        state.set_state_from_scratch(base_tree.root_inventory, trees, [])
1373
 
 
1374
1296
 
1375
1297
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1376
1298
 
1381
1303
        """See dirstate.SHA1Provider.sha1()."""
1382
1304
        filters = self.tree._content_filter_stack(
1383
1305
            self.tree.relpath(osutils.safe_unicode(abspath)))
1384
 
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1306
        return internal_size_sha_file_byname(abspath, filters)[1]
1385
1307
 
1386
1308
    def stat_and_sha1(self, abspath):
1387
1309
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1391
1313
        try:
1392
1314
            statvalue = os.fstat(file_obj.fileno())
1393
1315
            if filters:
1394
 
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1316
                file_obj = filtered_input_file(file_obj, filters)
1395
1317
            sha1 = osutils.size_sha_file(file_obj)[1]
1396
1318
        finally:
1397
1319
            file_obj.close()
1427
1349
class WorkingTree4(DirStateWorkingTree):
1428
1350
    """This is the Format 4 working tree.
1429
1351
 
1430
 
    This differs from WorkingTree by:
 
1352
    This differs from WorkingTree3 by:
1431
1353
     - Having a consolidated internal dirstate, stored in a
1432
1354
       randomly-accessible sorted file on disk.
1433
1355
     - Not having a regular inventory attribute.  One can be synthesized
1461
1383
        return views.PathBasedViews(self)
1462
1384
 
1463
1385
 
1464
 
class DirStateWorkingTreeFormat(WorkingTreeFormatMetaDir):
1465
 
 
1466
 
    missing_parent_conflicts = True
1467
 
 
1468
 
    supports_versioned_directories = True
1469
 
 
1470
 
    _lock_class = LockDir
1471
 
    _lock_file_name = 'lock'
1472
 
 
1473
 
    def _open_control_files(self, a_bzrdir):
1474
 
        transport = a_bzrdir.get_workingtree_transport(None)
1475
 
        return LockableFiles(transport, self._lock_file_name,
1476
 
                             self._lock_class)
 
1386
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1477
1387
 
1478
1388
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1479
1389
                   accelerator_tree=None, hardlink=False):
1480
1390
        """See WorkingTreeFormat.initialize().
1481
1391
 
1482
1392
        :param revision_id: allows creating a working tree at a different
1483
 
            revision than the branch is at.
 
1393
        revision than the branch is at.
1484
1394
        :param accelerator_tree: A tree which can be used for retrieving file
1485
1395
            contents more quickly than the revision tree, i.e. a workingtree.
1486
1396
            The revision tree will be used for cases where accelerator_tree's
1497
1407
        control_files = self._open_control_files(a_bzrdir)
1498
1408
        control_files.create_lock()
1499
1409
        control_files.lock_write()
1500
 
        transport.put_bytes('format', self.as_string(),
 
1410
        transport.put_bytes('format', self.get_format_string(),
1501
1411
            mode=a_bzrdir._get_file_mode())
1502
1412
        if from_branch is not None:
1503
1413
            branch = from_branch
1563
1473
                transform.build_tree(basis, wt, accelerator_tree,
1564
1474
                                     hardlink=hardlink,
1565
1475
                                     delta_from_tree=delta_from_tree)
1566
 
                for hook in MutableTree.hooks['post_build_tree']:
1567
 
                    hook(wt)
1568
1476
            finally:
1569
1477
                basis.unlock()
1570
1478
        finally:
1581
1489
        :param wt: the WorkingTree object
1582
1490
        """
1583
1491
 
1584
 
    def open(self, a_bzrdir, _found=False):
1585
 
        """Return the WorkingTree object for a_bzrdir
1586
 
 
1587
 
        _found is a private parameter, do not use it. It is used to indicate
1588
 
               if format probing has already been done.
1589
 
        """
1590
 
        if not _found:
1591
 
            # we are being called directly and must probe.
1592
 
            raise NotImplementedError
1593
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
1594
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1595
 
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1596
 
        return wt
1597
 
 
1598
1492
    def _open(self, a_bzrdir, control_files):
1599
1493
        """Open the tree itself.
1600
1494
 
1613
1507
    def _get_matchingbzrdir(self):
1614
1508
        """Overrideable method to get a bzrdir for testing."""
1615
1509
        # please test against something that will let us do tree references
1616
 
        return controldir.format_registry.make_bzrdir(
1617
 
            'development-subtree')
 
1510
        return bzrdir.format_registry.make_bzrdir(
 
1511
            'dirstate-with-subtree')
1618
1512
 
1619
1513
    _matchingbzrdir = property(__get_matchingbzrdir)
1620
1514
 
1625
1519
    This format:
1626
1520
        - exists within a metadir controlling .bzr
1627
1521
        - includes an explicit version marker for the workingtree control
1628
 
          files, separate from the ControlDir format
 
1522
          files, separate from the BzrDir format
1629
1523
        - modifies the hash cache format
1630
1524
        - is new in bzr 0.15
1631
1525
        - uses a LockDir to guard access to it.
1635
1529
 
1636
1530
    _tree_class = WorkingTree4
1637
1531
 
1638
 
    @classmethod
1639
 
    def get_format_string(cls):
 
1532
    def get_format_string(self):
1640
1533
        """See WorkingTreeFormat.get_format_string()."""
1641
1534
        return "Bazaar Working Tree Format 4 (bzr 0.15)\n"
1642
1535
 
1653
1546
 
1654
1547
    _tree_class = WorkingTree5
1655
1548
 
1656
 
    @classmethod
1657
 
    def get_format_string(cls):
 
1549
    def get_format_string(self):
1658
1550
        """See WorkingTreeFormat.get_format_string()."""
1659
1551
        return "Bazaar Working Tree Format 5 (bzr 1.11)\n"
1660
1552
 
1674
1566
 
1675
1567
    _tree_class = WorkingTree6
1676
1568
 
1677
 
    @classmethod
1678
 
    def get_format_string(cls):
 
1569
    def get_format_string(self):
1679
1570
        """See WorkingTreeFormat.get_format_string()."""
1680
1571
        return "Bazaar Working Tree Format 6 (bzr 1.14)\n"
1681
1572
 
1693
1584
    def supports_views(self):
1694
1585
        return True
1695
1586
 
1696
 
    def _get_matchingbzrdir(self):
1697
 
        """Overrideable method to get a bzrdir for testing."""
1698
 
        # We use 'development-subtree' instead of '2a', because we have a
1699
 
        # few tests that want to test tree references
1700
 
        return bzrdir.format_registry.make_bzrdir('development-subtree')
1701
 
 
1702
 
 
1703
 
class DirStateRevisionTree(InventoryTree):
 
1587
 
 
1588
class DirStateRevisionTree(Tree):
1704
1589
    """A revision tree pulling the inventory from a dirstate.
1705
1590
    
1706
1591
    Note that this is one of the historical (ie revision) trees cached in the
1725
1610
    def annotate_iter(self, file_id,
1726
1611
                      default_revision=_mod_revision.CURRENT_REVISION):
1727
1612
        """See Tree.annotate_iter"""
1728
 
        text_key = (file_id, self.get_file_revision(file_id))
 
1613
        text_key = (file_id, self.inventory[file_id].revision)
1729
1614
        annotations = self._repository.texts.annotate(text_key)
1730
1615
        return [(key[-1], line) for (key, line) in annotations]
1731
1616
 
 
1617
    def _get_ancestors(self, default_revision):
 
1618
        return set(self._repository.get_ancestry(self._revision_id,
 
1619
                                                 topo_sorted=False))
1732
1620
    def _comparison_data(self, entry, path):
1733
1621
        """See Tree._comparison_data."""
1734
1622
        if entry is None:
1787
1675
        if path is not None:
1788
1676
            path = path.encode('utf8')
1789
1677
        parent_index = self._get_parent_index()
1790
 
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id,
1791
 
            path_utf8=path)
 
1678
        return self._dirstate._get_entry(parent_index, fileid_utf8=file_id, path_utf8=path)
1792
1679
 
1793
1680
    def _generate_inventory(self):
1794
1681
        """Create and set self.inventory from the dirstate object.
1876
1763
        # Make sure the file exists
1877
1764
        entry = self._get_entry(file_id, path=path)
1878
1765
        if entry == (None, None): # do we raise?
1879
 
            raise errors.NoSuchId(self, file_id)
 
1766
            return None
1880
1767
        parent_index = self._get_parent_index()
1881
1768
        last_changed_revision = entry[1][parent_index][4]
1882
1769
        try:
1893
1780
            return parent_details[1]
1894
1781
        return None
1895
1782
 
1896
 
    @needs_read_lock
1897
 
    def get_file_revision(self, file_id):
1898
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1899
 
        return inv[inv_file_id].revision
1900
 
 
1901
1783
    def get_file(self, file_id, path=None):
1902
1784
        return StringIO(self.get_file_text(file_id))
1903
1785
 
1904
1786
    def get_file_size(self, file_id):
1905
1787
        """See Tree.get_file_size"""
1906
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1907
 
        return inv[inv_file_id].text_size
 
1788
        return self.inventory[file_id].text_size
1908
1789
 
1909
1790
    def get_file_text(self, file_id, path=None):
1910
 
        content = None
1911
 
        for _, content_iter in self.iter_files_bytes([(file_id, None)]):
1912
 
            if content is not None:
1913
 
                raise AssertionError('iter_files_bytes returned'
1914
 
                    ' too many entries')
1915
 
            # For each entry returned by iter_files_bytes, we must consume the
1916
 
            # content_iter before we step the files iterator.
1917
 
            content = ''.join(content_iter)
1918
 
        if content is None:
1919
 
            raise AssertionError('iter_files_bytes did not return'
1920
 
                ' the requested data')
1921
 
        return content
 
1791
        _, content = list(self.iter_files_bytes([(file_id, None)]))[0]
 
1792
        return ''.join(content)
1922
1793
 
1923
1794
    def get_reference_revision(self, file_id, path=None):
1924
 
        inv, inv_file_id = self._unpack_file_id(file_id)
1925
 
        return inv[inv_file_id].reference_revision
 
1795
        return self.inventory[file_id].reference_revision
1926
1796
 
1927
1797
    def iter_files_bytes(self, desired_files):
1928
1798
        """See Tree.iter_files_bytes.
1938
1808
                                       identifier))
1939
1809
        return self._repository.iter_files_bytes(repo_desired_files)
1940
1810
 
1941
 
    def get_symlink_target(self, file_id, path=None):
 
1811
    def get_symlink_target(self, file_id):
1942
1812
        entry = self._get_entry(file_id=file_id)
1943
1813
        parent_index = self._get_parent_index()
1944
1814
        if entry[1][parent_index][0] != 'l':
1952
1822
        """Return the revision id for this tree."""
1953
1823
        return self._revision_id
1954
1824
 
1955
 
    def _get_root_inventory(self):
 
1825
    def _get_inventory(self):
1956
1826
        if self._inventory is not None:
1957
1827
            return self._inventory
1958
1828
        self._must_be_locked()
1959
1829
        self._generate_inventory()
1960
1830
        return self._inventory
1961
1831
 
1962
 
    root_inventory = property(_get_root_inventory,
1963
 
                         doc="Inventory of this Tree")
1964
 
 
1965
 
    @deprecated_method(deprecated_in((2, 5, 0)))
1966
 
    def _get_inventory(self):
1967
 
        return self.root_inventory
1968
 
 
1969
1832
    inventory = property(_get_inventory,
1970
1833
                         doc="Inventory of this Tree")
1971
1834
 
1989
1852
 
1990
1853
    def path_content_summary(self, path):
1991
1854
        """See Tree.path_content_summary."""
1992
 
        inv, inv_file_id = self._path2inv_file_id(path)
1993
 
        if inv_file_id is None:
 
1855
        id = self.inventory.path2id(path)
 
1856
        if id is None:
1994
1857
            return ('missing', None, None, None)
1995
 
        entry = inv[inv_file_id]
 
1858
        entry = self._inventory[id]
1996
1859
        kind = entry.kind
1997
1860
        if kind == 'file':
1998
1861
            return (kind, entry.text_size, entry.executable, entry.text_sha1)
2002
1865
            return (kind, None, None, None)
2003
1866
 
2004
1867
    def is_executable(self, file_id, path=None):
2005
 
        inv, inv_file_id = self._unpack_file_id(file_id)
2006
 
        ie = inv[inv_file_id]
 
1868
        ie = self.inventory[file_id]
2007
1869
        if ie.kind != "file":
2008
 
            return False
 
1870
            return None
2009
1871
        return ie.executable
2010
1872
 
2011
1873
    def is_locked(self):
2014
1876
    def list_files(self, include_root=False, from_dir=None, recursive=True):
2015
1877
        # We use a standard implementation, because DirStateRevisionTree is
2016
1878
        # dealing with one of the parents of the current state
 
1879
        inv = self._get_inventory()
2017
1880
        if from_dir is None:
2018
 
            inv = self.root_inventory
2019
1881
            from_dir_id = None
2020
1882
        else:
2021
 
            inv, from_dir_id = self._path2inv_file_id(from_dir)
 
1883
            from_dir_id = inv.path2id(from_dir)
2022
1884
            if from_dir_id is None:
2023
1885
                # Directory not versioned
2024
1886
                return
2025
 
        # FIXME: Support nested trees
2026
1887
        entries = inv.iter_entries(from_dir=from_dir_id, recursive=recursive)
2027
1888
        if inv.root is not None and not include_root and from_dir is None:
2028
1889
            entries.next()
2050
1911
    def path2id(self, path):
2051
1912
        """Return the id for path in this tree."""
2052
1913
        # lookup by path: faster than splitting and walking the ivnentory.
2053
 
        if isinstance(path, list):
2054
 
            if path == []:
2055
 
                path = [""]
2056
 
            path = osutils.pathjoin(*path)
2057
1914
        entry = self._get_entry(path=path)
2058
1915
        if entry == (None, None):
2059
1916
            return None
2082
1939
        # So for now, we just build up the parent inventory, and extract
2083
1940
        # it the same way RevisionTree does.
2084
1941
        _directory = 'directory'
2085
 
        inv = self._get_root_inventory()
 
1942
        inv = self._get_inventory()
2086
1943
        top_id = inv.path2id(prefix)
2087
1944
        if top_id is None:
2088
1945
            pending = []
2129
1986
    def make_source_parent_tree(source, target):
2130
1987
        """Change the source tree into a parent of the target."""
2131
1988
        revid = source.commit('record tree')
2132
 
        target.branch.fetch(source.branch, revid)
 
1989
        target.branch.repository.fetch(source.branch.repository, revid)
2133
1990
        target.set_parent_ids([revid])
2134
1991
        return target.basis_tree(), target
2135
1992
 
2227
2084
                path_entries = state._entries_for_path(path)
2228
2085
                if not path_entries:
2229
2086
                    # this specified path is not present at all: error
2230
 
                    not_versioned.append(path.decode('utf-8'))
 
2087
                    not_versioned.append(path)
2231
2088
                    continue
2232
2089
                found_versioned = False
2233
2090
                # for each id at this path
2241
2098
                if not found_versioned:
2242
2099
                    # none of the indexes was not 'absent' at all ids for this
2243
2100
                    # path.
2244
 
                    not_versioned.append(path.decode('utf-8'))
 
2101
                    not_versioned.append(path)
2245
2102
            if len(not_versioned) > 0:
2246
2103
                raise errors.PathsNotVersionedError(not_versioned)
2247
2104
        # -- remove redundancy in supplied specific_files to prevent over-scanning --
2314
2171
    def update_format(self, tree):
2315
2172
        """Change the format marker."""
2316
2173
        tree._transport.put_bytes('format',
2317
 
            self.target_format.as_string(),
 
2174
            self.target_format.get_format_string(),
2318
2175
            mode=tree.bzrdir._get_file_mode())
2319
2176
 
2320
2177
 
2337
2194
    def update_format(self, tree):
2338
2195
        """Change the format marker."""
2339
2196
        tree._transport.put_bytes('format',
2340
 
            self.target_format.as_string(),
 
2197
            self.target_format.get_format_string(),
2341
2198
            mode=tree.bzrdir._get_file_mode())
2342
2199
 
2343
2200
 
2366
2223
    def update_format(self, tree):
2367
2224
        """Change the format marker."""
2368
2225
        tree._transport.put_bytes('format',
2369
 
            self.target_format.as_string(),
 
2226
            self.target_format.get_format_string(),
2370
2227
            mode=tree.bzrdir._get_file_mode())