~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Vincent Ladeuil
  • Date: 2011-09-09 13:30:12 UTC
  • mfrom: (5609.48.11 2.3)
  • mto: (6015.33.3 2.4)
  • mto: This revision was merged to the branch mainline in revision 6134.
  • Revision ID: v.ladeuil+lp@free.fr-20110909133012-jc1d1zyqgak57123
Merge 2.3 into 2.4

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
31
31
import errno
32
32
import stat
33
33
 
34
 
import bzrlib
35
34
from bzrlib import (
36
35
    bzrdir,
37
36
    cache_utf8,
 
37
    conflicts as _mod_conflicts,
38
38
    debug,
39
39
    dirstate,
40
40
    errors,
 
41
    filters as _mod_filters,
41
42
    generate_ids,
42
43
    osutils,
43
44
    revision as _mod_revision,
46
47
    transform,
47
48
    views,
48
49
    )
49
 
import bzrlib.branch
50
 
import bzrlib.ui
51
50
""")
52
51
 
53
52
from bzrlib.decorators import needs_read_lock, needs_write_lock
54
 
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
55
53
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
 
import bzrlib.mutabletree
 
54
from bzrlib.lock import LogicalLockResult
 
55
from bzrlib.lockable_files import LockableFiles
 
56
from bzrlib.lockdir import LockDir
57
57
from bzrlib.mutabletree import needs_tree_write_lock
58
58
from bzrlib.osutils import (
59
59
    file_kind,
62
62
    realpath,
63
63
    safe_unicode,
64
64
    )
65
 
from bzrlib.trace import mutter
66
65
from bzrlib.transport.local import LocalTransport
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):
 
66
from bzrlib.tree import (
 
67
    InterTree,
 
68
    InventoryTree,
 
69
    )
 
70
from bzrlib.workingtree import (
 
71
    InventoryWorkingTree,
 
72
    WorkingTree,
 
73
    WorkingTreeFormat,
 
74
    )
 
75
 
 
76
 
 
77
class DirStateWorkingTree(InventoryWorkingTree):
 
78
 
 
79
    _DEFAULT_WORTH_SAVING_LIMIT = 10
 
80
 
73
81
    def __init__(self, basedir,
74
82
                 branch,
75
83
                 _control_files=None,
85
93
        self._format = _format
86
94
        self.bzrdir = _bzrdir
87
95
        basedir = safe_unicode(basedir)
88
 
        mutter("opening working tree %r", basedir)
 
96
        trace.mutter("opening working tree %r", basedir)
89
97
        self._branch = branch
90
98
        self.basedir = realpath(basedir)
91
99
        # if branch is at our basedir and is a format 6 or less
125
133
            state.add(f, file_id, kind, None, '')
126
134
        self._make_dirty(reset_inventory=True)
127
135
 
 
136
    def _get_check_refs(self):
 
137
        """Return the references needed to perform a check of this tree."""
 
138
        return [('trees', self.last_revision())]
 
139
 
128
140
    def _make_dirty(self, reset_inventory):
129
141
        """Make the tree state dirty.
130
142
 
182
194
 
183
195
    def _comparison_data(self, entry, path):
184
196
        kind, executable, stat_value = \
185
 
            WorkingTree3._comparison_data(self, entry, path)
 
197
            WorkingTree._comparison_data(self, entry, path)
186
198
        # it looks like a plain directory, but it's really a reference -- see
187
199
        # also kind()
188
200
        if (self._repo_supports_tree_reference and kind == 'directory'
194
206
    def commit(self, message=None, revprops=None, *args, **kwargs):
195
207
        # mark the tree as dirty post commit - commit
196
208
        # can change the current versioned list by doing deletes.
197
 
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
 
209
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
198
210
        self._make_dirty(reset_inventory=True)
199
211
        return result
200
212
 
219
231
        local_path = self.bzrdir.get_workingtree_transport(None
220
232
            ).local_abspath('dirstate')
221
233
        self._dirstate = dirstate.DirState.on_file(local_path,
222
 
            self._sha1_provider())
 
234
            self._sha1_provider(), self._worth_saving_limit())
223
235
        return self._dirstate
224
236
 
225
237
    def _sha1_provider(self):
234
246
        else:
235
247
            return None
