A whole bunch of changes, mostly Lua related.
[monky] / check_docs.py
1 #!/usr/bin/python
2 #
3 # This script will check the documentation consistency against the code.  It
4 # doesn't check the actual accuracy of the documentation, it just ensures that
5 # everything is documented and that nothing which doesn't exist in Conky
6 # appears in the documentation.
7 #
8 # This script also updates the vim and nano syntax files so it doesn't have to
9 # be done manually.
10 #
11 # Requires the ElementTree Python module for the sorting stuff, see:
12 # http://effbot.org/zone/element-index.htm
13 #
14 # You should also install htmltidy, but it's not necessary.
15 #
16
17 import os.path
18 import re
19 import sys
20
21 file_names = dict()
22 file_names["text_objects"]    = "src/text_object.h"
23 file_names["conky"]           = "src/conky.c"
24 file_names["vim_syntax"]      = "extras/vim/syntax/conkyrc.vim"
25 file_names["nano_syntax"]     = "extras/nano/conky.nanorc"
26 file_names["variables"]       = "doc/variables.xml"
27 file_names["config_settings"] = "doc/config_settings.xml"
28 file_names["lua"]             = "doc/lua.xml"
29 file_names["docs"]            = "doc/docs.xml"
30 file_names["command_options"] = "doc/command_options.xml"
31
32 for fn in file_names.values():
33         if not os.path.exists(fn) or not os.path.isfile(fn):
34                 print "'%s' doesn't exist, or isn't a file" % (fn)
35                 exit(1)
36
37 print 'sorting/tidying docs...'
38
39 # sort the docs by variable/config setting
40 import string
41 import xml.etree.ElementTree as ET
42
43 vars_xml = ET.parse(file_names['variables'])
44 config_xml = ET.parse(file_names['config_settings'])
45
46 getkey = lambda x: x.findtext('term/command/option')
47
48 vars = vars_xml.getroot()
49 vars[:] = sorted(vars, key=getkey)
50
51 configs = config_xml.getroot()
52 configs[:] = sorted(configs, key=getkey)
53
54 vars_xml.write(file_names['variables'])
55 config_xml.write(file_names['config_settings'])
56
57 def tidy(file):
58         command = ['tidy', '-qim', '-xml', '-utf8', '--indent-spaces', '4']
59         os.system('%s %s 2>/dev/null' % (string.join(command), file))
60
61 tidy(file_names['variables'])
62 tidy(file_names['config_settings'])
63 tidy(file_names['lua'])
64 tidy(file_names['command_options'])
65
66 #
67 # Do all the objects first
68 #
69
70 objects = []
71
72 file = open(file_names["text_objects"], "r")
73 exp = re.compile("\s*OBJ_(\w*).*")
74 while file:
75         line = file.readline()
76         if len(line) == 0:
77                 break
78         res = exp.match(line)
79         if res:
80                 obj = res.group(1)
81                 if not re.match("color\d", obj) and obj != "text":
82                         # ignore colourN stuff
83                         objects.append(res.group(1))
84 file.close()
85 print 'counted %i text objects' % len(objects)
86
87 doc_objects = []
88 exp = re.compile("\s*<command><option>(\w*)</option></command>.*")
89 print "checking docs -> objs consistency (in %s)" % (file_names["text_objects"])
90 for var in vars:
91         term = getkey(var)
92         doc_objects.append(term)
93         if ['templaten', 'colorn'].count(doc_objects[len(doc_objects) - 1].lower()):
94                 # ignore these
95                 continue
96         if doc_objects[len(doc_objects) - 1] not in objects:
97                 print "   '%s' is documented, but doesn't seem to be an object" % (doc_objects[len(doc_objects) - 1])
98 print "done\n"
99
100 print "checking objs -> docs consistency (in %s)" % (file_names["variables"])
101 for obj in objects:
102         if obj not in doc_objects:
103                 print "   '%s' seems to be undocumented" % (obj)
104 print "done\n"
105
106 #
107 # Now we'll do config settings
108 #
109
110 config_entries = []
111
112 file = open(file_names["conky"], "r")
113 exp1 = re.compile('\s*CONF\("(\w*)".*')
114 exp2 = re.compile('\s*CONF2\("(\w*)".*')
115 exp3 = re.compile('\s*CONF3\("(\w*)".*')
116 while file:
117         line = file.readline()
118         if len(line) == 0:
119                 break
120         res = exp1.match(line)
121         if not res:
122                 res = exp2.match(line)
123         if not res:
124                 res = exp3.match(line)
125         if res:
126                 conf = res.group(1)
127                 if re.match("color\d", conf):
128                         conf = "colorN"
129                 if config_entries.count(conf) == 0:
130                         config_entries.append(conf)
131 file.close()
132 print 'counted %i config settings' % len(config_entries)
133
134 doc_configs = []
135 print "checking docs -> configs consistency (in %s)" % (file_names["conky"])
136 for config in configs:
137         term = getkey(config)
138         doc_configs.append(term)
139         if ['text', 'templaten'].count(doc_configs[len(doc_configs) - 1].lower()):
140                 # ignore these
141                 continue
142         if doc_configs[len(doc_configs) - 1] not in config_entries:
143                 print "   '%s' is documented, but doesn't seem to be a config setting" % (doc_configs[len(doc_configs) - 1])
144 print "done\n"
145
146 print "checking configs -> docs consistency (in %s)" % (file_names["config_settings"])
147 for obj in config_entries:
148         if obj != "text" and obj != "template" and obj not in doc_configs:
149                 print "   '%s' seems to be undocumented" % (obj)
150 print "done\n"
151
152
153
154 # Cheat and add the colour/template stuff.
155
156 for i in range(0, 10):
157         objects.append("color" + str(i))
158         config_entries.append("color" + str(i))
159         objects.append("template" + str(i))
160         config_entries.append("template" + str(i))
161
162 # Finally, sort everything.
163 objects.sort()
164 config_entries.sort()
165
166 #
167 # Update nano syntax stuff
168 #
169
170 print "updating nano syntax...",
171 sys.stdout.flush()
172 file = open(file_names["nano_syntax"], "rw+")
173 lines = []
174 while file:
175         line = file.readline()
176         if len(line) == 0:
177                 break
178         lines.append(line)
179
180 # find the line we want to update
181 for line in lines:
182         if re.match("color green ", line):
183                 idx = lines.index(line)
184                 lines.pop(idx) # remove old line
185                 line = 'color green "\<('
186                 for obj in config_entries:
187                         line += "%s|" % (obj)
188                 line = line[:len(line) - 1]
189                 line += ')\>"\n'
190                 lines.insert(idx, line)
191         if re.match("color brightblue ", line):
192                 idx = lines.index(line)
193                 lines.pop(idx) # remove old line
194                 line = 'color brightblue "\<('
195                 for obj in objects:
196                         line += "%s|" % (obj)
197                 line = line[:len(line) - 1]
198                 line += ')\>"\n'
199                 lines.insert(idx, line)
200                 break # want to ignore everything after this line
201 file.truncate(0)
202 file.seek(0)
203 file.writelines(lines)
204 file.close()
205 print "done."
206
207 #
208 # Update vim syntax stuff
209 #
210
211 print "updating vim syntax...",
212 sys.stdout.flush()
213 file = open(file_names["vim_syntax"], "rw+")
214 lines = []
215 while file:
216         line = file.readline()
217         if len(line) == 0:
218                 break
219         lines.append(line)
220
221 # find the line we want to update
222 for line in lines:
223         if re.match("syn keyword ConkyrcSetting ", line):
224                 idx = lines.index(line)
225                 lines.pop(idx) # remove old line
226                 line = 'syn keyword ConkyrcSetting '
227                 for obj in config_entries:
228                         line += "%s " % (obj)
229                 line = line[:len(line) - 1]
230                 line += '\n'
231                 lines.insert(idx, line)
232         if re.match("syn keyword ConkyrcVarName contained nextgroup=ConkyrcNumber,ConkyrcColour skipwhite ", line):
233                 idx = lines.index(line)
234                 lines.pop(idx) # remove old line
235                 line = 'syn keyword ConkyrcVarName contained nextgroup=ConkyrcNumber,ConkyrcColour skipwhite '
236                 for obj in objects:
237                         line += "%s " % (obj)
238                 line = line[:len(line) - 1]
239                 line += '\n'
240                 lines.insert(idx, line)
241                 break # want to ignore everything after this line
242 file.truncate(0)
243 file.seek(0)
244 file.writelines(lines)
245 file.close()
246
247 print "done."