/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/versionedfile.py

Merge bzr.dev and resolve conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
37
37
from cStringIO import StringIO
38
38
 
39
39
from bzrlib.inter import InterObject
 
40
from bzrlib.registry import Registry
40
41
from bzrlib.symbol_versioning import *
41
42
from bzrlib.textmerge import TextMerge
42
43
 
43
44
 
 
45
adapter_registry = Registry()
 
46
adapter_registry.register_lazy(('knit-delta-gz', 'fulltext'), 'bzrlib.knit',
 
47
    'DeltaPlainToFullText')
 
48
adapter_registry.register_lazy(('knit-ft-gz', 'fulltext'), 'bzrlib.knit',
 
49
    'FTPlainToFullText')
 
50
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'knit-delta-gz'),
 
51
    'bzrlib.knit', 'DeltaAnnotatedToUnannotated')
 
52
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'fulltext'),
 
53
    'bzrlib.knit', 'DeltaAnnotatedToFullText')
 
54
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'knit-ft-gz'),
 
55
    'bzrlib.knit', 'FTAnnotatedToUnannotated')
 
56
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'fulltext'),
 
57
    'bzrlib.knit', 'FTAnnotatedToFullText')
 
58
 
 
59
 
 
60
class ContentFactory(object):
 
61
    """Abstract interface for insertion and retrieval from a VersionedFile.
 
62
    
 
63
    :ivar sha1: None, or the sha1 of the content fulltext.
 
64
    :ivar storage_kind: The native storage kind of this factory. One of
 
65
        'mpdiff', 'knit-annotated-ft', 'knit-annotated-delta', 'knit-ft',
 
66
        'knit-delta', 'fulltext', 'knit-annotated-ft-gz',
 
67
        'knit-annotated-delta-gz', 'knit-ft-gz', 'knit-delta-gz'.
 
68
    :ivar key: The key of this content. Each key is a tuple with a single
 
69
        string in it.
 
70
    :ivar parents: A tuple of parent keys for self.key. If the object has
 
71
        no parent information, None (as opposed to () for an empty list of
 
72
        parents).
 
73
        """
 
74
 
 
75
    def __init__(self):
 
76
        """Create a ContentFactory."""
 
77
        self.sha1 = None
 
78
        self.storage_kind = None
 
79
        self.key = None
 
80
        self.parents = None
 
81
 
 
82
 
 
83
class AbsentContentFactory(object):
 
84
    """A placeholder content factory for unavailable texts.
 
85
    
 
86
    :ivar sha1: None.
 
87
    :ivar storage_kind: 'absent'.
 
88
    :ivar key: The key of this content. Each key is a tuple with a single
 
89
        string in it.
 
90
    :ivar parents: None.
 
91
    """
 
92
 
 
93
    def __init__(self, key):
 
94
        """Create a ContentFactory."""
 
95
        self.sha1 = None
 
96
        self.storage_kind = 'absent'
 
97
        self.key = key
 
98
        self.parents = None
 
99
 
 
100
 
 
101
def filter_absent(record_stream):
 
102
    """Adapt a record stream to remove absent records."""
 
103
    for record in record_stream:
 
104
        if record.storage_kind != 'absent':
 
105
            yield record
 
106
 
 
107
 
44
108
class VersionedFile(object):
45
109
    """Versioned text file storage.
46
110
    
63
127
        """Copy this versioned file to name on transport."""
64
128
        raise NotImplementedError(self.copy_to)
65
129
 
66
 
    def versions(self):
67
 
        """Return a unsorted list of versions."""
68
 
        raise NotImplementedError(self.versions)
 
130
    def get_record_stream(self, versions, ordering, include_delta_closure):
 
131
        """Get a stream of records for versions.
69
132
 
70
 
    @deprecated_method(one_four)
71
 
    def has_ghost(self, version_id):
72
 
        """Returns whether version is present as a ghost."""
73
 
        raise NotImplementedError(self.has_ghost)
 
133
        :param versions: The versions to include. Each version is a tuple
 
134
            (version,).
 
135
        :param ordering: Either 'unordered' or 'topological'. A topologically
 
136
            sorted stream has compression parents strictly before their
 
137
            children.
 
138
        :param include_delta_closure: If True then the closure across any
 
139
            compression parents will be included (in the data content of the
 
140
            stream, not in the emitted records). This guarantees that
 
141
            'fulltext' can be used successfully on every record.
 
142
        :return: An iterator of ContentFactory objects, each of which is only
 
