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))
88 last_was_option = False
92 out.append('%s%s\n' % (last_was_option and '\n' or '',
94 last_was_option = False
96 (flags, extra) = l.split(' ', 1)
98 if flags.endswith('='):
103 g = re.search(r'\[([^\]]*)\]$', extra)
108 flagl = flags.split(',')
111 f,dvi = _remove_negative_kv(f, _intify(defval))
112 self._aliases[f] = _remove_negative_k(flagl[0])
113 self._hasparms[f] = has_parm
114 self._defaults[f] = dvi
116 self._shortopts += f + (has_parm and ':' or '')
117 flagl_nice.append('-' + f)
119 f_nice = re.sub(r'\W', '_', f)
120 self._aliases[f_nice] = _remove_negative_k(flagl[0])
121 self._longopts.append(f + (has_parm and '=' or ''))
122 self._longopts.append('no-' + f)
123 flagl_nice.append('--' + f)
124 flags_nice = ', '.join(flagl_nice)
127 prefix = ' %-20s ' % flags_nice
128 argtext = '\n'.join(textwrap.wrap(extra, width=70,
129 initial_indent=prefix,
130 subsequent_indent=' '*28))
131 out.append(argtext + '\n')
132 last_was_option = True
135 last_was_option = False
136 return ''.join(out).rstrip() + '\n'
138 def usage(self, msg=""):
139 """Print usage string to stderr and abort."""
140 sys.stderr.write(self._usagestr)
141 e = self._onabort and self._onabort(msg) or None
146 """Print an error message to stderr and abort with usage string."""
147 msg = 'error: %s\n' % s
148 sys.stderr.write(msg)
149 return self.usage(msg)
151 def parse(self, args):
152 """Parse a list of arguments and return (options, flags, extra).
154 In the returned tuple, "options" is an OptDict with known options,
155 "flags" is a list of option flags that were used on the command-line,
156 and "extra" is a list of positional arguments.
159 (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
160 except getopt.GetoptError, e:
165 for k,v in self._defaults.iteritems():
171 if k in ('h', '?', 'help'):
173 if k.startswith('no-'):
174 k = self._aliases[k[3:]]
178 if not self._hasparms[k]:
180 v = (opt._opts.get(k) or 0) + 1
184 for (f1,f2) in self._aliases.iteritems():
185 opt[f1] = opt._opts.get(f2)
186 return (opt,flags,extra)