1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """CLASS AttrFile Attributes file representation and trivial parser."""
25
26 import re, os, sys
27 import config
28 config = config.Config()
29
31
32 """Attributes file representation and trivial parser."""
33
34
35
37
38 """Constructor."""
39
40 self._path = path
41 self._attrmap = {}
42 self._dirty = 0
43 self._attrmap["coding"] = config.Coding
44
45
46
48
49 """Read the file and parse it."""
50
51 try:
52 f = open(self._path, "r")
53 self._lines = f.read()
54 f.close()
55 except IOError, e:
56 print >> sys.stderr, \
57 "Error: cannot open attributes file", self._path
58 self._lines = ''
59
60 self.parse(self._lines)
61 self._dirty = 0
62
63
64
66
67 """Resets the dirty flag. Why would you want to do this?"""
68
69 self._dirty = 0
70
71
72
74
75 """Write the file to disk, if dirty."""
76
77
78 if self._dirty == 0:
79 return
80
81 try:
82 coding = self._attrmap["coding"]
83 except:
84 coding = config.Coding
85
86
87 try:
88
89 if len(self._attrmap) == 0:
90 os.unlink(self._path)
91 return
92
93 f = open(self._path, "w")
94 for k in self._attrmap.keys():
95 f.write(k)
96 f.write(": ")
97
98 f.write(self._attrmap[k].encode(coding))
99 f.write("\n\n")
100 f.close()
101 except IOError, e:
102 print >> sys.stderr, "Error: cannot open attributes file", \
103 self._path
104 self._lines = ''
105 try:
106 os.chmod(self._path, config.DefaultFileMode)
107 except:
108 pass
109
110
112
113 """Parse attributes file lines into a map."""
114
115 mre1 = re.compile("^([^:\n]+)\s*:", re.M)
116 mre2 = re.compile("^\s*$", re.M)
117
118 pos = 0
119 while 1:
120 mo1 = mre1.search(lines, pos)
121
122 if not mo1:
123 break
124
125 txt = None
126 mo2 = mre2.search(lines, mo1.end())
127 if mo2:
128 txt = lines[ mo1.end() : mo2.start() ].strip()
129 else:
130 txt = lines[ mo1.end() : ] .strip()
131
132 self._attrmap[ mo1.group(1) ] = txt
133
134 if mo2:
135 pos = mo2.end()
136 else:
137 break
138 try:
139 coding = self._attrmap["coding"]
140 except:
141 coding = config.Coding
142
143 for key in self._attrmap.keys():
144 txt = self._attrmap[ key ]
145 try:
146 self._attrmap[ key ] = txt.decode(coding)
147 except:
148 self._attrmap[ key ] = txt
149
150
151
152 - def get(self, field):
153
154 """Returns an attribute field content extracted from this attributes
155 file."""
156
157 if self._attrmap.has_key(field):
158 return self._attrmap[ field ]
159 else:
160 raise KeyError()
161
162
163
164 - def get_def(self, field, default=None):
165
166 """Returns an attribute field content extracted from this attributes
167 file."""
168
169 if self._attrmap.has_key(field):
170 return self._attrmap[ field ]
171 else:
172 return default
173
174
175
176 - def set(self, field, value):
177
178 """Sets a field of the description file. Returns true if the value has
179 changed. Set a field value to None to remove the field."""
180
181 if value == None:
182 if self._attrmap.has_key(field):
183 del self._attrmap[ field ]
184 self._dirty = 1
185 return 1
186 else:
187 return 0
188
189
190 value = value.replace('\r', '')
191 value = value.strip()
192
193
194 mre2 = re.compile("^\s*$", re.M)
195 while 1:
196 mo = mre2.search(value)
197 if mo and mo.end() != len(value):
198 outval = value[:mo.start()]
199 id = mo.end()
200 while value[id] != '\n': id += 1
201 outval += value[id + 1:]
202 value = outval
203 else:
204 break
205
206 if '\n' in value:
207 value = '\n' + value
208
209 if self._attrmap.has_key(field):
210
211
212
213
214 if self._attrmap[ field ] == value:
215 return 0
216
217 self._attrmap[ field ] = value
218 self._dirty = 1
219 return 1
220
221
222
225
226
227
229 return self.set(key, value)
230
231
232
233
234
236 return self._attrmap.keys()
237
238
239
241 return self._attrmap.has_key(key)
242
243
244
246 return len(self._attrmap)
247
248
249
251
252 """Returns contents to a string for debugging purposes."""
253
254 txt = ""
255 for a in self._attrmap.keys():
256 txt += a + ":\n" + self._attrmap[a] + "\n\n"
257 return txt
258