143
            valid until the iterator is advanced.
 
144
        """
 
145
        raise NotImplementedError(self.get_record_stream)
74
146
 
75
147
    def has_version(self, version_id):
76
148
        """Returns whether version is present."""
77
149
        raise NotImplementedError(self.has_version)
78
150
 
 
151
    def insert_record_stream(self, stream):
 
152
        """Insert a record stream into this versioned file.
 
153
 
 
154
        :param stream: A stream of records to insert. 
 
155
        :return: None
 
156
        :seealso VersionedFile.get_record_stream:
 
157
        """
 
158
        raise NotImplementedError
 
159
 
79
160
    def add_lines(self, version_id, parents, lines, parent_texts=None,
80
161
        left_matching_blocks=None, nostore_sha=None, random_id=False,
81
162
        check_content=True):
157
238
            if '\n' in line[:-1]:
158
239
                raise errors.BzrBadParameterContainsNewline("lines")
159
240
 
160
 
    @deprecated_method(one_four)
161
 
    def enable_cache(self):
162
 
        """Tell this versioned file that it should cache any data it reads.
163
 
        
164
 
        This is advisory, implementations do not have to support caching.
165
 
        """
166
 
        pass
167
 
    
168
 
    @deprecated_method(one_four)
169
 
    def clear_cache(self):
170
 
        """Remove any data cached in the versioned file object.
171
 
 
172
 
        This only needs to be supported if caches are supported
173
 
        """
174
 
        pass
175
 
 
176
 
    @deprecated_method(one_four)
177
 
    def clone_text(self, new_version_id, old_version_id, parents):
178
 
        """Add an identical text to old_version_id as new_version_id.
179
 
 
180
 
        Must raise RevisionNotPresent if the old version or any of the
181
 
        parents are not present in file history.
182
 
 
183
 
        Must raise RevisionAlreadyPresent if the new version is
184
 
        already present in file history."""
185
 
        self._check_write_ok()
186
 
        return self.add_lines(new_version_id, parents,
187
 
            self.get_lines(old_version_id))
188
 
 
189
241
    def get_format_signature(self):
190
242
        """Get a text description of the data encoding in this file.
191
243
        
271
323
            if expected_sha1 != sha1:
272
324
                raise errors.VersionedFileInvalidChecksum(version)
273
325
 
274
 
    @deprecated_method(one_four)
275
 
    def get_sha1(self, version_id):
276
 
        """Get the stored sha1 sum for the given revision.
277
 
        
278
 
        :param version_id: The name of the version to lookup
279
 
        """
280
 
        return self.get_sha1s([version_id])[0]
281
 
 
282
326
    def get_sha1s(self, version_ids):
283
327
        """Get the stored sha1 sums for the given revisions.
284
328
 
340
384
        """
341
385
        raise NotImplementedError(self.get_ancestry_with_ghosts)
342
386
    
343
 
    @deprecated_method(one_four)
344
 
    def get_graph(self, version_ids=None):
345
 
        """Return a graph from the versioned file. 
346
 
        
347
 
        Ghosts are not listed or referenced in the graph.
348
 
        :param version_ids: Versions to select.
349
 
                            None means retrieve all versions.
350
 
        """
351
 
        if version_ids is None:
352
 
            result = self.get_parent_map(self.versions())
353
 
        else:
354
 
            result = {}
355
 
            pending = set(version_ids)
356
 
            while pending:
357
 
                this_iteration = pending
358
 
                pending = set()
359
 
                parents = self.get_parent_map(this_iteration)
360
 
                for version, parents in parents.iteritems():
361
 
                    result[version] = parents
362
 
                    for parent in parents:
363
 
                        if parent in result:
364
 
                            continue
365
 
                        pending.add(parent)
366
 
        references = set()
367
 
        for parents in result.itervalues():
368
 
            references.update(parents)
369
 
        existing_parents = self.get_parent_map(references)
370
 
        for key, parents in result.iteritems():
371
 
            present_parents = [parent for parent in parents if parent in
372
 
                existing_parents]
373
 
            result[key] = tuple(present_parents)
374
 
        return result
375
 
 
376
 
    @deprecated_method(one_four)
377
 
    def get_graph_with_ghosts(self):
378
 
        """Return a graph for the entire versioned file.
379
 
        
380
 
        Ghosts are referenced in parents list but are not
381
 
        explicitly listed.
382
 
        """
