153
154
supported_kinds = set(['file', 'directory', 'symlink'])
156
def write_inventory_to_string(self, inv):
157
"""Just call write_inventory with a StringIO and return the value"""
157
def _check_revisions(self, inv):
158
"""Extension point for subclasses to check during serialisation.
160
By default no checking is done.
162
:param inv: An inventory about to be serialised, to be checked.
163
:raises: AssertionError if an error has occured.
166
def write_inventory_to_lines(self, inv):
167
"""Return a list of lines with the encoded inventory."""
168
return self.write_inventory(inv, None)
170
def write_inventory_to_string(self, inv, working=False):
171
"""Just call write_inventory with a StringIO and return the value.
173
:param working: If True skip history data - text_sha1, text_size,
174
reference_revision, symlink_target.
158
176
sio = cStringIO.StringIO()
159
self.write_inventory(inv, sio)
177
self.write_inventory(inv, sio, working)
160
178
return sio.getvalue()
162
def write_inventory(self, inv, f):
180
def write_inventory(self, inv, f, working=False):
163
181
"""Write inventory to a file.
165
183
:param inv: the inventory to write.
166
:param f: the file to write.
184
:param f: the file to write. (May be None if the lines are the desired
186
:param working: If True skip history data - text_sha1, text_size,
187
reference_revision, symlink_target.
188
:return: The inventory as a list of lines.
168
190
_ensure_utf8_re()
191
self._check_revisions(inv)
170
193
append = output.append
171
194
self._append_inventory_root(append, inv)
174
197
root_path, root_ie = entries.next()
175
198
for path, ie in entries:
176
self._append_entry(append, ie)
199
if ie.parent_id != self.root_id:
200
parent_str = ' parent_id="'
201
parent_id = _encode_and_escape(ie.parent_id)
205
if ie.kind == 'file':
207
executable = ' executable="yes"'
211
append('<file%s file_id="%s name="%s%s%s revision="%s '
212
'text_sha1="%s" text_size="%d" />\n' % (
213
executable, _encode_and_escape(ie.file_id),
214
_encode_and_escape(ie.name), parent_str, parent_id,
215
_encode_and_escape(ie.revision), ie.text_sha1,
218
append('<file%s file_id="%s name="%s%s%s />\n' % (
219
executable, _encode_and_escape(ie.file_id),
220
_encode_and_escape(ie.name), parent_str, parent_id))
221
elif ie.kind == 'directory':
223
append('<directory file_id="%s name="%s%s%s revision="%s '
225
_encode_and_escape(ie.file_id),
226
_encode_and_escape(ie.name),
227
parent_str, parent_id,
228
_encode_and_escape(ie.revision)))
230
append('<directory file_id="%s name="%s%s%s />\n' % (
231
_encode_and_escape(ie.file_id),
232
_encode_and_escape(ie.name),
233
parent_str, parent_id))
234
elif ie.kind == 'symlink':
236
append('<symlink file_id="%s name="%s%s%s revision="%s '
237
'symlink_target="%s />\n' % (
238
_encode_and_escape(ie.file_id),
239
_encode_and_escape(ie.name),
240
parent_str, parent_id,
241
_encode_and_escape(ie.revision),
242
_encode_and_escape(ie.symlink_target)))
244
append('<symlink file_id="%s name="%s%s%s />\n' % (
245
_encode_and_escape(ie.file_id),
246
_encode_and_escape(ie.name),
247
parent_str, parent_id))
248
elif ie.kind == 'tree-reference':
249
if ie.kind not in self.supported_kinds:
250
raise errors.UnsupportedInventoryKind(ie.kind)
252
append('<tree-reference file_id="%s name="%s%s%s '
253
'revision="%s reference_revision="%s />\n' % (
254
_encode_and_escape(ie.file_id),
255
_encode_and_escape(ie.name),
256
parent_str, parent_id,
257
_encode_and_escape(ie.revision),
258
_encode_and_escape(ie.reference_revision)))
260
append('<tree-reference file_id="%s name="%s%s%s />\n' % (
261
_encode_and_escape(ie.file_id),
262
_encode_and_escape(ie.name),
263
parent_str, parent_id))
265
raise errors.UnsupportedInventoryKind(ie.kind)
177
266
append('</inventory>\n')
179
269
# Just to keep the cache from growing without bounds
180
270
# but we may actually not want to do clear the cache
183
274
def _append_inventory_root(self, append, inv):
184
275
"""Append the inventory root to output."""
186
276
if inv.root.file_id not in (None, ROOT_ID):
188
append(_encode_and_escape(inv.root.file_id))
189
append(' format="5"')
277
fileid1 = ' file_id="'
278
fileid2 = _encode_and_escape(inv.root.file_id)
190
282
if inv.revision_id is not None:
191
append(' revision_id="')
192
append(_encode_and_escape(inv.revision_id))
283
revid1 = ' revision_id="'
284
revid2 = _encode_and_escape(inv.revision_id)
288
append('<inventory%s%s format="5"%s%s>\n' % (
289
fileid1, fileid2, revid1, revid2))
195
def _append_entry(self, append, ie):
196
"""Convert InventoryEntry to XML element and append to output."""
197
# TODO: should just be a plain assertion
198
if ie.kind not in self.supported_kinds:
199
raise errors.UnsupportedInventoryKind(ie.kind)
204
append(' executable="yes"')
206
append(_encode_and_escape(ie.file_id))
208
append(_encode_and_escape(ie.name))
209
if self._parent_condition(ie):
210
assert isinstance(ie.parent_id, basestring)
211
append(' parent_id="')
212
append(_encode_and_escape(ie.parent_id))
213
if ie.revision is not None:
214
append(' revision="')
215
append(_encode_and_escape(ie.revision))
216
if ie.symlink_target is not None:
217
append(' symlink_target="')
218
append(_encode_and_escape(ie.symlink_target))
219
if ie.text_sha1 is not None:
220
append(' text_sha1="')
223
if ie.text_size is not None:
224
append(' text_size="%d"' % ie.text_size)
225
if getattr(ie, 'reference_revision', None) is not None:
226
append(' reference_revision="')
227
append(_encode_and_escape(ie.reference_revision))
231
def _parent_condition(self, ie):
232
return ie.parent_id != ROOT_ID
234
291
def _pack_revision(self, rev):
235
292
"""Revision object -> xml tree"""
236
293
# For the XML format, we need to write them as Unicode rather than as