~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: John Arbash Meinel
  • Date: 2009-07-30 23:54:26 UTC
  • mto: This revision was merged to the branch mainline in revision 4580.
  • Revision ID: john@arbash-meinel.com-20090730235426-o8h73swbh7seqaf7
Update the breakin support to support CTRL-BREAK on Windows.

The signal handling code is very similar, but the testing code got a bit clumsy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 Canonical Ltd
 
1
# Copyright (C) 2005, 2006, 2007, 2008, 2009 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
34
35
from bzrlib import (
35
36
    bzrdir,
36
37
    cache_utf8,
37
 
    config,
38
 
    conflicts as _mod_conflicts,
39
38
    debug,
40
39
    dirstate,
41
40
    errors,
42
 
    filters as _mod_filters,
43
41
    generate_ids,
44
42
    osutils,
45
43
    revision as _mod_revision,
48
46
    transform,
49
47
    views,
50
48
    )
 
49
import bzrlib.branch
 
50
import bzrlib.ui
51
51
""")
52
52
 
53
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
54
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
55
 
from bzrlib.lock import LogicalLockResult
56
 
from bzrlib.lockable_files import LockableFiles
57
 
from bzrlib.lockdir import LockDir
 
56
import bzrlib.mutabletree
58
57
from bzrlib.mutabletree import needs_tree_write_lock
59
58
from bzrlib.osutils import (
60
59
    file_kind,
63
62
    realpath,
64
63
    safe_unicode,
65
64
    )
 
65
from bzrlib.trace import mutter
66
66
from bzrlib.transport.local import LocalTransport
67
 
from bzrlib.tree import (
68
 
    InterTree,
69
 
    InventoryTree,
70
 
    )
71
 
from bzrlib.workingtree import (
72
 
    InventoryWorkingTree,
73
 
    WorkingTree,
74
 
    WorkingTreeFormat,
75
 
    )
76
 
 
77
 
 
78
 
class DirStateWorkingTree(InventoryWorkingTree):
79
 
 
 
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):
80
73
    def __init__(self, basedir,
81
74
                 branch,
82
75
                 _control_files=None,
92
85
        self._format = _format
93
86
        self.bzrdir = _bzrdir
94
87
        basedir = safe_unicode(basedir)
95
 
        trace.mutter("opening working tree %r", basedir)
 
88
        mutter("opening working tree %r", basedir)
96
89
        self._branch = branch
97
90
        self.basedir = realpath(basedir)
98
91
        # if branch is at our basedir and is a format 6 or less
132
125
            state.add(f, file_id, kind, None, '')
133
126
        self._make_dirty(reset_inventory=True)
134
127
 
135
 
    def _get_check_refs(self):
136
 
        """Return the references needed to perform a check of this tree."""
137
 
        return [('trees', self.last_revision())]
138
 
 
139
128
    def _make_dirty(self, reset_inventory):
140
129
        """Make the tree state dirty.
141
130
 
193
182
 
194
183
    def _comparison_data(self, entry, path):
195
184
        kind, executable, stat_value = \
196
 
            WorkingTree._comparison_data(self, entry, path)
 
185
            WorkingTree3._comparison_data(self, entry, path)
197
186
        # it looks like a plain directory, but it's really a reference -- see
198
187
        # also kind()
199
188
        if (self._repo_supports_tree_reference and kind == 'directory'
205
194
    def commit(self, message=None, revprops=None, *args, **kwargs):
206
195
        # mark the tree as dirty post commit - commit
207
196
        # can change the current versioned list by doing deletes.
208
 
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
 
197
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
209
198
        self._make_dirty(reset_inventory=True)
210
199
        return result
211
200
 
230
219
        local_path = self.bzrdir.get_workingtree_transport(None
231
220
            ).local_abspath('dirstate')
232
221
        self._dirstate = dirstate.DirState.on_file(local_path,
233
 
            self._sha1_provider(), self._worth_saving_limit())
 
222
            self._sha1_provider())
234
223
        return self._dirstate
235
224
 
236
225
    def _sha1_provider(self):
245
234
        else:
246
235
            return None
