/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar
1185.44.1 by Martin Pool
Start bringing in basicio code
1
# Copyright (C) 2005 by Canonical Ltd
2
#
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.
7
#
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.
12
#
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
17
"""basic_io - simple text metaformat
18
19
The stored data consists of a series of *stanzas*, each of which contains
20
*fields* identified by an ascii name.  The contents of each field can be
21
either an integer (scored in decimal) or a Unicode string.
22
"""
23
24
import re
25
1185.44.19 by Martin Pool
New BasicReader to pull a sequence of stanzas from a file, and test.
26
# XXX: basic_io is kind of a dumb name; it seems to imply an io layer not a
27
# format
28
#
29
# XXX: some redundancy is allowing to write stanzas in isolation as well as
1185.44.22 by Martin Pool
More basic_io tweaking
30
# through a writer object.  
1185.44.19 by Martin Pool
New BasicReader to pull a sequence of stanzas from a file, and test.
31
1185.44.1 by Martin Pool
Start bringing in basicio code
32
class BasicWriter(object):
1185.44.16 by Martin Pool
More basic_io development:
33
    def __init__(self, to_file):
34
        self._soft_nl = False
35
        self._to_file = to_file
1185.44.1 by Martin Pool
Start bringing in basicio code
36
37
    def write_stanza(self, stanza):
1185.44.16 by Martin Pool
More basic_io development:
38
        if self._soft_nl:
39
            print >>self._to_file
40
        stanza.write(self._to_file)
41
        self._soft_nl = True
1185.44.1 by Martin Pool
Start bringing in basicio code
42
43
1185.44.19 by Martin Pool
New BasicReader to pull a sequence of stanzas from a file, and test.
44
class BasicReader(object):
45
    """Read stanzas from a file as a sequence
46
    
47
    to_file can be anything that can be enumerated as a sequence of 
48
    lines (with newlines.)
49
    """
50
    def __init__(self, from_file):
51
        self._from_file = from_file
52
53
    def __iter__(self):
54
        while True:
1185.44.23 by Martin Pool
More basic_io tweaking; break format
55
            s = read_stanza(self._from_file)
1185.44.19 by Martin Pool
New BasicReader to pull a sequence of stanzas from a file, and test.
56
            if s is None:
57
                break
58
            else:
59
                yield s
60
1185.44.23 by Martin Pool
More basic_io tweaking; break format
61
def read_stanzas(from_file):
62
    while True:
63
        s = read_stanza(from_file)
64
        if s is None:
65
            break
66
        else:
67
            yield s
1185.44.19 by Martin Pool
New BasicReader to pull a sequence of stanzas from a file, and test.
68
1185.44.1 by Martin Pool
Start bringing in basicio code
69
class Stanza(object):
70
    """One stanza for basic_io.
71
72
    Each stanza contains a set of named fields.  
73
    
74
    Names must be non-empty ascii alphanumeric plus _.  Names can be repeated
75
    within a stanza.  Names are case-sensitive.  The ordering of fields is
76
    preserved.
77
78
    Each field value must be either an int or a string.
79
    """
80
1185.44.23 by Martin Pool
More basic_io tweaking; break format
81
    __slots__ = ['items']
82
83
    def __init__(self, **kwargs):
1185.44.1 by Martin Pool
Start bringing in basicio code
84
        """Construct a new Stanza.
85
86
        The keyword arguments, if any, are added in sorted order to the stanza.
87
        """
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
88
        if kwargs:
1185.44.23 by Martin Pool
More basic_io tweaking; break format
89
            self.items = sorted(kwargs.items())
90
        else:
91
            self.items = []
1185.44.1 by Martin Pool
Start bringing in basicio code
92
93
    def add(self, tag, value):
94
        """Append a name and value to the stanza."""
