1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 """
17 Commandline Handling
18 ====================
19
20 This modules handles commandline parsing and initial bootstrapping.
21 """
22 __author__ = u"Andr\xe9 Malo"
23 __docformat__ = "restructuredtext en"
24
25 import optparse as _optparse
26 import os as _os
27 import sys as _sys
28
29 from wtf import Error
30
32 """ Error on command line """
33
34
36 """
37 Return terminal width if determined, None otherwise
38
39 :return: The width
40 :rtype: ``int``
41 """
42 fd = None
43 def isatty(fd):
44 """ Determine if the fd is a TTY """
45 try:
46 _isatty = bool(_os.isatty(fd))
47 except AttributeError:
48 _isatty = False
49 return _isatty
50
51 for fp in (_sys.stdout, _sys.stdin):
52 try:
53 _fd = fp.fileno()
54 except (AttributeError, ValueError):
55 continue
56 else:
57 if isatty(_fd):
58 fd = _fd
59 break
60
61 if fd is not None:
62 try:
63 import fcntl, struct, termios
64
65
66
67
68
69
70
71 return struct.unpack("4H", fcntl.ioctl(
72 fd, termios.TIOCGWINSZ, struct.pack("4H", 0, 0, 0, 0)
73 ))[1]
74
75 except (SystemExit, KeyboardInterrupt):
76 raise
77
78 except:
79
80 pass
81
82 return None
83
84
86 """ Extended option parser for better behaviour """
87
89 """ Initialization """
90 kwargs.setdefault('prog', "<prog>")
91 kwargs.setdefault('usage', "1")
92 kwargs.setdefault('version', "2")
93 _optparse.OptionParser.__init__(self, **kwargs)
94
96 """
97 Parse the argument list provided by ``sys.argv``
98
99 :Parameters:
100 - `args`: Additional arguments for the parser
101 - `kwargs`: Additional arguments for the parser
102
103 :Types:
104 - `args`: ``tuple``
105 - `kwargs`: ``dict``
106
107 :return: The ``OptionContainer`` instance and the positional args
108 (``(optparse.OptionContainer, list)``)
109 :rtype: ``tuple``
110
111 :Exceptions:
112 - `CommandlineError`: The argument list was invalid
113 """
114
115
116 self.prog = _os.path.basename(_sys.argv[0])
117 return _optparse.OptionParser.parse_args(self,
118 _sys.argv[1:], *args, **kwargs)
119
121 """
122 Raise an exception instead of calling ``sys.exit``
123
124 :Parameters:
125 - `msg`: The error message
126
127 :Types:
128 - `msg`: ``str``
129
130 :Exceptions:
131 - `CommandlineError`: command line error
132 """
133 raise CommandlineError(str(msg))
134
136 """
137 Return the version string
138
139 :return: The version string
140 :rtype: ``str``
141 """
142 from wtf import version
143 return str(version)
144
146 """
147 Return the usage string
148
149 :return: The usage string
150 :rtype: ``str``
151 """
152 return "Usage: %s <options> start|stop|logrotate\n" % \
153 self.get_prog_name()
154
156 """
157 Returns the program name
158
159 :return: The program name
160 :rtype: ``str``
161 """
162 return self.prog
163 _get_prog_name = get_prog_name
164
198
199
201 """
202 Parse command line
203
204 :Parameters:
205 - `opts`: Option spec (WRITEME: need more info here :-)
206 (``({key: value, ...}, ...)``)
207 Special keys are '' and 'ENV'.
208
209 :Types:
210 - `opts`: ``tuple``
211
212 :return: The option container and the fixed args
213 (``(optparse.OptionContainer, list)``)
214 :rtype: ``tuple``
215 """
216 optlist = []
217 for opt in opts:
218 opt = opt.copy()
219 names = opt.pop('')
220 if 'ENV' in opt:
221 defaultval = _os.environ.get(opt.pop('ENV'))
222 if defaultval is not None:
223 opt['default'] = defaultval
224 optlist.append(_optparse.make_option(*names, **opt))
225 parser = _OptionParser(option_list=optlist)
226 return parser.parse_args()
227
228
230 """ Main command line runner """
231 opts, args = parse(
232 {'': ['-c', '--config'], 'action': 'store', 'type': 'string',
233 'ENV': 'WTFRC',
234 'help': 'Configuration file, overrides the WTFRC variable'},
235 {'': ['--dump-config'], 'action': 'store_true',
236 'help': 'Load config, dump it to STDOUT and exit'},
237 {'': ['--profile'], 'action': 'store', 'type': 'string',
238 'metavar': 'FILENAME',
239 'help': 'Run with (c)profiler, output to FILENAME'},
240 {'': ['--keep-descriptors'], 'action': 'store_true',
241 'help': "Don't close all file descriptors during startup "
242 "(useful for debugging)"},
243 {'': ['-l', '--listen'], 'action': 'append',
244 'help': 'Override the listen configuration in config file '
245 '(Can be used more than once)'},
246 {'': ['--checkinterval'], 'action': 'store', 'type': 'int',
247 'help': 'Set the number of byte code instructions between thread '
248 'switches (sys.setcheckinterval())'},
249 {'': ['--max-descriptors'], 'action': 'store', 'type': 'int',
250 'help': 'Set the maximum number of file descriptors '
251 '(ulimit -n)'},
252 {'': ['-m', '--workermodel'], 'action': 'store',
253 'help': 'Override the workermodel configuration in config file '},
254 )
255 args = [_sys.argv[0]] + list(args)
256 if not opts.config:
257 raise CommandlineError("No configuration file given")
258
259 from wtf import init as _init
260 config = _init.config(opts.config, opts=opts, dump=opts.dump_config)
261
262 def start():
263 """ Starter """
264 from wtf import opi as _opi
265 try:
266 _opi.factory(config, opts, args).work()
267 except _opi.OPIError, e:
268 msg = str(e)
269 if msg:
270 print >> _sys.stderr, msg
271 _sys.exit(e.exit_code)
272
273 if opts.profile:
274 try:
275 import cProfile as _profile
276 except ImportError:
277 import profile as _profile
278 _profile.runctx("start()", globals(), locals(), opts.profile)
279
280 else:
281 start()
282