247
236
 
248
 
    def _worth_saving_limit(self):
249
 
        """How many hash changes are ok before we must save the dirstate.
250
 
 
251
 
        :return: an integer. -1 means never save.
252
 
        """
253
 
        # FIXME: We want a WorkingTreeStack here -- vila 20110812
254
 
        conf = config.BranchStack(self.branch)
255
 
        return conf.get('bzr.workingtree.worth_saving_limit')
256
 
 
257
237
    def filter_unversioned_files(self, paths):
258
238
        """Filter out paths that are versioned.
259
239
 
389
369
        state = self.current_dirstate()
390
370
        if stat_value is None:
391
371
            try:
392
 
                stat_value = osutils.lstat(file_abspath)
 
372
                stat_value = os.lstat(file_abspath)
393
373
            except OSError, e:
394
374
                if e.errno == errno.ENOENT:
395
375
                    return None
498
478
            self._must_be_locked()
499
479
            if not path:
500
480
                path = self.id2path(file_id)
501
 
            mode = osutils.lstat(self.abspath(path)).st_mode
 
481
            mode = os.lstat(self.abspath(path)).st_mode
502
482
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
503
483
 
504
484
    def all_file_ids(self):
588
568
            return _mod_revision.NULL_REVISION
589
569
 
590
570
    def lock_read(self):
591
 
        """See Branch.lock_read, and WorkingTree.unlock.
592
 
 
593
 
        :return: A bzrlib.lock.LogicalLockResult.
594
 
        """
 
571
        """See Branch.lock_read, and WorkingTree.unlock."""
595
572
        self.branch.lock_read()
596
573
        try:
597
574
            self._control_files.lock_read()
610
587
        except:
611
588
            self.branch.unlock()
612
589
            raise
613
 
        return LogicalLockResult(self.unlock)
614
590
 
615
591
    def _lock_self_write(self):
616
592
        """This should be called after the branch is locked."""
631
607
        except:
632
608
            self.branch.unlock()
633
609
            raise
634
 
        return LogicalLockResult(self.unlock)
635
610
 
636
611
    def lock_tree_write(self):
637
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
638
 
 
639
 
        :return: A bzrlib.lock.LogicalLockResult.
640
 
        """
 
612
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
641
613
        self.branch.lock_read()
642
 
        return self._lock_self_write()
 
614
        self._lock_self_write()
643
615
 
644
616
    def lock_write(self):
645
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
646
 
 
647
 
        :return: A bzrlib.lock.LogicalLockResult.
