comparison hq/command.py @ 6:321721b581f1

general improvements to the command parser
author Jeff Hammel <jhammel@mozilla.com>
date Wed, 26 May 2010 18:56:34 -0700
parents b5671297a0db
children
comparison
equal deleted inserted replaced
5:448c248b3738 6:321721b581f1
11 # TODO: add `help` command 11 # TODO: add `help` command
12 12
13 def __init__(self, _class, description=None): 13 def __init__(self, _class, description=None):
14 self._class = _class 14 self._class = _class
15 self.commands = {} 15 self.commands = {}
16 usage = '%prog [options] command [command-options]' 16 usage = '%prog [options] <command> [command-options]'
17 description = description or _class.__doc__ 17 description = description or _class.__doc__.strip()
18 description += ' Use `%prog help <command>` to display the usage of a command'
19
18 OptionParser.__init__(self, usage=usage, description=description) 20 OptionParser.__init__(self, usage=usage, description=description)
19 commands = [ getattr(_class, i) for i in dir(_class) 21 commands = [ getattr(_class, i) for i in dir(_class)
20 if not i.startswith('_') ] 22 if not i.startswith('_') ]
21 commands = [ method for method in commands 23 commands = [ method for method in commands
22 if hasattr(method, '__call__') ] 24 if hasattr(method, '__call__') ]
23 for _command in commands: 25 for command in commands:
24 self.command(_command) 26 self.add_command(command)
25 self.disable_interspersed_args() 27 self.disable_interspersed_args()
26 28
27 def print_help(self): 29 def print_help(self):
28 # XXX should probably use the optparse formatters to help out here 30 # XXX should probably use the optparse formatters to help out here
29 31
72 74
73 # parse 75 # parse
74 name, args = self.parse(args) 76 name, args = self.parse(args)
75 77
76 # setup 78 # setup
77 _object = self._class(self, self.options) 79 options = self.options.__dict__.copy()
80 _object = self._class(**options)
81 # XXX should only pass values in options that self._class.__init__
82 # needs/wants
78 83
79 # command specific args 84 # command specific args
80 command = self.commands[name] 85 command = self.commands[name]
81 commandparser = self.command2parser(name) 86 commandparser = self.command2parser(name)
82 command_options, command_args = commandparser.parse_args(args) 87 command_options, command_args = commandparser.parse_args(args)
93 pass 98 pass
94 else: 99 else:
95 pprint(retval) 100 pprint(retval)
96 return retval 101 return retval
97 102
103 def add_command(self, function):
104 command = self.command(function)
105 self.commands[command['name']] = command
106
98 def command(self, function): 107 def command(self, function):
99 name = function.func_name 108 name = function.func_name
100 if function.__doc__: 109 if function.__doc__:
101 doc = inspect.cleandoc(function.__doc__) 110 doc = inspect.cleandoc(function.__doc__)
102 else: 111 else:
107 args = argspec.args[1:-len(defaults)] 116 args = argspec.args[1:-len(defaults)]
108 optional = dict(zip(argspec.args[-len(defaults):], defaults)) 117 optional = dict(zip(argspec.args[-len(defaults):], defaults))
109 else: 118 else:
110 args = argspec.args[1:] 119 args = argspec.args[1:]
111 optional = None 120 optional = None
112 self.commands[name] = { 'doc': doc, 121 return { 'name': name,
113 'args': args, 122 'doc': doc,
114 'optional': optional, 123 'args': args,
115 'varargs': argspec.varargs 124 'optional': optional,
116 } 125 'varargs': argspec.varargs
117 return function # XXX to restructure??? 126 }
118 127
119 def commandargs2str(self, command): 128 def commandargs2str(self, command):
120 if isinstance(command, basestring): 129 if isinstance(command, basestring):
121 command = self.commands[command] 130 command = self.commands[command]
122 retval = [] 131 retval = []
140 lines = [ i.strip() for i in docstring.split('\n') ] 149 lines = [ i.strip() for i in docstring.split('\n') ]
141 argdict = {} 150 argdict = {}
142 doc = [] 151 doc = []
143 option = None 152 option = None
144 for line in lines: 153 for line in lines:
145 if not line and option: # blank lines terminate [?] 154 if not line and option: # blank lines terminate [???]
146 break 155 break
147 if line.startswith(decoration) and delimeter in line: 156 if line.startswith(decoration) and delimeter in line:
148 name, description = line.split(delimeter, 1) 157 name, description = line.split(delimeter, 1)
149 name = name.lstrip(decoration).strip() 158 name = name.lstrip(decoration).strip()
150 description = description.strip() 159 description = description.strip()
158 argdict = dict([(key, ' '.join(value)) 167 argdict = dict([(key, ' '.join(value))
159 for key, value in argdict.items()]) 168 for key, value in argdict.items()])
160 return ('\n'.join(doc), argdict) 169 return ('\n'.join(doc), argdict)
161 170
162 def command2parser(self, command): 171 def command2parser(self, command):
163 doc, argdict = self.doc2arghelp(self.commands[command]['doc']) 172 if isinstance(command, basestring):
164 parser = OptionParser('%%prog %s %s' % (command, self.commandargs2str(command)), 173 command = self.commands[command]
174 doc, argdict = self.doc2arghelp(command['doc'])
175 parser = OptionParser('%%prog %s %s' % (command['name'], self.commandargs2str(command['name'])),
165 description=doc, add_help_option=False) 176 description=doc, add_help_option=False)
166 if self.commands[command]['optional']: 177 if command['optional']:
167 for key, value in self.commands[command]['optional'].items(): 178 for key, value in command['optional'].items():
168 help = argdict.get(key, '') 179 help = argdict.get(key, '')
169 if value is True: 180 if value is True:
170 parser.add_option('--no-%s' % key, dest=key, 181 parser.add_option('--no-%s' % key, dest=key,
171 action='store_false', default=True, 182 action='store_false', default=True,
172 help=help) 183 help=help)