/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 breezy/bzr/versionedfile.py

  • Committer: Jelmer Vernooij
  • Date: 2019-06-03 23:48:08 UTC
  • mfrom: (7316 work)
  • mto: This revision was merged to the branch mainline in revision 7328.
  • Revision ID: jelmer@jelmer.uk-20190603234808-15yk5c7054tj8e2b
Merge trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
from breezy import (
30
30
    annotate,
31
31
    bencode,
 
32
    errors,
32
33
    graph as _mod_graph,
33
34
    osutils,
34
35
    multiparent,
42
43
    knit,
43
44
    )
44
45
""")
45
 
from .. import (
46
 
    errors,
47
 
    )
48
46
from ..registry import Registry
49
47
from ..sixish import (
50
48
    BytesIO,
56
54
 
57
55
 
58
56
adapter_registry = Registry()
 
57
adapter_registry.register_lazy(('knit-delta-gz', 'fulltext'), 'breezy.bzr.knit',
 
58
                               'DeltaPlainToFullText')
 
59
adapter_registry.register_lazy(('knit-ft-gz', 'fulltext'), 'breezy.bzr.knit',
 
60
                               'FTPlainToFullText')
59
61
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'knit-delta-gz'),
60
62
                               'breezy.bzr.knit', 'DeltaAnnotatedToUnannotated')
 
63
adapter_registry.register_lazy(('knit-annotated-delta-gz', 'fulltext'),
 
64
                               'breezy.bzr.knit', 'DeltaAnnotatedToFullText')
61
65
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'knit-ft-gz'),
62
66
                               'breezy.bzr.knit', 'FTAnnotatedToUnannotated')
63
 
for target_storage_kind in ('fulltext', 'chunked', 'lines'):
64
 
    adapter_registry.register_lazy(('knit-delta-gz', target_storage_kind), 'breezy.bzr.knit',
65
 
                                   'DeltaPlainToFullText')
66
 
    adapter_registry.register_lazy(('knit-ft-gz', target_storage_kind), 'breezy.bzr.knit',
67
 
                                   'FTPlainToFullText')
68
 
    adapter_registry.register_lazy(('knit-annotated-ft-gz', target_storage_kind),
69
 
                                   'breezy.bzr.knit', 'FTAnnotatedToFullText')
70
 
    adapter_registry.register_lazy(('knit-annotated-delta-gz', target_storage_kind),
71
 
                                   'breezy.bzr.knit', 'DeltaAnnotatedToFullText')
 
67
adapter_registry.register_lazy(('knit-annotated-ft-gz', 'fulltext'),
 
68
                               'breezy.bzr.knit', 'FTAnnotatedToFullText')
 
69
# adapter_registry.register_lazy(('knit-annotated-ft-gz', 'chunked'),
 
70
#     'breezy.bzr.knit', 'FTAnnotatedToChunked')
72
71
 
73
72
 
74
73
class ContentFactory(object):
75
74
    """Abstract interface for insertion and retrieval from a VersionedFile.
76
75
 
77
76
    :ivar sha1: None, or the sha1 of the content fulltext.
78
 
    :ivar size: None, or the size of the content fulltext.
79
77
    :ivar storage_kind: The native storage kind of this factory. One of
80
78
        'mpdiff', 'knit-annotated-ft', 'knit-annotated-delta', 'knit-ft',
81
79
        'knit-delta', 'fulltext', 'knit-annotated-ft-gz',
90
88
    def __init__(self):
91
89
        """Create a ContentFactory."""
92
90
        self.sha1 = None
93
 
        self.size = None
94
91
        self.storage_kind = None
95
92
        self.key = None
96
93
        self.parents = None
104
101
    satisfies this, as does a list of lines.
105
102
 
106
103
    :ivar sha1: None, or the sha1 of the content fulltext.
107
 
    :ivar size: None, or the size of the content fulltext.
108
104
    :ivar storage_kind: The native storage kind of this factory. Always
109
105
        'chunked'
110
106
    :ivar key: The key of this content. Each key is a tuple with a single
112
108
    :ivar parents: A tuple of parent keys for self.key. If the object has
113
109
        no parent information, None (as opposed to () for an empty list of
114
110
        parents).
115
 
    :ivar chunks_are_lines: Whether chunks are lines.
116
111
     """
117
112
 
118
 
    def __init__(self, key, parents, sha1, chunks, chunks_are_lines=None):
 
113
    def __init__(self, key, parents, sha1, chunks):
119
114
        """Create a ContentFactory."""
120
115
        self.sha1 = sha1
121
 
        self.size = sum(map(len, chunks))
122
116
        self.storage_kind = 'chunked'
123
117
        self.key = key
124
118
        self.parents = parents
125
119
        self._chunks = chunks
126
 
        self._chunks_are_lines = chunks_are_lines
127
120
 
128
121
    def get_bytes_as(self, storage_kind):
129
122
        if storage_kind == 'chunked':
130
123
            return self._chunks
131
124
        elif storage_kind == 'fulltext':
132
125
            return b''.join(self._chunks)
133
 
        elif storage_kind == 'lines':
134
 
            if self._chunks_are_lines:
135
 
                return self._chunks
136
 
            return list(osutils.chunks_to_lines(self._chunks))
137
126
        raise errors.UnavailableRepresentation(self.key, storage_kind,
138
127
                                               self.storage_kind)
139
128
 
140
 
    def iter_bytes_as(self, storage_kind):
141
 
        if storage_kind == 'chunked':
142
 
            return iter(self._chunks)
143
 
        elif storage_kind == 'lines':
144
 
            if self._chunks_are_lines:
145
 
                return iter(self._chunks)
146
 
            return iter(osutils.chunks_to_lines(self._chunks))
147
 
        raise errors.UnavailableRepresentation(self.key, storage_kind,
148
 
                                               self.storage_kind)
149
129
 
150
130
class FulltextContentFactory(ContentFactory):
151
131
    """Static data content factory.
