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