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, optspec, optfunc=getopt.gnu_getopt,
80 onabort=_default_onabort):
81 self.optspec = optspec
82 self._onabort = onabort
83 self.optfunc = optfunc
85 self._shortopts = 'h?'
86 self._longopts = ['help']
89 self._usagestr = self._gen_usage()
93 lines = self.optspec.strip().split('\n')
99 out.append('%s: %s\n' % (first_syn and 'usage' or ' or', l))
102 last_was_option = False
105 if l.startswith(' '):
106 out.append('%s%s\n' % (last_was_option and '\n' or '',
108 last_was_option = False
110 (flags, extra) = l.split(' ', 1)
111 extra = extra.strip()
112 if flags.endswith('='):
117 g = re.search(r'\[([^\]]*)\]$', extra)
122 flagl = flags.split(',')
125 f,dvi = _remove_negative_kv(f, _intify(defval))
126 self._aliases[f] = _remove_negative_k(flagl[0])
127 self._hasparms[f] = has_parm
128 self._defaults[f] = dvi
130 self._shortopts += f + (has_parm and ':' or '')
131 flagl_nice.append('-' + f)
133 f_nice = re.sub(r'\W', '_', f)
134 self._aliases[f_nice] = _remove_negative_k(flagl[0])
135 self._longopts.append(f + (has_parm and '=' or ''))
136 self._longopts.append('no-' + f)
137 flagl_nice.append('--' + f)
138 flags_nice = ', '.join(flagl_nice)
141 prefix = ' %-20s ' % flags_nice
142 argtext = '\n'.join(textwrap.wrap(extra, width=_tty_width(),
143 initial_indent=prefix,
144 subsequent_indent=' '*28))
145 out.append(argtext + '\n')
146 last_was_option = True
149 last_was_option = False
150 return ''.join(out).rstrip() + '\n'
152 def usage(self, msg=""):
153 """Print usage string to stderr and abort."""
154 sys.stderr.write(self._usagestr)
155 e = self._onabort and self._onabort(msg) or None
160 """Print an error message to stderr and abort with usage string."""
161 msg = 'error: %s\n' % s
162 sys.stderr.write(msg)
163 return self.usage(msg)
165 def parse(self, args):
166 """Parse a list of arguments and return (options, flags, extra).
168 In the returned tuple, "options" is an OptDict with known options,
169 "flags" is a list of option flags that were used on the command-line,
170 and "extra" is a list of positional arguments.
173 (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
174 except getopt.GetoptError, e:
179 for k,v in self._defaults.iteritems():
185 if k in ('h', '?', 'help'):
187 if k.startswith('no-'):
188 k = self._aliases[k[3:]]
192 if not self._hasparms[k]:
194 v = (opt._opts.get(k) or 0) + 1
198 for (f1,f2) in self._aliases.iteritems():
199 opt[f1] = opt._opts.get(f2)
200 return (opt,flags,extra)