648
 
        """
 
617
        """See MutableTree.lock_write, and WorkingTree.unlock."""
649
618
        self.branch.lock_write()
650
 
        return self._lock_self_write()
 
619
        self._lock_self_write()
651
620
 
652
621
    @needs_tree_write_lock
653
622
    def move(self, from_paths, to_dir, after=False):
870
839
                rollback_rename()
871
840
                raise
872
841
            result.append((from_rel, to_rel))
873
 
            state._mark_modified()
 
842
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
874
843
            self._make_dirty(reset_inventory=False)
875
844
 
876
845
        return result
1133
1102
                        _mod_revision.NULL_REVISION)))
1134
1103
                ghosts.append(rev_id)
1135
1104
            accepted_revisions.add(rev_id)
1136
 
        updated = False
1137
 
        if (len(real_trees) == 1
1138
 
            and not ghosts
1139
 
            and self.branch.repository._format.fast_deltas
1140
 
            and isinstance(real_trees[0][1],
1141
 
                revisiontree.InventoryRevisionTree)
1142
 
            and self.get_parent_ids()):
1143
 
            rev_id, rev_tree = real_trees[0]
1144
 
            basis_id = self.get_parent_ids()[0]
1145
 
            # There are times when basis_tree won't be in
1146
 
            # self.branch.repository, (switch, for example)
1147
 
            try:
1148
 
                basis_tree = self.branch.repository.revision_tree(basis_id)
1149
 
            except errors.NoSuchRevision:
1150
 
                # Fall back to the set_parent_trees(), since we can't use
1151
 
                # _make_delta if we can't get the RevisionTree
1152
 
                pass
1153
 
            else:
1154
 
                delta = rev_tree.inventory._make_delta(basis_tree.inventory)
1155
 
                dirstate.update_basis_by_delta(delta, rev_id)
1156
 
                updated = True
1157
 
        if not updated:
1158
 
            dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
1105
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1159
1106
        self._make_dirty(reset_inventory=False)
1160
1107
 
1161
1108
    def _set_root_id(self, file_id):
1181
1128
 
1182
1129
    def unlock(self):
1183
1130
        """Unlock in format 4 trees needs to write the entire dirstate."""
 
1131
        # do non-implementation specific cleanup
 
1132
        self._cleanup()
 
1133
 
1184
1134
        if self._control_files._lock_count == 1:
1185
 
            # do non-implementation specific cleanup
1186
 
            self._cleanup()
1187
 
 
1188
1135
            # eventually we should do signature checking during read locks for
1189
1136
            # dirstate updates.
1190
1137
            if self._control_files._lock_mode == 'w':
1289
1236
        # have to change the legacy inventory too.
1290
1237
        if self._inventory is not None:
1291
1238
            for file_id in file_ids:
1292
 
                if self._inventory.has_id(file_id):
1293
 
                    self._inventory.remove_recursive_id(file_id)
 
1239
                self._inventory.remove_recursive_id(file_id)
1294
1240
 
1295
1241
    @needs_tree_write_lock
1296
1242
    def rename_one(self, from_rel, to_rel, after=False):
1297
1243
        """See WorkingTree.rename_one"""
1298
1244
        self.flush()
1299
 
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
 
1245
        WorkingTree.rename_one(self, from_rel, to_rel, after)
1300
1246
 
1301
1247
    @needs_tree_write_lock
1302
1248
    def apply_inventory_delta(self, changes):
1321
1267
        if self._dirty:
1322
1268
            raise AssertionError("attempting to write an inventory when the "
1323
1269
                "dirstate is dirty will lose pending changes")
1324
 
        had_inventory = self._inventory is not None
1325
 
        # Setting self._inventory = None forces the dirstate to regenerate the
1326
 
        # working inventory. We do this because self.inventory may be inv, or
1327
 
        # may have been modified, and either case would prevent a clean delta
1328
 
        # being created.
1329
 
        self._inventory = None
1330
 
        # generate a delta,
1331
 
        delta = inv._make_delta(self.inventory)
1332
 
        # and apply it.
1333
 
        self.apply_inventory_delta(delta)
1334
 
        if had_inventory:
 
1270
        self.current_dirstate().set_state_from_inventory(inv)
 
1271
        self._make_dirty(reset_inventory=False)
 
1272
        if self._inventory is not None:
1335
1273
            self._inventory = inv
1336
1274
        self.flush()
1337
1275
 
1338
 
    @needs_tree_write_lock
1339
 
    def reset_state(self, revision_ids=None):
1340
 
        """Reset the state of the working tree.
1341
 
 
1342
 
        This does a hard-reset to a last-known-good state. This is a way to
1343
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
1344
 
        """
1345
 
        if revision_ids is None:
1346
 
            revision_ids = self.get_parent_ids()
1347
 
        if not revision_ids:
1348
 
            base_tree = self.branch.repository.revision_tree(
1349
 
                _mod_revision.NULL_REVISION)
1350
 
            trees = []
1351
 
        else:
1352
 
            trees = zip(revision_ids,
1353
 
                        self.branch.repository.revision_trees(revision_ids))
1354
 
            base_tree = trees[0][1]
1355
 
        state = self.current_dirstate()
1356
 
        # We don't support ghosts yet
1357
 
        state.set_state_from_scratch(base_tree.inventory, trees, [])
1358
 
 
1359
1276
 
1360
1277
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1361
1278
 
1366
1283
        """See dirstate.SHA1Provider.sha1()."""
1367
1284
        filters = self.tree._content_filter_stack(
1368
1285
            self.tree.relpath(osutils.safe_unicode(abspath)))
1369
 
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1286
        return internal_size_sha_file_byname(abspath, filters)[1]
1370
1287
 
1371
1288
    def stat_and_sha1(self, abspath):
1372
1289
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1376
1293
        try:
1377
1294
            statvalue = os.fstat(file_obj.fileno())
1378
1295
            if filters:
1379
 
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1296
                file_obj = filtered_input_file(file_obj, filters)
1380
1297
            sha1 = osutils.size_sha_file(file_obj)[1]
1381
1298
        finally:
1382
1299
            file_obj.close()
1383
1300
        return statvalue, sha1
1384
1301
 
1385
1302
 
1386
 
class ContentFilteringDirStateWorkingTree(DirStateWorkingTree):
1387
 
    """Dirstate working tree that supports content filtering.
