PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/doc/check-seclevel.py

https://bitbucket.org/mirror/mercurial/
Python | 169 lines | 145 code | 19 blank | 5 comment | 23 complexity | 8f94f7f305fd539ebc34802ba0843acb MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/usr/bin/env python
  2. #
  3. # checkseclevel - checking section title levels in each online help documents
  4. import sys, os
  5. import optparse
  6. # import from the live mercurial repo
  7. sys.path.insert(0, "..")
  8. # fall back to pure modules if required C extensions are not available
  9. sys.path.append(os.path.join('..', 'mercurial', 'pure'))
  10. from mercurial import demandimport; demandimport.enable()
  11. from mercurial.commands import table
  12. from mercurial.help import helptable
  13. from mercurial import extensions
  14. from mercurial import minirst
  15. _verbose = False
  16. def verbose(msg):
  17. if _verbose:
  18. print msg
  19. def error(msg):
  20. sys.stderr.write('%s\n' % msg)
  21. level2mark = ['"', '=', '-', '.', '#']
  22. reservedmarks = ['"']
  23. mark2level = {}
  24. for m, l in zip(level2mark, xrange(len(level2mark))):
  25. if m not in reservedmarks:
  26. mark2level[m] = l
  27. initlevel_topic = 0
  28. initlevel_cmd = 1
  29. initlevel_ext = 1
  30. initlevel_ext_cmd = 3
  31. def showavailables(initlevel):
  32. error(' available marks and order of them in this help: %s' %
  33. (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]])))
  34. def checkseclevel(doc, name, initlevel):
  35. verbose('checking "%s"' % name)
  36. blocks, pruned = minirst.parse(doc, 0, ['verbose'])
  37. errorcnt = 0
  38. curlevel = initlevel
  39. for block in blocks:
  40. if block['type'] != 'section':
  41. continue
  42. mark = block['underline']
  43. title = block['lines'][0]
  44. if (mark not in mark2level) or (mark2level[mark] <= initlevel):
  45. error('invalid section mark %r for "%s" of %s' %
  46. (mark * 4, title, name))
  47. showavailables(initlevel)
  48. errorcnt += 1
  49. continue
  50. nextlevel = mark2level[mark]
  51. if curlevel < nextlevel and curlevel + 1 != nextlevel:
  52. error('gap of section level at "%s" of %s' %
  53. (title, name))
  54. showavailables(initlevel)
  55. errorcnt += 1
  56. continue
  57. verbose('appropriate section level for "%s %s"' %
  58. (mark * (nextlevel * 2), title))
  59. curlevel = nextlevel
  60. return errorcnt
  61. def checkcmdtable(cmdtable, namefmt, initlevel):
  62. errorcnt = 0
  63. for k, entry in cmdtable.items():
  64. name = k.split("|")[0].lstrip("^")
  65. if not entry[0].__doc__:
  66. verbose('skip checking %s: no help document' %
  67. (namefmt % name))
  68. continue
  69. errorcnt += checkseclevel(entry[0].__doc__,
  70. namefmt % name,
  71. initlevel)
  72. return errorcnt
  73. def checkhghelps():
  74. errorcnt = 0
  75. for names, sec, doc in helptable:
  76. if callable(doc):
  77. doc = doc()
  78. errorcnt += checkseclevel(doc,
  79. '%s help topic' % names[0],
  80. initlevel_topic)
  81. errorcnt += checkcmdtable(table, '%s command', initlevel_cmd)
  82. for name in sorted(extensions.enabled().keys() +
  83. extensions.disabled().keys()):
  84. mod = extensions.load(None, name, None)
  85. if not mod.__doc__:
  86. verbose('skip checking %s extension: no help document' % name)
  87. continue
  88. errorcnt += checkseclevel(mod.__doc__,
  89. '%s extension' % name,
  90. initlevel_ext)
  91. cmdtable = getattr(mod, 'cmdtable', None)
  92. if cmdtable:
  93. errorcnt += checkcmdtable(cmdtable,
  94. '%s command of ' + name + ' extension',
  95. initlevel_ext_cmd)
  96. return errorcnt
  97. def checkfile(filename, initlevel):
  98. if filename == '-':
  99. filename = 'stdin'
  100. doc = sys.stdin.read()
  101. else:
  102. fp = open(filename)
  103. try:
  104. doc = fp.read()
  105. finally:
  106. fp.close()
  107. verbose('checking input from %s with initlevel %d' %
  108. (filename, initlevel))
  109. return checkseclevel(doc, 'input from %s' % filename, initlevel)
  110. if __name__ == "__main__":
  111. optparser = optparse.OptionParser("""%prog [options]
  112. This checks all help documents of Mercurial (topics, commands,
  113. extensions and commands of them), if no file is specified by --file
  114. option.
  115. """)
  116. optparser.add_option("-v", "--verbose",
  117. help="enable additional output",
  118. action="store_true")
  119. optparser.add_option("-f", "--file",
  120. help="filename to read in (or '-' for stdin)",
  121. action="store", default="")
  122. optparser.add_option("-t", "--topic",
  123. help="parse file as help topic",
  124. action="store_const", dest="initlevel", const=0)
  125. optparser.add_option("-c", "--command",
  126. help="parse file as help of core command",
  127. action="store_const", dest="initlevel", const=1)
  128. optparser.add_option("-e", "--extension",
  129. help="parse file as help of extension",
  130. action="store_const", dest="initlevel", const=1)
  131. optparser.add_option("-C", "--extension-command",
  132. help="parse file as help of extension command",
  133. action="store_const", dest="initlevel", const=3)
  134. optparser.add_option("-l", "--initlevel",
  135. help="set initial section level manually",
  136. action="store", type="int", default=0)
  137. (options, args) = optparser.parse_args()
  138. _verbose = options.verbose
  139. if options.file:
  140. if checkfile(options.file, options.initlevel):
  141. sys.exit(1)
  142. else:
  143. if checkhghelps():
  144. sys.exit(1)