166
146
    def __init__(self, key, parents, sha1, text):
167
147
        """Create a ContentFactory."""
168
148
        self.sha1 = sha1
169
 
        self.size = len(text)
170
149
        self.storage_kind = 'fulltext'
171
150
        self.key = key
172
151
        self.parents = parents
179
158
            return self._text
180
159
        elif storage_kind == 'chunked':
181
160
            return [self._text]
182
 
        elif storage_kind == 'lines':
183
 
            return osutils.split_lines(self._text)
184
 
        raise errors.UnavailableRepresentation(self.key, storage_kind,
185
 
                                               self.storage_kind)
186
 
 
187
 
    def iter_bytes_as(self, storage_kind):
188
 
        if storage_kind == 'chunked':
189
 
            return iter([self._text])
190
 
        elif storage_kind == 'lines':
191
 
            return iter(osutils.split_lines(self._text))
192
 
        raise errors.UnavailableRepresentation(self.key, storage_kind,
193
 
                                               self.storage_kind)
194
 
 
195
 
 
196
 
class FileContentFactory(ContentFactory):
197
 
    """File-based content factory.
198
 
    """
199
 
 
200
 
    def __init__(self, key, parents, fileobj, sha1=None, size=None):
201
 
        self.key = key
202
 
        self.parents = parents
203
 
        self.file = fileobj
204
 
        self.storage_kind = 'file'
205
 
        self.sha1 = sha1
206
 
        self.size = size
207
 
 
208
 
    def get_bytes_as(self, storage_kind):
209
 
        self.file.seek(0)
210
 
        if storage_kind == 'fulltext':
211
 
            return self.file.read()
212
 
        elif storage_kind == 'chunked':
213
 
            return list(osutils.file_iterator(self.file))
214
 
        elif storage_kind == 'lines':
215
 
            return list(self.file.readlines())
216
 
        raise errors.UnavailableRepresentation(self.key, storage_kind,
217
 
                                               self.storage_kind)
218
 
 
219
 
    def iter_bytes_as(self, storage_kind):
220
 
        self.file.seek(0)
221
 
        if storage_kind == 'chunked':
222
 
            return osutils.file_iterator(self.file)
223
 
        elif storage_kind == 'lines':
224
 
            return self.file
225
161
        raise errors.UnavailableRepresentation(self.key, storage_kind,
226
162
                                               self.storage_kind)
227
163
 
239
175
    def __init__(self, key):
240
176
        """Create a ContentFactory."""
241
177
        self.sha1 = None
242
 
        self.size = None
243
178
        self.storage_kind = 'absent'
244
179
        self.key = key
245
180
        self.parents = None
250
185
                         ' code does not handle if it is missing.'
251
186
                         % (self.key,))
252
187
 
253
 
    def iter_bytes_as(self, storage_kind):
254
 
        raise ValueError('A request was made for key: %s, but that'
255
 
                         ' content is not available, and the calling'
256
 
                         ' code does not handle if it is missing.'
257
 
                         % (self.key,))
258
 
 
259
188
 
260
189
class AdapterFactory(ContentFactory):
261
190
    """A content factory to adapt between key prefix's."""
794
723
        return self._backing_vf.add_lines(key, parents, lines, parent_texts,
795
724
                                          left_matching_blocks, nostore_sha, random_id, check_content)
796
725
 
797
 
    def add_content(self, factory, parent_texts=None,
798
 
                    left_matching_blocks=None, nostore_sha=None, random_id=False,
799
 
                    check_content=True):
800
 
        self.calls.append(("add_content", factory, parent_texts,
801
 
                           left_matching_blocks, nostore_sha, random_id, check_content))
802
 
        return self._backing_vf.add_content(
803
 
            factory, parent_texts, left_matching_blocks, nostore_sha,
804
 
            random_id, check_content)
805
 
 
806
726
    def check(self):
807
727
        self._backing_vf.check()
808
728
 
1058
978
        """
1059
979
        raise NotImplementedError(self.add_lines)
1060
980
 
1061
 
    def add_content(self, factory, parent_texts=None,
1062
 
                    left_matching_blocks=None, nostore_sha=None, random_id=False,
1063
 
                    check_content=True):
1064
 
        """Add a text to the store from a chunk iterable.
1065
 
 
1066
 
        :param key: The key tuple of the text to add. If the last element is
