Mercurial > public > mercurial-scm > hg
comparison doc/check-seclevel.py @ 17648:07f1ac17b722
doc: add the tool to check section marks in help documents
This patch adds "doc/check-seclevel.py" which checks below in help
documents:
- whether unknown or unavailable section marks are used or not
- whether appropriate section mark is used at sub-sectioning
It should be invoked in "doc" directory.
It checks all help documents of Mercurial (topics, commands,
extensions), if no file is specified by --file option.
With --file option, it checks contents of the specified file as help
document, for self testing purpose: -t/-c/-e/-C are used to specify
what kind of help document contents of the specified file is.
This checking is related to changeset 979b107eaea2.
author | FUJIWARA Katsunori <foozy@lares.dti.ne.jp> |
---|---|
date | Mon, 13 Aug 2012 21:25:48 +0900 |
parents | |
children | e15c991fe2ec |
comparison
equal
deleted
inserted
replaced
17647:d34ba4991188 | 17648:07f1ac17b722 |
---|---|
1 #!/usr/bin/env python | |
2 # | |
3 # checkseclevel - checking section title levels in each online help documents | |
4 | |
5 import sys, os | |
6 import optparse | |
7 | |
8 # import from the live mercurial repo | |
9 sys.path.insert(0, "..") | |
10 # fall back to pure modules if required C extensions are not available | |
11 sys.path.append(os.path.join('..', 'mercurial', 'pure')) | |
12 from mercurial import demandimport; demandimport.enable() | |
13 from mercurial.commands import table | |
14 from mercurial.help import helptable | |
15 from mercurial import extensions | |
16 from mercurial import minirst | |
17 from mercurial import util | |
18 | |
19 _verbose = False | |
20 | |
21 def verbose(msg): | |
22 if _verbose: | |
23 print msg | |
24 | |
25 def error(msg): | |
26 sys.stderr.write('%s\n' % msg) | |
27 | |
28 level2mark = ['"', '=', '-', '.', '#'] | |
29 reservedmarks = ['"'] | |
30 | |
31 mark2level = {} | |
32 for m, l in zip(level2mark, xrange(len(level2mark))): | |
33 if m not in reservedmarks: | |
34 mark2level[m] = l | |
35 | |
36 initlevel_topic = 0 | |
37 initlevel_cmd = 1 | |
38 initlevel_ext = 1 | |
39 initlevel_ext_cmd = 3 | |
40 | |
41 def showavailables(initlevel): | |
42 error(' available marks and order of them in this help: %s' % | |
43 (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]]))) | |
44 | |
45 def checkseclevel(doc, name, initlevel): | |
46 verbose('checking "%s"' % name) | |
47 blocks, pruned = minirst.parse(doc, 0, ['verbose']) | |
48 errorcnt = 0 | |
49 curlevel = initlevel | |
50 for block in blocks: | |
51 if block['type'] != 'section': | |
52 continue | |
53 mark = block['underline'] | |
54 title = block['lines'][0] | |
55 if (mark not in mark2level) or (mark2level[mark] <= initlevel): | |
56 error('invalid section mark %r for "%s" of %s' % | |
57 (mark * 4, title, name)) | |
58 showavailables(initlevel) | |
59 errorcnt += 1 | |
60 continue | |
61 nextlevel = mark2level[mark] | |
62 if curlevel < nextlevel and curlevel + 1 != nextlevel: | |
63 error('gap of section level at "%s" of %s' % | |
64 (title, name)) | |
65 showavailables(initlevel) | |
66 errorcnt += 1 | |
67 continue | |
68 verbose('appropriate section level for "%s %s"' % | |
69 (mark * (nextlevel * 2), title)) | |
70 curlevel = nextlevel | |
71 | |
72 return errorcnt | |
73 | |
74 def checkcmdtable(cmdtable, namefmt, initlevel): | |
75 errorcnt = 0 | |
76 for k, entry in cmdtable.items(): | |
77 name = k.split("|")[0].lstrip("^") | |
78 if not entry[0].__doc__: | |
79 verbose('skip checking %s: no help document' % | |
80 (namefmt % name)) | |
81 continue | |
82 errorcnt += checkseclevel(entry[0].__doc__, | |
83 namefmt % name, | |
84 initlevel) | |
85 return errorcnt | |
86 | |
87 def checkhghelps(): | |
88 errorcnt = 0 | |
89 for names, sec, doc in helptable: | |
90 if util.safehasattr(doc, '__call__'): | |
91 doc = doc() | |
92 errorcnt += checkseclevel(doc, | |
93 '%s help topic' % names[0], | |
94 initlevel_topic) | |
95 | |
96 errorcnt += checkcmdtable(table, '%s command', initlevel_cmd) | |
97 | |
98 for name in sorted(extensions.enabled().keys() + | |
99 extensions.disabled().keys()): | |
100 mod = extensions.load(None, name, None) | |
101 if not mod.__doc__: | |
102 verbose('skip checking %s extension: no help document' % name) | |
103 continue | |
104 errorcnt += checkseclevel(mod.__doc__, | |
105 '%s extension' % name, | |
106 initlevel_ext) | |
107 | |
108 cmdtable = getattr(mod, 'cmdtable', None) | |
109 if cmdtable: | |
110 errorcnt += checkcmdtable(cmdtable, | |
111 '%s command of ' + name + ' extension', | |
112 initlevel_ext_cmd) | |
113 return errorcnt | |
114 | |
115 def checkfile(filename, initlevel): | |
116 if filename == '-': | |
117 filename = 'stdin' | |
118 doc = sys.stdin.read() | |
119 else: | |
120 fp = open(filename) | |
121 try: | |
122 doc = fp.read() | |
123 finally: | |
124 fp.close() | |
125 | |
126 verbose('checking input from %s with initlevel %d' % | |
127 (filename, initlevel)) | |
128 return checkseclevel(doc, 'input from %s' % filename, initlevel) | |
129 | |
130 if __name__ == "__main__": | |
131 optparser = optparse.OptionParser("""%prog [options] | |
132 | |
133 This checks all help documents of Mercurial (topics, commands, | |
134 extensions and commands of them), if no file is specified by --file | |
135 option. | |
136 """) | |
137 optparser.add_option("-v", "--verbose", | |
138 help="enable additional output", | |
139 action="store_true") | |
140 optparser.add_option("-f", "--file", | |
141 help="filename to read in (or '-' for stdin)", | |
142 action="store", default="") | |
143 | |
144 optparser.add_option("-t", "--topic", | |
145 help="parse file as help topic", | |
146 action="store_const", dest="initlevel", const=0) | |
147 optparser.add_option("-c", "--command", | |
148 help="parse file as help of core command", | |
149 action="store_const", dest="initlevel", const=1) | |
150 optparser.add_option("-e", "--extension", | |
151 help="parse file as help of extension", | |
152 action="store_const", dest="initlevel", const=1) | |
153 optparser.add_option("-C", "--extension-command", | |
154 help="parse file as help of extension command", | |
155 action="store_const", dest="initlevel", const=3) | |
156 | |
157 optparser.add_option("-l", "--initlevel", | |
158 help="set initial section level manually", | |
159 action="store", type="int", default=0) | |
160 | |
161 (options, args) = optparser.parse_args() | |
162 | |
163 _verbose = options.verbose | |
164 | |
165 if options.file: | |
166 if checkfile(options.file, options.initlevel): | |
167 sys.exit(1) | |
168 else: | |
169 if checkhghelps(): | |
170 sys.exit(1) |