~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/xml5.py

Merge inventory serialisation tweaks.

Show diffs side-by-side

added added

removed removed

Lines of Context:
146
146
    
147
147
    __slots__ = []
148
148
 
 
149
    root_id = ROOT_ID
149
150
    support_altered_by_hack = True
150
151
    # This format supports the altered-by hack that reads file ids directly out
151
152
    # of the versionedfile, without doing XML parsing.
153
154
    supported_kinds = set(['file', 'directory', 'symlink'])
154
155
    format_num = '5'
155
156
 
156
 
    def write_inventory_to_string(self, inv):
157
 
        """Just call write_inventory with a StringIO and return the value"""
 
157
    def write_inventory_to_lines(self, inv):
 
158
        """Return a list of lines with the encoded inventory."""
 
159
        return self.write_inventory(inv, None)
 
160
 
 
161
    def write_inventory_to_string(self, inv, working=False):
 
162
        """Just call write_inventory with a StringIO and return the value.
 
163
 
 
164
        :param working: If True skip history data - text_sha1, text_size,
 
165
            reference_revision, symlink_target.
 
166
        """
158
167
        sio = cStringIO.StringIO()
159
 
        self.write_inventory(inv, sio)
 
168
        self.write_inventory(inv, sio, working)
160
169
        return sio.getvalue()
161
170
 
162
 
    def write_inventory(self, inv, f):
 
171
    def write_inventory(self, inv, f, working=False):
163
172
        """Write inventory to a file.
164
173
        
165
174
        :param inv: the inventory to write.
166
 
        :param f: the file to write.
 
175
        :param f: the file to write. (May be None if the lines are the desired
 
176
            output).
 
177
        :param working: If True skip history data - text_sha1, text_size,
 
178
            reference_revision, symlink_target.
 
179
        :return: The inventory as a list of lines.
167
180
        """
168
181
        _ensure_utf8_re()
169
182
        output = []
173
186
        # Skip the root
174
187
        root_path, root_ie = entries.next()
175
188
        for path, ie in entries:
176
 
            self._append_entry(append, ie)
 
189
            if ie.parent_id != self.root_id:
 
190
                parent_str = ' parent_id="'
 
191
                parent_id  = _encode_and_escape(ie.parent_id)
 
192
            else:
 
193
                parent_str = ''
 
194
                parent_id  = ''
 
195
            if ie.kind == 'file':
 
196
                if ie.executable:
 
197
                    executable = ' executable="yes"'
 
198
                else:
 
199
                    executable = ''
 
200
                if not working:
 
201
                    append('<file%s file_id="%s name="%s%s%s revision="%s '
 
202
                        'text_sha1="%s" text_size="%d" />\n' % (
 
203
                        executable, _encode_and_escape(ie.file_id),
 
204
                        _encode_and_escape(ie.name), parent_str, parent_id,
 
205
                        _encode_and_escape(ie.revision), ie.text_sha1,
 
206
                        ie.text_size))
 
207
                else:
 
208
                    append('<file%s file_id="%s name="%s%s%s />\n' % (
 
209
                        executable, _encode_and_escape(ie.file_id),
 
210
                        _encode_and_escape(ie.name), parent_str, parent_id))
 
211
            elif ie.kind == 'directory':
 
212
                if not working:
 
213
                    append('<directory file_id="%s name="%s%s%s revision="%s '
 
214
                        '/>\n' % (
 
215
                        _encode_and_escape(ie.file_id),
 
216
                        _encode_and_escape(ie.name),
 
217
                        parent_str, parent_id,
 
218
                        _encode_and_escape(ie.revision)))
 
219
                else:
 
220
                    append('<directory file_id="%s name="%s%s%s />\n' % (
 
221
                        _encode_and_escape(ie.file_id),
 
222
                        _encode_and_escape(ie.name),
 
223
                        parent_str, parent_id))
 
224
            elif ie.kind == 'symlink':
 
225
                if not working:
 
226
                    append('<symlink file_id="%s name="%s%s%s revision="%s '
 
227
                        'symlink_target="%s />\n' % (
 
228
                        _encode_and_escape(ie.file_id),
 
229
                        _encode_and_escape(ie.name),
 
230
                        parent_str, parent_id,
 
231
                        _encode_and_escape(ie.revision),
 
232
                        _encode_and_escape(ie.symlink_target)))
 
233
                else:
 
234
                    append('<symlink file_id="%s name="%s%s%s />\n' % (
 
235
                        _encode_and_escape(ie.file_id),
 
236
                        _encode_and_escape(ie.name),
 
237
                        parent_str, parent_id))
 
238
            elif ie.kind == 'tree-reference':
 
239
                if ie.kind not in self.supported_kinds:
 
240
                    raise errors.UnsupportedInventoryKind(ie.kind)
 
241
                if not working:
 
242
                    append('<tree-reference file_id="%s name="%s%s%s '
 
243
                        'revision="%s reference_revision="%s />\n' % (
 
244
                        _encode_and_escape(ie.file_id),
 
245
                        _encode_and_escape(ie.name),
 
246
                        parent_str, parent_id,
 
247
                        _encode_and_escape(ie.revision),
 
248
                        _encode_and_escape(ie.reference_revision)))
 
249
                else:
 
250
                    append('<tree-reference file_id="%s name="%s%s%s />\n' % (
 
251
                        _encode_and_escape(ie.file_id),
 
252
                        _encode_and_escape(ie.name),
 
253
                        parent_str, parent_id))
 
254
            else:
 
255
                raise errors.UnsupportedInventoryKind(ie.kind)
177
256
        append('</inventory>\n')
178
 
        f.writelines(output)
 
257
        if f is not None:
 
258
            f.writelines(output)
179
259
        # Just to keep the cache from growing without bounds
180
260
        # but we may actually not want to do clear the cache
181
261
        #_clear_cache()
 
262
        return output
182
263
 
183
264
    def _append_inventory_root(self, append, inv):
184
265
        """Append the inventory root to output."""
185
 
        append('<inventory')
186
266
        if inv.root.file_id not in (None, ROOT_ID):
187
 
            append(' file_id="')
188
 
            append(_encode_and_escape(inv.root.file_id))
189
 
        append(' format="5"')
 
267
            fileid1 = ' file_id="'
 
268
            fileid2 = _encode_and_escape(inv.root.file_id)
 
269
        else:
 
270
            fileid1 = ""
 
271
            fileid2 = ""
190
272
        if inv.revision_id is not None:
191
 
            append(' revision_id="')
192
 
            append(_encode_and_escape(inv.revision_id))
193
 
        append('>\n')
 
273
            revid1 = ' revision_id="'
 
274
            revid2 = _encode_and_escape(inv.revision_id)
 
275
        else:
 
276
            revid1 = ""
 
277
            revid2 = ""
 
278
        append('<inventory%s%s format="5"%s%s>\n' % (
 
279
            fileid1, fileid2, revid1, revid2))
194
280
        
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)
200
 
 
201
 
        append("<")
202
 
        append(ie.kind)
203
 
        if ie.executable:
204
 
            append(' executable="yes"')
205
 
        append(' file_id="')
206
 
        append(_encode_and_escape(ie.file_id))
207
 
        append(' name="')
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="')
221
 
            append(ie.text_sha1)
222
 
            append('"')
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))
228
 
        append(" />\n")
229
 
        return
230
 
 
231
 
    def _parent_condition(self, ie):
232
 
        return ie.parent_id != ROOT_ID
233
 
 
234
281
    def _pack_revision(self, rev):
235
282
        """Revision object -> xml tree"""
236
283
        # For the XML format, we need to write them as Unicode rather than as