/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/chk_serializer.py

  • Committer: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2018-03-25 11:54:30 UTC
  • mfrom: (6855.4.10 more-bees)
  • Revision ID: breezy.the.bot@gmail.com-20180325115430-75xnlbrmzjoomd83
Add more bees. In particular:

* for file ids
* for revision ids
* for file contents in build_tree_contents()

Merged from https://code.launchpad.net/~jelmer/brz/more-bees/+merge/337919

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
"""Serializer object for CHK based inventory storage."""
18
18
 
19
 
from bzrlib import (
 
19
from __future__ import absolute_import
 
20
 
 
21
from .. import lazy_import
 
22
lazy_import.lazy_import(globals(),
 
23
"""
 
24
from breezy.bzr import (
 
25
    xml_serializer,
 
26
    )
 
27
""")
 
28
from .. import (
20
29
    bencode,
21
30
    cache_utf8,
22
 
    inventory,
 
31
    errors,
23
32
    revision as _mod_revision,
24
 
    xml6,
25
 
    xml7,
26
 
    )
 
33
    )
 
34
from . import (
 
35
    serializer,
 
36
    )
 
37
from ..sixish import (
 
38
    BytesIO,
 
39
    )
 
40
 
27
41
 
28
42
 
29
43
def _validate_properties(props, _decode=cache_utf8._utf8_decode):
30
44
    # TODO: we really want an 'isascii' check for key
31
45
    # Cast the utf8 properties into Unicode 'in place'
32
 
    for key, value in props.iteritems():
 
46
    for key, value in props.items():
33
47
        props[key] = _decode(value)[0]
34
48
    return props
35
49
 
70
84
        # This lets us control the ordering, so that we are able to create
71
85
        # smaller deltas
72
86
        ret = [
73
 
            ("format", 10),
74
 
            ("committer", encode_utf8(rev.committer)[0]),
 
87
            (b"format", 10),
 
88
            (b"committer", encode_utf8(rev.committer)[0]),
75
89
        ]
76
90
        if rev.timezone is not None:
77
 
            ret.append(("timezone", rev.timezone))
 
91
            ret.append((b"timezone", rev.timezone))
78
92
        # For bzr revisions, the most common property is just 'branch-nick'
79
93
        # which changes infrequently.
80
94
        revprops = {}
81
 
        for key, value in rev.properties.iteritems():
82
 
            revprops[key] = encode_utf8(value)[0]
83
 
        ret.append(('properties', revprops))
 
95
        for key, value in rev.properties.items():
 
96
            revprops[encode_utf8(key)[0]] = encode_utf8(value)[0]
 
97
        ret.append((b'properties', revprops))
84
98
        ret.extend([
85
 
            ("timestamp", "%.3f" % rev.timestamp),
86
 
            ("revision-id", rev.revision_id),
87
 
            ("parent-ids", rev.parent_ids),
88
 
            ("inventory-sha1", rev.inventory_sha1),
89
 
            ("message", encode_utf8(rev.message)[0]),
 
99
            (b"timestamp", b"%.3f" % rev.timestamp),
 
100
            (b"revision-id", rev.revision_id),
 
101
            (b"parent-ids", rev.parent_ids),
 
102
            (b"inventory-sha1", rev.inventory_sha1),
 
103
            (b"message", encode_utf8(rev.message)[0]),
90
104
        ])
91
105
        return bencode.bencode(ret)
92
106
 
99
113
        #       However, to decode all 25k revisions of bzr takes approx 1.3s
100
114
        #       If we remove all extra validation that goes down to about 1.2s.
101
115
        #       Of that time, probably 0.6s is spend in bencode.bdecode().
102
 
        #       Regardless 'time bzr log' of everything is 7+s, so 1.3s to
 
116
        #       Regardless 'time brz log' of everything is 7+s, so 1.3s to
103
117
        #       extract revision texts isn't a majority of time.
104
118
        ret = bencode.bdecode(text)
105
119
        if not isinstance(ret, list):
119
133
                value = validator(value)
120
134
            bits[var_name] = value
121
135
        if len(bits) != len(schema):
