]> arthur.barton.de Git - bup.git/blob - lib/bup/options.py
lib/options: Add an onabort argument to Options()
[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 class Options:
22     def __init__(self, exe, optspec, optfunc=getopt.gnu_getopt,
23                  onabort=_default_onabort):
24         self.exe = exe
25         self.optspec = optspec
26         self._onabort = onabort
27         self.optfunc = optfunc
28         self._aliases = {}
29         self._shortopts = 'h?'
30         self._longopts = ['help']
31         self._hasparms = {}
32         self._usagestr = self._gen_usage()
33
34     def _gen_usage(self):
35         out = []
36         lines = self.optspec.strip().split('\n')
37         lines.reverse()
38         first_syn = True
39         while lines:
40             l = lines.pop()
41             if l == '--': break
42             out.append('%s: %s\n' % (first_syn and 'usage' or '   or', l))
43             first_syn = False
44         out.append('\n')
45         while lines:
46             l = lines.pop()
47             if l.startswith(' '):
48                 out.append('\n%s\n' % l.lstrip())
49             elif l:
50                 (flags, extra) = l.split(' ', 1)
51                 extra = extra.strip()
52                 if flags.endswith('='):
53                     flags = flags[:-1]
54                     has_parm = 1
55                 else:
56                     has_parm = 0
57                 flagl = flags.split(',')
58                 flagl_nice = []
59                 for f in flagl:
60                     self._aliases[f] = flagl[0]
61                     self._hasparms[f] = has_parm
62                     if len(f) == 1:
63                         self._shortopts += f + (has_parm and ':' or '')
64                         flagl_nice.append('-' + f)
65                     else:
66                         f_nice = re.sub(r'\W', '_', f)
67                         self._aliases[f_nice] = flagl[0]
68                         assert(not f.startswith('no-')) # supported implicitly
69                         self._longopts.append(f + (has_parm and '=' or ''))
70                         self._longopts.append('no-' + f)
71                         flagl_nice.append('--' + f)
72                 flags_nice = ', '.join(flagl_nice)
73                 if has_parm:
74                     flags_nice += ' ...'
75                 prefix = '    %-20s  ' % flags_nice
76                 argtext = '\n'.join(textwrap.wrap(extra, width=70,
77                                                 initial_indent=prefix,
78                                                 subsequent_indent=' '*28))
79                 out.append(argtext + '\n')
80             else:
81                 out.append('\n')
82         return ''.join(out).rstrip() + '\n'
83
84     def usage(self, msg=""):
85         sys.stderr.write(self._usagestr)
86         e = self._onabort and self._onabort(msg) or None
87         if e:
88             raise e
89
90     def fatal(self, s):
91         msg = 'error: %s\n' % s
92         sys.stderr.write(msg)
93         return self.usage(msg)
94
95     def parse(self, args):
96         try:
97             (flags,extra) = self.optfunc(args, self._shortopts, self._longopts)
98         except getopt.GetoptError, e:
99             self.fatal(e)
100
101         opt = OptDict()
102         for (k,v) in flags:
103             k = k.lstrip('-')
104             if k in ('h', '?', 'help'):
105                 self.usage()
106             if k.startswith('no-'):
107                 k = self._aliases[k[3:]]
108                 v = 0
109             else:
110                 k = self._aliases[k]
111                 if not self._hasparms[k]:
112                     assert(v == '')
113                     v = (opt._opts.get(k) or 0) + 1
114                 else:
115                     try:
116                         vv = int(v)
117                         if str(vv) == v:
118                             v = vv
119                     except ValueError:
120                         pass
121             opt[k] = v
122         for (f1,f2) in self._aliases.iteritems():
123             opt[f1] = opt._opts.get(f2)
124         return (opt,flags,extra)