Package wtf :: Module cmdline
[hide private]
[frames] | no frames]

Source Code for Module wtf.cmdline

  1  # -*- coding: ascii -*- 
  2  # 
  3  # Copyright 2006-2012 Andr\xe9 Malo or his licensors, as applicable 
  4  # 
  5  # Licensed under the Apache License, Version 2.0 (the "License"); 
  6  # you may not use this file except in compliance with the License. 
  7  # You may obtain a copy of the License at 
  8  # 
  9  #     http://www.apache.org/licenses/LICENSE-2.0 
 10  # 
 11  # Unless required by applicable law or agreed to in writing, software 
 12  # distributed under the License is distributed on an "AS IS" BASIS, 
 13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 14  # See the License for the specific language governing permissions and 
 15  # limitations under the License. 
 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   
31 -class CommandlineError(Error):
32 """ Error on command line """
33 34
35 -def terminal_width():
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 # struct winsize { /* on linux in asm/termios.h */ 66 # unsigned short ws_row; 67 # unsigned short ws_col; 68 # unsigned short ws_xpixel; 69 # unsigned short ws_ypixel; 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 # don't even ignore 80 pass 81 82 return None 83 84
85 -class _OptionParser(_optparse.OptionParser): # old style class
86 """ Extended option parser for better behaviour """ 87
88 - def __init__(self, **kwargs):
89 """ Initialization """ 90 kwargs.setdefault('prog', "<prog>") 91 kwargs.setdefault('usage', "1") 92 kwargs.setdefault('version', "2") 93 _optparse.OptionParser.__init__(self, **kwargs)
94
95 - def parse_args(self, *args, **kwargs):
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 # pylint: disable = W0221 115 116 self.prog = _os.path.basename(_sys.argv[0]) 117 return _optparse.OptionParser.parse_args(self, 118 _sys.argv[1:], *args, **kwargs)
119
120 - def error(self, msg):
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
135 - def get_version(self):
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
145 - def get_usage(self):
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
155 - def get_prog_name(self):
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 # 2.3.4 <= python < 2.4.0 164
165 - def format_help(self, formatter=None):
166 """ 167 Return the formatted help string 168 169 The string consists of the normal option help generated by 170 the optparse module and a short description of the old style 171 options. All text is tried to be wrapped to fit into the 172 current terminal width. 173 174 :Parameters: 175 - `formatter`: unused 176 177 :Types: 178 - `formatter`: any 179 180 :return: The formatted help string 181 :rtype: ``str`` 182 """ 183 # determine possible with 184 width = (terminal_width() or 80) - 1 185 optionhelp = None 186 while optionhelp is None: 187 formatter = _optparse.IndentedHelpFormatter(width=width) 188 try: 189 optionhelp = \ 190 _optparse.OptionParser.format_help(self, formatter) 191 except ValueError: 192 # terminal too small 193 if width < 79: 194 width = 79 195 else: 196 width += 10 197 return optionhelp
198 199
200 -def parse(*opts):
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
229 -def run():
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