383
 
        raise NotImplementedError(self.get_graph_with_ghosts)
384
 
 
385
387
    def get_parent_map(self, version_ids):
386
388
        """Get a map of the parents of version_ids.
387
389
 
390
392
        """
391
393
        raise NotImplementedError(self.get_parent_map)
392
394
 
393
 
    @deprecated_method(one_four)
394
 
    def get_parents(self, version_id):
395
 
        """Return version names for parents of a version.
396
 
 
397
 
        Must raise RevisionNotPresent if version is not present in
398
 
        file history.
399
 
        """
400
 
        try:
401
 
            all = self.get_parent_map([version_id])[version_id]
402
 
        except KeyError:
403
 
            raise errors.RevisionNotPresent(version_id, self)
404
 
        result = []
405
 
        parent_parents = self.get_parent_map(all)
406
 
        for version_id in all:
407
 
            if version_id in parent_parents:
408
 
                result.append(version_id)
409
 
        return result
410
 
 
411
395
    def get_parents_with_ghosts(self, version_id):
412
396
        """Return version names for parents of version_id.
413
397
 
422
406
        except KeyError:
423
407
            raise errors.RevisionNotPresent(version_id, self)
424
408
 
425
 
    @deprecated_method(one_four)
426
 
    def annotate_iter(self, version_id):
427
 
        """Yield list of (version-id, line) pairs for the specified
428
 
        version.
429
 
 
430
 
        Must raise RevisionNotPresent if the given version is
431
 
        not present in file history.
432
 
        """
433
 
        return iter(self.annotate(version_id))
434
 
 
435
409
    def annotate(self, version_id):
436
410
        """Return a list of (version-id, line) tuples for version_id.
437
411
 
440
414
        """
441
415
        raise NotImplementedError(self.annotate)
442
416
 
 
417
    @deprecated_method(one_five)
443
418
    def join(self, other, pb=None, msg=None, version_ids=None,
444
419
             ignore_missing=False):
445
420
        """Integrate versions from other into this versioned file.
480
455
        """
481
456
        raise NotImplementedError(self.iter_lines_added_or_present_in_versions)
482
457
 
483
 
    @deprecated_method(one_four)
484
 
    def iter_parents(self, version_ids):
485
 
        """Iterate through the parents for many version ids.
486
 
 
487
 
        :param version_ids: An iterable yielding version_ids.
488
 
        :return: An iterator that yields (version_id, parents). Requested 
489
 
            version_ids not present in the versioned file are simply skipped.
490
 
            The order is undefined, allowing for different optimisations in
491
 
            the underlying implementation.
492
 
        """
493
 
        return self.get_parent_map(version_ids).iteritems()
494
 
 
495
458
    def plan_merge(self, ver_a, ver_b):
496
459
        """Return pseudo-annotation indicating how the two versions merge.
497
460
 
519
482
        return PlanWeaveMerge(plan, a_marker, b_marker).merge_lines()[0]
520
483
 
521
484
 
 
485
class RecordingVersionedFileDecorator(object):
 
486
    """A minimal versioned file that records calls made on it.
 
487
    
 
488
    Only enough methods have been added to support tests using it to date.
 
489
 
 
490
    :ivar calls: A list of the calls made; can be reset at any time by
 
491
        assigning [] to it.
 
492
    """
 
493
 
 
494
    def __init__(self, backing_vf):
 
495
        """Create a RecordingVersionedFileDecorator decorating backing_vf.
 
496
        
 
497
        :param backing_vf: The versioned file to answer all methods.
 
498
        """
 
499
        self._backing_vf = backing_vf
 
500
        self.calls = []
 
501
 
 
502
    def get_lines(self, version_ids):
 
503
        self.calls.append(("get_lines", version_ids))
 
504
        return self._backing_vf.get_lines(version_ids)
 
505
 
 
506
 
522
507
class _PlanMergeVersionedFile(object):
523
508
    """A VersionedFile for uncommitted and committed texts.
524
509
 
712
697
                ch_b = ch_a = True
713
698
                lines_b.append(line)
714
699
            else:
715
 
                assert state in ('irrelevant', 'ghost-a', 'ghost-b', 
716
 
                                 'killed-base', 'killed-both'), state
 
700
                if state not in ('irrelevant', 'ghost-a', 'ghost-b',
 
701
                        'killed-base', 'killed-both'):
 
702
                    raise AssertionError(state)
717
703
        for struct in outstanding_struct():
718
704
            yield struct
719
705