236
248
 
 
249
    def _worth_saving_limit(self):
 
250
        """How many hash changes are ok before we must save the dirstate.
 
251
 
 
252
        :return: an integer. -1 means never save.
 
253
        """
 
254
        config = self.branch.get_config()
 
255
        val = config.get_user_option('bzr.workingtree.worth_saving_limit')
 
256
        if val is None:
 
257
            val = self._DEFAULT_WORTH_SAVING_LIMIT
 
258
        else:
 
259
            try:
 
260
                val = int(val)
 
261
            except ValueError, e:
 
262
                trace.warning('Invalid config value for'
 
263
                              ' "bzr.workingtree.worth_saving_limit"'
 
264
                              ' value %r is not an integer.'
 
265
                              % (val,))
 
266
                val = self._DEFAULT_WORTH_SAVING_LIMIT
 
267
        return val
 
268
 
237
269
    def filter_unversioned_files(self, paths):
238
270
        """Filter out paths that are versioned.
239
271
 
369
401
        state = self.current_dirstate()
370
402
        if stat_value is None:
371
403
            try:
372
 
                stat_value = os.lstat(file_abspath)
 
404
                stat_value = osutils.lstat(file_abspath)
373
405
            except OSError, e:
374
406
                if e.errno == errno.ENOENT:
375
407
                    return None
478
510
            self._must_be_locked()
479
511
            if not path:
480
512
                path = self.id2path(file_id)
481
 
            mode = os.lstat(self.abspath(path)).st_mode
 
513
            mode = osutils.lstat(self.abspath(path)).st_mode
482
514
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
483
515
 
484
516
    def all_file_ids(self):
568
600
            return _mod_revision.NULL_REVISION
569
601
 
570
602
    def lock_read(self):
571
 
        """See Branch.lock_read, and WorkingTree.unlock."""
 
603
        """See Branch.lock_read, and WorkingTree.unlock.
 
604
 
 
605
        :return: A bzrlib.lock.LogicalLockResult.
 
606
        """
572
607
        self.branch.lock_read()
573
608
        try:
574
609
            self._control_files.lock_read()
587
622
        except:
588
623
            self.branch.unlock()
589
624
            raise
 
625
        return LogicalLockResult(self.unlock)
590
626
 
591
627
    def _lock_self_write(self):
592
628
        """This should be called after the branch is locked."""
607
643
        except:
608
644
            self.branch.unlock()
609
645
            raise
 
646
        return LogicalLockResult(self.unlock)
610
647
 
611
648
    def lock_tree_write(self):
612
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
 
649
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
 
650
 
 
651
        :return: A bzrlib.lock.LogicalLockResult.
 
652
        """
613
653
        self.branch.lock_read()
614
 
        self._lock_self_write()
 
654
        return self._lock_self_write()
615
655
 
616
656
    def lock_write(self):
617
 
        """See MutableTree.lock_write, and WorkingTree.unlock."""
 
657
        """See MutableTree.lock_write, and WorkingTree.unlock.
 
658
 
 
659
        :return: A bzrlib.lock.LogicalLockResult.
 
660
        """
618
661
        self.branch.lock_write()
619
 
        self._lock_self_write()
 
662
        return self._lock_self_write()
620
663
 
621
664
    @needs_tree_write_lock
622
665
    def move(self, from_paths, to_dir, after=False):
839
882
                rollback_rename()
840
883
                raise
841
884
            result.append((from_rel, to_rel))
842
 
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
 
885
            state._mark_modified()
843
886
            self._make_dirty(reset_inventory=False)
844
887
 
845
888
        return result
1102
1145
                        _mod_revision.NULL_REVISION)))
1103
1146
                ghosts.append(rev_id)
1104
1147
            accepted_revisions.add(rev_id)
1105
 
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1148
        updated = False
 
1149
        if (len(real_trees) == 1
 
1150
            and not ghosts
 
1151
            and self.branch.repository._format.fast_deltas
 
1152
            and isinstance(real_trees[0][1],
 
1153
                revisiontree.InventoryRevisionTree)
 
1154
            and self.get_parent_ids()):
 
1155
            rev_id, rev_tree = real_trees[0]
 
1156
            basis_id = self.get_parent_ids()[0]
 
1157
            # There are times when basis_tree won't be in
 
