3 # vi:si:et:sw=4:sts=4:ts=4
6 parse, merge and write gstdoc-scanobj files
9 from __future__ import print_function, unicode_literals
17 # OrderedDict class based on
18 # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/107747
19 # Licensed under the Python License
20 class OrderedDict(dict):
25 def __delitem__(self, key):
26 dict.__delitem__(self, key)
27 self._keys.remove(key)
29 def __setitem__(self, key, item):
30 dict.__setitem__(self, key, item)
31 if key not in self._keys: self._keys.append(key)
38 dict = dict.copy(self)
39 dict._keys = self._keys[:]
43 return zip(self._keys, self.values())
52 raise KeyError('dictionary is empty')
59 def setdefault(self, key, failobj = None):
60 dict.setdefault(self, key, failobj)
61 if key not in self._keys: self._keys.append(key)
63 def update(self, dict):
64 dict.update(self, dict)
65 for key in dict.keys():
66 if key not in self._keys: self._keys.append(key)
69 return map(self.get, self._keys)
72 def __init__(self, name):
73 self._signals = OrderedDict()
74 self._args = OrderedDict()
78 return "<Object %s>" % self.name
80 def add_signal(self, signal, overwrite=True):
81 if not overwrite and signal.name in self._signals:
82 raise IndexError("signal %s already in %r" % (signal.name, self))
83 self._signals[signal.name] = signal
85 def add_arg(self, arg, overwrite=True):
86 if not overwrite and arg.name in self._args:
87 raise IndexError("arg %s already in %r" % (arg.name, self))
88 self._args[arg.name] = arg
91 def __init__(self, **kwargs):
92 for key in self.attrs:
93 setattr(self, key, kwargs[key])
97 return "<%r %s>" % (str(self.__class__), self.name)
99 class Signal(Docable):
100 attrs = ['name', 'returns', 'args']
103 attrs = ['name', 'type', 'range', 'flags', 'nick', 'blurb', 'default']
106 def load_file(self, filename):
108 lines = open(filename).readlines()
109 self.load_data("".join(lines))
111 print ("WARNING - could not read from %s" % filename)
113 def save_file(self, filename, backup=False):
115 Save the information to the given file if the file content changed.
119 lines = open(filename).readlines()
120 olddata = "".join(lines)
122 print ("WARNING - could not read from %s" % filename)
123 newdata = self.get_data()
124 if olddata and olddata == newdata:
129 os.rename(filename, filename + '.bak')
131 handle = open(filename, "w")
132 handle.write(newdata)
137 self._objects = OrderedDict()
139 def load_data(self, data):
141 Load the .signals lines, creating our list of objects and signals.
144 smatcher = re.compile(
145 '(?s)' # make . match \n
146 '<SIGNAL>\n(.*?)</SIGNAL>\n'
148 nmatcher = re.compile(
150 '(?P<object>\S*)' # store object
152 '(?P<signal>\S*)' # store signal
155 rmatcher = re.compile(
156 '(?s)' # make . match \n
157 '<RETURNS>(?P<returns>\S*)</RETURNS>\n' # store returns
158 '(?P<args>.*)' # store args
160 for block in smatcher.findall(data):
161 nmatch = nmatcher.search(block)
163 o = nmatch.group('object')
164 debug("Found object", o)
165 debug("Found signal", nmatch.group('signal'))
166 if o not in self._objects:
168 self._objects[o] = object
170 rmatch = rmatcher.search(block)
172 dict = rmatch.groupdict().copy()
173 dict['name'] = nmatch.group('signal')
174 signal = Signal(**dict)
175 self._objects[o].add_signal(signal)
179 for o in self._objects.values():
180 for s in o._signals.values():
182 <NAME>%(object)s::%(name)s</NAME>
183 <RETURNS>%(returns)s</RETURNS>
188 lines.append(block % d)
190 return "\n".join(lines) + '\n'
194 self._objects = OrderedDict()
196 def load_data(self, data):
198 Load the .args lines, creating our list of objects and args.
201 amatcher = re.compile(
202 '(?s)' # make . match \n
203 '<ARG>\n(.*?)</ARG>\n'
205 nmatcher = re.compile(
207 '(?P<object>\S*)' # store object
209 '(?P<arg>\S*)' # store arg
212 rmatcher = re.compile(
213 '(?s)' # make . match \n
214 '<TYPE>(?P<type>\S*)</TYPE>\n' # store type
215 '<RANGE>(?P<range>.*?)</RANGE>\n' # store range
216 '<FLAGS>(?P<flags>\S*)</FLAGS>\n' # store flags
217 '<NICK>(?P<nick>.*?)</NICK>\n' # store nick
218 '<BLURB>(?P<blurb>.*?)</BLURB>\n' # store blurb
219 '<DEFAULT>(?P<default>.*?)</DEFAULT>\n' # store default
221 for block in amatcher.findall(data):
222 nmatch = nmatcher.search(block)
224 o = nmatch.group('object')
225 debug("Found object", o)
226 debug("Found arg", nmatch.group('arg'))
227 if o not in self._objects:
229 self._objects[o] = object
231 rmatch = rmatcher.search(block)
233 dict = rmatch.groupdict().copy()
234 dict['name'] = nmatch.group('arg')
236 self._objects[o].add_arg(arg)
238 print ("ERROR: could not match arg from block %s" % block)
242 for o in self._objects.values():
243 for a in o._args.values():
245 <NAME>%(object)s::%(name)s</NAME>
246 <TYPE>%(type)s</TYPE>
247 <RANGE>%(range)s</RANGE>
248 <FLAGS>%(flags)s</FLAGS>
249 <NICK>%(nick)s</NICK>
250 <BLURB>%(blurb)s</BLURB>
251 <DEFAULT>%(default)s</DEFAULT>
256 lines.append(block % d)
258 return "\n".join(lines) + '\n'
260 class SingleLine(GDoc):
264 def load_data(self, data):
266 Load the .interfaces/.prerequisites lines, merge duplicates
269 lines = data.splitlines();
270 # merge them into self._objects
272 if line not in self._objects:
273 self._objects.append(line)
276 lines = sorted(self._objects)
277 return "\n".join(lines) + '\n'
284 sys.stderr.write('Please provide a documentation module name\n')
288 signals.load_file(modulename + '.signals')
289 signals.load_file(modulename + '.signals.new')
290 signals.save_file(modulename + '.signals', backup=True)
291 os.unlink(modulename + '.signals.new')
294 args.load_file(modulename + '.args')
295 args.load_file(modulename + '.args.new')
296 args.save_file(modulename + '.args', backup=True)
297 os.unlink(modulename + '.args.new')
299 ifaces = SingleLine()
300 ifaces.load_file(modulename + '.interfaces')
301 ifaces.load_file(modulename + '.interfaces.new')
302 ifaces.save_file(modulename + '.interfaces', backup=True)
303 os.unlink(modulename + '.interfaces.new')
305 prereq = SingleLine()
306 prereq.load_file(modulename + '.prerequisites')
307 prereq.load_file(modulename + '.prerequisites.new')
308 prereq.save_file(modulename + '.prerequisites', backup=True)
309 os.unlink(modulename + '.prerequisites.new')