/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
1
# Copyright (C) 2005, 2006 Canonical Ltd
2
#
1189 by Martin Pool
- BROKEN: partial support for commit into weave
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
7
#
1189 by Martin Pool
- BROKEN: partial support for commit into weave
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
1887.1.1 by Adeodato Simó
Do not separate paragraphs in the copyright statement with blank lines,
12
#
1189 by Martin Pool
- BROKEN: partial support for commit into weave
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
17
import cStringIO
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
18
import re
1189 by Martin Pool
- BROKEN: partial support for commit into weave
19
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
20
from bzrlib import (
21
    cache_utf8,
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
22
    errors,
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
23
    inventory,
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
24
    )
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
25
from bzrlib.xml_serializer import SubElement, Element, Serializer
1189 by Martin Pool
- BROKEN: partial support for commit into weave
26
from bzrlib.inventory import ROOT_ID, Inventory, InventoryEntry
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
27
from bzrlib.revision import Revision
1189 by Martin Pool
- BROKEN: partial support for commit into weave
28
from bzrlib.errors import BzrError
29
30
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
31
_utf8_re = None
32
_utf8_escape_map = {
33
    "&":'&',
34
    "'":"'", # FIXME: overkill
35
    "\"":""",
36
    "<":"&lt;",
37
    ">":"&gt;",
38
    }
39
40
41
def _ensure_utf8_re():
42
    """Make sure the _utf8_re regex has been compiled"""
43
    global _utf8_re
44
    if _utf8_re is not None:
45
        return
1934.1.12 by John Arbash Meinel
Switch back to using Entity serializer, since performance is equivalent, yet still compatible
46
    _utf8_re = re.compile(u'[&<>\'\"\u0080-\uffff]')
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
47
48
49
def _utf8_escape_replace(match, _map=_utf8_escape_map):
50
    """Replace a string of non-ascii, non XML safe characters with their escape
51
52
    This will escape both Standard XML escapes, like <>"', etc.
53
    As well as escaping non ascii characters, because ElementTree did.
54
    This helps us remain compatible to older versions of bzr. We may change
55
    our policy in the future, though.
56
    """
1934.1.7 by John Arbash Meinel
Comment why we do caching the way we do
57
    # jam 20060816 Benchmarks show that try/KeyError is faster if you
58
    # expect the entity to rarely miss. There is about a 10% difference
59
    # in overall time. But if you miss frequently, then if None is much
60
    # faster. For our use case, we *rarely* have a revision id, file id
61
    # or path name that is unicode. So use try/KeyError.
1934.1.12 by John Arbash Meinel
Switch back to using Entity serializer, since performance is equivalent, yet still compatible
62
    try:
63
        return _map[match.group()]
64
    except KeyError:
65
        return "&#%d;" % ord(match.group())
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
66
67
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
68
_unicode_to_escaped_map = {}
69
1934.1.12 by John Arbash Meinel
Switch back to using Entity serializer, since performance is equivalent, yet still compatible
70
def _encode_and_escape(unicode_str, _map=_unicode_to_escaped_map):
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
71
    """Encode the string into utf8, and escape invalid XML characters"""
1934.1.7 by John Arbash Meinel
Comment why we do caching the way we do
72
    # We frequently get entities we have not seen before, so it is better
73
    # to check if None, rather than try/KeyError
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
74
    text = _map.get(unicode_str)
75
    if text is None:
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
76
        # The alternative policy is to do a regular UTF8 encoding
1934.1.12 by John Arbash Meinel
Switch back to using Entity serializer, since performance is equivalent, yet still compatible
77
        # and then escape only XML meta characters.
78
        # Performance is equivalent once you use cache_utf8. *However*
79
        # this makes the serialized texts incompatible with old versions
80
        # of bzr. So no net gain. (Perhaps the read code would handle utf8
81
        # better than entity escapes, but cElementTree seems to do just fine
82
        # either way)
83
        text = str(_utf8_re.sub(_utf8_escape_replace, unicode_str)) + '"'
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
84
        _map[unicode_str] = text
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
85
    return text
86
87
88
def _clear_cache():
89
    """Clean out the unicode => escaped map"""
90
    _unicode_to_escaped_map.clear()
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
91
92
1189 by Martin Pool
- BROKEN: partial support for commit into weave
93
class Serializer_v5(Serializer):
94
    """Version 5 serializer
95
96
    Packs objects into XML and vice versa.
97
    """
98
    
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
99
    __slots__ = []
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
100
1910.2.48 by Aaron Bentley
Update from review comments
101
    support_altered_by_hack = True
102
    # This format supports the altered-by hack that reads file ids directly out
103
    # of the versionedfile, without doing XML parsing.
104
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
105
    supported_kinds = set(['file', 'directory', 'symlink'])
106
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
107
    def write_inventory_to_string(self, inv):
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
108
        """Just call write_inventory with a StringIO and return the value"""
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
109
        sio = cStringIO.StringIO()
110
        self.write_inventory(inv, sio)
111
        return sio.getvalue()
112
113
    def write_inventory(self, inv, f):
114
        """Write inventory to a file.
115
        
116
        :param inv: the inventory to write.
117
        :param f: the file to write.
118
        """
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
119
        _ensure_utf8_re()
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
120
        output = []
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
121
        append = output.append
122
        self._append_inventory_root(append, inv)
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
123
        entries = inv.iter_entries()
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
124
        # Skip the root
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
125
        root_path, root_ie = entries.next()
126
        for path, ie in entries:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
127
            self._append_entry(append, ie)
128
        append('</inventory>\n')
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
129
        f.writelines(output)
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
130
        # Just to keep the cache from growing without bounds
131
        # but we may actually not want to do clear the cache
1934.1.6 by John Arbash Meinel
With a full cache the time is down to 381 ms
132
        #_clear_cache()
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
133
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
134
    def _append_inventory_root(self, append, inv):
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
135
        """Append the inventory root to output."""
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
136
        append('<inventory')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
137
        if inv.root.file_id not in (None, ROOT_ID):
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
138
            append(' file_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
139
            append(_encode_and_escape(inv.root.file_id))
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
140
        append(' format="5"')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
141
        if inv.revision_id is not None:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
142
            append(' revision_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
143
            append(_encode_and_escape(inv.revision_id))
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
144
        append('>\n')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
145
        
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
146
    def _append_entry(self, append, ie):
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
147
        """Convert InventoryEntry to XML element and append to output."""
148
        # TODO: should just be a plain assertion
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
149
        if ie.kind not in self.supported_kinds:
150
            raise errors.UnsupportedInventoryKind(ie.kind)
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
151
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
152
        append("<")
153
        append(ie.kind)
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
154
        if ie.executable:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
155
            append(' executable="yes"')
156
        append(' file_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
157
        append(_encode_and_escape(ie.file_id))
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
158
        append(' name="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
159
        append(_encode_and_escape(ie.name))
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
160
        if self._parent_condition(ie):
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
161
            assert isinstance(ie.parent_id, basestring)
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
162
            append(' parent_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
163
            append(_encode_and_escape(ie.parent_id))
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
164
        if ie.revision is not None:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
165
            append(' revision="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
166
            append(_encode_and_escape(ie.revision))
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
167
        if ie.symlink_target is not None:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
168
            append(' symlink_target="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
169
            append(_encode_and_escape(ie.symlink_target))
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
170
        if ie.text_sha1 is not None:
1934.1.15 by John Arbash Meinel
One field was incorrect, need text_sha1 not text_size
171
            append(' text_sha1="')
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
172
            append(ie.text_sha1)
173
            append('"')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
174
        if ie.text_size is not None:
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
175
            append(' text_size="%d"' % ie.text_size)
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
176
        if getattr(ie, 'reference_revision', None) is not None:
177
            append(' reference_revision="')
178
            append(_encode_and_escape(ie.reference_revision))
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
179
        append(" />\n")
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
180
        return
181
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
182
    def _parent_condition(self, ie):
183
        return ie.parent_id != ROOT_ID
184
1189 by Martin Pool
- BROKEN: partial support for commit into weave
185
    def _pack_revision(self, rev):
186
        """Revision object -> xml tree"""
187
        root = Element('revision',
188
                       committer = rev.committer,
2102.4.1 by John Arbash Meinel
Switch to using millisecond resolution in Revision XML
189
                       timestamp = '%.3f' % rev.timestamp,
1189 by Martin Pool
- BROKEN: partial support for commit into weave
190
                       revision_id = rev.revision_id,
191
                       inventory_sha1 = rev.inventory_sha1,
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
192
                       format='5',
1189 by Martin Pool
- BROKEN: partial support for commit into weave
193
                       )
1913.1.1 by John Arbash Meinel
Fix bug #55783
194
        if rev.timezone is not None:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
195
            root.set('timezone', str(rev.timezone))
196
        root.text = '\n'
197
        msg = SubElement(root, 'message')
198
        msg.text = rev.message
199
        msg.tail = '\n'
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
200
        if rev.parent_ids:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
201
            pelts = SubElement(root, 'parents')
202
            pelts.tail = pelts.text = '\n'
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
203
            for parent_id in rev.parent_ids:
1311 by Martin Pool
- remove RevisionReference; just hold parent ids directly
204
                assert isinstance(parent_id, basestring)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
205
                p = SubElement(pelts, 'revision_ref')
206
                p.tail = '\n'
1311 by Martin Pool
- remove RevisionReference; just hold parent ids directly
207
                p.set('revision_id', parent_id)
1185.16.36 by Martin Pool
- store revision properties in revision xml
208
        if rev.properties:
209
            self._pack_revision_properties(rev, root)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
210
        return root
1185.16.36 by Martin Pool
- store revision properties in revision xml
211
212
    def _pack_revision_properties(self, rev, under_element):
213
        top_elt = SubElement(under_element, 'properties')
214
        for prop_name, prop_value in sorted(rev.properties.items()):
215
            assert isinstance(prop_name, basestring) 
216
            assert isinstance(prop_value, basestring) 
217
            prop_elt = SubElement(top_elt, 'property')
218
            prop_elt.set('name', prop_name)
219
            prop_elt.text = prop_value
220
            prop_elt.tail = '\n'
221
        top_elt.tail = '\n'
222
1189 by Martin Pool
- BROKEN: partial support for commit into weave
223
    def _unpack_inventory(self, elt):
224
        """Construct from XML Element
225
        """
226
        assert elt.tag == 'inventory'
227
        root_id = elt.get('file_id') or ROOT_ID
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
228
        format = elt.get('format')
229
        if format is not None:
230
            if format != '5':
231
                raise BzrError("invalid format version %r on inventory"
232
                                % format)
1638.1.2 by Robert Collins
Change the basis-inventory file to not have the revision-id in the file name.
233
        revision_id = elt.get('revision_id')
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
234
        if revision_id is not None:
235
            revision_id = cache_utf8.get_cached_unicode(revision_id)
1638.1.2 by Robert Collins
Change the basis-inventory file to not have the revision-id in the file name.
236
        inv = Inventory(root_id, revision_id=revision_id)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
237
        for e in elt:
238
            ie = self._unpack_entry(e)
239
            if ie.parent_id == ROOT_ID:
240
                ie.parent_id = root_id
241
            inv.add(ie)
242
        return inv
243
1910.2.22 by Aaron Bentley
Make commits preserve root entry data
244
    def _unpack_entry(self, elt, none_parents=False):
1189 by Martin Pool
- BROKEN: partial support for commit into weave
245
        kind = elt.tag
1399.1.6 by Robert Collins
move exporting functionality into inventory.py - uncovers bug in symlink support
246
        if not InventoryEntry.versionable_kind(kind):
1092.2.20 by Robert Collins
symlink and weaves, whaddya know
247
            raise AssertionError('unsupported entry kind %s' % kind)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
248
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
249
        get_cached = cache_utf8.get_cached_unicode
250
1189 by Martin Pool
- BROKEN: partial support for commit into weave
251
        parent_id = elt.get('parent_id')
1910.2.47 by Aaron Bentley
Merge bzr.dev
252
        if parent_id is None and not none_parents:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
253
            parent_id = ROOT_ID
1934.1.20 by John Arbash Meinel
Document why we aren't caching file ids at the moment
254
        # TODO: jam 20060817 At present, caching file ids costs us too 
255
        #       much time. It slows down overall read performances from
256
        #       approx 500ms to 700ms. And doesn't improve future reads.
257
        #       it might be because revision ids and file ids are mixing.
258
        #       Consider caching *just* the file ids, for a limited period
259
        #       of time.
1934.1.18 by John Arbash Meinel
Caching revision_ids costs us a little (512 vs 475), but caching file-ids costs us a lot (780 vs 512), so disabling caching of file ids for now
260
        #parent_id = get_cached(parent_id)
261
        #file_id = get_cached(elt.get('file_id'))
262
        file_id = elt.get('file_id')
1189 by Martin Pool
- BROKEN: partial support for commit into weave
263
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
264
        if kind == 'directory':
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
265
            ie = inventory.InventoryDirectory(file_id,
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
266
                                              elt.get('name'),
267
                                              parent_id)
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
268
        elif kind == 'file':
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
269
            ie = inventory.InventoryFile(file_id,
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
270
                                         elt.get('name'),
271
                                         parent_id)
272
            ie.text_sha1 = elt.get('text_sha1')
273
            if elt.get('executable') == 'yes':
274
                ie.executable = True
275
            v = elt.get('text_size')
276
            ie.text_size = v and int(v)
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
277
        elif kind == 'symlink':
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
278
            ie = inventory.InventoryLink(file_id,
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
279
                                         elt.get('name'),
280
                                         parent_id)
281
            ie.symlink_target = elt.get('symlink_target')
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
282
        else:
2100.3.1 by Aaron Bentley
Start roundtripping tree-reference entries
283
            raise errors.UnsupportedInventoryKind(kind)
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
284
        revision = elt.get('revision')
285
        if revision is not None:
286
            revision = get_cached(revision)
287
        ie.revision = revision
1189 by Martin Pool
- BROKEN: partial support for commit into weave
288
289
        return ie
290
291
    def _unpack_revision(self, elt):
292
        """XML Element -> Revision object"""
293
        assert elt.tag == 'revision'
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
294
        format = elt.get('format')
295
        if format is not None:
296
            if format != '5':
297
                raise BzrError("invalid format version %r on inventory"
298
                                % format)
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
299
        get_cached = cache_utf8.get_cached_unicode
1189 by Martin Pool
- BROKEN: partial support for commit into weave
300
        rev = Revision(committer = elt.get('committer'),
301
                       timestamp = float(elt.get('timestamp')),
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
302
                       revision_id = get_cached(elt.get('revision_id')),
1189 by Martin Pool
- BROKEN: partial support for commit into weave
303
                       inventory_sha1 = elt.get('inventory_sha1')
304
                       )
305
        parents = elt.find('parents') or []
306
        for p in parents:
307
            assert p.tag == 'revision_ref', \
308
                   "bad parent node tag %r" % p.tag
1911.2.6 by John Arbash Meinel
Cache revision ids and file ids as part of xml processing. A custom xml parser could just call decode/encode directly.
309
            rev.parent_ids.append(get_cached(p.get('revision_id')))
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
310
        self._unpack_revision_properties(elt, rev)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
311
        v = elt.get('timezone')
1913.1.1 by John Arbash Meinel
Fix bug #55783
312
        if v is None:
313
            rev.timezone = 0
314
        else:
315
            rev.timezone = int(v)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
316
        rev.message = elt.findtext('message') # text of <message>
317
        return rev
318
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
319
    def _unpack_revision_properties(self, elt, rev):
320
        """Unpack properties onto a revision."""
321
        props_elt = elt.find('properties')
322
        assert len(rev.properties) == 0
323
        if not props_elt:
324
            return
325
        for prop_elt in props_elt:
326
            assert prop_elt.tag == 'property', \
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
327
                "bad tag under properties list: %r" % prop_elt.tag
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
328
            name = prop_elt.get('name')
329
            value = prop_elt.text
1886.1.1 by John Arbash Meinel
Fix bug #47782,
330
            # If a property had an empty value ('') cElementTree reads
331
            # that back as None, convert it back to '', so that all
332
            # properties have string values
333
            if value is None:
334
                value = ''
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
335
            assert name not in rev.properties, \
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
336
                "repeated property %r" % name
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
337
            rev.properties[name] = value
338
339
1189 by Martin Pool
- BROKEN: partial support for commit into weave
340
serializer_v5 = Serializer_v5()