/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/xml_serializer.py

  • Committer: Robert J. Tanner
  • Date: 2009-06-10 03:56:49 UTC
  • mfrom: (4423 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4425.
  • Revision ID: tanner@real-time.com-20090610035649-7rfx4cls4550zc3c
Merge 1.15.1 back to trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: UTF-8 -*-
2
 
 
 
1
# Copyright (C) 2005, 2006 Canonical Ltd
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
14
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
 
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16
16
 
17
17
"""XML externalization support."""
18
18
 
22
22
# importing this module is fairly slow because it has to load several
23
23
# ElementTree bits
24
24
 
 
25
from bzrlib.serializer import Serializer
25
26
from bzrlib.trace import mutter, warning
26
27
 
27
28
try:
28
 
    from cElementTree import (ElementTree, SubElement, Element,
29
 
                              XMLTreeBuilder, fromstring, tostring)
 
29
    try:
 
30
        # it's in this package in python2.5
 
31
        from xml.etree.cElementTree import (ElementTree, SubElement, Element,
 
32
            XMLTreeBuilder, fromstring, tostring)
 
33
        import xml.etree as elementtree
 
34
    except ImportError:
 
35
        from cElementTree import (ElementTree, SubElement, Element,
 
36
                                  XMLTreeBuilder, fromstring, tostring)
 
37
        import elementtree.ElementTree
 
38
    ParseError = SyntaxError
30
39
except ImportError:
31
 
    ## from warnings import warn
32
 
    ## warn('using slower ElementTree; consider installing cElementTree')
 
40
    mutter('WARNING: using slower ElementTree; consider installing cElementTree'
 
41
           " and make sure it's on your PYTHONPATH")
 
42
    # this copy is shipped with bzr
33
43
    from util.elementtree.ElementTree import (ElementTree, SubElement,
34
44
                                              Element, XMLTreeBuilder,
35
45
                                              fromstring, tostring)
36
 
 
37
 
from bzrlib.inventory import ROOT_ID, Inventory, InventoryEntry
38
 
from bzrlib.errors import BzrError
39
 
 
40
 
 
41
 
class Serializer(object):
42
 
    """Abstract object serialize/deserialize"""
43
 
    def write_inventory(self, inv, f):
44
 
        """Write inventory to a file"""
45
 
        elt = self._pack_inventory(inv)
46
 
        self._write_element(elt, f)
47
 
 
48
 
    def write_inventory_to_string(self, inv):
49
 
        return tostring(self._pack_inventory(inv))
50
 
 
51
 
    def read_inventory_from_string(self, xml_string):
52
 
        return self._unpack_inventory(fromstring(xml_string))
53
 
 
54
 
    def read_inventory(self, f):
55
 
        return self._unpack_inventory(self._read_element(f))
 
46
    import util.elementtree as elementtree
 
47
    from xml.parsers.expat import ExpatError as ParseError
 
48
 
 
49
from bzrlib import errors
 
50
 
 
51
 
 
52
class XMLSerializer(Serializer):
 
53
    """Abstract XML object serialize/deserialize"""
 
54
 
 
55
    def read_inventory_from_string(self, xml_string, revision_id=None,
 
56
                                   entry_cache=None):
 
57
        """Read xml_string into an inventory object.
 
58
 
 
59
        :param xml_string: The xml to read.
 
60
        :param revision_id: If not-None, the expected revision id of the
 
61
            inventory. Some serialisers use this to set the results' root
 
62
            revision. This should be supplied for deserialising all
 
63
            from-repository inventories so that xml5 inventories that were
 
64
            serialised without a revision identifier can be given the right
 
65
            revision id (but not for working tree inventories where users can
 
66
            edit the data without triggering checksum errors or anything).
 
67
        :param entry_cache: An optional cache of InventoryEntry objects. If
 
68
            supplied we will look up entries via (file_id, revision_id) which
 
69
            should map to a valid InventoryEntry (File/Directory/etc) object.
 
70
        """
 
71
        try:
 
72
            return self._unpack_inventory(fromstring(xml_string), revision_id,
 
73
                                          entry_cache=entry_cache)
 
74
        except ParseError, e:
 
75
            raise errors.UnexpectedInventoryFormat(e)
 
76
 
 
77
    def read_inventory(self, f, revision_id=None):
 
78
        try:
 
79
            return self._unpack_inventory(self._read_element(f),
 
80
                revision_id=None)
 
81
        except ParseError, e:
 
82
            raise errors.UnexpectedInventoryFormat(e)
56
83
 
57
84
    def write_revision(self, rev, f):
58
85
        self._write_element(self._pack_revision(rev), f)
59
86
 
60
87
    def write_revision_to_string(self, rev):
61
 
        return tostring(self._pack_revision(rev), f)
 
88
        return tostring(self._pack_revision(rev)) + '\n'
62
89
 
63
90
    def read_revision(self, f):
64
91
        return self._unpack_revision(self._read_element(f))
73
100
    def _read_element(self, f):
74
101
        return ElementTree().parse(f)
75
102
 
 
103
 
 
104
# performance tuning for elementree's serialiser. This should be
 
105
# sent upstream - RBC 20060523.
 
106
# the functions here are patched into elementtree at runtime.
 
107
import re
 
108
escape_re = re.compile("[&'\"<>]")
 
109
escape_map = {
 
110
    "&":'&amp;',
 
111
    "'":"&apos;", # FIXME: overkill
 
112
    "\"":"&quot;",
 
113
    "<":"&lt;",
 
114
    ">":"&gt;",
 
115
    }
 
116
def _escape_replace(match, map=escape_map):
 
117
    return map[match.group()]
 
118
 
 
119
def _escape_attrib(text, encoding=None, replace=None):
 
120
    # escape attribute value
 
121
    try:
 
122
        if encoding:
 
123
            try:
 
124
                text = elementtree.ElementTree._encode(text, encoding)
 
125
            except UnicodeError:
 
126
                return elementtree.ElementTree._encode_entity(text)
 
127
        if replace is None:
 
128
            return escape_re.sub(_escape_replace, text)
 
129
        else:
 
130
            text = replace(text, "&", "&amp;")
 
131
            text = replace(text, "'", "&apos;") # FIXME: overkill
 
132
            text = replace(text, "\"", "&quot;")
 
133
            text = replace(text, "<", "&lt;")
 
134
            text = replace(text, ">", "&gt;")
 
135
            return text
 
136
    except (TypeError, AttributeError):
 
137
        elementtree.ElementTree._raise_serialization_error(text)
 
138
 
 
139
elementtree.ElementTree._escape_attrib = _escape_attrib
 
140
 
 
141
escape_cdata_re = re.compile("[&<>]")
 
142
escape_cdata_map = {
 
143
    "&":'&amp;',
 
144
    "<":"&lt;",
 
145
    ">":"&gt;",
 
146
    }
 
147
def _escape_cdata_replace(match, map=escape_cdata_map):
 
148
    return map[match.group()]
 
149
 
 
150
def _escape_cdata(text, encoding=None, replace=None):
 
151
    # escape character data
 
152
    try:
 
153
        if encoding:
 
154
            try:
 
155
                text = elementtree.ElementTree._encode(text, encoding)
 
156
            except UnicodeError:
 
157
                return elementtree.ElementTree._encode_entity(text)
 
158
        if replace is None:
 
159
            return escape_cdata_re.sub(_escape_cdata_replace, text)
 
160
        else:
 
161
            text = replace(text, "&", "&amp;")
 
162
            text = replace(text, "<", "&lt;")
 
163
            text = replace(text, ">", "&gt;")
 
164
            return text
 
165
    except (TypeError, AttributeError):
 
166
        elementtree.ElementTree._raise_serialization_error(text)
 
167
 
 
168
elementtree.ElementTree._escape_cdata = _escape_cdata
 
169
 
 
170
 
 
171
def escape_invalid_chars(message):
 
172
    """Escape the XML-invalid characters in a commit message.
 
173
 
 
174
    :param message: Commit message to escape
 
175
    :return: tuple with escaped message and number of characters escaped
 
176
    """
 
177
    # Python strings can include characters that can't be
 
178
    # represented in well-formed XML; escape characters that
 
179
    # aren't listed in the XML specification
 
180
    # (http://www.w3.org/TR/REC-xml/#NT-Char).
 
181
    return re.subn(u'[^\x09\x0A\x0D\u0020-\uD7FF\uE000-\uFFFD]+',
 
182
            lambda match: match.group(0).encode('unicode_escape'),
 
183
            message)