~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

  • Committer: Vincent Ladeuil
  • Date: 2011-02-10 12:37:27 UTC
  • mto: This revision was merged to the branch mainline in revision 5661.
  • Revision ID: v.ladeuil+lp@free.fr-20110210123727-8e0pu4wtlt6fj7nf
thread is already a python module, avoid confusion and use cethread instead.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
56
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
65
66
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
 
 
79
 
    _DEFAULT_WORTH_SAVING_LIMIT = 10
80
 
 
 
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):
81
73
    def __init__(self, basedir,
82
74
                 branch,
83
75
                 _control_files=None,
93
85
        self._format = _format
94
86
        self.bzrdir = _bzrdir
95
87
        basedir = safe_unicode(basedir)
96
 
        trace.mutter("opening working tree %r", basedir)
 
88
        mutter("opening working tree %r", basedir)
97
89
        self._branch = branch
98
90
        self.basedir = realpath(basedir)
99
91
        # if branch is at our basedir and is a format 6 or less
133
125
            state.add(f, file_id, kind, None, '')
134
126
        self._make_dirty(reset_inventory=True)
135
127
 
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
 
 
140
128
    def _make_dirty(self, reset_inventory):
141
129
        """Make the tree state dirty.
142
130
 
194
182
 
195
183
    def _comparison_data(self, entry, path):
196
184
        kind, executable, stat_value = \
197
 
            WorkingTree._comparison_data(self, entry, path)
 
185
            WorkingTree3._comparison_data(self, entry, path)
198
186
        # it looks like a plain directory, but it's really a reference -- see
199
187
        # also kind()
200
188
        if (self._repo_supports_tree_reference and kind == 'directory'
206
194
    def commit(self, message=None, revprops=None, *args, **kwargs):
207
195
        # mark the tree as dirty post commit - commit
208
196
        # can change the current versioned list by doing deletes.
209
 
        result = WorkingTree.commit(self, message, revprops, *args, **kwargs)
 
197
        result = WorkingTree3.commit(self, message, revprops, *args, **kwargs)
210
198
        self._make_dirty(reset_inventory=True)
211
199
        return result
212
200
 
231
219
        local_path = self.bzrdir.get_workingtree_transport(None
232
220
            ).local_abspath('dirstate')
233
221
        self._dirstate = dirstate.DirState.on_file(local_path,
234
 
            self._sha1_provider(), self._worth_saving_limit())
 
222
            self._sha1_provider())
235
223
        return self._dirstate
236
224
 
237
225
    def _sha1_provider(self):
246
234
        else:
247
235
            return None
248
236
 
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
 
 
269
237
    def filter_unversioned_files(self, paths):
270
238
        """Filter out paths that are versioned.
271
239
 
401
369
        state = self.current_dirstate()
402
370
        if stat_value is None:
403
371
            try:
404
 
                stat_value = osutils.lstat(file_abspath)
 
372
                stat_value = os.lstat(file_abspath)
405
373
            except OSError, e:
406
374
                if e.errno == errno.ENOENT:
407
375
                    return None
510
478
            self._must_be_locked()
511
479
            if not path:
512
480
                path = self.id2path(file_id)
513
 
            mode = osutils.lstat(self.abspath(path)).st_mode
 
481
            mode = os.lstat(self.abspath(path)).st_mode
514
482
            return bool(stat.S_ISREG(mode) and stat.S_IEXEC & mode)
515
483
 
516
484
    def all_file_ids(self):
882
850
                rollback_rename()
883
851
                raise
884
852
            result.append((from_rel, to_rel))
885
 
            state._mark_modified()
 
853
            state._dirblock_state = dirstate.DirState.IN_MEMORY_MODIFIED
886
854
            self._make_dirty(reset_inventory=False)
887
855
 
888
856
        return result
1145
1113
                        _mod_revision.NULL_REVISION)))
1146
1114
                ghosts.append(rev_id)
1147
1115
            accepted_revisions.add(rev_id)
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)
 
1116
        dirstate.set_parent_trees(real_trees, ghosts=ghosts)
1171
1117
        self._make_dirty(reset_inventory=False)
1172
1118
 
1173
1119
    def _set_root_id(self, file_id):
1193
1139
 
1194
1140
    def unlock(self):
1195
1141
        """Unlock in format 4 trees needs to write the entire dirstate."""
 
1142
        # do non-implementation specific cleanup
 
1143
        self._cleanup()
 
1144
 
1196
1145
        if self._control_files._lock_count == 1:
1197
 
            # do non-implementation specific cleanup
1198
 
            self._cleanup()
1199
 
 
1200
1146
            # eventually we should do signature checking during read locks for
1201
1147
            # dirstate updates.
1202
1148
            if self._control_files._lock_mode == 'w':
1308
1254
    def rename_one(self, from_rel, to_rel, after=False):
1309
1255
        """See WorkingTree.rename_one"""
1310
1256
        self.flush()
1311
 
        super(DirStateWorkingTree, self).rename_one(from_rel, to_rel, after)
 
1257
        WorkingTree.rename_one(self, from_rel, to_rel, after)
