1 """Command-line options parser.
2 With the help of an options spec string, easily parse command-line options.
4 import sys, os, textwrap, getopt, re, struct
10 def __setitem__(self, k, v):
11 if k.startswith('no-') or k.startswith('no_'):
16 def __getitem__(self, k):
17 if k.startswith('no-') or k.startswith('no_'):
18 return not self._opts[k[3:]]
21 def __getattr__(self, k):
25 def _default_onabort(msg):
46 def _remove_negative_kv(k, v):
47 if k.startswith('no-') or k.startswith('no_'):
51 def _remove_negative_k(k):
52 return _remove_negative_kv(k, None)[0]
56 s = struct.pack("HHHH", 0, 0, 0, 0)
59 s = fcntl.ioctl(sys.stderr.fileno(), termios.TIOCGWINSZ, s)
60 except (IOError, ImportError):
61 return _atoi(os.environ.get('WIDTH')) or 70
62 (ysize,xsize,ypix,xpix) = struct.unpack('HHHH', s)
68 When constructed, two strings are mandatory. The first one is the command
69 name showed before error messages. The second one is a string called an
70 optspec that specifies the synopsis and option flags and their description.
71 For more information about optspecs, consult the bup-options(1) man page.
73 Two optional arguments specify an alternative parsing function and an
74 alternative behaviour on abort (after having output the usage string).
76 By default, the parser function is getopt.gnu_getopt, and the abort
77 behaviour is to exit the program.
79 def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt,
80 onabort=_default_onabort):
82 self.optspec = optspec
83 self._onabort = onabort
84 self.optfunc = optfunc
86 self._shortopts = 'h?'
87 self._longopts = ['help']
90 self._usagestr = self._gen_usage()
94 lines = self.optspec.strip().split('\n')
100 out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
103 last_was_option = False
106 if l.startswith(' '):
107 out.append('%s%s\n' % (last_was_option and '\n' or '',
109 last_was_option = False
111 (flags, extra) = l.split(' ', 1)
112 extra = extra.strip()
113 if flags.endswith('='):
118 g = re.search(r'\[([^\]]*)\]$', extra)
123 flagl = flags.split(',')
126 f,dvi = _remove_negative_kv(f, _intify(defval))
127 self._aliases[f] = _remove_negative_k(flagl[0])
128 self._hasparms[f] = has_parm
129 self._defaults[f] = dvi
131 self._shortopts += f + (has_parm and ':' or '')
132 flagl_nice.append('-' + f)
134 f_nice = re.sub(r'\W', '_', f)
135 self._aliases[f_nice] = _remove_negative_k(flagl[0])
136 self._longopts.append(f + (has_parm and '=' or ''))
137 self._longopts.append('no-' + f)
138 flagl_nice.append('--' + f)
139 flags_nice = ', '.join(flagl_nice)
142 prefix = ' %-20s ' % flags_nice
143 argtext = '\n'.join(textwrap.wrap(extra, width=_tty_width(),
144 initial_indent=prefix,
145 subsequent_indent=' '*28))
146 out.append(argtext + '\n')
147 last_was_option = True
150 last_was_option = False
151 return ''.join(out).rstrip() + '\n'
153 def usage(self, msg=""):
154 """Print usage string to stderr and abort."""
155 sys.stderr.write(self._usagestr)
156 e = self._onabort and self._onabort(msg) or None
161 """Print an error message to stderr and abort with usage string."""
162 msg = 'error: %s\n' % s
163 sys.stderr.write(msg)
164 return self.usage(msg)
166 def parse(self, args):
167 """Parse a list of arguments and return (options, flags, extra).
169 In the returned tuple, "options" is an OptDict with known options,
170 "flags" is a list of option flags that were used on the command-line,
171 and "extra" is a list of positional arguments.
174 (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
175 except getopt.GetoptError, e:
180 for k,v in self._defaults.iteritems():
186 if k in ('h', '?', 'help'):
188 if k.startswith('no-'):
189 k = self._aliases[k[3:]]
193 if not self._hasparms[k]:
195 v = (opt._opts.get(k) or 0) + 1
199 for (f1,f2) in self._aliases.iteritems():
200 opt[f1] = opt._opts.get(f2)
201 return (opt,flags,extra)