~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/xml5.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2008-04-07 07:52:50 UTC
  • mfrom: (3340.1.1 208418-1.4)
  • Revision ID: pqm@pqm.ubuntu.com-20080407075250-phs53xnslo8boaeo
Return the correct knit serialisation method in _StreamAccess.
        (Andrew Bennetts, Martin Pool, Robert Collins)

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
    cache_utf8,
22
22
    errors,
23
23
    inventory,
 
24
    revision as _mod_revision,
24
25
    )
25
26
from bzrlib.xml_serializer import SubElement, Element, Serializer
26
27
from bzrlib.inventory import ROOT_ID, Inventory, InventoryEntry
145
146
    
146
147
    __slots__ = []
147
148
 
 
149
    root_id = ROOT_ID
148
150
    support_altered_by_hack = True
149
151
    # This format supports the altered-by hack that reads file ids directly out
150
152
    # of the versionedfile, without doing XML parsing.
151
153
 
152
154
    supported_kinds = set(['file', 'directory', 'symlink'])
153
 
 
154
 
    def write_inventory_to_string(self, inv):
155
 
        """Just call write_inventory with a StringIO and return the value"""
 
155
    format_num = '5'
 
156
 
 
157
    def _check_revisions(self, inv):
 
158
        """Extension point for subclasses to check during serialisation.
 
159
 
 
160
        By default no checking is done.
 
161
 
 
162
        :param inv: An inventory about to be serialised, to be checked.
 
163
        :raises: AssertionError if an error has occured.
 
164
        """
 
165
 
 
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)
 
169
 
 
170
    def write_inventory_to_string(self, inv, working=False):
 
171
        """Just call write_inventory with a StringIO and return the value.
 
172
 
 
173
        :param working: If True skip history data - text_sha1, text_size,
 
174
            reference_revision, symlink_target.
 
175
        """
156
176
        sio = cStringIO.StringIO()
157
 
        self.write_inventory(inv, sio)
 
177
        self.write_inventory(inv, sio, working)
158
178
        return sio.getvalue()
159
179
 
160
 
    def write_inventory(self, inv, f):
 
180
    def write_inventory(self, inv, f, working=False):
161
181
        """Write inventory to a file.
162
182
        
163
183
        :param inv: the inventory to write.
164
 
        :param f: the file to write.
 
184
        :param f: the file to write. (May be None if the lines are the desired
 
185
            output).
 
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.
165
189
        """
166
190
        _ensure_utf8_re()
 
191
        self._check_revisions(inv)
167
192
        output = []
168
193
        append = output.append
169
194
        self._append_inventory_root(append, inv)
171
196
        # Skip the root
172
197
        root_path, root_ie = entries.next()
173
198
        for path, ie in entries:
174
 
            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)
 
202
            else:
 
203
                parent_str = ''
 
204
                parent_id  = ''
 
205
            if ie.kind == 'file':
 
206
                if ie.executable:
 
207
                    executable = ' executable="yes"'
 
208
                else:
 
209
                    executable = ''
 
210
                if not working:
 
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,
 
216
                        ie.text_size))
 
217
                else:
 
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':
 
222
                if not working:
 
223
                    append('<directory file_id="%s name="%s%s%s revision="%s '
 
224
                        '/>\n' % (
 
225
                        _encode_and_escape(ie.file_id),
 
226
                        _encode_and_escape(ie.name),
 
227
                        parent_str, parent_id,
 
228
                        _encode_and_escape(ie.revision)))
 
229
                else:
 
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':
 
235
                if not working:
 
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)))
 
243
                else:
 
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)
 
251
                if not working:
 
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)))
 
259
                else:
 
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))
 
264
            else:
 
265
                raise errors.UnsupportedInventoryKind(ie.kind)
175
266
        append('</inventory>\n')
176
 
        f.writelines(output)
 
267
        if f is not None:
 
268
            f.writelines(output)
177
269
        # Just to keep the cache from growing without bounds
178
270
        # but we may actually not want to do clear the cache
179
271
        #_clear_cache()
 
272
        return output
180
273
 
181
274
    def _append_inventory_root(self, append, inv):
182
275
        """Append the inventory root to output."""
183
 
        append('<inventory')
184
276
        if inv.root.file_id not in (None, ROOT_ID):
185
 
            append(' file_id="')
