~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/rio.py

  • Committer: Canonical.com Patch Queue Manager
  • Date: 2006-05-11 10:05:33 UTC
  • mfrom: (1185.50.95 jam-integration)
  • Revision ID: pqm@pqm.ubuntu.com-20060511100533-e3d066b362716fe2
(jam) update web page url to http://bazaar-vcs.org

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2005 by Canonical Ltd
2
2
#
3
3
# Distributed under the GNU General Public Licence v2
4
 
#
 
4
 
5
5
# \subsection{\emph{rio} - simple text metaformat}
6
6
7
7
# \emph{r} stands for `restricted', `reproducible', or `rfc822-like'.
18
18
# stream representation of an object and vice versa, and that this relation
19
19
# will continue to hold for future versions of bzr.
20
20
 
21
 
# In comments, $\min(1,10)$
22
 
 
23
 
min(1,10)
24
 
 
25
21
import re
26
22
 
 
23
from bzrlib.iterablefile import IterableFile
 
24
 
27
25
# XXX: some redundancy is allowing to write stanzas in isolation as well as
28
26
# through a writer object.  
29
27
 
56
54
            else:
57
55
                yield s
58
56
 
 
57
 
 
58
def rio_file(stanzas, header=None):
 
59
    """Produce a rio IterableFile from an iterable of stanzas"""
 
60
    def str_iter():
 
61
        if header is not None:
 
62
            yield header + '\n'
 
63
        first_stanza = True
 
64
        for s in stanzas:
 
65
            if first_stanza is not True:
 
66
                yield '\n'
 
67
            for line in s.to_lines():
 
68
                yield line
 
69
            first_stanza = False
 
70
    return IterableFile(str_iter())
 
71
 
 
72
 
59
73
def read_stanzas(from_file):
60
74
    while True:
61
75
        s = read_stanza(from_file)
92
106
        """Append a name and value to the stanza."""
93
107
        assert valid_tag(tag), \
94
108
            ("invalid tag %r" % tag)
95
 
        if isinstance(value, (str, unicode)):
 
109
        if isinstance(value, str):
 
110
            value = unicode(value)
 
111
        elif isinstance(value, unicode):
96
112
            pass
97
113
        ## elif isinstance(value, (int, long)):
98
114
        ##    value = str(value)           # XXX: python2.4 without L-suffix
99
115
        else:
100
 
            raise ValueError("invalid value %r" % value)
 
116
            raise TypeError("invalid type for rio value: %r of type %s"
 
117
                            % (value, type(value)))
101
118
        self.items.append((tag, value))
102
119
        
103
120
    def __contains__(self, find_tag):
127
144
        return iter(self.items)
128
145
 
129
146
    def to_lines(self):
130
 
        """Generate sequence of lines for external version of this file."""
 
147
        """Generate sequence of lines for external version of this file.
 
148
        
 
149
        The lines are always utf-8 encoded strings.
 
150
        """
131
151
        if not self.items:
132
152
            # max() complains if sequence is empty
133
153
            return []
134
154
        result = []
135
155
        for tag, value in self.items:
136
 
            assert isinstance(value, (str, unicode))
 
156
            assert isinstance(tag, str), type(tag)
 
157
            assert isinstance(value, unicode)
137
158
            if value == '':
138
159
                result.append(tag + ': \n')
139
160
            elif '\n' in value:
140
161
                # don't want splitlines behaviour on empty lines
141
162
                val_lines = value.split('\n')
142
 
                result.append(tag + ': ' + val_lines[0] + '\n')
 
163
                result.append(tag + ': ' + val_lines[0].encode('utf-8') + '\n')
143
164
                for line in val_lines[1:]:
144
 
                    result.append('\t' + line + '\n')
 
165
                    result.append('\t' + line.encode('utf-8') + '\n')
145
166
            else:
146
 
                result.append(tag + ': ' + value + '\n')
 
167
                result.append(tag + ': ' + value.encode('utf-8') + '\n')
147
168
        return result
148
169
 
149
170
    def to_string(self):
174
195
            if t == tag:
175
196
                r.append(v)
176
197
        return r
 
198
 
 
199
    def as_dict(self):
 
200
        """Return a dict containing the unique values of the stanza.
 
201
        """
 
202
        d = {}
 
203
        for tag, value in self.items:
 
204
            assert tag not in d
 
205
            d[tag] = value
 
206
        return d
177
207
         
178
208
_tag_re = re.compile(r'^[-a-zA-Z0-9_]+$')
179
209
def valid_tag(tag):
190
220
 
191
221
    Only the stanza lines and the trailing blank (if any) are consumed
192
222
    from the line_iter.
 
223
 
 
224
    The raw lines must be in utf-8 encoding.
193
225
    """
194
226
    items = []
195
227
    stanza = Stanza()
200
232
            break       # end of file
201
233
        if line == '\n':
202
234
            break       # end of stanza
 
235
        line = line.decode('utf-8')
203
236
        assert line[-1] == '\n'
204
237
        real_l = line
205
238
        if line[0] == '\t': # continues previous value
213
246
                colon_index = line.index(': ')
214
247
            except ValueError:
215
248
                raise ValueError('tag/value separator not found in line %r' % real_l)
216
 
            tag = line[:colon_index]
 
249
            tag = str(line[:colon_index])
217
250
            assert valid_tag(tag), \
218
251
                    "invalid rio tag %r" % tag
219
252
            accum_value = line[colon_index+2:-1]