~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/workingtree_4.py

Most of the integration of dirstate and subtree

Show diffs side-by-side

added added

removed removed

Lines of Context:
105
105
    """This is the Format 4 working tree.
106
106
 
107
107
    This differs from WorkingTree3 by:
108
 
     - having a consolidated internal dirstate.
109
 
     - not having a regular inventory attribute.
 
108
     - Having a consolidated internal dirstate, stored in a
 
109
       randomly-accessible sorted file on disk.
 
110
     - Not having a regular inventory attribute.  One can be synthesized 
 
111
       on demand but this is expensive and should be avoided.
110
112
 
111
 
    This is new in bzr TODO FIXME SETMEBEFORE MERGE.
 
113
    This is new in bzr 0.15.
112
114
    """
113
115
 
114
116
    def __init__(self, basedir,
180
182
            state.add(f, file_id, kind, None, '')
181
183
        self._dirty = True
182
184
 
 
185
    @needs_tree_write_lock
 
186
    def add_reference(self, sub_tree):
 
187
        # use standard implementation, which calls back to self._add
 
188
        # 
 
189
        # So we don't store the reference_revision in the working dirstate,
 
190
        # it's just recorded at the moment of commit. 
 
191
        self._add_reference(sub_tree)
 
192
 
183
193
    def break_lock(self):
184
194
        """Break a lock if one is present from another instance.
185
195
 
217
227
        self._control_files.break_lock()
218
228
        self.branch.break_lock()
219
229
 
 
230
    def _comparison_data(self, entry, path):
 
231
        kind, executable, stat_value = \
 
232
            WorkingTree3._comparison_data(self, entry, path)
 
233
        # it looks like a plain directory, but it's really a reference
 
234
        if kind == 'directory' and entry.kind == 'tree-reference':
 
235
            kind = 'tree-reference'
 
236
        return kind, executable, stat_value
 
237
 
220
238
    def current_dirstate(self):
221
239
        """Return the current dirstate object. 
222
240
 
225
243
 
226
244
        :raises errors.NotWriteLocked: when not in a lock. 
227
245
        """
228
 
        if not self._control_files._lock_count:
229
 
            raise errors.ObjectNotLocked(self)
 
246
        self._must_be_locked()
230
247
        return self._current_dirstate()
231
248
 
232
249
    def _current_dirstate(self):
357
374
        """Get the inventory for the tree. This is only valid within a lock."""
358
375
        if self._inventory is not None:
359
376
            return self._inventory
 
377
        self._must_be_locked()
360
378
        self._generate_inventory()
361
379
        return self._inventory
362
380
 
371
389
        """
372
390
        return self.current_dirstate().get_parent_ids()
373
391
 
 
392
    def get_reference_revision(self, entry, path=None):
 
393
        # referenced tree's revision is whatever's currently there
 
394
        return self.get_nested_tree(entry, path).last_revision()
 
395
 
 
396
    def get_nested_tree(self, entry, path=None):
 
397
        if path is None:
 
398
            path = self.id2path(entry.file_id)
 
399
        return WorkingTree.open(self.abspath(path))
 
400
 
374
401
    @needs_read_lock
375
402
    def get_root_id(self):
376
403
        """Return the id of this trees root"""
415
442
                result.append(key[2])
416
443
        return iter(result)
417
444
 
 
445
    def kind(self, file_id):
 
446
        # The kind of a file is whatever it actually is on disk, except that 
 
447
        # tree-references need to be reported as such rather than as the
 
448
        # directiories
 
449
        #
 
450
        # TODO: Possibly we should check that the directory still really
 
451
        # contains a subtree, at least during commit? mbp 20070227
 
452
        kind = WorkingTree3.kind(self, file_id)
 
453
        if kind == 'directory':
 
454
            # TODO: ask the dirstate not the inventory -- mbp 20060227
 
455
            entry = self.inventory[file_id]
 
456
            if entry.kind == 'tree-reference':
 
457
                kind = 'tree-reference'
 
458
        return kind
 
459
 
418
460
    @needs_read_lock
419
461
    def _last_revision(self):
420
462
        """See Mutable.last_revision."""
659
701
 
660
702
        return #rename_tuples
661
703
 
 
704
    def _must_be_locked(self):
 
705
        if not self._control_files._lock_count:
 
706
            raise errors.ObjectNotLocked(self)
 
707
 
662
708
    def _new_tree(self):
663
709
        """Initialize the state in this tree to be a new tree."""
664
710
        self._dirty = True
1033
1079
        - uses a LockDir to guard access to it.
1034
1080
    """
1035
1081
 
 
1082
    supports_tree_reference = True
 
1083
 
1036
1084
    def get_format_string(self):
1037
1085
        """See WorkingTreeFormat.get_format_string()."""
1038
1086
        return "Bazaar Working Tree format 4\n"
1093
1141
                           _bzrdir=a_bzrdir,
1094
1142
                           _control_files=control_files)
1095
1143
 
 
1144
    def __get_matchingbzrdir(self):
 
1145
        # please test against something that will let us do tree references
 
1146
        return bzrdir.format_registry.make_bzrdir(
 
1147
            'experimental-reference-dirstate')
 
1148
 
 
1149
    _matchingbzrdir = property(__get_matchingbzrdir)
 
1150
 
1096
1151
 
1097
1152
class DirStateRevisionTree(Tree):
1098
1153
    """A revision tree pulling the inventory from a dirstate."""
1112
1167
        return w.annotate_iter(self.inventory[file_id].revision)
1113
1168
 
1114
1169
    def _comparison_data(self, entry, path):
1115
 
        """See Tree._comparison_data."""
1116
1170
        if entry is None:
1117
1171
            return None, False, None
1118
1172
        # trust the entry as RevisionTree does, but this may not be
1156
1210
    def _generate_inventory(self):
1157
1211
        """Create and set self.inventory from the dirstate object.
1158
1212
 
 
1213
        (So this is only called the first time the inventory is requested for
 
1214
        this tree; it then remains in memory.)
 
1215
 
1159
1216
        This is relatively expensive: we have to walk the entire dirstate.
1160
 
        Ideally we would not, and instead would """
 
1217
        """
1161
1218
        assert self._locked, 'cannot generate inventory of an unlocked '\
1162
1219
            'dirstate revision tree'
1163
1220
        # separate call for profiling - makes it clear where the costs are.
1189
1246
                # all the paths in this block are not versioned in this tree
1190
1247
                continue
1191
1248
            for key, entry in block[1]:
1192
 
                minikind, link_or_sha1, size, executable, revid = entry[parent_index]
 
1249
                minikind, fingerprint, size, executable, revid = entry[parent_index]
1193
1250
                if minikind in ('a', 'r'): # absent, relocated
1194
1251
                    # not this tree
1195
1252
                    continue
1203
1260
                if kind == 'file':
1204
1261
                    inv_entry.executable = executable
1205
1262
                    inv_entry.text_size = size
1206
 
                    inv_entry.text_sha1 = link_or_sha1
 
1263
                    inv_entry.text_sha1 = fingerprint
1207
1264
                elif kind == 'directory':
1208
1265
                    parent_ies[(dirname + '/' + name).strip('/')] = inv_entry
1209
1266
                elif kind == 'symlink':
1210
1267
                    inv_entry.executable = False
1211
1268
                    inv_entry.text_size = size
1212
 
                    inv_entry.symlink_target = utf8_decode(link_or_sha1)[0]
 
1269
                    inv_entry.symlink_target = utf8_decode(fingerprint)[0]
 
1270
                elif kind == 'tree-reference':
 
1271
                    inv_entry.reference_revision = fingerprint
1213
1272
                else:
1214
 
                    raise Exception, kind
 
1273
                    raise AssertionError("cannot convert entry %r into an InventoryEntry"
 
1274
                            % entry)
1215
1275
                # These checks cost us around 40ms on a 55k entry tree
1216
1276
                assert file_id not in inv_byid
1217
1277
                assert name_unicode not in parent_ie.children
1272
1332
    def has_filename(self, filename):
1273
1333
        return bool(self.path2id(filename))
1274
1334
 
1275
 
    def kind(self, file_id):
1276
 
        return self.inventory[file_id].kind
1277
 
 
1278
1335
    def is_executable(self, file_id, path=None):
1279
1336
        ie = self.inventory[file_id]
1280
1337
        if ie.kind != "file":