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