1
# Copyright (C) 2005 by Canonical Ltd
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.
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.
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
17
"""basic_io - simple text metaformat
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.
26
class BasicWriter(object):
30
def write_stanza(self, stanza):
33
_StanzaWriter(stanza.items).write()
37
class _StanzaWriter(object):
38
def __init__(self, list):
42
def write_pair(self, tag, value):
43
if not valid_tag(tag):
44
raise ValueError("invalid basicio tag %r" % tag)
45
if isinstance(value, basestring):
46
self.write_string(tag, value)
47
elif isinstance(value, (int, long)):
48
self.write_number(tag, value)
50
raise ValueError("invalid basicio value %r" % (value))
52
def write_number(self, tag, value):
53
print "%*s %d" % (self.indent, tag, value)
55
def write_string(self, tag, value):
56
print "%*s %s" % (self.indent, tag, self.quote_string(value))
58
def quote_string(self, value):
59
qv = value.replace('\\', '\\\\') \
60
.replace('\n', '\\n') \
61
.replace('\r', '\\r') \
62
.replace('\t', '\\t') \
67
self.indent = max(len(kv[0]) for kv in self.items)
68
for tag, value in self.items:
69
self.write_pair(tag, value)
73
"""One stanza for basic_io.
75
Each stanza contains a set of named fields.
77
Names must be non-empty ascii alphanumeric plus _. Names can be repeated
78
within a stanza. Names are case-sensitive. The ordering of fields is
81
Each field value must be either an int or a string.
84
def __init__(self, **kwargs):
85
"""Construct a new Stanza.
87
The keyword arguments, if any, are added in sorted order to the stanza.
90
for tag, value in sorted(kwargs.items()):
93
def add(self, tag, value):
94
"""Append a name and value to the stanza."""
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)
99
self.items.append((tag, value))
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:
109
TAG_RE = re.compile(r'^[-a-zA-Z0-9_]+$')
111
return bool(TAG_RE.match(tag))
118
# XXX: Move these to object serialization code.
120
def write_revision(writer, revision):
121
s = Stanza(revision=revision.revision_id,
122
committer=revision.committer,
123
timezone=long(revision.timezone),
124
timestamp=long(revision.timestamp),
125
inventory_sha1=revision.inventory_sha1)
126
for parent_id in revision.parent_ids:
127
s.add('parent', parent_id)
128
for prop_name, prop_value in revision.properties.items():
129
s.add(prop_name, prop_value)
130
writer.write_stanza(s)
132
def write_inventory(writer, inventory):
133
s = Stanza(inventory_version=7)
134
writer.write_stanza(s)
136
for path, ie in inventory.iter_entries():
138
for attr in ['kind', 'name', 'file_id', 'parent_id', 'revision',
139
'text_sha1', 'text_size', 'executable', 'symlink_target',
141
attr_val = getattr(ie, attr, None)
142
if attr == 'executable' and attr_val == 0:
144
if attr == 'parent_id' and attr_val == 'TREE_ROOT':
146
if attr_val is not None:
147
s.add(attr, attr_val)
148
writer.write_stanza(s)