196
223
def _read_header(self):
197
224
"""Read the bzr header"""
198
225
header = common.get_header()
199
for head_line, line in zip(header, self.from_file):
202
or line[2:-1] != head_line):
203
raise MalformedHeader('Did not read the opening'
204
' header information.')
227
for line in self._next():
229
if (line[:2] != '# ' or line[-1:] != '\n'
230
or line[2:-1] != header[0]):
231
raise MalformedHeader('Found a header, but it'
232
' was improperly formatted')
233
header.pop(0) # We read this line.
235
break # We found everything.
236
elif (line[:1] == '#' and line[-1:] == '\n'):
237
line = line[1:-1].strip()
238
if line[:len(common.header_str)] == common.header_str:
239
if line == header[0]:
242
raise MalformedHeader('Found what looks like'
243
' a header, but did not match')
246
raise MalformedHeader('Did not find an opening header')
206
for line in self.from_file:
207
if self._handle_info_line(line) is not None:
248
for line in self._next():
249
# The bzr header is terminated with a blank line
250
# which does not start with '#'
210
def _handle_info_line(self, line, in_footer=False):
211
"""Handle reading a single line.
213
This may call itself, in the case that we read_multi,
214
and then had a dangling line on the end.
253
self._handle_next(line)
255
def _read_next_entry(self, line, indent=1):
256
"""Read in a key-value pair
216
# The bzr header is terminated with a blank line
217
# which does not start with #
222
raise MalformedHeader('Opening bzr header did not start with #')
224
line = line[2:-1] # Remove the '# '
259
raise MalformedHeader('Bzr header did not start with #')
260
line = line[1:-1] # Remove the '#' and '\n'
261
if line[:indent] == ' '*indent:
226
return # Ignore blank lines
228
if in_footer and line in ('BEGIN BZR FOOTER', 'END BZR FOOTER'):
264
return None, None# Ignore blank lines
231
266
loc = line.find(': ')
234
269
value = line[loc+2:]
236
value, next_line = self._read_many()
271
value = self._read_many(indent=indent+3)
272
elif line[-1:] == ':':
274
value = self._read_many(indent=indent+3)
240
value, next_line = self._read_many()
242
raise MalformedHeader('While looking for key: value pairs,'
243
' did not find the colon %r' % (line))
276
raise MalformedHeader('While looking for key: value pairs,'
277
' did not find the colon %r' % (line))
245
279
key = key.replace(' ', '_')
246
if hasattr(self.info, key):
282
def _handle_next(self, line):
283
key, value = self._read_next_entry(line, indent=1)
287
if key == 'revision':
288
self._read_revision(value)
289
elif hasattr(self.info, key):
247
290
if getattr(self.info, key) is None:
248
291
setattr(self.info, key, value)
252
295
# What do we do with a key we don't recognize
253
296
raise MalformedHeader('Unknown Key: %s' % key)
256
self._handle_info_line(next_line, in_footer=in_footer)
258
def _read_many(self):
298
def _read_many(self, indent):
259
299
"""If a line ends with no entry, that means that it should be
260
300
followed with multiple lines of values.
262
302
This detects the end of the list, because it will be a line that
263
does not start with '# '. Because it has to read that extra
264
line, it returns the tuple: (values, next_line)
303
does not start properly indented.
267
for line in self.from_file:
270
values.append(line[5:-1])
273
def _read_one_patch(self, first_line=None):
306
start = '#' + (' '*indent)
308
if self._next_line[:len(start)] != start:
311
for line in self._next():
312
values.append(line[len(start):-1])
313
if self._next_line[:len(start)] != start:
317
def _read_one_patch(self):
274
318
"""Read in one patch, return the complete patch, along with
277
:return: action, lines, next_line, do_continue
321
:return: action, lines, do_continue
282
def parse_firstline(line):
285
if line[:3] != '***':
286
raise MalformedPatches('The first line of all patches'
287
' should be a bzr meta line "***"')
290
if first_line is not None:
291
action = parse_firstline(first_line)
294
return None, [], first_line, False
323
# Peek and see if there are no patches
324
if self._next_line[:1] == '#':
325
return None, [], False
327
line = self._next().next()
328
if line[:3] != '***':
329
raise MalformedPatches('The first line of all patches'
330
' should be a bzr meta line "***"')
297
for line in self.from_file:
299
action = parse_firstline(line)
302
return None, [], line, False
304
if line[:3] == '***':
305
return action, lines, line, True
306
elif line[:1] == '#':
307
return action, lines, line, False
309
return action, lines, None, False
334
for line in self._next():
337
if self._next_line[:3] == '***':
338
return action, lines, True
339
elif self._next_line[:1] == '#':
340
return action, lines, False
341
return action, lines, False
311
343
def _read_patches(self):
313
344
do_continue = True
314
345
while do_continue:
315
action, lines, next_line, do_continue = \
316
self._read_one_patch(next_line)
346
action, lines, do_continue = self._read_one_patch()
317
347
if action is not None:
318
348
self.info.actions.append((action, lines))
321
def _read_footer(self, first_line=None):
350
def _read_revision(self, rev_id):
351
"""Revision entries have extra information associated.
353
rev_info = RevisionInfo(rev_id)
355
for line in self._next():
356
key,value = self._read_next_entry(line, indent=4)
359
if hasattr(rev_info, key):
360
if getattr(rev_info, key) is None:
361
setattr(rev_info, key, value)
363
raise MalformedHeader('Duplicated Key: %s' % key)
365
# What do we do with a key we don't recognize
366
raise MalformedHeader('Unknown Key: %s' % key)
368
if self._next_line[:len(start)] != start:
371
self.info.revisions.append(rev_info)
373
def _read_footer(self):
322
374
"""Read the rest of the meta information.
324
376
:param first_line: The previous step iterates past what it
325
377
can handle. That extra line is given here.
327
if first_line is not None:
328
if self._handle_info_line(first_line, in_footer=True) is not None:
379
line = self._next().next()
380
if line != '# BEGIN BZR FOOTER\n':
381
raise MalformedFooter('Footer did not begin with BEGIN BZR FOOTER')
383
for line in self._next():
384
if line == '# END BZR FOOTER\n':
330
for line in self.from_file:
331
if self._handle_info_line(line, in_footer=True) is not None:
386
self._handle_next(line)
335
388
def read_changeset(from_file):
336
389
"""Read in a changeset from a filelike object (must have "readline" support), and