~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/pack.py

  • Committer: Launchpad Translations on behalf of bzr-core
  • Date: 2012-07-12 04:32:54 UTC
  • mto: (6581.1.1 trunk)
  • mto: This revision was merged to the branch mainline in revision 6582.
  • Revision ID: launchpad_translations_on_behalf_of_bzr-core-20120712043254-vm9rgwkm2ijlzr2l
Launchpad automatic translations update.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2007 Canonical Ltd
 
1
# Copyright (C) 2007, 2009, 2010 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
12
12
#
13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""Container format for Bazaar data.
18
18
 
19
 
"Containers" and "records" are described in doc/developers/container-format.txt.
 
19
"Containers" and "records" are described in
 
20
doc/developers/container-format.txt.
20
21
"""
21
22
 
 
23
from __future__ import absolute_import
 
24
 
 
25
from cStringIO import StringIO
22
26
import re
23
27
 
24
28
from bzrlib import errors
32
36
 
33
37
def _check_name(name):
34
38
    """Do some basic checking of 'name'.
35
 
    
 
39
 
36
40
    At the moment, this just checks that there are no whitespace characters in a
37
41
    name.
38
42
 
45
49
 
46
50
def _check_name_encoding(name):
47
51
    """Check that 'name' is valid UTF-8.
48
 
    
 
52
 
49
53
    This is separate from _check_name because UTF-8 decoding is relatively
50
54
    expensive, and we usually want to avoid it.
51
55
 
57
61
        raise errors.InvalidRecordError(str(e))
58
62
 
59
63
 
 
64
class ContainerSerialiser(object):
 
65
    """A helper class for serialising containers.
 
66
 
 
67
    It simply returns bytes from method calls to 'begin', 'end' and
 
68
    'bytes_record'.  You may find ContainerWriter to be a more convenient
 
69
    interface.
 
70
    """
 
71
 
 
72
    def begin(self):
 
73
        """Return the bytes to begin a container."""
 
74
        return FORMAT_ONE + "\n"
 
75
 
 
76
    def end(self):
 
77
        """Return the bytes to finish a container."""
 
78
        return "E"
 
79
 
 
80
    def bytes_header(self, length, names):
 
81
        """Return the header for a Bytes record."""
 
82
        # Kind marker
 
83
        byte_sections = ["B"]
 
84
        # Length
 
85
        byte_sections.append(str(length) + "\n")
 
86
        # Names
 
87
        for name_tuple in names:
 
88
            # Make sure we're writing valid names.  Note that we will leave a
 
89
            # half-written record if a name is bad!
 
90
            for name in name_tuple:
 
91
                _check_name(name)
 
92
            byte_sections.append('\x00'.join(name_tuple) + "\n")
 
93
        # End of headers
 
94
        byte_sections.append("\n")
 
95
        return ''.join(byte_sections)
 
96
 
 
97
    def bytes_record(self, bytes, names):
 
98
        """Return the bytes for a Bytes record with the given name and
 
99
        contents.
 
100
 
 
101
        If the content may be large, construct the header separately and then
 
102
        stream out the contents.
 
103
        """
 
104
        return self.bytes_header(len(bytes), names) + bytes
 
105
 
 
106
 
60
107
class ContainerWriter(object):
61
 
    """A class for writing containers."""
 
108
    """A class for writing containers to a file.
 
109
 
 
110
    :attribute records_written: The number of user records added to the
 
111
        container. This does not count the prelude or suffix of the container
 
112
        introduced by the begin() and end() methods.
 
113
    """
 
114
 
 
115
    # Join up headers with the body if writing fewer than this many bytes:
 
116
    # trades off memory usage and copying to do less IO ops.
 
117
    _JOIN_WRITES_THRESHOLD = 100000
62
118
 
63
119
    def __init__(self, write_func):
64
120
        """Constructor.
66
122
        :param write_func: a callable that will be called when this
67
123
            ContainerWriter needs to write some bytes.