1185.44.22 by Martin Pool
More basic_io tweaking
95
##         if not valid_tag(tag):
96
##             raise ValueError("invalid tag %r" % tag)
97
##         if not isinstance(value, (int, long, str, unicode)):
98
##             raise ValueError("invalid value %r" % value)
1185.44.1 by Martin Pool
Start bringing in basicio code
99
        self.items.append((tag, value))
100
        
101
    def __contains__(self, find_tag):
102
        """True if there is any field in this stanza with the given tag."""
103
        for tag, value in self.items:
104
            if tag == find_tag:
105
                return True
106
        return False
107
1185.44.9 by Martin Pool
Add len(Stanza)
108
    def __len__(self):
109
        """Return number of pairs in the stanza."""
110
        return len(self.items)
111
1185.44.11 by Martin Pool
Add Stanza eq and ne methods and test.
112
    def __eq__(self, other):
113
        if not isinstance(other, Stanza):
114
            return False
115
        return self.items == other.items
116
117
    def __ne__(self, other):
118
        return not self.__eq__(other)
119
1185.44.12 by Martin Pool
Fix up reading basic_io multiline strings
120
    def __repr__(self):
121
        return "Stanza(%r)" % self.items
122
1185.44.6 by Martin Pool
Simple basic_io from_lines and .get()
123
    def iter_pairs(self):
1185.44.2 by Martin Pool
Iteration of Stanzas()
124
        """Return iterator of tag, value pairs."""
125
        return iter(self.items)
126
1185.44.3 by Martin Pool
More basic_io development
127
    def to_lines(self):
128
        """Generate sequence of lines for external version of this file."""
1185.44.22 by Martin Pool
More basic_io tweaking
129
        for tag, value in self.items:
130
            if isinstance(value, (int, long)):
131
                # must use %d so bools are written as ints
1185.44.23 by Martin Pool
More basic_io tweaking; break format
132
                yield '%s %d\n' % (tag, value)
1185.44.22 by Martin Pool
More basic_io tweaking
133
            else:
1185.44.23 by Martin Pool
More basic_io tweaking; break format
134
                assert isinstance(value, (str, unicode)), ("invalid value %r" % value)
135
                qv = value.replace('\\', r'\\') \
136
                          .replace('"',  r'\"') \
137
                          .replace('\n', r'\n')
138
                yield '%s "%s"\n' % (tag, qv)
1185.44.3 by Martin Pool
More basic_io development
139
140
    def to_string(self):
1185.44.6 by Martin Pool
Simple basic_io from_lines and .get()
141
        """Return stanza as a single string"""
1185.44.3 by Martin Pool
More basic_io development
142
        return ''.join(self.to_lines())
143
144
    def write(self, to_file):
1185.44.6 by Martin Pool
Simple basic_io from_lines and .get()
145
        """Write stanza to a file"""
1185.44.3 by Martin Pool
More basic_io development
146
        to_file.writelines(self.to_lines())
147
1185.44.6 by Martin Pool
Simple basic_io from_lines and .get()
148
    def get(self, tag):
149
        """Return the value for a field wih given tag.
150
151
        If there is more than one value, only the first is returned.  If the
152
        tag is not present, KeyError is raised.
153
        """
154
        for t, v in self.items:
155
            if t == tag:
156
                return v
157
        else:
158
            raise KeyError(tag)
1185.44.15 by Martin Pool
Add Stanza.get_all and test repeated fields
159
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
160
    __getitem__ = get
161
1185.44.15 by Martin Pool
Add Stanza.get_all and test repeated fields
162
    def get_all(self, tag):
163
        r = []
164
        for t, v in self.items:
165
            if t == tag:
166
                r.append(v)
167
        return r
1185.44.1 by Martin Pool
Start bringing in basicio code
168
         
169
TAG_RE = re.compile(r'^[-a-zA-Z0-9_]+$')
170
def valid_tag(tag):
171
    return bool(TAG_RE.match(tag))