122
 
            missing = [key for key, (var_name, _, _) in schema.iteritems()
 
136
            missing = [key for key, (var_name, _, _) in schema.items()
123
137
                       if var_name not in bits]
124
138
            raise ValueError('Revision text was missing expected keys %s.'
125
139
                             ' text %r' % (missing, text))
131
145
        return self.read_revision_from_string(f.read())
132
146
 
133
147
 
134
 
class CHKSerializerSubtree(BEncodeRevisionSerializer1, xml7.Serializer_v7):
135
 
    """A CHKInventory based serializer that supports tree references"""
 
148
class CHKSerializer(serializer.Serializer):
 
149
    """A CHKInventory based serializer with 'plain' behaviour."""
136
150
 
137
 
    supported_kinds = set(['file', 'directory', 'symlink', 'tree-reference'])
138
151
    format_num = '9'
139
152
    revision_format_num = None
140
153
    support_altered_by_hack = False
141
 
 
142
 
    def _unpack_entry(self, elt, entry_cache=None, return_from_cache=False):
143
 
        kind = elt.tag
144
 
        if not kind in self.supported_kinds:
145
 
            raise AssertionError('unsupported entry kind %s' % kind)
146
 
        if kind == 'tree-reference':
147
 
            file_id = elt.attrib['file_id']
148
 
            name = elt.attrib['name']
149
 
            parent_id = elt.attrib['parent_id']
150
 
            revision = elt.get('revision')
151
 
            reference_revision = elt.get('reference_revision')
152
 
            return inventory.TreeReference(file_id, name, parent_id, revision,
153
 
                                           reference_revision)
 
154
    supported_kinds = {'file', 'directory', 'symlink', 'tree-reference'}
 
155
 
 
156
    def __init__(self, node_size, search_key_name):
 
157
        self.maximum_size = node_size
 
158
        self.search_key_name = search_key_name
 
159
 
 
160
    def _unpack_inventory(self, elt, revision_id=None, entry_cache=None,
 
161
                          return_from_cache=False):
 
162
        """Construct from XML Element"""
 
163
        inv = xml_serializer.unpack_inventory_flat(elt, self.format_num,
 
164
            xml_serializer.unpack_inventory_entry, entry_cache,
 
165
            return_from_cache)
 
166
        return inv
 
167
 
 
168
    def read_inventory_from_string(self, xml_string, revision_id=None,
 
169
                                   entry_cache=None, return_from_cache=False):
 
170
        """Read xml_string into an inventory object.
 
171
 
 
172
        :param xml_string: The xml to read.
 
173
        :param revision_id: If not-None, the expected revision id of the
 
174
            inventory.
 
175
        :param entry_cache: An optional cache of InventoryEntry objects. If
 
176
            supplied we will look up entries via (file_id, revision_id) which
 
177
            should map to a valid InventoryEntry (File/Directory/etc) object.
 
178
        :param return_from_cache: Return entries directly from the cache,
 
179
            rather than copying them first. This is only safe if the caller
 
180
            promises not to mutate the returned inventory entries, but it can
 
181
            make some operations significantly faster.
 
182
        """
 
183
        try:
 
184
            return self._unpack_inventory(
 
185
                xml_serializer.fromstring(xml_string), revision_id,
 
186
                entry_cache=entry_cache,
 
187
                return_from_cache=return_from_cache)
 
188
        except xml_serializer.ParseError as e:
 
189
            raise errors.UnexpectedInventoryFormat(e)
 
190
 
 
191
    def read_inventory(self, f, revision_id=None):
 
192
        """Read an inventory from a file-like object."""
 
193
        try:
 
194
            try:
 
195
                return self._unpack_inventory(self._read_element(f),
 
196
                    revision_id=None)
 
197
            finally:
 
198
                f.close()
 
199
        except xml_serializer.ParseError as e:
 
200
            raise errors.UnexpectedInventoryFormat(e)
 
201
 
 
202
    def write_inventory_to_lines(self, inv):
 
203
        """Return a list of lines with the encoded inventory."""
 
204
        return self.write_inventory(inv, None)
 
205
 
 
206
    def write_inventory_to_string(self, inv, working=False):
 
207
        """Just call write_inventory with a BytesIO and return the value.
 
208
 
 
209
        :param working: If True skip history data - text_sha1, text_size,
 
210
            reference_revision, symlink_target.
 
211
        """
 
212
        sio = BytesIO()
 
213
        self.write_inventory(inv, sio, working)
 
214
        return sio.getvalue()
 
215
 
 
216
    def write_inventory(self, inv, f, working=False):
 
217
        """Write inventory to a file.
 
218
 
 
219
        :param inv: the inventory to write.
 
220
        :param f: the file to write. (May be None if the lines are the desired
 
221
            output).
 
222
        :param working: If True skip history data - text_sha1, text_size,
 
223
            reference_revision, symlink_target.
 
224
        :return: The inventory as a list of lines.
 
225
        """
 
226
        output = []
 
227
        append = output.append
 
228
        if inv.revision_id is not None:
 
229
            revid1 = ' revision_id="'
 
230
            revid2 = xml_serializer.encode_and_escape(inv.revision_id)
154
231
        else:
155
 
            return xml7.Serializer_v7._unpack_entry(self, elt,
156
 
                entry_cache=entry_cache, return_from_cache=return_from_cache)
157
 
 
158
 
    def __init__(self, node_size, search_key_name):
159
 
        self.maximum_size = node_size
160
 
        self.search_key_name = search_key_name
161
 
 
162
 
 
163
 
class CHKSerializer(xml6.Serializer_v6):
164
 
    """A CHKInventory based serializer with 'plain' behaviour."""
165
 
 
166
 
    format_num = '9'
167
 
    revision_format_num = None
168
 
    support_altered_by_hack = False
169
 
 
170
 
    def __init__(self, node_size, search_key_name):
171
 
        self.maximum_size = node_size
172
 
        self.search_key_name = search_key_name
 
232
            revid1 = ""
 
233
            revid2 = ""
 
234
        append('<inventory format="%s"%s%s>\n' % (
 
235
            self.format_num, revid1, revid2))
 
236
        append('<directory file_id="%s name="%s revision="%s />\n' % (
 
237
            xml_serializer.encode_and_escape(inv.root.file_id),
 
238
            xml_serializer.encode_and_escape(inv.root.name),
 
239
            xml_serializer.encode_and_escape(inv.root.revision)))
 
240
        xml_serializer.serialize_inventory_flat(inv,
 
241
            append,
 
242
            root_id=None, supported_kinds=self.supported_kinds, 
 
243
            working=working)
 
244
        if f is not None:
 
245
            f.writelines(output)
 
246
        return output
173
247
 
174
248
 
175
249
chk_serializer_255_bigpage = CHKSerializer(65536, 'hash-255-way')