~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: John Arbash Meinel
  • Date: 2010-05-11 10:45:26 UTC
  • mto: This revision was merged to the branch mainline in revision 5225.
  • Revision ID: john@arbash-meinel.com-20100511104526-zxnstcxta22hzw2n
Implement a compiled extension for parsing the text key out of a CHKInventory value.

Related to bug #562666. This seems to shave 5-10% out of the time spent doing a complete
branch of bzr.dev/launchpad/etc.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2011 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
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
 
    conflicts as _mod_conflicts,
38
38
    debug,
39
39
    dirstate,
40
40
    errors,
41
 
    filters as _mod_filters,
42
41
    generate_ids,
43
42
    osutils,
44
43
    revision as _mod_revision,
47
46
    transform,
48
47
    views,
49
48
    )
 
49
import bzrlib.branch
 
50
import bzrlib.ui
50
51
""")
51
52
 
52
53
from bzrlib.decorators import needs_read_lock, needs_write_lock
 
54
from bzrlib.filters import filtered_input_file, internal_size_sha_file_byname
53
55
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
54
 
from bzrlib.lock import LogicalLockResult
55
 
from bzrlib.lockable_files import LockableFiles
56
 
from bzrlib.lockdir import LockDir
57
56
from bzrlib.mutabletree import needs_tree_write_lock
58
57
from bzrlib.osutils import (
59
58
    file_kind,
62
61
    realpath,
63
62
    safe_unicode,
64
63
    )
 
64
from bzrlib.trace import mutter
65
65
from bzrlib.transport.local import LocalTransport
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
 
 
 
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):
79
72
    def __init__(self, basedir,
80
73
                 branch,
81
74
                 _control_files=None,
91
84
        self._format = _format
92
85
        self.bzrdir = _bzrdir
93
86
        basedir = safe_unicode(basedir)
94
 
        trace.mutter("opening working tree %r", basedir)
 
87
        mutter("opening working tree %r", basedir)
95
88
        self._branch = branch
96
89
        self.basedir = realpath(basedir)
97
90
        # if branch is at our basedir and is a format 6 or less
131
124
            state.add(f, file_id, kind, None, '')
132
125
        self._make_dirty(reset_inventory=True)
133
126
 
134
 
    def _get_check_refs(self):
135
 
        """Return the references needed to perform a check of this tree."""
136
 
        return [('trees', self.last_revision())]
137
 
 
138
127
    def _make_dirty(self, reset_inventory):
139
128
        """Make the tree state dirty.
140
129
 
192
181
 
193
182
    def _comparison_data(self, entry, path):
194
183
        kind, executable, stat_value = \
195
 
            WorkingTree._comparison_data(self, entry, path)
 
184
            WorkingTree3._comparison_data(self, entry, path)
196
185
        # it looks like a plain directory, but it's really a reference -- see
197
186
        # also kind()