1158
            # self.branch.repository, (switch, for example)
 
1159
            try:
 
1160
                basis_tree = self.branch.repository.revision_tree(basis_id)
 
1161
            except errors.NoSuchRevision:
 
1162
                # Fall back to the set_parent_trees(), since we can't use
 
1163
                # _make_delta if we can't get the RevisionTree
 
1164
                pass
 
1165
            else:
 
1166
                delta = rev_tree.inventory._make_delta(basis_tree.inventory)
 
1167
                dirstate.update_basis_by_delta(delta, rev_id)
 
1168
                updated = True
 
1169
        if not updated:
 
1170
            dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1106
1171
        self._make_dirty(reset_inventory=False)
1107
1172
 
1108
1173
    def _set_root_id(self, file_id):
1128
1193
 
1129
1194
    def unlock(self):
1130
1195
        """Unlock in format 4 trees needs to write the entire dirstate."""
1131
 
        # do non-implementation specific cleanup
1132
 
        self._cleanup()
1133
 
 
1134
1196
        if self._control_files._lock_count == 1:
 
1197
            # do non-implementation specific cleanup
 
1198
            self._cleanup()
 
1199
 
1135
1200
            # eventually we should do signature checking during read locks for
1136
1201
            # dirstate updates.
1137
1202
            if self._control_files._lock_mode == 'w':
1236
1301
        # have to change the legacy inventory too.
1237
1302
        if self._inventory is not None:
1238
1303
            for file_id in file_ids:
1239
 
                self._inventory.remove_recursive_id(file_id)
 
1304
                if self._inventory.has_id(file_id):
 
1305
                    self._inventory.remove_recursive_id(file_id)
1240
1306
 
1241
1307
    @needs_tree_write_lock
1242
1308
    def rename_one(self, from_rel, to_rel, after=False):
1243
1309
        """See WorkingTree.rename_one"""
1244
1310
        self.flush()
1245
 
        WorkingTree.rename_one(self, from_rel, to_rel, after)
 
1311
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1246
1312
 
1247
1313
    @needs_tree_write_lock
1248
1314
    def apply_inventory_delta(self, changes):
1267
1333
        if self._dirty:
1268
1334
            raise AssertionError("attempting to write an inventory when the "
1269
1335
                "dirstate is dirty will lose pending changes")
1270
 
        self.current_dirstate().set_state_from_inventory(inv)
1271
 
        self._make_dirty(reset_inventory=False)
1272
 
        if self._inventory is not None:
 
1336
        had_inventory = self._inventory is not None
 
1337
        # Setting self._inventory = None forces the dirstate to regenerate the
 
1338
        # working inventory. We do this because self.inventory may be inv, or
 
1339
        # may have been modified, and either case would prevent a clean delta
 
1340
        # being created.
 
1341
        self._inventory = None
 
1342
        # generate a delta,
 
1343
        delta = inv._make_delta(self.inventory)
 
1344
        # and apply it.
 
1345
        self.apply_inventory_delta(delta)
 
1346
        if had_inventory:
1273
1347
            self._inventory = inv
1274
1348
        self.flush()
1275
1349
 
 
1350
    @needs_tree_write_lock
 
1351
    def reset_state(self, revision_ids=None):
 
1352
        """Reset the state of the working tree.
 
1353
 
 
1354
        This does a hard-reset to a last-known-good state. This is a way to
 
1355
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
 
1356
        """
 
1357
        if revision_ids is None:
 
1358
            revision_ids = self.get_parent_ids()
 
1359
        if not revision_ids:
 
1360
            base_tree = self.branch.repository.revision_tree(
 
1361
                _mod_revision.NULL_REVISION)
 
1362
            trees = []
 
1363
        else:
 
1364
            trees = zip(revision_ids,
 
1365
                        self.branch.repository.revision_trees(revision_ids))
 
1366
            base_tree = trees[0][1]
 
1367
        state = self.current_dirstate()
 
1368
        # We don't support ghosts yet
 
1369
        state.set_state_from_scratch(base_tree.inventory, trees, [])
 
1370
 
1276
1371
 
1277
1372
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1278
1373
 
1283
1378
        """See dirstate.SHA1Provider.sha1()."""
