/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,
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
22
    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.
23
    )
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
24
from bzrlib.xml_serializer import SubElement, Element, Serializer
1189 by Martin Pool
- BROKEN: partial support for commit into weave
25
from bzrlib.inventory import ROOT_ID, Inventory, InventoryEntry
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
26
from bzrlib.revision import Revision
1189 by Martin Pool
- BROKEN: partial support for commit into weave
27
from bzrlib.errors import BzrError
28
29
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
30
_utf8_re = None
31
_utf8_escape_map = {
32
    "&":'&',
33
    "'":"'", # FIXME: overkill
34
    "\"":""",
35
    "<":"&lt;",
36
    ">":"&gt;",
37
    }
38
39
40
def _ensure_utf8_re():
41
    """Make sure the _utf8_re regex has been compiled"""
42
    global _utf8_re
43
    if _utf8_re is not None:
44
        return
1934.1.10 by John Arbash Meinel
Using real utf8 and cache_utf8 has similar performance, 272ms, and 363ms
45
    _utf8_re = re.compile('[&<>\'\"]')
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
46
47
48
def _utf8_escape_replace(match, _map=_utf8_escape_map):
49
    """Replace a string of non-ascii, non XML safe characters with their escape
50
51
    This will escape both Standard XML escapes, like <>"', etc.
52
    As well as escaping non ascii characters, because ElementTree did.
53
    This helps us remain compatible to older versions of bzr. We may change
54
    our policy in the future, though.
55
    """
1934.1.7 by John Arbash Meinel
Comment why we do caching the way we do
56
    # jam 20060816 Benchmarks show that try/KeyError is faster if you
57
    # expect the entity to rarely miss. There is about a 10% difference
58
    # in overall time. But if you miss frequently, then if None is much
59
    # faster. For our use case, we *rarely* have a revision id, file id
60
    # or path name that is unicode. So use try/KeyError.
1934.1.10 by John Arbash Meinel
Using real utf8 and cache_utf8 has similar performance, 272ms, and 363ms
61
    return _map[match.group()]
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
62
63
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
64
_unicode_to_escaped_map = {}
65
1934.1.10 by John Arbash Meinel
Using real utf8 and cache_utf8 has similar performance, 272ms, and 363ms
66
def _encode_and_escape(unicode_str, _map=_unicode_to_escaped_map,
67
                       _encode=cache_utf8.encode):
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
68
    """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
69
    # We frequently get entities we have not seen before, so it is better
70
    # to check if None, rather than try/KeyError
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
71
    text = _map.get(unicode_str)
72
    if text is None:
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
73
        # The alternative policy is to do a regular UTF8 encoding
74
        # and then escape only XML meta characters. This could take
75
        # advantage of cache_utf8 since a lot of the revision ids
76
        # and file ids would already be cached.
1934.1.10 by John Arbash Meinel
Using real utf8 and cache_utf8 has similar performance, 272ms, and 363ms
77
        text = _utf8_re.sub(_utf8_escape_replace, _encode(unicode_str)) + '"'
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
78
        _map[unicode_str] = text
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
79
    return text
80
81
82
def _clear_cache():
83
    """Clean out the unicode => escaped map"""
84
    _unicode_to_escaped_map.clear()
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
85
86
1189 by Martin Pool
- BROKEN: partial support for commit into weave
87
class Serializer_v5(Serializer):
88
    """Version 5 serializer
89
90
    Packs objects into XML and vice versa.
91
    """
92
    
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
93
    __slots__ = []
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
94
95
    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')
96
        """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
97
        sio = cStringIO.StringIO()
98
        self.write_inventory(inv, sio)
99
        return sio.getvalue()
100
101
    def write_inventory(self, inv, f):
102
        """Write inventory to a file.
103
        
104
        :param inv: the inventory to write.
105
        :param f: the file to write.
106
        """
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
107
        _ensure_utf8_re()
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
108
        output = []
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
109
        append = output.append
110
        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
111
        entries = inv.iter_entries()
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
112
        # Skip the root
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
113
        root_path, root_ie = entries.next()
114
        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
115
            self._append_entry(append, ie)
116
        append('</inventory>\n')
1934.1.4 by John Arbash Meinel
rewrite escaper to use xml numerical entities, rather than using encode('utf8')
117
        f.writelines(output)
1934.1.5 by John Arbash Meinel
Cache the entity escaping cuts us down to 450ms
118
        # Just to keep the cache from growing without bounds
119
        # 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
120
        #_clear_cache()
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
121
1934.1.8 by John Arbash Meinel
Passing around the append function rather than the list shaves off another 10%, down to 400ms
122
    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
123
        """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
124
        append('<inventory')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
125
        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
126
            append(' file_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
127
            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
128
        append(' format="5"')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
129
        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
130
            append(' revision_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
131
            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
132
        append('>\n')
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_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
135
        """Convert InventoryEntry to XML element and append to output."""
136
        # TODO: should just be a plain assertion
137
        assert InventoryEntry.versionable_kind(ie.kind), \
138
            'unsupported entry kind %s' % ie.kind
139
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("<")
141
        append(ie.kind)
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
142
        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
143
            append(' executable="yes"')
144
        append(' file_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
145
        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
146
        append(' name="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
147
        append(_encode_and_escape(ie.name))
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
148
        if ie.parent_id != ROOT_ID:
149
            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
150
            append(' parent_id="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
151
            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
152
        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
153
            append(' revision="')
1934.1.9 by John Arbash Meinel
Caching the trailing " and directly appending, down another 50ms, 275ms cached, 354ms uncached
154
            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
155
        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
156
            append(' symlink_target="')
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.symlink_target))
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
158
        if ie.text_sha1 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
159
            append(' text_size="')
160
            append(ie.text_sha1)
161
            append('"')
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
162
        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
163
            append(' text_size="%d"' % ie.text_size)
164
        append(" />\n")
1934.1.3 by John Arbash Meinel
[merge] robert's custom XML serializer, and cleanup for benchmarks and iter_entries() differences
165
        return
166
1189 by Martin Pool
- BROKEN: partial support for commit into weave
167
    def _pack_inventory(self, inv):
168
        """Convert to XML Element"""
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
169
        entries = inv.iter_entries()
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
170
        e = Element('inventory',
171
                    format='5')
1189 by Martin Pool
- BROKEN: partial support for commit into weave
172
        e.text = '\n'
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
173
        path, root = entries.next()
174
        if root.file_id not in (None, ROOT_ID):
175
            e.set('file_id', root.file_id)
1638.1.2 by Robert Collins
Change the basis-inventory file to not have the revision-id in the file name.
176
        if inv.revision_id is not None:
177
            e.set('revision_id', inv.revision_id)
1852.6.3 by Robert Collins
Make iter(Tree) consistent for all tree types.
178
        for path, ie in entries:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
179
            e.append(self._pack_entry(ie))
180
        return e
181
182
    def _pack_entry(self, ie):
183
        """Convert InventoryEntry to XML element"""
1704.2.24 by Martin Pool
todo
184
        # TODO: should just be a plain assertion
1399.1.6 by Robert Collins
move exporting functionality into inventory.py - uncovers bug in symlink support
185
        if not InventoryEntry.versionable_kind(ie.kind):
186
            raise AssertionError('unsupported entry kind %s' % ie.kind)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
187
        e = Element(ie.kind)
188
        e.set('name', ie.name)
189
        e.set('file_id', ie.file_id)
190
191
        if ie.text_size != None:
192
            e.set('text_size', '%d' % ie.text_size)
193
1092.2.22 by Robert Collins
text_version and name_version unification looking reasonable
194
        for f in ['text_sha1', 'revision', 'symlink_target']:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
195
            v = getattr(ie, f)
196
            if v != None:
197
                e.set(f, v)
198
1398 by Robert Collins
integrate in Gustavos x-bit patch
199
        if ie.executable:
200
            e.set('executable', 'yes')
201
1189 by Martin Pool
- BROKEN: partial support for commit into weave
202
        # to be conservative, we don't externalize the root pointers
203
        # for now, leaving them as null in the xml form.  in a future
204
        # version it will be implied by nested elements.
205
        if ie.parent_id != ROOT_ID:
206
            assert isinstance(ie.parent_id, basestring)
207
            e.set('parent_id', ie.parent_id)
208
        e.tail = '\n'
209
        return e
210
211
    def _pack_revision(self, rev):
212
        """Revision object -> xml tree"""
213
        root = Element('revision',
214
                       committer = rev.committer,
215
                       timestamp = '%.9f' % rev.timestamp,
216
                       revision_id = rev.revision_id,
217
                       inventory_sha1 = rev.inventory_sha1,
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
218
                       format='5',
1189 by Martin Pool
- BROKEN: partial support for commit into weave
219
                       )
1913.1.1 by John Arbash Meinel
Fix bug #55783
220
        if rev.timezone is not None:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
221
            root.set('timezone', str(rev.timezone))
222
        root.text = '\n'
223
        msg = SubElement(root, 'message')
224
        msg.text = rev.message
225
        msg.tail = '\n'
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
226
        if rev.parent_ids:
1189 by Martin Pool
- BROKEN: partial support for commit into weave
227
            pelts = SubElement(root, 'parents')
228
            pelts.tail = pelts.text = '\n'
1313 by Martin Pool
- rename to Revision.parent_ids to avoid confusion with old usage
229
            for parent_id in rev.parent_ids:
1311 by Martin Pool
- remove RevisionReference; just hold parent ids directly
230
                assert isinstance(parent_id, basestring)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
231
                p = SubElement(pelts, 'revision_ref')
232
                p.tail = '\n'
1311 by Martin Pool
- remove RevisionReference; just hold parent ids directly
233
                p.set('revision_id', parent_id)
1185.16.36 by Martin Pool
- store revision properties in revision xml
234
        if rev.properties:
235
            self._pack_revision_properties(rev, root)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
236
        return root
1185.16.36 by Martin Pool
- store revision properties in revision xml
237
238
239
    def _pack_revision_properties(self, rev, under_element):
240
        top_elt = SubElement(under_element, 'properties')
241
        for prop_name, prop_value in sorted(rev.properties.items()):
242
            assert isinstance(prop_name, basestring) 
243
            assert isinstance(prop_value, basestring) 
244
            prop_elt = SubElement(top_elt, 'property')
245
            prop_elt.set('name', prop_name)
246
            prop_elt.text = prop_value
247
            prop_elt.tail = '\n'
248
        top_elt.tail = '\n'
249
1189 by Martin Pool
- BROKEN: partial support for commit into weave
250
251
    def _unpack_inventory(self, elt):
252
        """Construct from XML Element
253
        """
254
        assert elt.tag == 'inventory'
255
        root_id = elt.get('file_id') or ROOT_ID
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
256
        format = elt.get('format')
257
        if format is not None:
258
            if format != '5':
259
                raise BzrError("invalid format version %r on inventory"
260
                                % format)
1638.1.2 by Robert Collins
Change the basis-inventory file to not have the revision-id in the file name.
261
        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.
262
        if revision_id is not None:
263
            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.
264
        inv = Inventory(root_id, revision_id=revision_id)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
265
        for e in elt:
266
            ie = self._unpack_entry(e)
267
            if ie.parent_id == ROOT_ID:
268
                ie.parent_id = root_id
269
            inv.add(ie)
270
        return inv
271
272
273
    def _unpack_entry(self, elt):
274
        kind = elt.tag
1399.1.6 by Robert Collins
move exporting functionality into inventory.py - uncovers bug in symlink support
275
        if not InventoryEntry.versionable_kind(kind):
1092.2.20 by Robert Collins
symlink and weaves, whaddya know
276
            raise AssertionError('unsupported entry kind %s' % kind)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
277
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
        get_cached = cache_utf8.get_cached_unicode
279
1189 by Martin Pool
- BROKEN: partial support for commit into weave
280
        parent_id = elt.get('parent_id')
281
        if parent_id == None:
282
            parent_id = ROOT_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.
283
        parent_id = get_cached(parent_id)
284
        file_id = get_cached(elt.get('file_id'))
1189 by Martin Pool
- BROKEN: partial support for commit into weave
285
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
286
        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.
287
            ie = inventory.InventoryDirectory(file_id,
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
288
                                              elt.get('name'),
289
                                              parent_id)
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
290
        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.
291
            ie = inventory.InventoryFile(file_id,
1399.1.9 by Robert Collins
factor out file related logic from InventoryEntry to InventoryFile
292
                                         elt.get('name'),
293
                                         parent_id)
294
            ie.text_sha1 = elt.get('text_sha1')
295
            if elt.get('executable') == 'yes':
296
                ie.executable = True
297
            v = elt.get('text_size')
298
            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
299
        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.
300
            ie = inventory.InventoryLink(file_id,
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
301
                                         elt.get('name'),
302
                                         parent_id)
303
            ie.symlink_target = elt.get('symlink_target')
1399.1.8 by Robert Collins
factor out inventory directory logic into 'InventoryDirectory' class
304
        else:
1399.1.10 by Robert Collins
remove kind from the InventoryEntry constructor - only child classes should be created now
305
            raise BzrError("unknown kind %r" % 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.
306
        revision = elt.get('revision')
307
        if revision is not None:
308
            revision = get_cached(revision)
309
        ie.revision = revision
1189 by Martin Pool
- BROKEN: partial support for commit into weave
310
311
        return ie
312
313
314
    def _unpack_revision(self, elt):
315
        """XML Element -> Revision object"""
316
        assert elt.tag == 'revision'
1393.1.59 by Martin Pool
- put 'format=5' on inventory and revision xml
317
        format = elt.get('format')
318
        if format is not None:
319
            if format != '5':
320
                raise BzrError("invalid format version %r on inventory"
321
                                % 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.
322
        get_cached = cache_utf8.get_cached_unicode
1189 by Martin Pool
- BROKEN: partial support for commit into weave
323
        rev = Revision(committer = elt.get('committer'),
324
                       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.
325
                       revision_id = get_cached(elt.get('revision_id')),
1189 by Martin Pool
- BROKEN: partial support for commit into weave
326
                       inventory_sha1 = elt.get('inventory_sha1')
327
                       )
328
        parents = elt.find('parents') or []
329
        for p in parents:
330
            assert p.tag == 'revision_ref', \
331
                   "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.
332
            rev.parent_ids.append(get_cached(p.get('revision_id')))
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
333
        self._unpack_revision_properties(elt, rev)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
334
        v = elt.get('timezone')
1913.1.1 by John Arbash Meinel
Fix bug #55783
335
        if v is None:
336
            rev.timezone = 0
337
        else:
338
            rev.timezone = int(v)
1189 by Martin Pool
- BROKEN: partial support for commit into weave
339
        rev.message = elt.findtext('message') # text of <message>
340
        return rev
341
342
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
343
    def _unpack_revision_properties(self, elt, rev):
344
        """Unpack properties onto a revision."""
345
        props_elt = elt.find('properties')
346
        assert len(rev.properties) == 0
347
        if not props_elt:
348
            return
349
        for prop_elt in props_elt:
350
            assert prop_elt.tag == 'property', \
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
351
                "bad tag under properties list: %r" % prop_elt.tag
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
352
            name = prop_elt.get('name')
353
            value = prop_elt.text
1886.1.1 by John Arbash Meinel
Fix bug #47782,
354
            # If a property had an empty value ('') cElementTree reads
355
            # that back as None, convert it back to '', so that all
356
            # properties have string values
357
            if value is None:
358
                value = ''
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
359
            assert name not in rev.properties, \
1773.4.1 by Martin Pool
Add pyflakes makefile target; fix many warnings
360
                "repeated property %r" % name
1185.16.37 by Martin Pool
- properties are retrieved when revisions are loaded
361
            rev.properties[name] = value
362
363
1189 by Martin Pool
- BROKEN: partial support for commit into weave
364
serializer_v5 = Serializer_v5()