32
32
FORMAT_1 = 'bzr inventory delta v1 (bzr 1.14)'
35
class InventoryDeltaError(errors.BzrError):
36
"""An error when serializing or deserializing an inventory delta."""
38
# Most errors when serializing and deserializing are due to bugs, although
39
# damaged input (i.e. a bug in a different process) could cause
40
# deserialization errors too.
44
class IncompatibleInventoryDelta(errors.BzrError):
45
"""The delta could not be deserialised because its contents conflict with
46
the allow_versioned_root or allow_tree_references flags of the
49
internal_error = False
34
52
def _directory_content(entry):
35
53
"""Serialize the content component of entry which is a directory.
51
69
size_exec_sha = (entry.text_size, exec_bytes, entry.text_sha1)
52
70
if None in size_exec_sha:
53
raise errors.BzrError('Missing size or sha for %s' % entry.file_id)
71
raise InventoryDeltaError('Missing size or sha for %s' % entry.file_id)
54
72
return "file\x00%d\x00%s\x00%s" % size_exec_sha
62
80
target = entry.symlink_target
64
raise errors.BzrError('Missing target for %s' % entry.file_id)
82
raise InventoryDeltaError('Missing target for %s' % entry.file_id)
65
83
return "link\x00%s" % target.encode('utf8')
73
91
tree_revision = entry.reference_revision
74
92
if tree_revision is None:
75
raise errors.BzrError('Missing reference revision for %s' % entry.file_id)
93
raise InventoryDeltaError(
94
'Missing reference revision for %s' % entry.file_id)
76
95
return "tree\x00%s" % tree_revision
152
171
:return: The serialized delta as lines.
154
if self._versioned_root is None or self._tree_references is None:
155
raise AssertionError(
156
"Cannot serialise unless versioned_root/tree_references flags "
158
173
if type(old_name) is not str:
159
174
raise TypeError('old_name should be str, got %r' % (old_name,))
160
175
if type(new_name) is not str:
164
179
for delta_item in delta_to_new:
165
180
line = to_line(delta_item, new_name)
166
181
if line.__class__ != str:
167
raise errors.BzrError(
182
raise InventoryDeltaError(
168
183
'to_line generated non-str output %r' % lines[-1])
169
184
lines.append(line)
218
233
# file-ids other than TREE_ROOT, e.g. repo formats that use the
219
234
# xml5 serializer.
220
235
if last_modified != new_version:
221
raise errors.BzrError(
236
raise InventoryDeltaError(
222
237
'Version present for / in %s (%s != %s)'
223
238
% (file_id, last_modified, new_version))
224
239
if last_modified is None:
225
raise errors.BzrError("no version for fileid %s" % file_id)
240
raise InventoryDeltaError("no version for fileid %s" % file_id)
226
241
content = self._entry_to_content[entry.kind](entry)
227
242
return ("%s\x00%s\x00%s\x00%s\x00%s\x00%s\n" %
228
243
(oldpath_utf8, newpath_utf8, file_id, parent_id, last_modified,
248
263
elif value == "false":
251
raise errors.BzrError("value %r is not a bool" % (value,))
266
raise InventoryDeltaError("value %r is not a bool" % (value,))
253
268
def parse_text_bytes(self, bytes):
254
269
"""Parse the text bytes of a serialized inventory delta.
265
280
if bytes[-1:] != '\n':
266
281
last_line = bytes.rsplit('\n', 1)[-1]
267
raise errors.BzrError('last line not empty: %r' % (last_line,))
282
raise InventoryDeltaError('last line not empty: %r' % (last_line,))
268
283
lines = bytes.split('\n')[:-1] # discard the last empty line
269
284
if not lines or lines[0] != 'format: %s' % FORMAT_1:
270
raise errors.BzrError('unknown format %r' % lines[0:1])
285
raise InventoryDeltaError('unknown format %r' % lines[0:1])
271
286
if len(lines) < 2 or not lines[1].startswith('parent: '):
272
raise errors.BzrError('missing parent: marker')
287
raise InventoryDeltaError('missing parent: marker')
273
288
delta_parent_id = lines[1][8:]
274
289
if len(lines) < 3 or not lines[2].startswith('version: '):
275
raise errors.BzrError('missing version: marker')
290
raise InventoryDeltaError('missing version: marker')
276
291
delta_version_id = lines[2][9:]
277
292
if len(lines) < 4 or not lines[3].startswith('versioned_root: '):
278
raise errors.BzrError('missing versioned_root: marker')
293
raise InventoryDeltaError('missing versioned_root: marker')
279
294
delta_versioned_root = self._deserialize_bool(lines[3][16:])
280
295
if len(lines) < 5 or not lines[4].startswith('tree_references: '):
281
raise errors.BzrError('missing tree_references: marker')
296
raise InventoryDeltaError('missing tree_references: marker')
282
297
delta_tree_references = self._deserialize_bool(lines[4][17:])
283
298
if (not self._allow_versioned_root and delta_versioned_root):
284
raise _IncompatibleDelta("versioned_root not allowed")
299
raise IncompatibleInventoryDelta("versioned_root not allowed")
287
302
line_iter = iter(lines)
292
307
content) = line.split('\x00', 5)
293
308
parent_id = parent_id or None
294
309
if file_id in seen_ids:
295
raise errors.BzrError(
310
raise InventoryDeltaError(
296
311
"duplicate file id in inventory delta %r" % lines)
297
312
seen_ids.add(file_id)
298
313
if (newpath_utf8 == '/' and not delta_versioned_root and
299
314
last_modified != delta_version_id):
300
315
# Delta claims to be not have a versioned root, yet here's
301
316
# a root entry with a non-default version.
302
raise errors.BzrError("Versioned root found: %r" % line)
317
raise InventoryDeltaError("Versioned root found: %r" % line)
303
318
elif newpath_utf8 != 'None' and last_modified[-1] == ':':
304
319
# Deletes have a last_modified of null:, but otherwise special
305
320
# revision ids should not occur.
306
raise errors.BzrError('special revisionid found: %r' % line)
321
raise InventoryDeltaError('special revisionid found: %r' % line)
307
322
if content.startswith('tree\x00'):
308
323
if delta_tree_references is False:
309
raise errors.BzrError(
324
raise InventoryDeltaError(
310
325
"Tree reference found (but header said "
311
326
"tree_references: false): %r" % line)
312
327
elif not self._allow_tree_references:
313
raise _IncompatibleDelta("Tree reference not allowed")
328
raise IncompatibleInventoryDelta(
329
"Tree reference not allowed")
314
330
if oldpath_utf8 == 'None':
316
332
elif oldpath_utf8[:1] != '/':
317
raise errors.BzrError(
333
raise InventoryDeltaError(
318
334
"oldpath invalid (does not start with /): %r"
319
335
% (oldpath_utf8,))
357
373
content, name, parent_id, file_id, last_modified)
360
class _IncompatibleDelta(errors.InternalBzrError):
361
"""The delta could not be deserialised because its contents conflict with
362
the allow_versioned_root or allow_tree_references flags of the