1388
 
 
1389
 
    The dirstate holds the hash and size of the canonical form of the file, 
1390
 
    and most methods must return that.
1391
 
    """
1392
 
 
1393
 
    def _file_content_summary(self, path, stat_result):
1394
 
        # This is to support the somewhat obsolete path_content_summary method
1395
 
        # with content filtering: see
1396
 
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
1397
 
        #
1398
 
        # If the dirstate cache is up to date and knows the hash and size,
1399
 
        # return that.
1400
 
        # Otherwise if there are no content filters, return the on-disk size
1401
 
        # and leave the hash blank.
1402
 
        # Otherwise, read and filter the on-disk file and use its size and
1403
 
        # hash.
1404
 
        #
1405
 
        # The dirstate doesn't store the size of the canonical form so we
1406
 
        # can't trust it for content-filtered trees.  We just return None.
1407
 
        dirstate_sha1 = self._dirstate.sha1_from_stat(path, stat_result)
1408
 
        executable = self._is_executable_from_path_and_stat(path, stat_result)
1409
 
        return ('file', None, executable, dirstate_sha1)
1410
 
 
1411
 
 
1412
1303
class WorkingTree4(DirStateWorkingTree):
1413
1304
    """This is the Format 4 working tree.
1414
1305
 
1415
 
    This differs from WorkingTree by:
 
1306
    This differs from WorkingTree3 by:
1416
1307
     - Having a consolidated internal dirstate, stored in a
1417
1308
       randomly-accessible sorted file on disk.
1418
1309
     - Not having a regular inventory attribute.  One can be synthesized
1422
1313
    """
1423
1314
 
1424
1315
 
1425
 
class WorkingTree5(ContentFilteringDirStateWorkingTree):
 
1316
class WorkingTree5(DirStateWorkingTree):
1426
1317
    """This is the Format 5 working tree.
1427
1318
 
1428
1319
    This differs from WorkingTree4 by:
1432
1323
    """
1433
1324
 
1434
1325
 
1435
 
class WorkingTree6(ContentFilteringDirStateWorkingTree):
 
1326
class WorkingTree6(DirStateWorkingTree):
1436
1327
    """This is the Format 6 working tree.
1437
1328
 
1438
1329
    This differs from WorkingTree5 by:
1446
1337
        return views.PathBasedViews(self)
1447
1338
 
1448
1339
 
1449
 
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1450
 
 
1451
 
    missing_parent_conflicts = True
1452
 
 
1453
 
    supports_versioned_directories = True
1454
 
 
1455
 
    _lock_class = LockDir
1456
 
    _lock_file_name = 'lock'
1457
 
 
1458
 
    def _open_control_files(self, a_bzrdir):
1459
 
        transport = a_bzrdir.get_workingtree_transport(None)
1460
 
        return LockableFiles(transport, self._lock_file_name,
1461
 
                             self._lock_class)
1462
 
 
 
1340
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1463
1341
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1464
1342
                   accelerator_tree=None, hardlink=False):
