doc/check-seclevel.py
changeset 26411 dd62eaa82cbe
parent 26398 70abba798098
child 26413 e0c572d4d112
equal deleted inserted replaced
26410:4c4b3c37776c 26411:dd62eaa82cbe
    12 from mercurial import demandimport; demandimport.enable()
    12 from mercurial import demandimport; demandimport.enable()
    13 from mercurial.commands import table
    13 from mercurial.commands import table
    14 from mercurial.help import helptable
    14 from mercurial.help import helptable
    15 from mercurial import extensions
    15 from mercurial import extensions
    16 from mercurial import minirst
    16 from mercurial import minirst
    17 
    17 from mercurial import ui as uimod
    18 _verbose = False
       
    19 
       
    20 def verbose(msg):
       
    21     if _verbose:
       
    22         print msg
       
    23 
       
    24 def error(msg):
       
    25     sys.stderr.write('%s\n' % msg)
       
    26 
    18 
    27 level2mark = ['"', '=', '-', '.', '#']
    19 level2mark = ['"', '=', '-', '.', '#']
    28 reservedmarks = ['"']
    20 reservedmarks = ['"']
    29 
    21 
    30 mark2level = {}
    22 mark2level = {}
    35 initlevel_topic = 0
    27 initlevel_topic = 0
    36 initlevel_cmd = 1
    28 initlevel_cmd = 1
    37 initlevel_ext = 1
    29 initlevel_ext = 1
    38 initlevel_ext_cmd = 3
    30 initlevel_ext_cmd = 3
    39 
    31 
    40 def showavailables(initlevel):
    32 def showavailables(ui, initlevel):
    41     error('    available marks and order of them in this help: %s' %
    33     ui.warn(('    available marks and order of them in this help: %s\n') %
    42           (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]])))
    34             (', '.join(['%r' % (m * 4) for m in level2mark[initlevel + 1:]])))
    43 
    35 
    44 def checkseclevel(doc, name, initlevel):
    36 def checkseclevel(ui, doc, name, initlevel):
    45     verbose('checking "%s"' % name)
    37     ui.note(('checking "%s"\n') % name)
    46     blocks, pruned = minirst.parse(doc, 0, ['verbose'])
    38     blocks, pruned = minirst.parse(doc, 0, ['verbose'])
    47     errorcnt = 0
    39     errorcnt = 0
    48     curlevel = initlevel
    40     curlevel = initlevel
    49     for block in blocks:
    41     for block in blocks:
    50         if block['type'] != 'section':
    42         if block['type'] != 'section':
    51             continue
    43             continue
    52         mark = block['underline']
    44         mark = block['underline']
    53         title = block['lines'][0]
    45         title = block['lines'][0]
    54         if (mark not in mark2level) or (mark2level[mark] <= initlevel):
    46         if (mark not in mark2level) or (mark2level[mark] <= initlevel):
    55             error('invalid section mark %r for "%s" of %s' %
    47             ui.warn(('invalid section mark %r for "%s" of %s\n') %
    56                   (mark * 4, title, name))
    48                     (mark * 4, title, name))
    57             showavailables(initlevel)
    49             showavailables(ui, initlevel)
    58             errorcnt += 1
    50             errorcnt += 1
    59             continue
    51             continue
    60         nextlevel = mark2level[mark]
    52         nextlevel = mark2level[mark]
    61         if curlevel < nextlevel and curlevel + 1 != nextlevel:
    53         if curlevel < nextlevel and curlevel + 1 != nextlevel:
    62             error('gap of section level at "%s" of %s' %
    54             ui.warn(('gap of section level at "%s" of %s\n') %
    63                   (title, name))
    55                     (title, name))
    64             showavailables(initlevel)
    56             showavailables(ui, initlevel)
    65             errorcnt += 1
    57             errorcnt += 1
    66             continue
    58             continue
    67         verbose('appropriate section level for "%s %s"' %
    59         ui.note(('appropriate section level for "%s %s"\n') %
    68                 (mark * (nextlevel * 2), title))
    60                 (mark * (nextlevel * 2), title))
    69         curlevel = nextlevel
    61         curlevel = nextlevel
    70 
    62 
    71     return errorcnt
    63     return errorcnt
    72 
    64 
    73 def checkcmdtable(cmdtable, namefmt, initlevel):
    65 def checkcmdtable(ui, cmdtable, namefmt, initlevel):
    74     errorcnt = 0
    66     errorcnt = 0
    75     for k, entry in cmdtable.items():
    67     for k, entry in cmdtable.items():
    76         name = k.split("|")[0].lstrip("^")
    68         name = k.split("|")[0].lstrip("^")
    77         if not entry[0].__doc__:
    69         if not entry[0].__doc__:
    78             verbose('skip checking %s: no help document' %
    70             ui.note(('skip checking %s: no help document\n') %
    79                     (namefmt % name))
    71                     (namefmt % name))
    80             continue
    72             continue
    81         errorcnt += checkseclevel(entry[0].__doc__,
    73         errorcnt += checkseclevel(ui, entry[0].__doc__,
    82                                   namefmt % name,
    74                                   namefmt % name,
    83                                   initlevel)
    75                                   initlevel)
    84     return errorcnt
    76     return errorcnt
    85 
    77 
    86 def checkhghelps():
    78 def checkhghelps(ui):
    87     errorcnt = 0
    79     errorcnt = 0
    88     for names, sec, doc in helptable:
    80     for names, sec, doc in helptable:
    89         if callable(doc):
    81         if callable(doc):
    90             doc = doc()
    82             doc = doc()
    91         errorcnt += checkseclevel(doc,
    83         errorcnt += checkseclevel(ui, doc,
    92                                   '%s help topic' % names[0],
    84                                   '%s help topic' % names[0],
    93                                   initlevel_topic)
    85                                   initlevel_topic)
    94 
    86 
    95     errorcnt += checkcmdtable(table, '%s command', initlevel_cmd)
    87     errorcnt += checkcmdtable(ui, table, '%s command', initlevel_cmd)
    96 
    88 
    97     for name in sorted(extensions.enabled().keys() +
    89     for name in sorted(extensions.enabled().keys() +
    98                        extensions.disabled().keys()):
    90                        extensions.disabled().keys()):
    99         mod = extensions.load(None, name, None)
    91         mod = extensions.load(None, name, None)
   100         if not mod.__doc__:
    92         if not mod.__doc__:
   101             verbose('skip checking %s extension: no help document' % name)
    93             ui.note(('skip checking %s extension: no help document\n') % name)
   102             continue
    94             continue
   103         errorcnt += checkseclevel(mod.__doc__,
    95         errorcnt += checkseclevel(ui, mod.__doc__,
   104                                   '%s extension' % name,
    96                                   '%s extension' % name,
   105                                   initlevel_ext)
    97                                   initlevel_ext)
   106 
    98 
   107         cmdtable = getattr(mod, 'cmdtable', None)
    99         cmdtable = getattr(mod, 'cmdtable', None)
   108         if cmdtable:
   100         if cmdtable:
   109             errorcnt += checkcmdtable(cmdtable,
   101             errorcnt += checkcmdtable(ui, cmdtable,
   110                                       '%s command of ' + name + ' extension',
   102                                       '%s command of ' + name + ' extension',
   111                                       initlevel_ext_cmd)
   103                                       initlevel_ext_cmd)
   112     return errorcnt
   104     return errorcnt
   113 
   105 
   114 def checkfile(filename, initlevel):
   106 def checkfile(ui, filename, initlevel):
   115     if filename == '-':
   107     if filename == '-':
   116         filename = 'stdin'
   108         filename = 'stdin'
   117         doc = sys.stdin.read()
   109         doc = sys.stdin.read()
   118     else:
   110     else:
   119         fp = open(filename)
   111         fp = open(filename)
   120         try:
   112         try:
   121             doc = fp.read()
   113             doc = fp.read()
   122         finally:
   114         finally:
   123             fp.close()
   115             fp.close()
   124 
   116 
   125     verbose('checking input from %s with initlevel %d' %
   117     ui.note(('checking input from %s with initlevel %d\n') %
   126             (filename, initlevel))
   118             (filename, initlevel))
   127     return checkseclevel(doc, 'input from %s' % filename, initlevel)
   119     return checkseclevel(ui, doc, 'input from %s' % filename, initlevel)
   128 
   120 
   129 def main():
   121 def main():
   130     optparser = optparse.OptionParser("""%prog [options]
   122     optparser = optparse.OptionParser("""%prog [options]
   131 
   123 
   132 This checks all help documents of Mercurial (topics, commands,
   124 This checks all help documents of Mercurial (topics, commands,
   157                          help="set initial section level manually",
   149                          help="set initial section level manually",
   158                          action="store", type="int", default=0)
   150                          action="store", type="int", default=0)
   159 
   151 
   160     (options, args) = optparser.parse_args()
   152     (options, args) = optparser.parse_args()
   161 
   153 
   162     global _verbose
   154     ui = uimod.ui()
   163     _verbose = options.verbose
   155     ui.setconfig('ui', 'verbose', options.verbose, '--verbose')
   164 
   156 
   165     if options.file:
   157     if options.file:
   166         if checkfile(options.file, options.initlevel):
   158         if checkfile(ui, options.file, options.initlevel):
   167             sys.exit(1)
   159             sys.exit(1)
   168     else:
   160     else:
   169         if checkhghelps():
   161         if checkhghelps(ui):
   170             sys.exit(1)
   162             sys.exit(1)
   171 
   163 
   172 if __name__ == "__main__":
   164 if __name__ == "__main__":
   173     main()
   165     main()