##// END OF EJS Templates
doc: add the tool to check section marks in help documents...
FUJIWARA Katsunori -
r17648:07f1ac17 default
parent child Browse files
Show More
@@ -0,0 +1,170 b''
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)
@@ -802,3 +802,7 b' Test keyword search help'
802
802
803 qclone clone main and patch repository at same time
803 qclone clone main and patch repository at same time
804
804
805 Test usage of section marks in help documents
806
807 $ cd "$TESTDIR"/../doc
808 $ python check-seclevel.py
General Comments 0
You need to be logged in to leave comments. Login now