68
124
        """
69
 
        self.write_func = write_func
 
125
        self._write_func = write_func
 
126
        self.current_offset = 0
 
127
        self.records_written = 0
 
128
        self._serialiser = ContainerSerialiser()
70
129
 
71
130
    def begin(self):
72
131
        """Begin writing a container."""
73
 
        self.write_func(FORMAT_ONE + "\n")
 
132
        self.write_func(self._serialiser.begin())
 
133
 
 
134
    def write_func(self, bytes):
 
135
        self._write_func(bytes)
 
136
        self.current_offset += len(bytes)
74
137
 
75
138
    def end(self):
76
139
        """Finish writing a container."""
77
 
        self.write_func("E")
 
140
        self.write_func(self._serialiser.end())
78
141
 
79
142
    def add_bytes_record(self, bytes, names):
80
 
        """Add a Bytes record with the given names."""
81
 
        # Kind marker
82
 
        self.write_func("B")
83
 
        # Length
84
 
        self.write_func(str(len(bytes)) + "\n")
85
 
        # Names
86
 
        for name in names:
87
 
            # Make sure we're writing valid names.  Note that we will leave a
88
 
            # half-written record if a name is bad!
89
 
            _check_name(name)
90
 
            self.write_func(name + "\n")
91
 
        # End of headers
92
 
        self.write_func("\n")
93
 
        # Finally, the contents.
94
 
        self.write_func(bytes)
 
143
        """Add a Bytes record with the given names.
 
144
 
 
145
        :param bytes: The bytes to insert.
 
146
        :param names: The names to give the inserted bytes. Each name is
 
147
            a tuple of bytestrings. The bytestrings may not contain
 
148
            whitespace.
 
149
        :return: An offset, length tuple. The offset is the offset
 
150
            of the record within the container, and the length is the
 
151
            length of data that will need to be read to reconstitute the
 
152
            record. These offset and length can only be used with the pack
 
153
            interface - they might be offset by headers or other such details
 
154
            and thus are only suitable for use by a ContainerReader.
 
155
        """
 
156
        current_offset = self.current_offset
 
157
        length = len(bytes)
 
158
        if length < self._JOIN_WRITES_THRESHOLD:
 
159
            self.write_func(self._serialiser.bytes_header(length, names)
 
160
                + bytes)
 
161
        else:
 
162
            self.write_func(self._serialiser.bytes_header(length, names))
 
163
            self.write_func(bytes)
 
164
        self.records_written += 1
 
165
        # return a memo of where we wrote data to allow random access.
 
166
        return current_offset, self.current_offset - current_offset
 
167
 
 
168
 
 
169
class ReadVFile(object):
 
170
    """Adapt a readv result iterator to a file like protocol.
 
171
    
 
172
    The readv result must support the iterator protocol returning (offset,
 
173
    data_bytes) pairs.
 
174
    """
 
175
 
 
176
    # XXX: This could be a generic transport class, as other code may want to
 
177
    # gradually consume the readv result.
 
178
 
 
179
    def __init__(self, readv_result):
 
180
        """Construct a new ReadVFile wrapper.
 
181
 
 
182
        :seealso: make_readv_reader
 
183
 
 
184
        :param readv_result: the most recent readv result - list or generator
 
185
        """
 
186
        # readv can return a sequence or an iterator, but we require an
 
187
        # iterator to know how much has been consumed.
 
188
        readv_result = iter(readv_result)
 
189
        self.readv_result = readv_result
 
190
        self._string = None
 
191
 
 
192
    def _next(self):
 
193
        if (self._string is None or
 
194
            self._string.tell() == self._string_length):
 
195
            offset, data = self.readv_result.next()
 
196
            self._string_length = len(data)
 
197
            self._string = StringIO(data)
 
198
 
 
199
    def read(self, length):
 
200
        self._next()
 
201
        result = self._string.read(length)
 
202
        if len(result) < length:
 
203
            raise errors.BzrError('wanted %d bytes but next '
 
204
                'hunk only contains %d: %r...' %
 
205
                (length, len(result), result[:20]))
 
206
        return result
 
207
 
 
208
    def readline(self):
 
209
        """Note that readline will not cross readv segments."""
 
210
        self._next()
 
211
        result = self._string.readline()
 
212
        if self._string.tell() == self._string_length and result[-1] != '\n':
 
213
            raise errors.BzrError('short readline in the readvfile hunk: %r'
 
214
                % (result, ))
 
215
        return result
 
216
 
 
217
 
 
218
def make_readv_reader(transport, filename, requested_records):
 
219
    """Create a ContainerReader that will read selected records only.
 
220
 
 
221
    :param transport: The transport the pack file is located on.
 
222
    :param filename: The filename of the pack file.
 
223
    :param requested_records: The record offset, length tuples as returned
 
224
        by add_bytes_record for the desired records.
 