172
173
1185.44.23 by Martin Pool
More basic_io tweaking; break format
174
def read_stanza(from_lines):
175
    """Return new Stanza read from list of lines or a file"""
176
    items = []
177
    for l in from_lines:
178
        if l == None or l == '' or l == '\n':
179
            break
180
        assert l[-1] == '\n'
181
        space = l.index(' ')
182
        tag = l[:space]
183
        assert valid_tag(tag), \
184
                "invalid basic_io tag %r" % tag
185
        rest = l[space+1:]
186
        if l[space+1] == '"':
187
            # keep reading in lines, accumulating into value, until we're done
188
            assert l[-2] == '"'
189
            value = l[space+2:-2]
190
            value = value.replace(r'\n', '\n') \
191
                  .replace(r'\"', '\"') \
192
                  .replace(r'\\', '\\')
193
        else:
194
            value = int(l[space+1:])
195
        items.append((tag, value))
196
    if not items:
197
        return None         # didn't see any content
198
    s = Stanza()
199
    s.items = items
200
    return s
1185.44.22 by Martin Pool
More basic_io tweaking
201
202
1185.44.6 by Martin Pool
Simple basic_io from_lines and .get()
203
############################################################
1185.44.1 by Martin Pool
Start bringing in basicio code
204
205
# XXX: Move these to object serialization code. 
206
207
def write_revision(writer, revision):
208
    s = Stanza(revision=revision.revision_id,
209
               committer=revision.committer, 
210
               timezone=long(revision.timezone),
211
               timestamp=long(revision.timestamp),
212
               inventory_sha1=revision.inventory_sha1)
213
    for parent_id in revision.parent_ids:
214
        s.add('parent', parent_id)
215
    for prop_name, prop_value in revision.properties.items():
216
        s.add(prop_name, prop_value)
1185.44.15 by Martin Pool
Add Stanza.get_all and test repeated fields
217
    s.write(writer)
1185.44.1 by Martin Pool
Start bringing in basicio code
218
219
def write_inventory(writer, inventory):
220
    s = Stanza(inventory_version=7)
221
    writer.write_stanza(s)
222
223
    for path, ie in inventory.iter_entries():
224
        s = Stanza()
1185.44.16 by Martin Pool
More basic_io development:
225
        s.add(ie.kind, ie.file_id)
226
        for attr in ['name', 'parent_id', 'revision',
1185.44.1 by Martin Pool
Start bringing in basicio code
227
                     'text_sha1', 'text_size', 'executable', 'symlink_target',
228
                     ]:
229
            attr_val = getattr(ie, attr, None)
230
            if attr == 'executable' and attr_val == 0:
231
                continue
232
            if attr == 'parent_id' and attr_val == 'TREE_ROOT':
233
                continue
234
            if attr_val is not None:
235
                s.add(attr, attr_val)
236
        writer.write_stanza(s)
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
237
238
239
def read_inventory(inv_file):
240
    """Read inventory object from basic_io formatted inventory file"""
241
    from bzrlib.inventory import Inventory, InventoryFile
1185.44.23 by Martin Pool
More basic_io tweaking; break format
242
    s = read_stanza(inv_file)
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
243
    assert s['inventory_version'] == 7
244
    inv = Inventory()
1185.44.23 by Martin Pool
More basic_io tweaking; break format
245
    for s in read_stanzas(inv_file):
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
246
        kind, file_id = s.items[0]
247
        parent_id = None
248
        if 'parent_id' in s:
249
            parent_id = s['parent_id']
250
        if kind == 'file':
251
            ie = InventoryFile(file_id, s['name'], parent_id)
1185.44.23 by Martin Pool
More basic_io tweaking; break format
252
            ie.text_sha1 = s['text_sha1']
253
            ie.text_size = s['text_size']
1185.44.21 by Martin Pool
Experiments with basic_io for inventory
254
        else:
255
            raise NotImplementedError()
256
        inv.add(ie)
257
    return inv