doc/check-seclevel.py
branchstable
changeset 26813 b66e3ca0b90c
parent 26413 e0c572d4d112
child 27221 ab776610fc6d
equal deleted inserted replaced
26535:d3712209921d 26813:b66e3ca0b90c
     1 #!/usr/bin/env python
     1 #!/usr/bin/env python
     2 #
     2 #
     3 # checkseclevel - checking section title levels in each online help documents
     3 # checkseclevel - checking section title levels in each online help document
     4 
     4 
     5 import sys, os
     5 import sys, os
     6 import optparse
     6 import optparse
     7 
     7 
     8 # import from the live mercurial repo
     8 # import from the live mercurial repo
    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(ui)
    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 if __name__ == "__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,
   133 extensions and commands of them), if no file is specified by --file
   125 extensions and commands of them), if no file is specified by --file
   134 option.
   126 option.
   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     _verbose = options.verbose
   154     ui = uimod.ui()
       
   155     ui.setconfig('ui', 'verbose', options.verbose, '--verbose')
   163 
   156 
   164     if options.file:
   157     if options.file:
   165         if checkfile(options.file, options.initlevel):
   158         if checkfile(ui, options.file, options.initlevel):
   166             sys.exit(1)
   159             sys.exit(1)
   167     else:
   160     else:
   168         if checkhghelps():
   161         if checkhghelps(ui):
   169             sys.exit(1)
   162             sys.exit(1)
       
   163 
       
   164 if __name__ == "__main__":
       
   165     main()