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, logging
27 import config
28 config = config.Config()
29
31 """Attributes file representation and trivial parser."""
32
33
35 """Constructor."""
36 self._path = path
37 self._attrmap = {}
38 self._dirty = False
39 self._attrmap["coding"] = config.Coding
40
41
43 """Read the file and parse it."""
44 logging.debug("AttrFile.read file %s" % self._path)
45 try:
46 f = open(self._path, "rb")
47 self._lines = f.read()
48 f.close()
49 except IOError, e:
50 logging.error("Cannot open attributes file %s" % self._path)
51 self._lines = ''
52
53 self.parse(self._lines)
54 self._dirty = False
55
56
58 """Resets the dirty flag. Why would you want to do this?"""
59 self._dirty = False
60
61
63 """Write the file to disk, if dirty."""
64 logging.debug("AttrFile.write file %s" % self._path)
65
66 if not self._dirty:
67 return
68 try:
69 coding = self._attrmap["coding"]
70 except:
71 coding = config.Coding
72
73 try:
74
75 if len(self._attrmap) == 0:
76 os.unlink(self._path)
77 return
78
79 f = open(self._path, "w")
80 for k in self._attrmap.keys():
81 f.write(k)
82 f.write(": ")
83 f.write(self._attrmap[k].encode(coding))
84 f.write("\n\n")
85 f.close()
86 except IOError, e:
87 print >> sys.stderr, "Error: cannot open attributes file", \
88 self._path
89 self._lines = ''
90 try:
91 os.chmod(self._path, config.DefaultFileMode)
92 except:
93 logging.warning("Unable to chmod %s" % self._path)
94
95
97 """
98 Parse attributes file lines into a map.
99 """
100 logging.debug("AttrFile.parse")
101 mre1 = re.compile("^([^:\n]+)\s*:", re.M)
102 mre2 = re.compile("^\s*$", re.M)
103
104 pos = 0
105 while 1:
106 mo1 = mre1.search(lines, pos)
107
108 if not mo1:
109 break
110
111 txt = None
112 mo2 = mre2.search(lines, mo1.end())
113 if mo2:
114 txt = lines[ mo1.end() : mo2.start() ].strip()
115 else:
116 txt = lines[ mo1.end() : ] .strip()
117
118 self._attrmap[ mo1.group(1) ] = txt
119
120 if mo2:
121 pos = mo2.end()
122 else:
123 break
124 try:
125 coding = self._attrmap["coding"]
126 except:
127 coding = config.Coding
128
129 for key in self._attrmap.keys():
130 txt = self._attrmap[ key ]
131 try:
132 self._attrmap[ key ] = txt.decode(coding)
133 except:
134 self._attrmap[ key ] = txt
135
136
137 - def get(self, field):
138 """
139 Returns an attribute field content extracted from this attributes
140 file.
141 """
142 logging.debug("AttrFile.get(%s)" % field)
143 if field in self._attrmap:
144 return self._attrmap[ field ]
145 else:
146 logging.error("AttrFile.get(%s): No such field in %s" % (field, self._path))
147 raise KeyError("AttrFile.get(%s): No such field in %s" % (field, self._path))
148
149
150 - def get_def(self, field, default=None):
151 """
152 Returns an attribute field content extracted from this attributes
153 file.
154 """
155 logging.debug("AttrFile.get_def(%s)" % field)
156 if field in self._attrmap:
157 return self._attrmap[ field ]
158 else:
159 logging.debug("AttrFile.get_def(%s), returned default:%s" % (field, default))
160 return default
161
162
163 - def set(self, field, value):
164 """
165 Sets a field of the description file. Returns true if the value has
166 changed.
167 Set a field value to None to remove the field.
168 """
169 logging.debug("AttrFile.set(%s,value: %s)" % field, type(value))
170 if value == None:
171 if field in self._attrmap:
172 self._attrmap.pop(field)
173 self._dirty = True
174 return 1
175 else:
176 return 0
177
178
179 value = value.strip()
180
181
182 mre2 = re.compile("^\s*$", re.M)
183 while 1:
184 mo = mre2.search(value)
185 if mo and mo.end() != len(value):
186 outval = value[:mo.start()]
187 id = mo.end()
188 while value[id] != '\n': id += 1
189 outval += value[id + 1:]
190 value = outval
191 else:
192 break
193
194 if '\n' in value:
195 value = '\n' + value
196
197 if field in self._attrmap:
198 if self._attrmap[ field ] == value:
199 return 0
200
201 self._attrmap[ field ] = value
202 self._dirty = True
203 return 1
204
205
208
209
211 return self.set(key, value)
212
213
215 return self._attrmap.keys()
216
217
219 return self._attrmap.has_key(key)
220
221
223 return len(self._attrmap)
224
225
227 """
228 Returns contents to a string for debugging purposes.
229 """
230 lsttxt = ["AttrFile for %s" % self._path]
231 for a in self._attrmap:
232 lsttxt += [a + ":", self._attrmap[a], ""]
233 return os.linesep.join(lsttxt)
234