~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Patch Queue Manager
  • Date: 2011-09-22 14:12:18 UTC
  • mfrom: (6155.3.1 jam)
  • Revision ID: pqm@pqm.ubuntu.com-20110922141218-86s4uu6nqvourw4f
(jameinel) Cleanup comments bzrlib/smart/__init__.py (John A Meinel)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007-2010 Canonical Ltd
 
1
# Copyright (C) 2007-2011 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
    config,
 
38
    conflicts as _mod_conflicts,
38
39
    debug,
39
40
    dirstate,
40
41
    errors,
 
42
    filters as _mod_filters,
41
43
    generate_ids,
42
44
    osutils,
43
45
    revision as _mod_revision,
46
48
    transform,
47
49
    views,
48
50
    )
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
55
54
from bzrlib.inventory import Inventory, ROOT_ID, entry_factory
56
55
from bzrlib.lock import LogicalLockResult
 
56
from bzrlib.lockable_files import LockableFiles
 
57
from bzrlib.lockdir import LockDir
57
58
from bzrlib.mutabletree import needs_tree_write_lock
58
59
from bzrlib.osutils import (
59
60
    file_kind,
62
63
    realpath,
63
64
    safe_unicode,
64
65
    )
65
 
from bzrlib.trace import mutter
66
66
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):
 
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
 
73
80
    def __init__(self, basedir,
74
81
                 branch,
75
82
                 _control_files=None,
85
92
        self._format = _format
86
93
        self.bzrdir = _bzrdir
87
94
        basedir = safe_unicode(basedir)
88
 
        mutter("opening working tree %r", basedir)
 
95
        trace.mutter("opening working tree %r", basedir)
89
96
        self._branch = branch
90
97
        self.basedir = realpath(basedir)
91
98
        # if branch is at our basedir and is a format 6 or less
125
132
            state.add(f, file_id, kind, None, '')
126
133
        self._make_dirty(reset_inventory=True)
127
134
 
 
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
 
128
139
    def _make_dirty(self, reset_inventory):
129
140
        """Make the tree state dirty.
130
141
 
182
193
 
183
194
    def _comparison_data(self, entry, path):
184
195
        kind, executable, stat_value = \
185
 
            WorkingTree3._comparison_data(self, entry, path)
 
196
            WorkingTree._comparison_data(self, entry, path)
186
197
        # it looks like a plain directory, but it's really a reference -- see
187
198
        # also kind()
188
199
        if (self._repo_supports_tree_reference and kind == 'directory'
194
205
    def commit(self, message=None, revprops=None, *args, **kwargs):
195
206
        # mark the tree as dirty post commit - commit
196
207
        # can change the current versioned list by doing deletes.
197
 
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
 
208
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
198
209
        self._make_dirty(reset_inventory=True)
199
210
        return result
200
211
 
219
230
        local_path = self.bzrdir.get_workingtree_transport(None
220
231
            ).local_abspath('dirstate')
221
232
        self._dirstate = dirstate.DirState.on_file(local_path,
222
 
            self._sha1_provider())
 
233
            self._sha1_provider(), self._worth_saving_limit())
223
234
        return self._dirstate
224
235
 
225
236
    def _sha1_provider(self):
234
245
        else:
235
246
            return None
236
247
 
 
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
 
237
257
    def filter_unversioned_files(self, paths):
238
258
        """Filter out paths that are versioned.
239
259
 
369
389
        state = self.current_dirstate()
370
390
        if stat_value is None:
371
391
            try:
372
 
                stat_value = os.lstat(file_abspath)
 
392
                stat_value = osutils.lstat(file_abspath)
373
393
            except OSError, e:
374
394
                if e.errno == errno.ENOENT:
375
395
                    return None
478
498
            self._must_be_locked()
479
499
            if not path:
480
500
                path = self.id2path(file_id)
481
 
            mode = os.lstat(self.abspath(path)).st_mode
 
501
            mode = osutils.lstat(self.abspath(path)).st_mode
482
502
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
483
503
 
484
504
    def all_file_ids(self):
850
870
                rollback_rename()
851
871
                raise
852
872
            result.append((from_rel, to_rel))
853
 
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
 
873
            state._mark_modified()
854
874
            self._make_dirty(reset_inventory=False)
855
875
 
856
876
        return result
1113
1133
                        _mod_revision.NULL_REVISION)))
1114
1134
                ghosts.append(rev_id)
1115
1135
            accepted_revisions.add(rev_id)
1116
 
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
 
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)
1117
1159
        self._make_dirty(reset_inventory=False)
1118
1160
 
1119
1161
    def _set_root_id(self, file_id):
1139
1181
 
1140
1182
    def unlock(self):
1141
1183
        """Unlock in format 4 trees needs to write the entire dirstate."""
1142
 
        # do non-implementation specific cleanup
1143
 
        self._cleanup()
1144
 
 
1145
1184
        if self._control_files._lock_count == 1:
 
1185
            # do non-implementation specific cleanup
 
1186
            self._cleanup()
 
1187
 
1146
1188
            # eventually we should do signature checking during read locks for
1147
1189
            # dirstate updates.
1148
1190
            if self._control_files._lock_mode == 'w':
1254
1296
    def rename_one(self, from_rel, to_rel, after=False):
1255
1297
        """See WorkingTree.rename_one"""
1256
1298
        self.flush()
1257
 
        WorkingTree.rename_one(self, from_rel, to_rel, after)
 
1299
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
1258
1300
 
1259
1301
    @needs_tree_write_lock