225
    """
 
226
    readv_blocks = [(0, len(FORMAT_ONE)+1)]
 
227
    readv_blocks.extend(requested_records)
 
228
    result = ContainerReader(ReadVFile(
 
229
        transport.readv(filename, readv_blocks)))
 
230
    return result
95
231
 
96
232
 
97
233
class BaseReader(object):
124
260
        is a ``list`` and bytes is a function that takes one argument,
125
261
        ``max_length``.
126
262
 
127
 
        You **must not** call the callable after advancing the interator to the
 
263
        You **must not** call the callable after advancing the iterator to the
128
264
        next record.  That is, this code is invalid::
129
265
 
130
266
            record_iter = container.iter_records()
131
267
            names1, callable1 = record_iter.next()
132
268
            names2, callable2 = record_iter.next()
133
269
            bytes1 = callable1(None)
134
 
        
 
270
 
135
271
        As it will give incorrect results and invalidate the state of the
136
272
        ContainerReader.
137
273
 
138
 
        :raises ContainerError: if any sort of containter corruption is
 
274
        :raises ContainerError: if any sort of container corruption is
139
275
            detected, e.g. UnknownContainerFormatError is the format of the
140
276
            container is unrecognised.
141
277
        :seealso: ContainerReader.read
142
278
        """
143
279
        self._read_format()
144
280
        return self._iter_records()
145
 
    
 
281
 
146
282
    def iter_record_objects(self):
147
283
        """Iterate over the container, yielding each record as it is read.
148
284
 
150
286
        methods.  Like with iter_records, it is not safe to use a record object
151
287
        after advancing the iterator to yield next record.
152
288
 
153
 
        :raises ContainerError: if any sort of containter corruption is
 
289
        :raises ContainerError: if any sort of container corruption is
154
290
            detected, e.g. UnknownContainerFormatError is the format of the
155
291
            container is unrecognised.
156
292
        :seealso: iter_records
157
293
        """
158
294
        self._read_format()
159
295
        return self._iter_record_objects()
160
 
    
 
296
 
161
297
    def _iter_records(self):
162
298
        for record in self._iter_record_objects():
163
299
            yield record.read()
197
333
        all_names = set()
198
334
        for record_names, read_bytes in self.iter_records():
199
335
            read_bytes(None)
200
 
            for name in record_names:
201
 
                _check_name_encoding(name)
 
336
            for name_tuple in record_names:
 
337
                for name in name_tuple:
 
338
                    _check_name_encoding(name)
202
339
                # Check that the name is unique.  Note that Python will refuse
203
340
                # to decode non-shortest forms of UTF-8 encoding, so there is no
204
341
                # risk that the same unicode string has been encoded two
205
342
                # different ways.
206
 
                if name in all_names:
207
 
                    raise errors.DuplicateRecordNameError(name)
208
 
                all_names.add(name)
 
343
                if name_tuple in all_names:
 
344
                    raise errors.DuplicateRecordNameError(name_tuple[0])
 
345
                all_names.add(name_tuple)
209
346
        excess_bytes = self.reader_func(1)
210
347
        if excess_bytes != '':
211
348
            raise errors.ContainerHasExcessDataError(excess_bytes)
231
368
        except ValueError:
232
369
            raise errors.InvalidRecordError(
233
370
                "%r is not a valid length." % (length_line,))
234
 
        
 
371
 
235
372
        # Read the list of names.
236
373
        names = []
237
374
        while True:
238
 
            name = self._read_line()
239
 
            if name == '':
 
375
            name_line = self._read_line()
 
376
            if name_line == '':
240
377
                break
241
 
            _check_name(name)
242
 
            names.append(name)
 
378
            name_tuple = tuple(name_line.split('\x00'))
 
379
            for name in name_tuple:
 
380
                _check_name(name)
 
381
            names.append(name_tuple)
243
382
 
244
383
        self._remaining_length = length
245
384
        return names, self._content_reader
263
402
        :raises ContainerError: if this record is invalid.
264
403
        """
265
404
        names, read_bytes = self.read()
266
 
        for name in names:
267
 
            _check_name_encoding(name)
 
405
        for name_tuple in names:
 
406
            for name in name_tuple:
 
407
                _check_name_encoding(name)
268
408
        read_bytes(None)
269
409
 
 
410
 
 
411
class ContainerPushParser(object):
 
412
    """A "push" parser for container format 1.
 
413
 
 
414
    It accepts bytes via the ``accept_bytes`` method, and parses them into
 
415
    records which can be retrieved via the ``read_pending_records`` method.
 
