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

  • Committer: Robert Collins
  • Date: 2010-05-06 11:08:10 UTC
  • mto: This revision was merged to the branch mainline in revision 5223.
  • Revision ID: robertc@robertcollins.net-20100506110810-h3j07fh5gmw54s25
Cleaner matcher matching revised unlocking protocol.

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