check-seclevel.py
227 lines
| 5.8 KiB
| text/x-python
|
PythonLexer
/ doc / check-seclevel.py
|
r17648 | #!/usr/bin/env python | ||
# | ||||
|
r26192 | # checkseclevel - checking section title levels in each online help document | ||
|
r17648 | |||
|
r28965 | from __future__ import absolute_import | ||
|
r17648 | import optparse | ||
|
r28965 | import os | ||
import sys | ||||
|
r17648 | |||
# import from the live mercurial repo | ||||
|
r27221 | os.environ['HGMODULEPOLICY'] = 'py' | ||
|
r17648 | sys.path.insert(0, "..") | ||
|
r43346 | from mercurial import demandimport | ||
demandimport.enable() | ||||
|
r28965 | from mercurial import ( | ||
commands, | ||||
extensions, | ||||
help, | ||||
minirst, | ||||
ui as uimod, | ||||
) | ||||
table = commands.table | ||||
helptable = help.helptable | ||||
|
r17648 | |||
|
r32544 | level2mark = [b'"', b'=', b'-', b'.', b'#'] | ||
reservedmarks = [b'"'] | ||||
|
r17648 | |||
mark2level = {} | ||||
|
r32544 | for m, l in zip(level2mark, range(len(level2mark))): | ||
|
r17648 | if m not in reservedmarks: | ||
mark2level[m] = l | ||||
initlevel_topic = 0 | ||||
initlevel_cmd = 1 | ||||
initlevel_ext = 1 | ||||
initlevel_ext_cmd = 3 | ||||
|
r43346 | |||
|
r26411 | def showavailables(ui, initlevel): | ||
|
r43346 | avail = ' available marks and order of them in this help: %s\n' % ( | ||
', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1 :]]) | ||||
) | ||||
|
r32544 | ui.warn(avail.encode('utf-8')) | ||
|
r17648 | |||
|
r43346 | |||
|
r26411 | def checkseclevel(ui, doc, name, initlevel): | ||
|
r43350 | ui.notenoi18n('checking "%s"\n' % name) | ||
|
r32544 | if not isinstance(doc, bytes): | ||
doc = doc.encode('utf-8') | ||||
|
r17648 | blocks, pruned = minirst.parse(doc, 0, ['verbose']) | ||
errorcnt = 0 | ||||
curlevel = initlevel | ||||
for block in blocks: | ||||
|
r32544 | if block[b'type'] != b'section': | ||
|
r17648 | continue | ||
|
r32544 | mark = block[b'underline'] | ||
title = block[b'lines'][0] | ||||
|
r17648 | if (mark not in mark2level) or (mark2level[mark] <= initlevel): | ||
|
r43346 | ui.warn( | ||
( | ||||
'invalid section mark %r for "%s" of %s\n' | ||||
% (mark * 4, title, name) | ||||
).encode('utf-8') | ||||
) | ||||
|
r26411 | showavailables(ui, initlevel) | ||
|
r17648 | errorcnt += 1 | ||
continue | ||||
nextlevel = mark2level[mark] | ||||
if curlevel < nextlevel and curlevel + 1 != nextlevel: | ||||
|
r43350 | ui.warnnoi18n('gap of section level at "%s" of %s\n' % (title, name)) | ||
|
r26411 | showavailables(ui, initlevel) | ||
|
r17648 | errorcnt += 1 | ||
continue | ||||
|
r43350 | ui.notenoi18n( | ||
|
r43346 | 'appropriate section level for "%s %s"\n' | ||
% (mark * (nextlevel * 2), title) | ||||
) | ||||
|
r17648 | curlevel = nextlevel | ||
return errorcnt | ||||
|
r43346 | |||
|
r26411 | def checkcmdtable(ui, cmdtable, namefmt, initlevel): | ||
|
r17648 | errorcnt = 0 | ||
for k, entry in cmdtable.items(): | ||||
|
r32544 | name = k.split(b"|")[0].lstrip(b"^") | ||
|
r17648 | if not entry[0].__doc__: | ||
|
r43350 | ui.notenoi18n('skip checking %s: no help document\n' % (namefmt % name)) | ||
|
r17648 | continue | ||
|
r43346 | errorcnt += checkseclevel( | ||
ui, entry[0].__doc__, namefmt % name, initlevel | ||||
) | ||||
|
r17648 | return errorcnt | ||
|
r43346 | |||
|
r26411 | def checkhghelps(ui): | ||
|
r17648 | errorcnt = 0 | ||
|
r40328 | for h in helptable: | ||
names, sec, doc = h[0:3] | ||||
|
r21792 | if callable(doc): | ||
|
r26413 | doc = doc(ui) | ||
|
r43346 | errorcnt += checkseclevel( | ||
ui, doc, '%s help topic' % names[0], initlevel_topic | ||||
) | ||||
|
r17648 | |||
|
r26411 | errorcnt += checkcmdtable(ui, table, '%s command', initlevel_cmd) | ||
|
r17648 | |||
|
r43346 | for name in sorted( | ||
list(extensions.enabled()) + list(extensions.disabled()) | ||||
): | ||||
|
r27511 | mod = extensions.load(ui, name, None) | ||
|
r17648 | if not mod.__doc__: | ||
|
r43350 | ui.notenoi18n('skip checking %s extension: no help document\n' % name) | ||
|
r17648 | continue | ||
|
r43346 | errorcnt += checkseclevel( | ||
ui, mod.__doc__, '%s extension' % name, initlevel_ext | ||||
) | ||||
|
r17648 | |||
cmdtable = getattr(mod, 'cmdtable', None) | ||||
if cmdtable: | ||||
|
r43346 | errorcnt += checkcmdtable( | ||
ui, | ||||
cmdtable, | ||||
'%%s command of %s extension' % name, | ||||
initlevel_ext_cmd, | ||||
) | ||||
|
r17648 | return errorcnt | ||
|
r43346 | |||
|
r26411 | def checkfile(ui, filename, initlevel): | ||
|
r17648 | if filename == '-': | ||
filename = 'stdin' | ||||
doc = sys.stdin.read() | ||||
else: | ||||
|
r27770 | with open(filename) as fp: | ||
|
r17648 | doc = fp.read() | ||
|
r43350 | ui.notenoi18n( | ||
|
r43346 | 'checking input from %s with initlevel %d\n' % (filename, initlevel) | ||
) | ||||
|
r26411 | return checkseclevel(ui, doc, 'input from %s' % filename, initlevel) | ||
|
r17648 | |||
|
r43346 | |||
|
r26398 | def main(): | ||
|
r43346 | optparser = optparse.OptionParser( | ||
"""%prog [options] | ||||
|
r17648 | |||
This checks all help documents of Mercurial (topics, commands, | ||||
extensions and commands of them), if no file is specified by --file | ||||
option. | ||||
|
r43346 | """ | ||
) | ||||
optparser.add_option( | ||||
"-v", "--verbose", help="enable additional output", action="store_true" | ||||
) | ||||
optparser.add_option( | ||||
"-d", "--debug", help="debug mode", action="store_true" | ||||
) | ||||
optparser.add_option( | ||||
"-f", | ||||
"--file", | ||||
help="filename to read in (or '-' for stdin)", | ||||
action="store", | ||||
default="", | ||||
) | ||||
|
r17648 | |||
|
r43346 | optparser.add_option( | ||
"-t", | ||||
"--topic", | ||||
help="parse file as help topic", | ||||
action="store_const", | ||||
dest="initlevel", | ||||
const=0, | ||||
) | ||||
optparser.add_option( | ||||
"-c", | ||||
"--command", | ||||
help="parse file as help of core command", | ||||
action="store_const", | ||||
dest="initlevel", | ||||
const=1, | ||||
) | ||||
optparser.add_option( | ||||
"-e", | ||||
"--extension", | ||||
help="parse file as help of extension", | ||||
action="store_const", | ||||
dest="initlevel", | ||||
const=1, | ||||
) | ||||
optparser.add_option( | ||||
"-C", | ||||
"--extension-command", | ||||
help="parse file as help of extension command", | ||||
action="store_const", | ||||
dest="initlevel", | ||||
const=3, | ||||
) | ||||
|
r17648 | |||
|
r43346 | optparser.add_option( | ||
"-l", | ||||
"--initlevel", | ||||
help="set initial section level manually", | ||||
action="store", | ||||
type="int", | ||||
default=0, | ||||
) | ||||
|
r17648 | |||
(options, args) = optparser.parse_args() | ||||
|
r30559 | ui = uimod.ui.load() | ||
|
r41391 | ui.setconfig(b'ui', b'verbose', options.verbose, b'--verbose') | ||
ui.setconfig(b'ui', b'debug', options.debug, b'--debug') | ||||
|
r17648 | |||
if options.file: | ||||
|
r26411 | if checkfile(ui, options.file, options.initlevel): | ||
|
r17648 | sys.exit(1) | ||
else: | ||||
|
r26411 | if checkhghelps(ui): | ||
|
r17648 | sys.exit(1) | ||
|
r26398 | |||
|
r43346 | |||
|
r26398 | if __name__ == "__main__": | ||
main() | ||||