hgbook

view en/cmdref.py @ 307:fb5c0d56d7f1

Fix test 'tour'.

Executing 'tour' test now creates some files in /tmp to store the
revision numbers as they are created on the fly and appear in the output
files. When SVG files are to be converted to PNG or EPS files within the
Makefile, a tool 'fixsvg' will be invoked to substitute some placeholder
markup by the real version number which fits to the test output, before
the final conversion takes place.
author Guido Ostkamp <hg@ostkamp.fastmail.fm>
date Wed Aug 20 22:15:35 2008 +0200 (2008-08-20)
parents
children
line source
1 #!/usr/bin/env python
3 import getopt
4 import itertools
5 import os
6 import re
7 import sys
9 def usage(exitcode):
10 print >> sys.stderr, ('usage: %s [-H|--hidden] hg_repo' %
11 os.path.basename(sys.argv[0]))
12 sys.exit(exitcode)
14 try:
15 opts, args = getopt.getopt(sys.argv[1:], 'AHh?', ['all', 'help', 'hidden'])
16 opt_all = False
17 opt_hidden = False
18 for o, a in opts:
19 if o in ('-h', '-?', '--help'):
20 usage(0)
21 if o in ('-A', '--all'):
22 opt_all = True
23 if o in ('-H', '--hidden'):
24 opt_hidden = True
25 except getopt.GetoptError, err:
26 print >> sys.stderr, 'error:', err
27 usage(1)
29 try:
30 hg_repo, ltx_file = args
31 except ValueError:
32 usage(1)
34 if not os.path.isfile(os.path.join(hg_repo, 'mercurial', 'commands.py')):
35 print >> sys.stderr, ('error: %r does not contain mercurial code' %
36 hg_repo)
37 sys.exit(1)
39 sys.path.insert(0, hg_repo)
41 from mercurial import commands
43 def get_commands():
44 seen = {}
45 for name, info in sorted(commands.table.iteritems()):
46 aliases = name.split('|', 1)
47 name = aliases.pop(0).lstrip('^')
48 function, options, synopsis = info
49 seen[name] = {}
50 for shortopt, longopt, arg, desc in options:
51 seen[name][longopt] = shortopt
52 return seen
54 def cmd_filter((name, aliases, options)):
55 if opt_all:
56 return True
57 if opt_hidden:
58 return name.startswith('debug')
59 return not name.startswith('debug')
61 def scan(ltx_file):
62 cmdref_re = re.compile(r'^\\cmdref{(?P<cmd>\w+)}')
63 optref_re = re.compile(r'^\\l?optref{(?P<cmd>\w+)}'
64 r'(?:{(?P<short>[^}])})?'
65 r'{(?P<long>[^}]+)}')
67 seen = {}
68 locs = {}
69 for lnum, line in enumerate(open(ltx_file)):
70 m = cmdref_re.match(line)
71 if m:
72 d = m.groupdict()
73 cmd = d['cmd']
74 seen[cmd] = {}
75 locs[cmd] = lnum + 1
76 continue
77 m = optref_re.match(line)
78 if m:
79 d = m.groupdict()
80 seen[d['cmd']][d['long']] = d['short']
81 continue
82 return seen, locs
84 documented, locs = scan(ltx_file)
85 known = get_commands()
87 doc_set = set(documented)
88 known_set = set(known)
90 errors = 0
92 for nonexistent in sorted(doc_set.difference(known_set)):
93 print >> sys.stderr, ('%s:%d: %r command does not exist' %
94 (ltx_file, locs[nonexistent], nonexistent))
95 errors += 1
97 def optcmp(a, b):
98 la, sa = a
99 lb, sb = b
100 sc = cmp(sa, sb)
101 if sc:
102 return sc
103 return cmp(la, lb)
105 for cmd in doc_set.intersection(known_set):
106 doc_opts = documented[cmd]
107 known_opts = known[cmd]
109 do_set = set(doc_opts)
110 ko_set = set(known_opts)
112 for nonexistent in sorted(do_set.difference(ko_set)):
113 print >> sys.stderr, ('%s:%d: %r option to %r command does not exist' %
114 (ltx_file, locs[cmd], nonexistent, cmd))
115 errors += 1
117 def mycmp(la, lb):
118 sa = known_opts[la]
119 sb = known_opts[lb]
120 return optcmp((la, sa), (lb, sb))
122 for undocumented in sorted(ko_set.difference(do_set), cmp=mycmp):
123 print >> sys.stderr, ('%s:%d: %r option to %r command not documented' %
124 (ltx_file, locs[cmd], undocumented, cmd))
125 shortopt = known_opts[undocumented]
126 if shortopt:
127 print '\optref{%s}{%s}{%s}' % (cmd, shortopt, undocumented)
128 else:
129 print '\loptref{%s}{%s}' % (cmd, undocumented)
130 errors += 1
131 sys.stdout.flush()
133 if errors:
134 sys.exit(1)
136 sorted_locs = sorted(locs.iteritems(), key=lambda x:x[1])
138 def next_loc(cmd):
139 for i, (name, loc) in enumerate(sorted_locs):
140 if name >= cmd:
141 return sorted_locs[i-1][1] + 1
142 return loc
144 for undocumented in sorted(known_set.difference(doc_set)):
145 print >> sys.stderr, ('%s:%d: %r command not documented' %
146 (ltx_file, next_loc(undocumented), undocumented))
147 print '\cmdref{%s}' % undocumented
148 for longopt, shortopt in sorted(known[undocumented].items(), cmp=optcmp):
149 if shortopt:
150 print '\optref{%s}{%s}{%s}' % (undocumented, shortopt, longopt)
151 else:
152 print '\loptref{%s}{%s}' % (undocumented, longopt)
153 sys.stdout.flush()
154 errors += 1
156 sys.exit(errors and 1 or 0)