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