1 """Command-line options parser.
2 With the help of an options spec string, easily parse command-line options.
13 def __setitem__(self, k, v):
14 if k.startswith('no-') or k.startswith('no_'):
19 def __getitem__(self, k):
20 if k.startswith('no-') or k.startswith('no_'):
21 return not self._opts[k[3:]]
24 def __getattr__(self, k):
28 def _default_onabort(msg):
42 def _remove_negative_kv(k, v):
43 if k.startswith('no-') or k.startswith('no_'):
47 def _remove_negative_k(k):
48 return _remove_negative_kv(k, None)[0]
53 When constructed, two strings are mandatory. The first one is the command
54 name showed before error messages. The second one is a string called an
55 optspec that specifies the synopsis and option flags and their description.
56 For more information about optspecs, consult the bup-options(1) man page.
58 Two optional arguments specify an alternative parsing function and an
59 alternative behaviour on abort (after having output the usage string).
61 By default, the parser function is getopt.gnu_getopt, and the abort
62 behaviour is to exit the program.
64 def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt,
65 onabort=_default_onabort):
67 self.optspec = optspec
68 self._onabort = onabort
69 self.optfunc = optfunc
71 self._shortopts = 'h?'
72 self._longopts = ['help']
75 self._usagestr = self._gen_usage()
79 lines = self.optspec.strip().split('\n')
85 out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
91 out.append('\n%s\n' % l.lstrip())
93 (flags, extra) = l.split(' ', 1)
95 if flags.endswith('='):
100 g = re.search(r'\[([^\]]*)\]', extra)
105 flagl = flags.split(',')
108 f,dvi = _remove_negative_kv(f, _intify(defval))
109 self._aliases[f] = _remove_negative_k(flagl[0])
110 self._hasparms[f] = has_parm
111 self._defaults[f] = dvi
113 self._shortopts += f + (has_parm and ':' or '')
114 flagl_nice.append('-' + f)
116 f_nice = re.sub(r'\W', '_', f)
117 self._aliases[f_nice] = _remove_negative_k(flagl[0])
118 self._longopts.append(f + (has_parm and '=' or ''))
119 self._longopts.append('no-' + f)
120 flagl_nice.append('--' + f)
121 flags_nice = ', '.join(flagl_nice)
124 prefix = ' %-20s ' % flags_nice
125 argtext = '\n'.join(textwrap.wrap(extra, width=70,
126 initial_indent=prefix,
127 subsequent_indent=' '*28))
128 out.append(argtext + '\n')
131 return ''.join(out).rstrip() + '\n'
133 def usage(self, msg=""):
134 """Print usage string to stderr and abort."""
135 sys.stderr.write(self._usagestr)
136 e = self._onabort and self._onabort(msg) or None
141 """Print an error message to stderr and abort with usage string."""
142 msg = 'error: %s\n' % s
143 sys.stderr.write(msg)
144 return self.usage(msg)
146 def parse(self, args):
147 """Parse a list of arguments and return (options, flags, extra).
149 In the returned tuple, "options" is an OptDict with known options,
150 "flags" is a list of option flags that were used on the command-line,
151 and "extra" is a list of positional arguments.
154 (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
155 except getopt.GetoptError, e:
160 for k,v in self._defaults.iteritems():
166 if k in ('h', '?', 'help'):
168 if k.startswith('no-'):
169 k = self._aliases[k[3:]]
173 if not self._hasparms[k]:
175 v = (opt._opts.get(k) or 0) + 1
179 for (f1,f2) in self._aliases.iteritems():
180 opt[f1] = opt._opts.get(f2)
181 return (opt,flags,extra)