198
187
        if (self._repo_supports_tree_reference and kind == 'directory'
204
193
    def commit(self, message=None, revprops=None, *args, **kwargs):
205
194
        # mark the tree as dirty post commit - commit
206
195
        # can change the current versioned list by doing deletes.
207
 
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
 
196
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
208
197
        self._make_dirty(reset_inventory=True)
209
198
        return result
210
199
 
379
368
        state = self.current_dirstate()
380
369
        if stat_value is None:
381
370
            try:
382
 
                stat_value = osutils.lstat(file_abspath)
 
371
                stat_value = os.lstat(file_abspath)
383
372
            except OSError, e:
384
373
                if e.errno == errno.ENOENT:
385
374
                    return None
488
477
            self._must_be_locked()
489
478
            if not path:
490
479
                path = self.id2path(file_id)
491
 
            mode = osutils.lstat(self.abspath(path)).st_mode
 
480
            mode = os.lstat(self.abspath(path)).st_mode
492
481
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
493
482
 
494
483
    def all_file_ids(self):
578
567
            return _mod_revision.NULL_REVISION
579
568
 
580
569
    def lock_read(self):
581
 
        """See Branch.lock_read, and WorkingTree.unlock.
582
 
 
583
 
        :return: A bzrlib.lock.LogicalLockResult.
584
 
        """
 
570
        """See Branch.lock_read, and WorkingTree.unlock."""
585
571
        self.branch.lock_read()
586
572
        try:
587
573
            self._control_files.lock_read()
600
586
        except:
601
587
            self.branch.unlock()
602
588
            raise
603
 
        return LogicalLockResult(self.unlock)
604
589
 
605
590
    def _lock_self_write(self):
606
591
        """This should be called after the branch is locked."""
621
606
        except:
622
607
            self.branch.unlock()
623
608
            raise
624
 
        return LogicalLockResult(self.unlock)
625
609
 
626
610
    def lock_tree_write(self):
627
 
        """See MutableTree.lock_tree_write, and WorkingTree.unlock.
628
 
 
629
 
        :return: A bzrlib.lock.LogicalLockResult.
630
 
        """
 
611
        """See MutableTree.lock_tree_write, and WorkingTree.unlock."""
631
612
        self.branch.lock_read()
632
 
        return self._lock_self_write()
 
613
        self._lock_self_write()
633
614
 
634
615
    def lock_write(self):
635
 
        """See MutableTree.lock_write, and WorkingTree.unlock.
636
 
 
637
 
        :return: A bzrlib.lock.LogicalLockResult.
638
 
        """
 
616
        """See MutableTree.lock_write, and WorkingTree.unlock."""
639
617
        self.branch.lock_write()
640
 
        return self._lock_self_write()
 
618
        self._lock_self_write()
641
619
 
642
620
    @needs_tree_write_lock
643
621
    def move(self, from_paths, to_dir, after=False):
1257
1235
        # have to change the legacy inventory too.
1258
1236
        if self._inventory is not None:
1259
1237
            for file_id in file_ids:
1260
 
                if self._inventory.has_id(file_id):
1261
 
                    self._inventory.remove_recursive_id(file_id)
 
1238
                self._inventory.remove_recursive_id(file_id)
1262
1239
 
1263
1240
    @needs_tree_write_lock
1264
1241
    def rename_one(self, from_rel, to_rel, after=False):
1265
1242
        """See WorkingTree.rename_one"""
1266
1243
        self.flush()
1267
 
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
 
1244
        WorkingTree.rename_one(self, from_rel, to_rel, after)
1268
1245
 
1269
1246
    @needs_tree_write_lock
1270
1247
    def apply_inventory_delta(self, changes):
1303
1280
            self._inventory = inv
1304
1281
        self.flush()
1305
1282
 
1306
 
    @needs_tree_write_lock
1307
 
    def reset_state(self, revision_ids=None):
1308
 
        """Reset the state of the working tree.
1309
 
 
1310
 
        This does a hard-reset to a last-known-good state. This is a way to
1311
 
        fix if something got corrupted (like the .bzr/checkout/dirstate file)
1312
 
        """
1313
 
        if revision_ids is None:
1314
 
            revision_ids = self.get_parent_ids()
1315
 
        if not revision_ids:
1316
 
            base_tree = self.branch.repository.revision_tree(
1317
 
                _mod_revision.NULL_REVISION)
1318
 
            trees = []
1319
 
        else:
1320
 
            trees = zip(revision_ids,
1321
 
                        self.branch.repository.revision_trees(revision_ids))
1322
 
            base_tree = trees[0][1]
1323
 
        state = self.current_dirstate()
1324
 
        # We don't support ghosts yet
1325
 
        state.set_state_from_scratch(base_tree.inventory, trees, [])
1326
 
 
1327
1283
 
1328
1284
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1329
1285
 
1334
1290
        """See dirstate.SHA1Provider.sha1()."""
1335
1291
        filters = self.tree._content_filter_stack(
1336
1292
            self.tree.relpath(osutils.safe_unicode(abspath)))
1337
 
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1293
        return internal_size_sha_file_byname(abspath, filters)[1]
1338
1294
 
1339
1295
    def stat_and_sha1(self, abspath):
1340
1296
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1344
1300
        try:
1345
1301
            statvalue = os.fstat(file_obj.fileno())
1346
1302
            if filters:
1347
 
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1303
                file_obj = filtered_input_file(file_obj, filters)
1348
1304
            sha1 = osutils.size_sha_file(file_obj)[1]
1349
1305
        finally:
1350
1306
            file_obj.close()
1361
1317
    def _file_content_summary(self, path, stat_result):
1362
1318
        # This is to support the somewhat obsolete path_content_summary method
1363
1319
        # with content filtering: see
1364
 
        # <https://bugs.launchpad.net/bzr/+bug/415508>.
 
1320
        # <https://bugs.edge.launchpad.net/bzr/+bug/415508>.
1365
1321
        #
1366
1322
        # If the dirstate cache is up to date and knows the hash and size,
1367
1323
        # return that.
1380
1336
class WorkingTree4(DirStateWorkingTree):
1381
1337
    """This is the Format 4 working tree.
1382
1338
 
1383
 
    This differs from WorkingTree by:
 
1339
    This differs from WorkingTree3 by:
1384
1340
     - Having a consolidated internal dirstate, stored in a
1385
1341
       randomly-accessible sorted file on disk.
1386
1342
     - Not having a regular inventory attribute.  One can be synthesized
1414
1370
        return views.PathBasedViews(self)
1415
1371
 
1416
1372
 
1417
 
class DirStateWorkingTreeFormat(WorkingTreeFormat):
1418
 
 
1419
 
    missing_parent_conflicts = True
1420
 
 
1421
 
    _lock_class = LockDir
1422
 
    _lock_file_name = 'lock'
1423
 
 
1424
 
    def _open_control_files(self, a_bzrdir):
1425
 
        transport = a_bzrdir.get_workingtree_transport(None)
1426
 
        return LockableFiles(transport, self._lock_file_name,
1427
 
                             self._lock_class)
 
1373
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1428
1374
 
1429
1375
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1430
1376
                   accelerator_tree=None, hardlink=False):
1530
1476
        :param wt: the WorkingTree object
1531
1477
        """
1532
1478
 
1533
 
    def open(self, a_bzrdir, _found=False):
1534
 
        """Return the WorkingTree object for a_bzrdir
1535
 
 
1536
 
        _found is a private parameter, do not use it. It is used to indicate
1537
 
               if format probing has already been done.
1538
 
        """
1539
 
        if not _found:
1540
 
            # we are being called directly and must probe.
1541
 
            raise NotImplementedError
1542
 
        if not isinstance(a_bzrdir.transport, LocalTransport):
1543
 
            raise errors.NotLocalUrl(a_bzrdir.transport.base)
1544
 
        wt = self._open(a_bzrdir, self._open_control_files(a_bzrdir))
1545
 
        return wt
1546
 
 
1547
1479
    def _open(self, a_bzrdir, control_files):
1548
1480
        """Open the tree itself.
1549
1481
 
1640
1572
        return True
1641
1573
 
1642
1574
 
1643
 
class DirStateRevisionTree(InventoryTree):
 
1575
class DirStateRevisionTree(Tree):
1644
1576
    """A revision tree pulling the inventory from a dirstate.
1645
1577
    
1646
1578
    Note that this is one of the historical (ie revision) trees cached in the
1665
1597
    def annotate_iter(self, file_id,
1666
1598
                      default_revision=_mod_revision.CURRENT_REVISION):
1667
1599
        """See Tree.annotate_iter"""
1668
 
        text_key = (file_id, self.get_file_revision(file_id))
 
1600
        text_key = (file_id, self.inventory[file_id].revision)
1669
1601
        annotations = self._repository.texts.annotate(text_key)
1670
1602
        return [(key[-1], line) for (key, line) in annotations]
1671
1603
 
1793
1725
                elif kind == 'directory':
1794
1726
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1795
1727
                elif kind == 'symlink':
 
1728
                    inv_entry.executable = False
 
1729
                    inv_entry.text_size = None
1796
1730
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
1797
1731
                elif kind == 'tree-reference':
1798
1732
                    inv_entry.reference_revision = fingerprint or None
1835
1769
            return parent_details[1]
1836
1770
        return None
1837
1771
 
1838
 
    @needs_read_lock
1839
 
    def get_file_revision(self, file_id):
1840
 
        return self.inventory[file_id].revision
1841
 
 
1842
1772
    def get_file(self, file_id, path=None):
1843
1773
        return StringIO(self.get_file_text(file_id))
1844
1774
 
1926
1856
    def is_executable(self, file_id, path=None):
1927
1857
        ie = self.inventory[file_id]
1928
1858
        if ie.kind != "file":
1929
 
            return False
 
1859
            return None
1930
1860
        return ie.executable
1931
1861
 
1932
 
    def is_locked(self):
1933
 
        return self._locked
1934
 
 
1935
1862
    def list_files(self, include_root=False, from_dir=None, recursive=True):
1936
1863
        # We use a standard implementation, because DirStateRevisionTree is
1937
1864
        # dealing with one of the parents of the current state
1950
1877
            yield path, 'V', entry.kind, entry.file_id, entry
1951
1878
 
1952
1879
    def lock_read(self):
1953
 
        """Lock the tree for a set of operations.
1954
 
 
1955
 
        :return: A bzrlib.lock.LogicalLockResult.
1956
 
        """
 
1880
        """Lock the tree for a set of operations."""
1957
1881
        if not self._locked:
1958
1882
            self._repository.lock_read()
1959
1883
            if self._dirstate._lock_token is None:
1960
1884
                self._dirstate.lock_read()
1961
1885
                self._dirstate_locked = True
1962
1886
        self._locked += 1
1963
 
        return LogicalLockResult(self.unlock)
1964
1887
 
1965
1888
    def _must_be_locked(self):
1966
1889
        if not self._locked:
2045
1968
    def make_source_parent_tree(source, target):
2046
1969
        """Change the source tree into a parent of the target."""
2047
1970
        revid = source.commit('record tree')
2048
 
        target.branch.fetch(source.branch, revid)
 
1971
        target.branch.repository.fetch(source.branch.repository, revid)
2049
1972
        target.set_parent_ids([revid])
2050
1973
        return target.basis_tree(), target
2051
1974