mirror of
https://github.com/facebook/sapling.git
synced 2024-10-11 01:07:15 +03:00
807a8f6caa
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 8d980034517b.
171 lines
5.7 KiB
Python
171 lines
5.7 KiB
Python
#!/usr/bin/env python
|
|
#
|
|
# checkseclevel - checking section title levels in each online help documents
|
|
|
|
import sys, os
|
|
import optparse
|
|
|
|
# import from the live mercurial repo
|
|
sys.path.insert(0, "..")
|
|
# fall back to pure modules if required C extensions are not available
|
|
sys.path.append(os.path.join('..', 'mercurial', 'pure'))
|
|
from mercurial import demandimport; demandimport.enable()
|
|
from mercurial.commands import table
|
|
from mercurial.help import helptable
|
|
from mercurial import extensions
|
|
from mercurial import minirst
|
|
from mercurial import util
|
|
|
|
_verbose = False
|
|
|
|
def verbose(msg):
|
|
if _verbose:
|
|
print msg
|
|
|
|
def error(msg):
|
|
sys.stderr.write('%s\n' % msg)
|
|
|
|
level2mark = ['"', '=', '-', '.', '#']
|
|
reservedmarks = ['"']
|
|
|
|
mark2level = {}
|
|
for m, l in zip(level2mark, xrange(len(level2mark))):
|
|
if m not in reservedmarks:
|
|
mark2level[m] = l
|
|
|
|
initlevel_topic = 0
|
|
initlevel_cmd = 1
|
|
initlevel_ext = 1
|
|
initlevel_ext_cmd = 3
|
|
|
|
def showavailables(initlevel):
|
|
error(' available marks and order of them in this help: %s' %
|
|
(', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]])))
|
|
|
|
def checkseclevel(doc, name, initlevel):
|
|
verbose('checking "%s"' % name)
|
|
blocks, pruned = minirst.parse(doc, 0, ['verbose'])
|
|
errorcnt = 0
|
|
curlevel = initlevel
|
|
for block in blocks:
|
|
if block['type'] != 'section':
|
|
continue
|
|
mark = block['underline']
|
|
title = block['lines'][0]
|
|
if (mark not in mark2level) or (mark2level[mark] <= initlevel):
|
|
error('invalid section mark %r for "%s" of %s' %
|
|
(mark * 4, title, name))
|
|
showavailables(initlevel)
|
|
errorcnt += 1
|
|
continue
|
|
nextlevel = mark2level[mark]
|
|
if curlevel < nextlevel and curlevel + 1 != nextlevel:
|
|
error('gap of section level at "%s" of %s' %
|
|
(title, name))
|
|
showavailables(initlevel)
|
|
errorcnt += 1
|
|
continue
|
|
verbose('appropriate section level for "%s %s"' %
|
|
(mark * (nextlevel * 2), title))
|
|
curlevel = nextlevel
|
|
|
|
return errorcnt
|
|
|
|
def checkcmdtable(cmdtable, namefmt, initlevel):
|
|
errorcnt = 0
|
|
for k, entry in cmdtable.items():
|
|
name = k.split("|")[0].lstrip("^")
|
|
if not entry[0].__doc__:
|
|
verbose('skip checking %s: no help document' %
|
|
(namefmt % name))
|
|
continue
|
|
errorcnt += checkseclevel(entry[0].__doc__,
|
|
namefmt % name,
|
|
initlevel)
|
|
return errorcnt
|
|
|
|
def checkhghelps():
|
|
errorcnt = 0
|
|
for names, sec, doc in helptable:
|
|
if util.safehasattr(doc, '__call__'):
|
|
doc = doc()
|
|
errorcnt += checkseclevel(doc,
|
|
'%s help topic' % names[0],
|
|
initlevel_topic)
|
|
|
|
errorcnt += checkcmdtable(table, '%s command', initlevel_cmd)
|
|
|
|
for name in sorted(extensions.enabled().keys() +
|
|
extensions.disabled().keys()):
|
|
mod = extensions.load(None, name, None)
|
|
if not mod.__doc__:
|
|
verbose('skip checking %s extension: no help document' % name)
|
|
continue
|
|
errorcnt += checkseclevel(mod.__doc__,
|
|
'%s extension' % name,
|
|
initlevel_ext)
|
|
|
|
cmdtable = getattr(mod, 'cmdtable', None)
|
|
if cmdtable:
|
|
errorcnt += checkcmdtable(cmdtable,
|
|
'%s command of ' + name + ' extension',
|
|
initlevel_ext_cmd)
|
|
return errorcnt
|
|
|
|
def checkfile(filename, initlevel):
|
|
if filename == '-':
|
|
filename = 'stdin'
|
|
doc = sys.stdin.read()
|
|
else:
|
|
fp = open(filename)
|
|
try:
|
|
doc = fp.read()
|
|
finally:
|
|
fp.close()
|
|
|
|
verbose('checking input from %s with initlevel %d' %
|
|
(filename, initlevel))
|
|
return checkseclevel(doc, 'input from %s' % filename, initlevel)
|
|
|
|
if __name__ == "__main__":
|
|
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")
|
|
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()
|
|
|
|
_verbose = options.verbose
|
|
|
|
if options.file:
|
|
if checkfile(options.file, options.initlevel):
|
|
sys.exit(1)
|
|
else:
|
|
if checkhghelps():
|
|
sys.exit(1)
|