1067
 
            None, a CHK string will be generated during the addition.
1068
 
        :param parents: The parents key tuples of the text to add.
1069
 
        :param chunk_iter: An iterable over bytestrings.
1070
 
        :param parent_texts: An optional dictionary containing the opaque
1071
 
            representations of some or all of the parents of version_id to
1072
 
            allow delta optimisations.  VERY IMPORTANT: the texts must be those
1073
 
            returned by add_lines or data corruption can be caused.
1074
 
        :param left_matching_blocks: a hint about which areas are common
1075
 
            between the text and its left-hand-parent.  The format is
1076
 
            the SequenceMatcher.get_matching_blocks format.
1077
 
        :param nostore_sha: Raise ExistingContent and do not add the lines to
1078
 
            the versioned file if the digest of the lines matches this.
1079
 
        :param random_id: If True a random id has been selected rather than
1080
 
            an id determined by some deterministic process such as a converter
1081
 
            from a foreign VCS. When True the backend may choose not to check
1082
 
            for uniqueness of the resulting key within the versioned file, so
1083
 
            this should only be done when the result is expected to be unique
1084
 
            anyway.
1085
 
        :param check_content: If True, the lines supplied are verified to be
1086
 
            bytestrings that are correctly formed lines.
1087
 
        :return: The text sha1, the number of bytes in the text, and an opaque
1088
 
                 representation of the inserted version which can be provided
1089
 
                 back to future add_lines calls in the parent_texts dictionary.
1090
 
        """
1091
 
        raise NotImplementedError(self.add_content)
1092
 
 
1093
981
    def add_mpdiffs(self, records):
1094
982
        """Add mpdiffs to this VersionedFile.
1095
983
 
1108
996
                                  if not mpvf.has_version(p))
1109
997
        # It seems likely that adding all the present parents as fulltexts can
1110
998
        # easily exhaust memory.
 
999
        chunks_to_lines = osutils.chunks_to_lines
1111
1000
        for record in self.get_record_stream(needed_parents, 'unordered',
1112
1001
                                             True):
1113
1002
            if record.storage_kind == 'absent':
1114
1003
                continue
1115
 
            mpvf.add_version(record.get_bytes_as('lines'), record.key, [])
 
1004
            mpvf.add_version(chunks_to_lines(record.get_bytes_as('chunked')),
 
1005
                             record.key, [])
1116
1006
        for (key, parent_keys, expected_sha1, mpdiff), lines in zip(
1117
1007
                records, mpvf.get_line_list(versions)):
1118
1008
            if len(parent_keys) == 1:
1311
1201
        self._mapper = mapper
1312
1202
        self._is_locked = is_locked
1313
1203
 
1314
 
    def add_content(self, factory, parent_texts=None,
1315
 
                    left_matching_blocks=None, nostore_sha=None, random_id=False):
1316
 
        """See VersionedFiles.add_content()."""
1317
 
        lines = factory.get_bytes_as('lines')
1318
 
        return self.add_lines(
1319
 
            factory.key, factory.parents, lines,
1320
 
            parent_texts=parent_texts,
1321
 
            left_matching_blocks=left_matching_blocks,
1322
 
            nostore_sha=nostore_sha,
1323
 
            random_id=random_id,
1324
 
            check_content=True)
1325
 
 
1326
1204
    def add_lines(self, key, parents, lines, parent_texts=None,
1327
1205
                  left_matching_blocks=None, nostore_sha=None, random_id=False,
1328
1206
                  check_content=True):
1600
1478
            ver_a, base, self, (self._file_id,), graph).plan_merge()
1601
1479
        return _PlanLCAMerge._subtract_plans(list(old_plan), list(new_plan))
1602
1480
 
1603
 
    def add_content(self, factory):
1604
 
        return self.add_lines(
1605
 
            factory.key, factory.parents, factory.get_bytes_as('lines'))
1606
 
 
1607
1481
    def add_lines(self, key, parents, lines):
1608
1482
        """See VersionedFiles.add_lines
1609
1483
 
1628
1502
                lines = self._lines[key]
1629
1503
                parents = self._parents[key]
1630
1504
                pending.remove(key)
1631
 
                yield ChunkedContentFactory(
1632
 
                    key, parents, None, lines,
1633
 
                    chunks_are_lines=True)
 
1505
                yield ChunkedContentFactory(key, parents, None, lines)
1634
1506
        for versionedfile in self.fallback_versionedfiles:
1635
1507
            for record in versionedfile.get_record_stream(
1636
1508
                    pending, 'unordered', True):
1859
1731
            if lines is not None:
1860
1732
                if not isinstance(lines, list):
1861
1733
                    raise AssertionError
1862
 
                yield ChunkedContentFactory(
1863
 
                    (k,), None, sha1=osutils.sha_strings(lines),
1864
 
                    chunks=lines, chunks_are_lines=True)
 
1734
                yield ChunkedContentFactory((k,), None,
 
1735
                                            sha1=osutils.sha_strings(lines),
 
1736
                                            chunks=lines)
1865
1737
            else:
1866
1738
                yield AbsentContentFactory((k,))
1867
1739