1312
1258
 
1313
1259
    @needs_tree_write_lock
1314
1260
    def apply_inventory_delta(self, changes):
1378
1324
        """See dirstate.SHA1Provider.sha1()."""
1379
1325
        filters = self.tree._content_filter_stack(
1380
1326
            self.tree.relpath(osutils.safe_unicode(abspath)))
1381
 
        return _mod_filters.internal_size_sha_file_byname(abspath, filters)[1]
 
1327
        return internal_size_sha_file_byname(abspath, filters)[1]
1382
1328
 
1383
1329
    def stat_and_sha1(self, abspath):
1384
1330
        """See dirstate.SHA1Provider.stat_and_sha1()."""
1388
1334
        try:
1389
1335
            statvalue = os.fstat(file_obj.fileno())
1390
1336
            if filters:
1391
 
                file_obj = _mod_filters.filtered_input_file(file_obj, filters)
 
1337
                file_obj = filtered_input_file(file_obj, filters)
1392
1338
            sha1 = osutils.size_sha_file(file_obj)[1]
1393
1339
        finally:
1394
1340
            file_obj.close()
1424
1370
class WorkingTree4(DirStateWorkingTree):
1425
1371
    """This is the Format 4 working tree.
1426
1372
 
1427
 
    This differs from WorkingTree by:
 
1373
    This differs from WorkingTree3 by:
1428
1374
     - Having a consolidated internal dirstate, stored in a
1429
1375
       randomly-accessible sorted file on disk.
1430
1376
     - Not having a regular inventory attribute.  One can be synthesized
1458
1404
        return views.PathBasedViews(self)
1459
1405
 
1460
1406
 
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)
 
1407
class DirStateWorkingTreeFormat(WorkingTreeFormat3):
1474
1408
 
1475
1409
    def initialize(self, a_bzrdir, revision_id=None, from_branch=None,
1476
1410
                   accelerator_tree=None, hardlink=False):
1477
1411
        """See WorkingTreeFormat.initialize().
1478
1412
 
1479
1413
        :param revision_id: allows creating a working tree at a different
1480
 
            revision than the branch is at.
 
1414
        revision than the branch is at.
1481
1415
        :param accelerator_tree: A tree which can be used for retrieving file
1482
1416
            contents more quickly than the revision tree, i.e. a workingtree.
1483
1417
            The revision tree will be used for cases where accelerator_tree's
1576
1510
        :param wt: the WorkingTree object
1577
1511
        """
1578
1512
 
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
 
 
1593
1513
    def _open(self, a_bzrdir, control_files):
1594
1514
        """Open the tree itself.
1595
1515
 
1686
1606
        return True
1687
1607
 
1688
1608
 
1689
 
class DirStateRevisionTree(InventoryTree):
 
1609
class DirStateRevisionTree(Tree):
1690
1610
    """A revision tree pulling the inventory from a dirstate.
1691
1611
    
1692
1612
    Note that this is one of the historical (ie revision) trees cached in the
1711
1631
    def annotate_iter(self, file_id,
1712
1632
                      default_revision=_mod_revision.CURRENT_REVISION):
1713
1633
        """See Tree.annotate_iter"""
1714
 
        text_key = (file_id, self.get_file_revision(file_id))
 
1634
        text_key = (file_id, self.inventory[file_id].revision)
1715
1635
        annotations = self._repository.texts.annotate(text_key)
1716
1636
        return [(key[-1], line) for (key, line) in annotations]
1717
1637
 
 
1638
    def _get_ancestors(self, default_revision):
 
1639
        return set(self._repository.get_ancestry(self._revision_id,
 
1640
                                                 topo_sorted=False))
1718
1641
    def _comparison_data(self, entry, path):
1719
1642
        """See Tree._comparison_data."""
1720
1643
        if entry is None:
1878
1801
            return parent_details[1]
1879
1802
        return None
1880
1803
 
1881
 
    @needs_read_lock
1882
 
    def get_file_revision(self, file_id):
1883
 
        return self.inventory[file_id].revision
1884
 
 
1885
1804
    def get_file(self, file_id, path=None):
1886
1805
        return StringIO(self.get_file_text(file_id))
1887
1806
 
1910
1829
                                       identifier))
1911
1830
        return self._repository.iter_files_bytes(repo_desired_files)
1912
1831
 
1913
 
    def get_symlink_target(self, file_id, path=None):
 
1832
    def get_symlink_target(self, file_id):
1914
1833
        entry = self._get_entry(file_id=file_id)
1915
1834
        parent_index = self._get_parent_index()
1916
1835
        if entry[1][parent_index][0] != 'l':
2088
2007
    def make_source_parent_tree(source, target):
2089
2008
        """Change the source tree into a parent of the target."""
2090
2009
        revid = source.commit('record tree')
2091
 
        target.branch.fetch(source.branch, revid)
 
2010
        target.branch.repository.fetch(source.branch.repository, revid)
2092
2011
        target.set_parent_ids([revid])
2093
2012
        return target.basis_tree(), target
2094
2013