1260
1302
    def apply_inventory_delta(self, changes):
1293
1335
            self._inventory = inv
1294
1336
        self.flush()
1295
1337
 
 
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
 
1296
1359
 
1297
1360
class ContentFilterAwareSHA1Provider(dirstate.SHA1Provider):
1298
1361
 
1303
1366
        """See dirstate.SHA1Provider.sha1()."""
1304
1367
        filters = self.tree._content_filter_stack(
1305
1368
            self.tree.relpath(osutils.safe_unicode(abspath)))
1306
 
        return internal_size_sha_file_byname(abspath, filters)[1]
 
1369
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
1307
1370
 
1308
1371
    def stat_and_sha1(self, abspath):
1309
1372
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1313
1376
        try:
1314
1377
            statvalue = os.fstat(file_obj.fileno())
1315
1378
            if filters:
1316
 
                file_obj = filtered_input_file(file_obj, filters)
 
1379
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
1317
1380
            sha1 = osutils.size_sha_file(file_obj)[1]
1318
1381
        finally:
1319
1382
            file_obj.close()
1349
1412
class WorkingTree4(DirStateWorkingTree):
1350
1413
    """This is the Format 4 working tree.
1351
1414
 
1352
 
    This differs from WorkingTree3 by:
 
1415
    This differs from WorkingTree by:
1353
1416
     - Having a consolidated internal dirstate, stored in a
1354
1417
       randomly-accessible sorted file on disk.
1355
1418
     - Not having a regular inventory attribute.  One can be synthesized
1383
1446
        return views.PathBasedViews(self)
1384
1447
 
1385
1448
 
1386
 
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
 
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)
1387
1462
 
1388
1463
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1389
1464
                   accelerator_tree=None, hardlink=False):
1390
1465
        """See WorkingTreeFormat.initialize().
1391
1466
 
1392
1467
        :param revision_id: allows creating a working tree at a different
1393
 
        revision than the branch is at.
 
1468
            revision than the branch is at.
1394
1469
        :param accelerator_tree: A tree which can be used for retrieving file
1395
1470
            contents more quickly than the revision tree, i.e. a workingtree.
1396
1471
            The revision tree will be used for cases where accelerator_tree's
1489
1564
        :param wt: the WorkingTree object
1490
1565
        """
1491
1566
 
 
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
 
1492
1581
    def _open(self, a_bzrdir, control_files):
1493
1582
        """Open the tree itself.
1494
1583
 
1585
1674
        return True
1586
1675
 
1587
1676
 
1588
 
class DirStateRevisionTree(Tree):
 
1677
class DirStateRevisionTree(InventoryTree):
1589
1678
    """A revision tree pulling the inventory from a dirstate.
1590
1679
    
1591
1680
    Note that this is one of the historical (ie revision) trees cached in the
1610
1699
    def annotate_iter(self, file_id,
1611
1700
                      default_revision=_mod_revision.CURRENT_REVISION):
1612
1701
        """See Tree.annotate_iter"""
1613
 
        text_key = (file_id, self.inventory[file_id].revision)
 
1702
        text_key = (file_id, self.get_file_revision(file_id))
1614
1703
        annotations = self._repository.texts.annotate(text_key)
1615
1704
        return [(key[-1], line) for (key, line) in annotations]
1616
1705
 
1617
 
    def _get_ancestors(self, default_revision):
1618
 
        return set(self._repository.get_ancestry(self._revision_id,
1619
 
                                                 topo_sorted=False))
1620
1706
    def _comparison_data(self, entry, path):
1621
1707
        """See Tree._comparison_data."""
1622
1708
        if entry is None:
1763
1849
        # Make sure the file exists
1764
1850
        entry = self._get_entry(file_id, path=path)
1765
1851
        if entry == (None, None): # do we raise?
1766
 
            return None
 
1852
            raise errors.NoSuchId(self, file_id)
1767
1853
        parent_index = self._get_parent_index()
1768
1854
        last_changed_revision = entry[1][parent_index][4]
1769
1855
        try:
1780
1866
            return parent_details[1]
1781
1867
        return None
1782
1868
 
 
1869
    @needs_read_lock
 
1870
    def get_file_revision(self, file_id):
 
1871
        return self.inventory[file_id].revision
 
1872
 
1783
1873
    def get_file(self, file_id, path=None):
1784
1874
        return StringIO(self.get_file_text(file_id))
1785
1875
 
1808
1898
                                       identifier))
1809
1899
        return self._repository.iter_files_bytes(repo_desired_files)
1810
1900
 
1811
 
    def get_symlink_target(self, file_id):
 
1901
    def get_symlink_target(self, file_id, path=None):
1812
1902
        entry = self._get_entry(file_id=file_id)
1813
1903
        parent_index = self._get_parent_index()
1814
1904
        if entry[1][parent_index][0] != 'l':
1867
1957
    def is_executable(self, file_id, path=None):
1868
1958
        ie = self.inventory[file_id]
1869
1959
        if ie.kind != "file":
1870
 
            return None
 
1960
            return False
1871
1961
        return ie.executable
1872
1962
 
1873
1963
    def is_locked(self):
1986
2076
    def make_source_parent_tree(source, target):
1987
2077
        """Change the source tree into a parent of the target."""
1988
2078
        revid = source.commit('record tree')
1989
 
        target.branch.repository.fetch(source.branch.repository, revid)
 
2079
        target.branch.fetch(source.branch, revid)
1990
2080
        target.set_parent_ids([revid])
1991
2081
        return target.basis_tree(), target
1992
2082