1284
1379
        filters = self.tree._content_filter_stack(
1285
1380
            self.tree.relpath(osutils.safe_unicode(abspath)))
1286
 
        return internal_size_sha_file_byname(abspath, filters)[1]
 
1381
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1287
1382
 
1288
1383
    def stat_and_sha1(self, abspath):
1289
1384
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1293
1388
        try:
1294
1389
            statvalue = os.fstat(file_obj.fileno())
1295
1390
            if filters:
1296
 
                file_obj = filtered_input_file(file_obj, filters)
 
1391
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1297
1392
            sha1 = osutils.size_sha_file(file_obj)[1]
1298
1393
        finally:
1299
1394
            file_obj.close()
1300
1395
        return statvalue, sha1
1301
1396
 
1302
1397
 
 
1398
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
 
1399
    """Dirstate working tree that supports content filtering.
 
1400
 
 
1401
    The dirstate holds the hash and size of the canonical form of the file, 
 
1402
    and most methods must return that.
 
1403
    """
 
1404
 
 
1405
    def _file_content_summary(self, path, stat_result):
 
1406
        # This is to support the somewhat obsolete path_content_summary method
 
1407
        # with content filtering: see
 
1408
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
 
1409
        #
 
1410
        # If the dirstate cache is up to date and knows the hash and size,
 
1411
        # return that.
 
1412
        # Otherwise if there are no content filters, return the on-disk size
 
1413
        # and leave the hash blank.
 
1414
        # Otherwise, read and filter the on-disk file and use its size and
 
1415
        # hash.
 
1416
        #
 
1417
        # The dirstate doesn't store the size of the canonical form so we
 
1418
        # can't trust it for content-filtered trees.  We just return None.
 
1419
        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
 
1420
        executable = self._is_executable_from_path_and_stat(path, stat_result)
 
1421
        return ('file', None, executable, dirstate_sha1)
 
1422
 
 
1423
 
1303
1424
class WorkingTree4(DirStateWorkingTree):
1304
1425
    """This is the Format 4 working tree.
1305
1426
 
1306
 
    This differs from WorkingTree3 by:
 
1427
    This differs from WorkingTree by:
1307
1428
     - Having a consolidated internal dirstate, stored in a
1308
1429
       randomly-accessible sorted file on disk.
1309
1430
     - Not having a regular inventory attribute.  One can be synthesized
1313
1434
    """
1314
1435
 
1315
1436
 
1316
 
class WorkingTree5(DirStateWorkingTree):
 
1437
class WorkingTree5(ContentFilteringDirStateWorkingTree):
1317
1438
    """This is the Format 5 working tree.
1318
1439
 
1319
1440
    This differs from WorkingTree4 by:
1323
1444
    """
1324
1445
 
1325
1446
 
1326
 
class WorkingTree6(DirStateWorkingTree):
 
1447
class WorkingTree6(ContentFilteringDirStateWorkingTree):
1327
1448
    """This is the Format 6 working tree.
1328
1449
 
1329
1450
    This differs from WorkingTree5 by:
1337
1458
        return views.PathBasedViews(self)
1338
1459
 
1339
1460
 
1340
 
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
 
1461
class DirStateWorkingTreeFormat(WorkingTreeFormat):
 
1462
 
 
1463
    missing_parent_conflicts = True
 
1464
 
 
1465
    supports_versioned_directories = True
 
1466
 
 
1467
    _lock_class = LockDir
 
1468
    _lock_file_name = 'lock'
 
1469
 
 
1470
    def _open_control_files(self, a_bzrdir):
 
1471
        transport = a_bzrdir.get_workingtree_transport(None)
 
1472
        return LockableFiles(transport, self._lock_file_name,
 
1473
                             self._lock_class)
 
1474
 
1341
1475
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1342
1476
                   accelerator_tree=None, hardlink=False):
1343
1477
        """See WorkingTreeFormat.initialize().
1344
1478
 
1345
1479
        :param revision_id: allows creating a working tree at a different
1346
 
        revision than the branch is at.
 
1480
            revision than the branch is at.
1347
1481
        :param accelerator_tree: A tree which can be used for retrieving file
1348
1482
            contents more quickly than the revision tree, i.e. a workingtree.
1349
1483
            The revision tree will be used for cases where accelerator_tree's