186
 
            append(_encode_and_escape(inv.root.file_id))
187
 
        append(' format="5"')
 
277
            fileid1 = ' file_id="'
 
278
            fileid2 = _encode_and_escape(inv.root.file_id)
 
279
        else:
 
280
            fileid1 = ""
 
281
            fileid2 = ""
188
282
        if inv.revision_id is not None:
189
 
            append(' revision_id="')
190
 
            append(_encode_and_escape(inv.revision_id))
191
 
        append('>\n')
 
283
            revid1 = ' revision_id="'
 
284
            revid2 = _encode_and_escape(inv.revision_id)
 
285
        else:
 
286
            revid1 = ""
 
287
            revid2 = ""
 
288
        append('<inventory%s%s format="5"%s%s>\n' % (
 
289
            fileid1, fileid2, revid1, revid2))
192
290
        
193
 
    def _append_entry(self, append, ie):
194
 
        """Convert InventoryEntry to XML element and append to output."""
195
 
        # TODO: should just be a plain assertion
196
 
        if ie.kind not in self.supported_kinds:
197
 
            raise errors.UnsupportedInventoryKind(ie.kind)
198
 
 
199
 
        append("<")
200
 
        append(ie.kind)
201
 
        if ie.executable:
202
 
            append(' executable="yes"')
203
 
        append(' file_id="')
204
 
        append(_encode_and_escape(ie.file_id))
205
 
        append(' name="')
206
 
        append(_encode_and_escape(ie.name))
207
 
        if self._parent_condition(ie):
208
 
            assert isinstance(ie.parent_id, basestring)
209
 
            append(' parent_id="')
210
 
            append(_encode_and_escape(ie.parent_id))
211
 
        if ie.revision is not None:
212
 
            append(' revision="')
213
 
            append(_encode_and_escape(ie.revision))
214
 
        if ie.symlink_target is not None:
215
 
            append(' symlink_target="')
216
 
            append(_encode_and_escape(ie.symlink_target))
217
 
        if ie.text_sha1 is not None:
218
 
            append(' text_sha1="')
219
 
            append(ie.text_sha1)
220
 
            append('"')
221
 
        if ie.text_size is not None:
222
 
            append(' text_size="%d"' % ie.text_size)
223
 
        if getattr(ie, 'reference_revision', None) is not None:
224
 
            append(' reference_revision="')
225
 
            append(_encode_and_escape(ie.reference_revision))
226
 
        append(" />\n")
227
 
        return
228
 
 
229
 
    def _parent_condition(self, ie):
230
 
        return ie.parent_id != ROOT_ID
231
 
 
232
291
    def _pack_revision(self, rev):
233
292
        """Revision object -> xml tree"""
234
293
        # For the XML format, we need to write them as Unicode rather than as
256
315
            pelts.tail = pelts.text = '\n'
257
316
            for parent_id in rev.parent_ids:
258
317
                assert isinstance(parent_id, basestring)
 
318
                _mod_revision.check_not_reserved_id(parent_id)
259
319
                p = SubElement(pelts, 'revision_ref')
260
320
                p.tail = '\n'
261
321
                if isinstance(parent_id, str):
276
336
            prop_elt.tail = '\n'
277
337
        top_elt.tail = '\n'
278
338
 
279
 
    def _unpack_inventory(self, elt):
 
339
    def _unpack_inventory(self, elt, revision_id):
280
340
        """Construct from XML Element
281
341
        """
282
342
        assert elt.tag == 'inventory'
288
348
            if format != '5':
289
349
                raise BzrError("invalid format version %r on inventory"
290
350
                                % format)
291
 
        revision_id = elt.get('revision_id')
292
 
        if revision_id is not None:
293
 
            revision_id = cache_utf8.encode(revision_id)
 
351
        data_revision_id = elt.get('revision_id')
 
352
        if data_revision_id is not None:
 
353
            revision_id = cache_utf8.encode(data_revision_id)
294
354
        inv = Inventory(root_id, revision_id=revision_id)
295
355
        for e in elt:
296
356
            ie = self._unpack_entry(e)
297
357
            if ie.parent_id is None:
298
358
                ie.parent_id = root_id
299
359
            inv.add(ie)
 
360
        if revision_id is not None:
 
361
            inv.root.revision = revision_id
300
362
        return inv
301
363
 
302
364
    def _unpack_entry(self, elt):