3 # vi:si:et:sw=4:sts=4:ts=4
6 parse, merge and write gstdoc-scanobj files
15 # OrderedDict class based on
16 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
17 # Licensed under the Python License
18 class OrderedDict(dict):
23 def __delitem__(self, key):
24 dict.__delitem__(self, key)
25 self._keys.remove(key)
27 def __setitem__(self, key, item):
28 dict.__setitem__(self, key, item)
29 if key not in self._keys: self._keys.append(key)
36 dict = dict.copy(self)
37 dict._keys = self._keys[:]
41 return zip(self._keys, self.values())
50 raise KeyError('dictionary is empty')
57 def setdefault(self, key, failobj = None):
58 dict.setdefault(self, key, failobj)
59 if key not in self._keys: self._keys.append(key)
61 def update(self, dict):
62 dict.update(self, dict)
63 for key in dict.keys():
64 if key not in self._keys: self._keys.append(key)
67 return map(self.get, self._keys)
70 def __init__(self, name):
71 self._signals = OrderedDict()
72 self._args = OrderedDict()
76 return "<Object %s>" % self.name
78 def add_signal(self, signal, overwrite=True):
79 if not overwrite and self._signals.has_key(signal.name):
80 raise IndexError, "signal %s already in %r" % (signal.name, self)
81 self._signals[signal.name] = signal
83 def add_arg(self, arg, overwrite=True):
84 if not overwrite and self._args.has_key(arg.name):
85 raise IndexError, "arg %s already in %r" % (arg.name, self)
86 self._args[arg.name] = arg
89 def __init__(self, **kwargs):
90 for key in self.attrs:
91 setattr(self, key, kwargs[key])
95 return "<%r %s>" % (str(self.__class__), self.name)
97 class Signal(Docable):
98 attrs = ['name', 'returns', 'args']
101 attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default']
104 def load_file(self, filename):
106 lines = open(filename).readlines()
107 self.load_data("".join(lines))
109 print "WARNING - could not read from %s" % filename
111 def save_file(self, filename, backup=False):
113 Save the information to the given file if the file content changed.
117 lines = open(filename).readlines()
118 olddata = "".join(lines)
120 print "WARNING - could not read from %s" % filename
121 newdata = self.get_data()
122 if olddata and olddata == newdata:
127 os.rename(filename, filename + '.bak')
129 handle = open(filename, "w")
130 handle.write(newdata)
135 self._objects = OrderedDict()
137 def load_data(self, data):
139 Load the .signals lines, creating our list of objects and signals.
142 smatcher = re.compile(
143 '(?s)' # make . match \n
144 '<SIGNAL>\n(.*?)</SIGNAL>\n'
146 nmatcher = re.compile(
148 '(?P<object>\S*)' # store object
150 '(?P<signal>\S*)' # store signal
153 rmatcher = re.compile(
154 '(?s)' # make . match \n
155 '<RETURNS>(?P<returns>\S*)</RETURNS>\n' # store returns
156 '(?P<args>.*)' # store args
158 for block in smatcher.findall(data):
159 nmatch = nmatcher.search(block)
161 o = nmatch.group('object')
162 debug("Found object", o)
163 debug("Found signal", nmatch.group('signal'))
164 if not self._objects.has_key(o):
166 self._objects[o] = object
168 rmatch = rmatcher.search(block)
170 dict = rmatch.groupdict().copy()
171 dict['name'] = nmatch.group('signal')
172 signal = Signal(**dict)
173 self._objects[o].add_signal(signal)
177 for o in self._objects.values():
178 for s in o._signals.values():
180 <NAME>%(object)s::%(name)s</NAME>
181 <RETURNS>%(returns)s</RETURNS>
186 lines.append(block % d)
188 return "\n".join(lines) + '\n'
192 self._objects = OrderedDict()
194 def load_data(self, data):
196 Load the .args lines, creating our list of objects and args.
199 amatcher = re.compile(
200 '(?s)' # make . match \n
201 '<ARG>\n(.*?)</ARG>\n'
203 nmatcher = re.compile(
205 '(?P<object>\S*)' # store object
207 '(?P<arg>\S*)' # store arg
210 rmatcher = re.compile(
211 '(?s)' # make . match \n
212 '<TYPE>(?P<type>\S*)</TYPE>\n' # store type
213 '<RANGE>(?P<range>.*?)</RANGE>\n' # store range
214 '<FLAGS>(?P<flags>\S*)</FLAGS>\n' # store flags
215 '<NICK>(?P<nick>.*?)</NICK>\n' # store nick
216 '<BLURB>(?P<blurb>.*?)</BLURB>\n' # store blurb
217 '<DEFAULT>(?P<default>.*?)</DEFAULT>\n' # store default
219 for block in amatcher.findall(data):
220 nmatch = nmatcher.search(block)
222 o = nmatch.group('object')
223 debug("Found object", o)
224 debug("Found arg", nmatch.group('arg'))
225 if not self._objects.has_key(o):
227 self._objects[o] = object
229 rmatch = rmatcher.search(block)
231 dict = rmatch.groupdict().copy()
232 dict['name'] = nmatch.group('arg')
234 self._objects[o].add_arg(arg)
236 print "ERROR: could not match arg from block %s" % block
240 for o in self._objects.values():
241 for a in o._args.values():
243 <NAME>%(object)s::%(name)s</NAME>
244 <TYPE>%(type)s</TYPE>
245 <RANGE>%(range)s</RANGE>
246 <FLAGS>%(flags)s</FLAGS>
247 <NICK>%(nick)s</NICK>
248 <BLURB>%(blurb)s</BLURB>
249 <DEFAULT>%(default)s</DEFAULT>
254 lines.append(block % d)
256 return "\n".join(lines) + '\n'
258 class SingleLine(GDoc):
262 def load_data(self, data):
264 Load the .interfaces/.prerequisites lines, merge duplicates
267 lines = data.splitlines();
268 # merge them into self._objects
270 if line not in self._objects:
271 self._objects.append(line)
274 lines = sorted(self._objects)
275 return "\n".join(lines) + '\n'
282 sys.stderr.write('Please provide a documentation module name\n')
286 signals.load_file(modulename + '.signals')
287 signals.load_file(modulename + '.signals.new')
288 signals.save_file(modulename + '.signals', backup=True)
289 os.unlink(modulename + '.signals.new')
292 args.load_file(modulename + '.args')
293 args.load_file(modulename + '.args.new')
294 args.save_file(modulename + '.args', backup=True)
295 os.unlink(modulename + '.args.new')
297 ifaces = SingleLine()
298 ifaces.load_file(modulename + '.interfaces')
299 ifaces.load_file(modulename + '.interfaces.new')
300 ifaces.save_file(modulename + '.interfaces', backup=True)
301 os.unlink(modulename + '.interfaces.new')
303 prereq = SingleLine()
304 prereq.load_file(modulename + '.prerequisites')
305 prereq.load_file(modulename + '.prerequisites.new')
306 prereq.save_file(modulename + '.prerequisites', backup=True)
307 os.unlink(modulename + '.prerequisites.new')