1413
1547
                if basis_root_id is not None:
1414
1548
                    wt._set_root_id(basis_root_id)
1415
1549
                    wt.flush()
1416
 
                # If content filtering is supported, do not use the accelerator
1417
 
                # tree - the cost of transforming the content both ways and
1418
 
                # checking for changed content can outweight the gains it gives.
1419
 
                # Note: do NOT move this logic up higher - using the basis from
1420
 
                # the accelerator tree is still desirable because that can save
1421
 
                # a minute or more of processing on large trees!
1422
 
                # The original tree may not have the same content filters
1423
 
                # applied so we can't safely build the inventory delta from
1424
 
                # the source tree.
1425
1550
                if wt.supports_content_filtering():
1426
 
                    accelerator_tree = None
 
1551
                    # The original tree may not have the same content filters
 
1552
                    # applied so we can't safely build the inventory delta from
 
1553
                    # the source tree.
1427
1554
                    delta_from_tree = False
1428
1555
                else:
1429
1556
                    delta_from_tree = True
1449
1576
        :param wt: the WorkingTree object
1450
1577
        """
1451
1578
 
 
1579
    def open(self, a_bzrdir, _found=False):
 
1580
        """Return the WorkingTree object for a_bzrdir
 
1581
 
 
1582
        _found is a private parameter, do not use it. It is used to indicate
 
1583
               if format probing has already been done.
 
1584
        """
 
1585
        if not _found:
 
1586
            # we are being called directly and must probe.
 
1587
            raise NotImplementedError
 
1588
        if not isinstance(a_bzrdir.transport, LocalTransport):
 
1589
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
 
1590
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
 
1591
        return wt
 
1592
 
1452
1593
    def _open(self, a_bzrdir, control_files):
1453
1594
        """Open the tree itself.
1454
1595
 
1545
1686
        return True
1546
1687
 
1547
1688
 
1548
 
class DirStateRevisionTree(Tree):
1549
 
    """A revision tree pulling the inventory from a dirstate."""
 
1689
class DirStateRevisionTree(InventoryTree):
 
1690
    """A revision tree pulling the inventory from a dirstate.
 
1691
    
 
1692
    Note that this is one of the historical (ie revision) trees cached in the
 
1693
    dirstate for easy access, not the workingtree.
 
1694
    """
1550
1695
 
1551
1696
    def __init__(self, dirstate, revision_id, repository):
1552
1697
        self._dirstate = dirstate
1566
1711
    def annotate_iter(self, file_id,
1567
1712
                      default_revision=_mod_revision.CURRENT_REVISION):
1568
1713
        """See Tree.annotate_iter"""
1569
 
        text_key = (file_id, self.inventory[file_id].revision)
 
1714
        text_key = (file_id, self.get_file_revision(file_id))
1570
1715
        annotations = self._repository.texts.annotate(text_key)
1571
1716
        return [(key[-1], line) for (key, line) in annotations]
1572
1717
 
1573
 
    def _get_ancestors(self, default_revision):
1574
 
        return set(self._repository.get_ancestry(self._revision_id,
1575
 
                                                 topo_sorted=False))
1576
1718
    def _comparison_data(self, entry, path):
1577
1719
        """See Tree._comparison_data."""
1578
1720
        if entry is None:
1694
1836
                elif kind == 'directory':
1695
1837
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1696
1838
                elif kind == 'symlink':
1697
 
                    inv_entry.executable = False
1698
 
                    inv_entry.text_size = None
1699
1839
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1700
1840
                elif kind == 'tree-reference':
1701
1841
                    inv_entry.reference_revision = fingerprint or None
1724
1864
            return None
1725
1865
        parent_index = self._get_parent_index()
1726
1866
        last_changed_revision = entry[1][parent_index][4]
1727
 
        return self._repository.get_revision(last_changed_revision).timestamp
 
1867
        try:
 
1868
            rev = self._repository.get_revision(last_changed_revision)
 
1869
        except errors.NoSuchRevision:
 
1870
            raise errors.FileTimestampUnavailable(self.id2path(file_id))
 
1871
        return rev.timestamp
1728
1872
 
1729
1873
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1730
1874
        entry = self._get_entry(file_id=file_id, path=path)
1734
1878
            return parent_details[1]