416
    """
 
417
 
 
418
    def __init__(self):
 
419
        self._buffer = ''
 
420
        self._state_handler = self._state_expecting_format_line
 
421
        self._parsed_records = []
 
422
        self._reset_current_record()
 
423
        self.finished = False
 
424
 
 
425
    def _reset_current_record(self):
 
426
        self._current_record_length = None
 
427
        self._current_record_names = []
 
428
 
 
429
    def accept_bytes(self, bytes):
 
430
        self._buffer += bytes
 
431
        # Keep iterating the state machine until it stops consuming bytes from
 
432
        # the buffer.
 
433
        last_buffer_length = None
 
434
        cur_buffer_length = len(self._buffer)
 
435
        last_state_handler = None
 
436
        while (cur_buffer_length != last_buffer_length
 
437
               or last_state_handler != self._state_handler):
 
438
            last_buffer_length = cur_buffer_length
 
439
            last_state_handler = self._state_handler
 
440
            self._state_handler()
 
441
            cur_buffer_length = len(self._buffer)
 
442
 
 
443
    def read_pending_records(self, max=None):
 
444
        if max:
 
445
            records = self._parsed_records[:max]
 
446
            del self._parsed_records[:max]
 
447
            return records
 
448
        else:
 
449
            records = self._parsed_records
 
450
            self._parsed_records = []
 
451
            return records
 
452
 
 
453
    def _consume_line(self):
 
454
        """Take a line out of the buffer, and return the line.
 
455
 
 
456
        If a newline byte is not found in the buffer, the buffer is
 
457
        unchanged and this returns None instead.
 
458
        """
 
459
        newline_pos = self._buffer.find('\n')
 
460
        if newline_pos != -1:
 
461
            line = self._buffer[:newline_pos]
 
462
            self._buffer = self._buffer[newline_pos+1:]
 
463
            return line
 
464
        else:
 
465
            return None
 
466
 
 
467
    def _state_expecting_format_line(self):
 
468
        line = self._consume_line()
 
469
        if line is not None:
 
470
            if line != FORMAT_ONE:
 
471
                raise errors.UnknownContainerFormatError(line)
 
472
            self._state_handler = self._state_expecting_record_type
 
473
 
 
474
    def _state_expecting_record_type(self):
 
475
        if len(self._buffer) >= 1:
 
476
            record_type = self._buffer[0]
 
477
            self._buffer = self._buffer[1:]
 
478
            if record_type == 'B':
 
479
                self._state_handler = self._state_expecting_length
 
480
            elif record_type == 'E':
 
481
                self.finished = True
 
482
                self._state_handler = self._state_expecting_nothing
 
483
            else:
 
484
                raise errors.UnknownRecordTypeError(record_type)
 
485
 
 
486
    def _state_expecting_length(self):
 
487
        line = self._consume_line()
 
488
        if line is not None:
 
489
            try:
 
490
                self._current_record_length = int(line)
 
491
            except ValueError:
 
492
                raise errors.InvalidRecordError(
 
493
                    "%r is not a valid length." % (line,))
 
494
            self._state_handler = self._state_expecting_name
 
495
 
 
496
    def _state_expecting_name(self):
 
497
        encoded_name_parts = self._consume_line()
 
498
        if encoded_name_parts == '':
 
499
            self._state_handler = self._state_expecting_body
 
500
        elif encoded_name_parts:
 
501
            name_parts = tuple(encoded_name_parts.split('\x00'))
 
502
            for name_part in name_parts:
 
503
                _check_name(name_part)
 
504
            self._current_record_names.append(name_parts)
 
505
 
 
506
    def _state_expecting_body(self):
 
507
        if len(self._buffer) >= self._current_record_length:
 
508
            body_bytes = self._buffer[:self._current_record_length]
 
509
            self._buffer = self._buffer[self._current_record_length:]
 
510
            record = (self._current_record_names, body_bytes)
 
511
            self._parsed_records.append(record)
 
512
            self._reset_current_record()
 
513
            self._state_handler = self._state_expecting_record_type
 
514
 
 
515
    def _state_expecting_nothing(self):
 
516
        pass
 
517
 
 
518
    def read_size_hint(self):
 
519
        hint = 16384
 
520
        if self._state_handler == self._state_expecting_body:
 
521
            remaining = self._current_record_length - len(self._buffer)
 
522
            if remaining < 0:
 
523
                remaining = 0
 
524
            return max(hint, remaining)
 
525
        return hint
 
526
 
 
527
 
 
528
def iter_records_from_file(source_file):
 
529
    parser = ContainerPushParser()
 
530
    while True:
 
531
        bytes = source_file.read(parser.read_size_hint())
 
532
        parser.accept_bytes(bytes)
 
533
        for record in parser.read_pending_records():
 
534
            yield record
 
535
        if parser.finished:
 
536
            break
 
537