1465
1343
        """See WorkingTreeFormat.initialize().
1466
1344
 
1467
1345
        :param revision_id: allows creating a working tree at a different
1468
 
            revision than the branch is at.
 
1346
        revision than the branch is at.
1469
1347
        :param accelerator_tree: A tree which can be used for retrieving file
1470
1348
            contents more quickly than the revision tree, i.e. a workingtree.
1471
1349
            The revision tree will be used for cases where accelerator_tree's
1535
1413
                if basis_root_id is not None:
1536
1414
                    wt._set_root_id(basis_root_id)
1537
1415
                    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.
1538
1425
                if wt.supports_content_filtering():
1539
 
                    # The original tree may not have the same content filters
1540
 
                    # applied so we can't safely build the inventory delta from
1541
 
                    # the source tree.
 
1426
                    accelerator_tree = None
1542
1427
                    delta_from_tree = False
1543
1428
                else:
1544
1429
                    delta_from_tree = True
1564
1449
        :param wt: the WorkingTree object
1565
1450
        """
1566
1451
 
1567
 
    def open(self, a_bzrdir, _found=False):
1568
 
        """Return the WorkingTree object for a_bzrdir
1569
 
 
1570
 
        _found is a private parameter, do not use it. It is used to indicate
1571
 
               if format probing has already been done.
1572
 
        """
1573
 
        if not _found:
1574
 
            # we are being called directly and must probe.
1575
 
            raise NotImplementedError
1576
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
1577
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1578
 
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1579
 
        return wt
1580
 
 
1581
1452
    def _open(self, a_bzrdir, control_files):
1582
1453
        """Open the tree itself.
1583
1454
 
1674
1545
        return True
1675
1546
 
1676
1547
 
1677
 
class DirStateRevisionTree(InventoryTree):
1678
 
    """A revision tree pulling the inventory from a dirstate.
1679
 
    
1680
 
    Note that this is one of the historical (ie revision) trees cached in the
1681
 
    dirstate for easy access, not the workingtree.
1682
 
    """
 
1548
class DirStateRevisionTree(Tree):
 
1549
    """A revision tree pulling the inventory from a dirstate."""
1683
1550
 
1684
1551
    def __init__(self, dirstate, revision_id, repository):
1685
1552
        self._dirstate = dirstate
1699
1566
    def annotate_iter(self, file_id,
1700
1567
                      default_revision=_mod_revision.CURRENT_REVISION):
1701
1568
        """See Tree.annotate_iter"""
1702
 
        text_key = (file_id, self.get_file_revision(file_id))
 
1569
        text_key = (file_id, self.inventory[file_id].revision)
1703
1570
        annotations = self._repository.texts.annotate(text_key)
1704
1571
        return [(key[-1], line) for (key, line) in annotations]
1705
1572
 
 
1573
    def _get_ancestors(self, default_revision):
 
1574
        return set(self._repository.get_ancestry(self._revision_id,
 
1575
                                                 topo_sorted=False))
1706
1576
    def _comparison_data(self, entry, path):
1707
1577
        """See Tree._comparison_data."""
1708
1578
        if entry is None:
1824
1694
                elif kind == 'directory':
1825
1695
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1826
1696
                elif kind == 'symlink':
 
1697
                    inv_entry.executable = False
 
1698
                    inv_entry.text_size = None
1827
1699
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1828
1700
                elif kind == 'tree-reference':
1829
1701
                    inv_entry.reference_revision = fingerprint or None
1852
1724
            return None
1853
1725
        parent_index = self._get_parent_index()
1854
1726
        last_changed_revision = entry[1][parent_index][4]
1855
 
        try:
1856
 
            rev = self._repository.get_revision(last_changed_revision)
1857
 
        except errors.NoSuchRevision:
1858
 
            raise errors.FileTimestampUnavailable(self.id2path(file_id))
1859
 
        return rev.timestamp
 
1727
        return self._repository.get_revision(last_changed_revision).timestamp
1860
1728
 
1861
1729
    def get_file_sha1(self, file_id, path=None, stat_value=None):
1862
1730
        entry = self._get_entry(file_id=file_id, path=path)
1866
1734
            return parent_details[1]
1867
1735
        return None
1868
1736
 
1869
 
    @needs_read_lock
1870
 
    def get_file_revision(self, file_id):
1871
 
        return self.inventory[file_id].revision
1872
 
 
1873
1737
    def get_file(self, file_id, path=None):
1874
1738
        return StringIO(self.get_file_text(file_id))
1875
1739
 
1898
1762
                                       identifier))
1899
1763
        return self._repository.iter_files_bytes(repo_desired_files)
1900
1764
 
1901
 
    def get_symlink_target(self, file_id, path=None):
 
1765
    def get_symlink_target(self, file_id):
1902
1766
        entry = self._get_entry(file_id=file_id)
1903
1767
        parent_index = self._get_parent_index()
1904
1768
        if entry[1][parent_index][0] != 'l':
1933
1797
        entry = self._get_entry(file_id=file_id)[1]
1934
1798
        if entry is None:
1935
1799
            raise errors.NoSuchId(tree=self, file_id=file_id)
1936
 
        parent_index = self._get_parent_index()
1937
 
        return dirstate.DirState._minikind_to_kind[entry[parent_index][0]]
 
1800
        return dirstate.DirState._minikind_to_kind[entry[1][0]]
1938
1801
 
1939
1802
    def stored_kind(self, file_id):
1940
1803
        """See Tree.stored_kind"""
1957
1820
    def is_executable(self, file_id, path=None):
1958
1821
        ie = self.inventory[file_id]
1959
1822
        if ie.kind != "file":
1960
 
            return False
 
1823
            return None
1961
1824
        return ie.executable
1962
1825
 
1963
 
    def is_locked(self):
1964
 
        return self._locked
1965
 
 
1966
1826
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1967
1827
        # We use a standard implementation, because DirStateRevisionTree is
1968
1828
        # dealing with one of the parents of the current state
1981
1841
            yield path, 'V', entry.kind, entry.file_id, entry
1982
1842
 
1983
1843
    def lock_read(self):
1984
 
        """Lock the tree for a set of operations.
