/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: John Ferlito
  • Date: 2009-09-02 04:31:45 UTC
  • mto: (4665.7.1 serve-init)
  • mto: This revision was merged to the branch mainline in revision 4913.
  • Revision ID: johnf@inodes.org-20090902043145-gxdsfw03ilcwbyn5
Add a debian init script for bzr --serve

Show diffs side-by-side

added added

removed removed

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