]> arthur.barton.de Git - bup.git/blob - lib/bup/options.py
options.py: support for putting default values in [square brackets].
[bup.git] / lib / bup / options.py
1 import sys, textwrap, getopt, re
2
3 class OptDict:
4     def __init__(self):
5         self._opts = {}
6
7     def __setitem__(self, k, v):
8         self._opts[k] = v
9
10     def __getitem__(self, k):
11         return self._opts[k]
12
13     def __getattr__(self, k):
14         return self[k]
15
16
17 def _default_onabort(msg):
18     sys.exit(97)
19
20
21 def _intify(v):
22     try:
23         vv = int(v or '')
24         if str(vv) == v:
25             return vv
26     except ValueError:
27         pass
28     return v
29
30
31 class Options:
32     def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt,
33                  onabort=_default_onabort):
34         self.exe = exe
35         self.optspec = optspec
36         self._onabort = onabort
37         self.optfunc = optfunc
38         self._aliases = {}
39         self._shortopts = 'h?'
40         self._longopts = ['help']
41         self._hasparms = {}
42         self._defaults = {}
43         self._usagestr = self._gen_usage()
44
45     def _gen_usage(self):
46         out = []
47         lines = self.optspec.strip().split('\n')
48         lines.reverse()
49         first_syn = True
50         while lines:
51             l = lines.pop()
52             if l == '--': break
53             out.append('%s: %s\n' % (first_syn and 'usage' or '   or', l))
54             first_syn = False
55         out.append('\n')
56         while lines:
57             l = lines.pop()
58             if l.startswith(' '):
59                 out.append('\n%s\n' % l.lstrip())
60             elif l:
61                 (flags, extra) = l.split(' ', 1)
62                 extra = extra.strip()
63                 if flags.endswith('='):
64                     flags = flags[:-1]
65                     has_parm = 1
66                 else:
67                     has_parm = 0
68                 g = re.search(r'\[([^\]]*)\]', extra)
69                 if g:
70                     defval = g.group(1)
71                 else:
72                     defval = None
73                 flagl = flags.split(',')
74                 flagl_nice = []
75                 for f in flagl:
76                     self._aliases[f] = flagl[0]
77                     self._hasparms[f] = has_parm
78                     self._defaults[f] = _intify(defval)
79                     if len(f) == 1:
80                         self._shortopts += f + (has_parm and ':' or '')
81                         flagl_nice.append('-' + f)
82                     else:
83                         f_nice = re.sub(r'\W', '_', f)
84                         self._aliases[f_nice] = flagl[0]
85                         assert(not f.startswith('no-')) # supported implicitly
86                         self._longopts.append(f + (has_parm and '=' or ''))
87                         self._longopts.append('no-' + f)
88                         flagl_nice.append('--' + f)
89                 flags_nice = ', '.join(flagl_nice)
90                 if has_parm:
91                     flags_nice += ' ...'
92                 prefix = '    %-20s  ' % flags_nice
93                 argtext = '\n'.join(textwrap.wrap(extra, width=70,
94                                                 initial_indent=prefix,
95                                                 subsequent_indent=' '*28))
96                 out.append(argtext + '\n')
97             else:
98                 out.append('\n')
99         return ''.join(out).rstrip() + '\n'
100
101     def usage(self, msg=""):
102         sys.stderr.write(self._usagestr)
103         e = self._onabort and self._onabort(msg) or None
104         if e:
105             raise e
106
107     def fatal(self, s):
108         msg = 'error: %s\n' % s
109         sys.stderr.write(msg)
110         return self.usage(msg)
111
112     def parse(self, args):
113         try:
114             (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
115         except getopt.GetoptError, e:
116             self.fatal(e)
117
118         opt = OptDict()
119
120         for k,v in self._defaults.iteritems():
121             k = self._aliases[k]
122             opt[k] = v
123         
124         for (k,v) in flags:
125             k = k.lstrip('-')
126             if k in ('h', '?', 'help'):
127                 self.usage()
128             if k.startswith('no-'):
129                 k = self._aliases[k[3:]]
130                 v = 0
131             else:
132                 k = self._aliases[k]
133                 if not self._hasparms[k]:
134                     assert(v == '')
135                     v = (opt._opts.get(k) or 0) + 1
136                 else:
137                     v = _intify(v)
138             opt[k] = v
139         for (f1,f2) in self._aliases.iteritems():
140             opt[f1] = opt._opts.get(f2)
141         return (opt,flags,extra)