1
# Copyright (C) 2005, 2006, 2007 Canonical Ltd
1
# Copyright (C) 2005, 2006, 2007, 2008 Canonical Ltd
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
138
138
_to_escaped_map.clear()
141
class Serializer_v5(Serializer):
142
"""Version 5 serializer
141
class Serializer_v8(Serializer):
142
"""This serialiser adds rich roots.
144
Packs objects into XML and vice versa.
144
Its revision format number matches its inventory number.
150
150
support_altered_by_hack = True
151
151
# This format supports the altered-by hack that reads file ids directly out
152
152
# of the versionedfile, without doing XML parsing.
154
154
supported_kinds = set(['file', 'directory', 'symlink'])
156
revision_format_num = None
157
158
def _check_revisions(self, inv):
158
159
"""Extension point for subclasses to check during serialisation.
160
By default no checking is done.
162
161
:param inv: An inventory about to be serialised, to be checked.
163
162
:raises: AssertionError if an error has occured.
164
if inv.revision_id is None:
165
raise AssertionError()
166
if inv.root.revision is None:
167
raise AssertionError()
166
169
def write_inventory_to_lines(self, inv):
167
170
"""Return a list of lines with the encoded inventory."""
274
277
def _append_inventory_root(self, append, inv):
275
278
"""Append the inventory root to output."""
276
if inv.root.file_id not in (None, ROOT_ID):
277
fileid1 = ' file_id="'
278
fileid2 = _encode_and_escape(inv.root.file_id)
282
279
if inv.revision_id is not None:
283
280
revid1 = ' revision_id="'
284
281
revid2 = _encode_and_escape(inv.revision_id)
288
append('<inventory%s%s format="5"%s%s>\n' % (
289
fileid1, fileid2, revid1, revid2))
285
append('<inventory format="%s"%s%s>\n' % (
286
self.format_num, revid1, revid2))
287
append('<directory file_id="%s name="%s revision="%s />\n' % (
288
_encode_and_escape(inv.root.file_id),
289
_encode_and_escape(inv.root.name),
290
_encode_and_escape(inv.root.revision)))
291
292
def _pack_revision(self, rev):
292
293
"""Revision object -> xml tree"""
293
294
# For the XML format, we need to write them as Unicode rather than as
297
298
revision_id = rev.revision_id
298
299
if isinstance(revision_id, str):
299
300
revision_id = decode_utf8(revision_id)
301
format_num = self.format_num
302
if self.revision_format_num is not None:
303
format_num = self.revision_format_num
300
304
root = Element('revision',
301
305
committer = rev.committer,
302
306
timestamp = '%.3f' % rev.timestamp,
303
307
revision_id = revision_id,
304
308
inventory_sha1 = rev.inventory_sha1,
307
311
if rev.timezone is not None:
308
312
root.set('timezone', str(rev.timezone))
314
318
pelts = SubElement(root, 'parents')
315
319
pelts.tail = pelts.text = '\n'
316
320
for parent_id in rev.parent_ids:
317
assert isinstance(parent_id, basestring)
318
321
_mod_revision.check_not_reserved_id(parent_id)
319
322
p = SubElement(pelts, 'revision_ref')
328
331
def _pack_revision_properties(self, rev, under_element):
329
332
top_elt = SubElement(under_element, 'properties')
330
333
for prop_name, prop_value in sorted(rev.properties.items()):
331
assert isinstance(prop_name, basestring)
332
assert isinstance(prop_value, basestring)
333
334
prop_elt = SubElement(top_elt, 'property')
334
335
prop_elt.set('name', prop_name)
335
336
prop_elt.text = prop_value
336
337
prop_elt.tail = '\n'
337
338
top_elt.tail = '\n'
339
def _unpack_inventory(self, elt, revision_id):
340
"""Construct from XML Element
342
assert elt.tag == 'inventory'
343
root_id = elt.get('file_id') or ROOT_ID
344
root_id = _get_utf8_or_ascii(root_id)
340
def _unpack_inventory(self, elt, revision_id=None):
341
"""Construct from XML Element"""
342
if elt.tag != 'inventory':
343
raise errors.UnexpectedInventoryFormat('Root tag is %r' % elt.tag)
346
344
format = elt.get('format')
347
if format is not None:
349
raise BzrError("invalid format version %r on inventory"
345
if format != self.format_num:
346
raise errors.UnexpectedInventoryFormat('Invalid format version %r'
351
348
revision_id = elt.get('revision_id')
352
349
if revision_id is not None:
353
350
revision_id = cache_utf8.encode(revision_id)
354
inv = Inventory(root_id, revision_id=revision_id)
351
inv = inventory.Inventory(root_id=None, revision_id=revision_id)
356
353
ie = self._unpack_entry(e)
357
if ie.parent_id is None:
358
ie.parent_id = root_id
360
if revision_id is not None:
361
inv.root.revision = revision_id
364
357
def _unpack_entry(self, elt):
403
396
def _unpack_revision(self, elt):
404
397
"""XML Element -> Revision object"""
405
assert elt.tag == 'revision'
406
398
format = elt.get('format')
399
format_num = self.format_num
400
if self.revision_format_num is not None:
401
format_num = self.revision_format_num
407
402
if format is not None:
409
raise BzrError("invalid format version %r on inventory"
403
if format != format_num:
404
raise BzrError("invalid format version %r on revision"
411
406
get_cached = _get_utf8_or_ascii
412
407
rev = Revision(committer = elt.get('committer'),
417
412
parents = elt.find('parents') or []
418
413
for p in parents:
419
assert p.tag == 'revision_ref', \
420
"bad parent node tag %r" % p.tag
421
414
rev.parent_ids.append(get_cached(p.get('revision_id')))
422
415
self._unpack_revision_properties(elt, rev)
423
416
v = elt.get('timezone')
431
424
def _unpack_revision_properties(self, elt, rev):
432
425
"""Unpack properties onto a revision."""
433
426
props_elt = elt.find('properties')
434
assert len(rev.properties) == 0
435
427
if not props_elt:
437
429
for prop_elt in props_elt:
438
assert prop_elt.tag == 'property', \
439
"bad tag under properties list: %r" % prop_elt.tag
430
if prop_elt.tag != 'property':
431
raise AssertionError(
432
"bad tag under properties list: %r" % prop_elt.tag)
440
433
name = prop_elt.get('name')
441
434
value = prop_elt.text
442
435
# If a property had an empty value ('') cElementTree reads
444
437
# properties have string values
445
438
if value is None:
447
assert name not in rev.properties, \
448
"repeated property %r" % name
440
if name in rev.properties:
441
raise AssertionError("repeated property %r" % name)
449
442
rev.properties[name] = value
452
serializer_v5 = Serializer_v5()
445
serializer_v8 = Serializer_v8()