hgbook

diff en/cmdref.py @ 225:a631aca1083f

Add special PDF header goo.
author Bryan O'Sullivan <bos@serpentine.com>
date Tue May 15 16:40:08 2007 -0700 (2007-05-15)
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/en/cmdref.py	Tue May 15 16:40:08 2007 -0700
     1.3 @@ -0,0 +1,156 @@
     1.4 +#!/usr/bin/env python
     1.5 +
     1.6 +import getopt
     1.7 +import itertools
     1.8 +import os
     1.9 +import re
    1.10 +import sys
    1.11 +
    1.12 +def usage(exitcode):
    1.13 +    print >> sys.stderr, ('usage: %s [-H|--hidden] hg_repo' % 
    1.14 +                          os.path.basename(sys.argv[0]))
    1.15 +    sys.exit(exitcode)
    1.16 +
    1.17 +try:
    1.18 +    opts, args = getopt.getopt(sys.argv[1:], 'AHh?', ['all', 'help', 'hidden'])
    1.19 +    opt_all = False
    1.20 +    opt_hidden = False
    1.21 +    for o, a in opts:
    1.22 +        if o in ('-h', '-?', '--help'):
    1.23 +            usage(0)
    1.24 +        if o in ('-A', '--all'):
    1.25 +            opt_all = True
    1.26 +        if o in ('-H', '--hidden'):
    1.27 +            opt_hidden = True
    1.28 +except getopt.GetoptError, err:
    1.29 +    print >> sys.stderr, 'error:', err
    1.30 +    usage(1)
    1.31 +
    1.32 +try:
    1.33 +    hg_repo, ltx_file = args
    1.34 +except ValueError:
    1.35 +    usage(1)
    1.36 +
    1.37 +if not os.path.isfile(os.path.join(hg_repo, 'mercurial', 'commands.py')):
    1.38 +    print >> sys.stderr, ('error: %r does not contain mercurial code' %
    1.39 +                          hg_repo)
    1.40 +    sys.exit(1)
    1.41 +
    1.42 +sys.path.insert(0, hg_repo)
    1.43 +
    1.44 +from mercurial import commands
    1.45 +
    1.46 +def get_commands():
    1.47 +    seen = {}
    1.48 +    for name, info in sorted(commands.table.iteritems()):
    1.49 +        aliases = name.split('|', 1)
    1.50 +        name = aliases.pop(0).lstrip('^')
    1.51 +        function, options, synopsis = info
    1.52 +        seen[name] = {}
    1.53 +        for shortopt, longopt, arg, desc in options:
    1.54 +            seen[name][longopt] = shortopt
    1.55 +    return seen
    1.56 +
    1.57 +def cmd_filter((name, aliases, options)):
    1.58 +    if opt_all:
    1.59 +        return True
    1.60 +    if opt_hidden:
    1.61 +        return name.startswith('debug')
    1.62 +    return not name.startswith('debug')
    1.63 +
    1.64 +def scan(ltx_file):
    1.65 +    cmdref_re = re.compile(r'^\\cmdref{(?P<cmd>\w+)}')
    1.66 +    optref_re = re.compile(r'^\\l?optref{(?P<cmd>\w+)}'
    1.67 +                           r'(?:{(?P<short>[^}])})?'
    1.68 +                           r'{(?P<long>[^}]+)}')
    1.69 +
    1.70 +    seen = {}
    1.71 +    locs = {}
    1.72 +    for lnum, line in enumerate(open(ltx_file)):
    1.73 +        m = cmdref_re.match(line)
    1.74 +        if m:
    1.75 +            d = m.groupdict()
    1.76 +            cmd = d['cmd']
    1.77 +            seen[cmd] = {}
    1.78 +            locs[cmd] = lnum + 1
    1.79 +            continue
    1.80 +        m = optref_re.match(line)
    1.81 +        if m:
    1.82 +            d = m.groupdict()
    1.83 +            seen[d['cmd']][d['long']] = d['short']
    1.84 +            continue
    1.85 +    return seen, locs
    1.86 +    
    1.87 +documented, locs = scan(ltx_file)
    1.88 +known = get_commands()
    1.89 +
    1.90 +doc_set = set(documented)
    1.91 +known_set = set(known)
    1.92 +
    1.93 +errors = 0
    1.94 +
    1.95 +for nonexistent in sorted(doc_set.difference(known_set)):
    1.96 +    print >> sys.stderr, ('%s:%d: %r command does not exist' %
    1.97 +                          (ltx_file, locs[nonexistent], nonexistent))
    1.98 +    errors += 1
    1.99 +
   1.100 +def optcmp(a, b):
   1.101 +    la, sa = a
   1.102 +    lb, sb = b
   1.103 +    sc = cmp(sa, sb)
   1.104 +    if sc:
   1.105 +        return sc
   1.106 +    return cmp(la, lb)
   1.107 +
   1.108 +for cmd in doc_set.intersection(known_set):
   1.109 +    doc_opts = documented[cmd]
   1.110 +    known_opts = known[cmd]
   1.111 +    
   1.112 +    do_set = set(doc_opts)
   1.113 +    ko_set = set(known_opts)
   1.114 +
   1.115 +    for nonexistent in sorted(do_set.difference(ko_set)):
   1.116 +        print >> sys.stderr, ('%s:%d: %r option to %r command does not exist' %
   1.117 +                              (ltx_file, locs[cmd], nonexistent, cmd))
   1.118 +        errors += 1
   1.119 +
   1.120 +    def mycmp(la, lb):
   1.121 +        sa = known_opts[la]
   1.122 +        sb = known_opts[lb]
   1.123 +        return optcmp((la, sa), (lb, sb))
   1.124 +
   1.125 +    for undocumented in sorted(ko_set.difference(do_set), cmp=mycmp):
   1.126 +        print >> sys.stderr, ('%s:%d: %r option to %r command not documented' %
   1.127 +                              (ltx_file, locs[cmd], undocumented, cmd))
   1.128 +        shortopt = known_opts[undocumented]
   1.129 +        if shortopt:
   1.130 +            print '\optref{%s}{%s}{%s}' % (cmd, shortopt, undocumented)
   1.131 +        else:
   1.132 +            print '\loptref{%s}{%s}' % (cmd, undocumented)
   1.133 +        errors += 1
   1.134 +    sys.stdout.flush()
   1.135 +
   1.136 +if errors:
   1.137 +    sys.exit(1)
   1.138 +
   1.139 +sorted_locs = sorted(locs.iteritems(), key=lambda x:x[1])
   1.140 +
   1.141 +def next_loc(cmd):
   1.142 +    for i, (name, loc) in enumerate(sorted_locs):
   1.143 +        if name >= cmd:
   1.144 +            return sorted_locs[i-1][1] + 1
   1.145 +    return loc
   1.146 +
   1.147 +for undocumented in sorted(known_set.difference(doc_set)):
   1.148 +    print >> sys.stderr, ('%s:%d: %r command not documented' %
   1.149 +                          (ltx_file, next_loc(undocumented), undocumented))
   1.150 +    print '\cmdref{%s}' % undocumented
   1.151 +    for longopt, shortopt in sorted(known[undocumented].items(), cmp=optcmp):
   1.152 +        if shortopt:
   1.153 +            print '\optref{%s}{%s}{%s}' % (undocumented, shortopt, longopt)
   1.154 +        else:
   1.155 +            print '\loptref{%s}{%s}' % (undocumented, longopt)
   1.156 +    sys.stdout.flush()
   1.157 +    errors += 1
   1.158 +
   1.159 +sys.exit(errors and 1 or 0)