1985
 
 
1986
 
        :return: A bzrlib.lock.LogicalLockResult.
1987
 
        """
 
1844
        """Lock the tree for a set of operations."""
1988
1845
        if not self._locked:
1989
1846
            self._repository.lock_read()
1990
1847
            if self._dirstate._lock_token is None:
1991
1848
                self._dirstate.lock_read()
1992
1849
                self._dirstate_locked = True
1993
1850
        self._locked += 1
1994
 
        return LogicalLockResult(self.unlock)
1995
1851
 
1996
1852
    def _must_be_locked(self):
1997
1853
        if not self._locked:
2076
1932
    def make_source_parent_tree(source, target):
2077
1933
        """Change the source tree into a parent of the target."""
2078
1934
        revid = source.commit('record tree')
2079
 
        target.branch.fetch(source.branch, revid)
 
1935
        target.branch.repository.fetch(source.branch.repository, revid)
2080
1936
        target.set_parent_ids([revid])
2081
1937
        return target.basis_tree(), target
2082
1938
 
2087
1943
        return result
2088
1944
 
2089
1945
    @classmethod
2090
 
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source,
2091
 
                                                  target):
 
1946
    def make_source_parent_tree_compiled_dirstate(klass, test_case, source, target):
2092
1947
        from bzrlib.tests.test__dirstate_helpers import \
2093
 
            compiled_dirstate_helpers_feature
2094
 
        test_case.requireFeature(compiled_dirstate_helpers_feature)
 
1948
            CompiledDirstateHelpersFeature
 
1949
        if not CompiledDirstateHelpersFeature.available():
 
1950
            from bzrlib.tests import UnavailableFeature
 
1951
            raise UnavailableFeature(CompiledDirstateHelpersFeature)
2095
1952
        from bzrlib._dirstate_helpers_pyx import ProcessEntryC
2096
1953
        result = klass.make_source_parent_tree(source, target)
2097
1954
        result[1]._iter_changes = ProcessEntryC
2128
1985
            output. An unversioned file is defined as one with (False, False)
2129
1986
            for the versioned pair.
2130
1987
        """
 
1988
        # NB: show_status depends on being able to pass in non-versioned files
 
1989
        # and report them as unknown
2131
1990
        # TODO: handle extra trees in the dirstate.
2132
1991
        if (extra_trees or specific_files == []):
2133
1992
            # we can't fast-path these cases (yet)