1735
1879
        return None
1736
1880
 
 
1881
    @needs_read_lock
 
1882
    def get_file_revision(self, file_id):
 
1883
        return self.inventory[file_id].revision
 
1884
 
1737
1885
    def get_file(self, file_id, path=None):
1738
1886
        return StringIO(self.get_file_text(file_id))
1739
1887
 
1762
1910
                                       identifier))
1763
1911
        return self._repository.iter_files_bytes(repo_desired_files)
1764
1912
 
1765
 
    def get_symlink_target(self, file_id):
 
1913
    def get_symlink_target(self, file_id, path=None):
1766
1914
        entry = self._get_entry(file_id=file_id)
1767
1915
        parent_index = self._get_parent_index()
1768
1916
        if entry[1][parent_index][0] != 'l':
1797
1945
        entry = self._get_entry(file_id=file_id)[1]
1798
1946
        if entry is None:
1799
1947
            raise errors.NoSuchId(tree=self, file_id=file_id)
1800
 
        return dirstate.DirState._minikind_to_kind[entry[1][0]]
 
1948
        parent_index = self._get_parent_index()
 
1949
        return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
1801
1950
 
1802
1951
    def stored_kind(self, file_id):
1803
1952
        """See Tree.stored_kind"""
1820
1969
    def is_executable(self, file_id, path=None):
1821
1970
        ie = self.inventory[file_id]
1822
1971
        if ie.kind != "file":
1823
 
            return None
 
1972
            return False
1824
1973
        return ie.executable
1825
1974
 
 
1975
    def is_locked(self):
 
1976
        return self._locked
 
1977
 
1826
1978
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1827
1979
        # We use a standard implementation, because DirStateRevisionTree is
1828
1980
        # dealing with one of the parents of the current state
1841
1993
            yield path, 'V', entry.kind, entry.file_id, entry
1842
1994
 
1843
1995
    def lock_read(self):
1844
 
        """Lock the tree for a set of operations."""
 
1996
        """Lock the tree for a set of operations.
 
1997
 
 
1998
        :return: A bzrlib.lock.LogicalLockResult.
 
1999
        """
1845
2000
        if not self._locked:
1846
2001
            self._repository.lock_read()
1847
2002
            if self._dirstate._lock_token is None:
1848
2003
                self._dirstate.lock_read()
1849
2004
                self._dirstate_locked = True
1850
2005
        self._locked += 1
 
2006
        return LogicalLockResult(self.unlock)
1851
2007
 
1852
2008
    def _must_be_locked(self):
1853
2009
        if not self._locked:
1932
2088
    def make_source_parent_tree(source, target):
1933
2089
        """Change the source tree into a parent of the target."""
1934
2090
        revid = source.commit('record tree')
1935
 
        target.branch.repository.fetch(source.branch.repository, revid)
 
2091
        target.branch.fetch(source.branch, revid)
1936
2092
        target.set_parent_ids([revid])
1937
2093
        return target.basis_tree(), target
1938
2094
 
1943
2099
        return result
1944
2100
 
1945
2101
    @classmethod
1946
 
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
 
2102
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
 
2103
                                                  target):
1947
2104
        from bzrlib.tests.test__dirstate_helpers import \
1948
 
            CompiledDirstateHelpersFeature
1949
 
        if not CompiledDirstateHelpersFeature.available():
1950
 
            from bzrlib.tests import UnavailableFeature
1951
 
            raise UnavailableFeature(CompiledDirstateHelpersFeature)
 
2105
            compiled_dirstate_helpers_feature
 
2106
        test_case.requireFeature(compiled_dirstate_helpers_feature)
1952
2107
        from bzrlib._dirstate_helpers_pyx import ProcessEntryC
1953
2108
        result = klass.make_source_parent_tree(source, target)
1954
2109
        result[1]._iter_changes = ProcessEntryC
1985
2140
            output. An unversioned file is defined as one with (False, False)
1986
2141
            for the versioned pair.
1987
2142
        """
1988
 
        # NB: show_status depends on being able to pass in non-versioned files
1989
 
        # and report them as unknown
1990
2143
        # TODO: handle extra trees in the dirstate.
1991
2144
        if (extra_trees or specific_files == []):
1992
2145
            # we can't fast-path these cases (yet)