~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/rio.py

  • Committer: Michael Ellerman
  • Date: 2005-12-10 22:11:13 UTC
  • mto: This revision was merged to the branch mainline in revision 1528.
  • Revision ID: michael@ellerman.id.au-20051210221113-99ca561aaab4661e
Simplify handling of DivergedBranches in cmd_pull()

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
 
21
25
import re
22
26
 
23
 
from bzrlib.iterablefile import IterableFile
24
 
 
25
27
# XXX: some redundancy is allowing to write stanzas in isolation as well as
26
28
# through a writer object.  
27
29
 
54
56
            else:
55
57
                yield s
56
58
 
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
 
 
73
59
def read_stanzas(from_file):
74
60
    while True:
75
61
        s = read_stanza(from_file)
106
92
        """Append a name and value to the stanza."""
107
93
        assert valid_tag(tag), \
108
94
            ("invalid tag %r" % tag)
109
 
        if isinstance(value, str):
110
 
            value = unicode(value)
111
 
        elif isinstance(value, unicode):
 
95
        if isinstance(value, (str, unicode)):
112
96
            pass
113
97
        ## elif isinstance(value, (int, long)):
114
98
        ##    value = str(value)           # XXX: python2.4 without L-suffix
115
99
        else:
116
 
            raise TypeError("invalid type for rio value: %r of type %s"
117
 
                            % (value, type(value)))
 
100
            raise ValueError("invalid value %r" % value)
118
101
        self.items.append((tag, value))
119
102
        
120
103
    def __contains__(self, find_tag):
144
127
        return iter(self.items)
145
128
 
146
129
    def to_lines(self):
147
 
        """Generate sequence of lines for external version of this file.
148
 
        
149
 
        The lines are always utf-8 encoded strings.
150
 
        """
 
130
        """Generate sequence of lines for external version of this file."""
151
131
        if not self.items:
152
132
            # max() complains if sequence is empty
153
133
            return []
154
134
        result = []
155
135
        for tag, value in self.items:
156
 
            assert isinstance(tag, str), type(tag)
157
 
            assert isinstance(value, unicode)
 
136
            assert isinstance(value, (str, unicode))
158
137
            if value == '':
159
138
                result.append(tag + ': \n')
160
139
            elif '\n' in value:
161
140
                # don't want splitlines behaviour on empty lines
162
141
                val_lines = value.split('\n')
163
 
                result.append(tag + ': ' + val_lines[0].encode('utf-8') + '\n')
 
142
                result.append(tag + ': ' + val_lines[0] + '\n')
164
143
                for line in val_lines[1:]:
165
 
                    result.append('\t' + line.encode('utf-8') + '\n')
 
144
                    result.append('\t' + line + '\n')
166
145
            else:
167
 
                result.append(tag + ': ' + value.encode('utf-8') + '\n')
 
146
                result.append(tag + ': ' + value + '\n')
168
147
        return result
169
148
 
170
149
    def to_string(self):
171
150
        """Return stanza as a single string"""
172
151
        return ''.join(self.to_lines())
173
152
 
174
 
    def to_unicode(self):
175
 
        """Return stanza as a single Unicode string.
176
 
 
177
 
        This is most useful when adding a Stanza to a parent Stanza
178
 
        """
179
 
        if not self.items:
180
 
            return u''
181
 
 
182
 
        result = []
183
 
        for tag, value in self.items:
184
 
            if value == '':
185
 
                result.append(tag + ': \n')
186
 
            elif '\n' in value:
187
 
                # don't want splitlines behaviour on empty lines
188
 
                val_lines = value.split('\n')
189
 
                result.append(tag + ': ' + val_lines[0] + '\n')
190
 
                for line in val_lines[1:]:
191
 
                    result.append('\t' + line + '\n')
192
 
            else:
193
 
                result.append(tag + ': ' + value + '\n')
194
 
        return u''.join(result)
195
 
 
196
153
    def write(self, to_file):
197
154
        """Write stanza to a file"""
198
155
        to_file.writelines(self.to_lines())
217
174
            if t == tag:
218
175
                r.append(v)
219
176
        return r
220
 
 
221
 
    def as_dict(self):
222
 
        """Return a dict containing the unique values of the stanza.
223
 
        """
224
 
        d = {}
225
 
        for tag, value in self.items:
226
 
            assert tag not in d
227
 
            d[tag] = value
228
 
        return d
229
177
         
230
178
_tag_re = re.compile(r'^[-a-zA-Z0-9_]+$')
231
179
def valid_tag(tag):
242
190
 
243
191
    Only the stanza lines and the trailing blank (if any) are consumed
244
192
    from the line_iter.
245
 
 
246
 
    The raw lines must be in utf-8 encoding.
247
 
    """
248
 
    unicode_iter = (line.decode('utf-8') for line in line_iter)
249
 
    return read_stanza_unicode(unicode_iter)
250
 
 
251
 
 
252
 
def read_stanza_unicode(unicode_iter):
253
 
    """Read a Stanza from a list of lines or a file.
254
 
 
255
 
    The lines should already be in unicode form. This returns a single
256
 
    stanza that was read. If there is a blank line at the end of the Stanza,
257
 
    it is consumed. It is not an error for there to be no blank line at
258
 
    the end of the iterable. If there is a blank line at the beginning,
259
 
    this is treated as an empty Stanza and None is returned.
260
 
 
261
 
    Only the stanza lines and the trailing blank (if any) are consumed
262
 
    from the unicode_iter
263
 
 
264
 
    :param unicode_iter: A iterable, yeilding Unicode strings. See read_stanza
265
 
        if you have a utf-8 encoded string.
266
 
    :return: A Stanza object if there are any lines in the file.
267
 
        None otherwise
268
 
    """
 
193
    """
 
194
    items = []
269
195
    stanza = Stanza()
270
196
    tag = None
271
197
    accum_value = None
272
 
    
273
 
    # TODO: jam 20060922 This code should raise real errors rather than
274
 
    #       using 'assert' to process user input, or raising ValueError
275
 
    #       rather than a more specific error.
276
 
 
277
 
    for line in unicode_iter:
278
 
        if line is None or line == '':
 
198
    for line in line_iter:
 
199
        if line == None or line == '':
279
200
            break       # end of file
280
201
        if line == '\n':
281
202
            break       # end of stanza
282
 
        assert line.endswith('\n')
 
203
        assert line[-1] == '\n'
283
204
        real_l = line
284
205
        if line[0] == '\t': # continues previous value
285
206
            if tag is None:
291
212
            try:
292
213
                colon_index = line.index(': ')
293
214
            except ValueError:
294
 
                raise ValueError('tag/value separator not found in line %r'
295
 
                                 % real_l)
296
 
            tag = str(line[:colon_index])
 
215
                raise ValueError('tag/value separator not found in line %r' % real_l)
 
216
            tag = line[:colon_index]
297
217
            assert valid_tag(tag), \
298
218
                    "invalid rio tag %r" % tag
299
219
            accum_value = line[colon_index+2:-1]
300
 
 
301
220
    if tag is not None: # add last tag-value
302
221
        stanza.add(tag, accum_value)
303
222
        return stanza