79
77
make some operations significantly faster.
82
return self._unpack_inventory(fromstringlist(lines), revision_id,
80
return self._unpack_inventory(fromstring(xml_string), revision_id,
83
81
entry_cache=entry_cache,
84
82
return_from_cache=return_from_cache)
85
except ParseError as e:
86
raise serializer.UnexpectedInventoryFormat(str(e))
84
raise errors.UnexpectedInventoryFormat(e)
88
86
def read_inventory(self, f, revision_id=None):
91
89
return self._unpack_inventory(self._read_element(f),
95
except ParseError as e:
96
raise serializer.UnexpectedInventoryFormat(str(e))
94
raise errors.UnexpectedInventoryFormat(e)
96
def write_revision(self, rev, f):
97
self._write_element(self._pack_revision(rev), f)
98
99
def write_revision_to_string(self, rev):
99
return b''.join(self.write_revision_to_lines(rev))
100
return tostring(self._pack_revision(rev)) + '\n'
101
102
def read_revision(self, f):
102
103
return self._unpack_revision(self._read_element(f))
188
192
decode back into Unicode, and then use the XML escape code.
191
return _map[match.group().decode('ascii', 'replace')].encode()
195
return _map[match.group()]
193
return b''.join(b'&#%d;' % ord(uni_chr)
194
for uni_chr in match.group().decode('utf8'))
197
return ''.join('&#%d;' % ord(uni_chr)
198
for uni_chr in match.group().decode('utf8'))
197
201
_to_escaped_map = {}
200
203
def encode_and_escape(unicode_or_utf8_str, _map=_to_escaped_map):
201
204
"""Encode the string into utf8, and escape invalid XML characters"""
202
205
# We frequently get entities we have not seen before, so it is better
203
206
# to check if None, rather than try/KeyError
204
207
text = _map.get(unicode_or_utf8_str)
206
if isinstance(unicode_or_utf8_str, str):
209
if unicode_or_utf8_str.__class__ is unicode:
207
210
# The alternative policy is to do a regular UTF8 encoding
208
211
# and then escape only XML meta characters.
209
212
# Performance is equivalent once you use cache_utf8. *However*
210
213
# this makes the serialized texts incompatible with old versions
211
214
# of bzr. So no net gain. (Perhaps the read code would handle utf8
212
# better than entity escapes, but cElementTree seems to do just
214
text = _unicode_re.sub(
215
_unicode_escape_replace, unicode_or_utf8_str).encode()
215
# better than entity escapes, but cElementTree seems to do just fine
217
text = str(_unicode_re.sub(_unicode_escape_replace,
218
unicode_or_utf8_str)) + '"'
217
220
# Plain strings are considered to already be in utf-8 so we do a
218
221
# slightly different method for escaping.
219
222
text = _utf8_re.sub(_utf8_escape_replace,
223
unicode_or_utf8_str) + '"'
221
224
_map[unicode_or_utf8_str] = text
310
311
ie.symlink_target = elt_get('symlink_target')
311
312
elif kind == 'tree-reference':
312
file_id = get_utf8_or_ascii(elt.attrib['file_id'])
313
file_id = elt.attrib['file_id']
313
314
name = elt.attrib['name']
314
parent_id = get_utf8_or_ascii(elt.attrib['parent_id'])
315
revision = get_utf8_or_ascii(elt.get('revision'))
316
reference_revision = get_utf8_or_ascii(elt.get('reference_revision'))
315
parent_id = elt.attrib['parent_id']
316
revision = elt.get('revision')
317
reference_revision = elt.get('reference_revision')
317
318
ie = inventory.TreeReference(file_id, name, parent_id, revision,
320
raise serializer.UnsupportedInventoryKind(kind)
321
raise errors.UnsupportedInventoryKind(kind)
321
322
ie.revision = revision
322
323
if revision is not None and entry_cache is not None:
323
324
# We cache a copy() because callers like to mutate objects, and
368
368
entries = inv.iter_entries()
370
root_path, root_ie = next(entries)
370
root_path, root_ie = entries.next()
371
371
for path, ie in entries:
372
372
if ie.parent_id != root_id:
373
parent_str = b''.join(
374
[b' parent_id="', encode_and_escape(ie.parent_id), b'"'])
373
parent_str = ' parent_id="'
374
parent_id = encode_and_escape(ie.parent_id)
377
378
if ie.kind == 'file':
378
379
if ie.executable:
379
executable = b' executable="yes"'
380
executable = ' executable="yes"'
383
append(b'<file%s file_id="%s" name="%s"%s revision="%s" '
384
b'text_sha1="%s" text_size="%d" />\n' % (
385
executable, encode_and_escape(ie.file_id),
386
encode_and_escape(ie.name), parent_str,
387
encode_and_escape(ie.revision), ie.text_sha1,
384
append('<file%s file_id="%s name="%s%s%s revision="%s '
385
'text_sha1="%s" text_size="%d" />\n' % (
386
executable, encode_and_escape(ie.file_id),
387
encode_and_escape(ie.name), parent_str, parent_id,
388
encode_and_escape(ie.revision), ie.text_sha1,
390
append(b'<file%s file_id="%s" name="%s"%s />\n' % (
391
append('<file%s file_id="%s name="%s%s%s />\n' % (
391
392
executable, encode_and_escape(ie.file_id),
392
encode_and_escape(ie.name), parent_str))
393
encode_and_escape(ie.name), parent_str, parent_id))
393
394
elif ie.kind == 'directory':
395
append(b'<directory file_id="%s" name="%s"%s revision="%s" '
397
encode_and_escape(ie.file_id),
398
encode_and_escape(ie.name),
400
encode_and_escape(ie.revision)))
396
append('<directory file_id="%s name="%s%s%s revision="%s '
398
encode_and_escape(ie.file_id),
399
encode_and_escape(ie.name),
400
parent_str, parent_id,
401
encode_and_escape(ie.revision)))
402
append(b'<directory file_id="%s" name="%s"%s />\n' % (
403
append('<directory file_id="%s name="%s%s%s />\n' % (
403
404
encode_and_escape(ie.file_id),
404
405
encode_and_escape(ie.name),
406
parent_str, parent_id))
406
407
elif ie.kind == 'symlink':
408
append(b'<symlink file_id="%s" name="%s"%s revision="%s" '
409
b'symlink_target="%s" />\n' % (
410
encode_and_escape(ie.file_id),
411
encode_and_escape(ie.name),
413
encode_and_escape(ie.revision),
414
encode_and_escape(ie.symlink_target)))
409
append('<symlink file_id="%s name="%s%s%s revision="%s '
410
'symlink_target="%s />\n' % (
411
encode_and_escape(ie.file_id),
412
encode_and_escape(ie.name),
413
parent_str, parent_id,
414
encode_and_escape(ie.revision),
415
encode_and_escape(ie.symlink_target)))
416
append(b'<symlink file_id="%s" name="%s"%s />\n' % (
417
append('<symlink file_id="%s name="%s%s%s />\n' % (
417
418
encode_and_escape(ie.file_id),
418
419
encode_and_escape(ie.name),
420
parent_str, parent_id))
420
421
elif ie.kind == 'tree-reference':
421
422
if ie.kind not in supported_kinds:
422
raise serializer.UnsupportedInventoryKind(ie.kind)
423
raise errors.UnsupportedInventoryKind(ie.kind)
424
append(b'<tree-reference file_id="%s" name="%s"%s '
425
b'revision="%s" reference_revision="%s" />\n' % (
426
encode_and_escape(ie.file_id),
427
encode_and_escape(ie.name),
429
encode_and_escape(ie.revision),
430
encode_and_escape(ie.reference_revision)))
425
append('<tree-reference file_id="%s name="%s%s%s '
426
'revision="%s reference_revision="%s />\n' % (
427
encode_and_escape(ie.file_id),
428
encode_and_escape(ie.name),
429
parent_str, parent_id,
430
encode_and_escape(ie.revision),
431
encode_and_escape(ie.reference_revision)))
432
append(b'<tree-reference file_id="%s" name="%s"%s />\n' % (
433
append('<tree-reference file_id="%s name="%s%s%s />\n' % (
433
434
encode_and_escape(ie.file_id),
434
435
encode_and_escape(ie.name),
436
parent_str, parent_id))
437
raise serializer.UnsupportedInventoryKind(ie.kind)
438
append(b'</inventory>\n')
438
raise errors.UnsupportedInventoryKind(ie.kind)
439
append('</inventory>\n')