Revision c41a86b2 kamaki/cli/argument.py

b/kamaki/cli/argument.py
1 1
#A. One-command CLI
2
#	1. Get a command string 		DONE
3
#	2. Parse out some Arguments 	DONE
4
#		a. We need an Argument "library" for each command-level 	DONE
5
#		b. Handle arg errors 	
6
#	3. Retrieve and validate command_sequence
7
#		a. For faster responses, first command can be chosen from
8
#			a prefixed list of names, loaded from the config file
9
#		b. Normally, each 1st level command has a file to read
10
#			command specs from. Load command_specs in this file
11
#			i. A dict with command specs is created
12
#				e.g. {'store':{'list':{'all', None}, 'info'}, 'server':{'list', 'info'}}
13
#				but in this case there will be only 'store', or 'server', etc.
14
#		c. Now, loop over the other parsed terms and check them against the commands
15
#			i. That will produce a path of the form ['store', 'list' 'all']
16
#		d. Catch syntax errors
17
#	4. Instaciate object to exec
18
#		a. For path ['store', 'list', 'all'] instatiate store_list_all()
19
#	5. Parse out some more Arguments 
20
#		a. Each command path has an "Argument library" to check your args against
21
#	6. Call object.main() and catch ClientErrors
22
#		a. Now, there are some command-level syntax errors that we should catch
23
#			as syntax errors? Maybe! Why not?
2
#    1. Get a command string         DONE
3
#    2. Parse out some Arguments     DONE
4
#        a. We need an Argument "library" for each command-level     DONE
5
#        b. Handle arg errors     
6
#    3. Retrieve and validate command_sequence
7
#        a. For faster responses, first command can be chosen from
8
#            a prefixed list of names, loaded from the config file
9
#        b. Normally, each 1st level command has a file to read
10
#            command specs from. Load command_specs in this file
11
#            i. A dict with command specs is created
12
#                e.g. {'store':{'list':{'all', None}, 'info'}, 'server':{'list', 'info'}}
13
#                but in this case there will be only 'store', or 'server', etc.
14
#        c. Now, loop over the other parsed terms and check them against the commands
15
#            i. That will produce a path of the form ['store', 'list' 'all']
16
#        d. Catch syntax errors
17
#    4. Instaciate object to exec
18
#        a. For path ['store', 'list', 'all'] instatiate store_list_all()
19
#    5. Parse out some more Arguments 
20
#        a. Each command path has an "Argument library" to check your args against
21
#    6. Call object.main() and catch ClientErrors
22
#        a. Now, there are some command-level syntax errors that we should catch
23
#            as syntax errors? Maybe! Why not?
24 24

  
25 25
#Shell
26
#	1. Load ALL available command specs in advance
27
#	2. Iimport cmd (and run it ?)
28
#	3. There is probably a way to tell cmd of the command paths you support.
29
#	4. If cmd does not support it, for the sellected path call parse out stuff
30
#		as in One-command
31
#	5. Instatiate, parse_out and run object like in One-command
32
#	6. Run object.main() . Again, catch ClientErrors and, probably, syntax errors
26
#    1. Load ALL available command specs in advance
27
#    2. Iimport cmd (and run it ?)
28
#    3. There is probably a way to tell cmd of the command paths you support.
29
#    4. If cmd does not support it, for the sellected path call parse out stuff
30
#        as in One-command
31
#    5. Instatiate, parse_out and run object like in One-command
32
#    6. Run object.main() . Again, catch ClientErrors and, probably, syntax errors
33 33
import gevent.monkey
34 34
#Monkey-patch everything for gevent early on
35 35
gevent.monkey.patch_all()
......
105 105
        """Overide this method to give functionality to ur args"""
106 106
        raise NotImplementedError
107 107

  
108
    @classmethod
109
    def test(self):
110
        h = Argument(arity=0, help='Display a help massage', parsed_name=('--help', '-h'))
111
        b = Argument(arity=1, help='This is a bbb', parsed_name='--bbb')
112
        c = Argument(arity=2, help='This is a ccc', parsed_name='--ccc')
113

  
114
        from argparse import ArgumentParser
115
        parser = ArgumentParser(add_help=False)
116
        h.update_parser(parser, 'hee')
117
        b.update_parser(parser, 'bee')
118
        c.update_parser(parser, 'cee')
119

  
120
        args, argv = parser.parse_known_args()
121
        print('args: %s\nargv: %s'%(args, argv))
122

  
123
class VersionArgument(Argument):
124
	@property 
125
	def value(self):
126
		return super(self.__class__, self).value
127
	@value.setter
128
	def value(self, newvalue):
129
		self._value = newvalue
130
		self.main()
131

  
132
	def main(self):
133
		if self.value:
134
			import kamaki
135
			print('kamaki %s'%kamaki.__version__)
136

  
137 108
class ConfigArgument(Argument):
138
	@property 
139
	def value(self):
140
		return super(self.__class__, self).value
141
	@value.setter
142
	def value(self, config_file):
143
		self._value = Config(config_file) if config_file is not None else Config()
109
    @property 
110
    def value(self):
111
        return super(self.__class__, self).value
112
    @value.setter
113
    def value(self, config_file):
114
        self._value = Config(config_file) if config_file is not None else Config()
144 115

  
145
	def get_groups(self):
146
		return self.value.apis()
116
    def get(self, group, term):
117
        return self.value.get(group, term)
118

  
119
    def get_groups(self):
120
        return self.value.apis()
147 121

  
148 122

  
149 123
_config_arg = ConfigArgument(1, 'Path to configuration file', '--config')
150 124

  
151 125
class CmdLineConfigArgument(Argument):
152
	def __init__(self, config_arg, help='', parsed_name=None, default=None):
153
		super(self.__class__, self).__init__(1, help, parsed_name, default)
154
		self._config_arg = config_arg
155

  
156
	@property 
157
	def value(self):
158
		return super(self.__class__, self).value
159
	@value.setter
160
	def value(self, options):
161
		if options == self.default:
162
			return
163
		options = [unicode(options)] if not isinstance(options, list) else options
164
		for option in options:
165
			keypath, sep, val = option.partition('=')
166
			if not sep:
167
				raise CLISyntaxError(details='Missing = between key and value: -o section.key=val')
168
			section, sep, key = keypath.partition('.')
169
			if not sep:
170
				raise CLISyntaxError(details='Missing . between section and key: -o section.key=val')
171
		self._config_arg.value.override(section.strip(), key.strip(), val.strip())
126
    def __init__(self, config_arg, help='', parsed_name=None, default=None):
127
        super(self.__class__, self).__init__(1, help, parsed_name, default)
128
        self._config_arg = config_arg
129

  
130
    @property 
131
    def value(self):
132
        return super(self.__class__, self).value
133
    @value.setter
134
    def value(self, options):
135
        if options == self.default:
136
            return
137
        options = [unicode(options)] if not isinstance(options, list) else options
138
        for option in options:
139
            keypath, sep, val = option.partition('=')
140
            if not sep:
141
                raise CLISyntaxError(details='Missing = between key and value: -o section.key=val')
142
            section, sep, key = keypath.partition('.')
143
            if not sep:
144
                raise CLISyntaxError(details='Missing . between section and key: -o section.key=val')
145
        self._config_arg.value.override(section.strip(), key.strip(), val.strip())
146

  
147
class FlagArgument(Argument):
148
    def __init__(self, help='', parsed_name=None, default=None):
149
        super(FlagArgument, self).__init__(0, help, parsed_name, default)
150

  
151
class ValueArgument(Argument):
152
    def __init__(self, help='', parsed_name=None, default=None):
153
        super(ValueArgument, self).__init__(1, help, parsed_name, default)
154

  
155
class VersionArgument(FlagArgument):
156
    @property 
157
    def value(self):
158
        return super(self.__class__, self).value
159
    @value.setter
160
    def value(self, newvalue):
161
        self._value = newvalue
162
        self.main()
163

  
164
    def main(self):
165
        if self.value:
166
            import kamaki
167
            print('kamaki %s'%kamaki.__version__)
172 168

  
173 169
_arguments = dict(config = _config_arg, help = Argument(0, 'Show help message', ('-h', '--help')),
174
	debug = Argument(0, 'Include debug output', ('-d', '--debug')),
175
	include = Argument(0, 'Include protocol headers in the output', ('-i', '--include')),
176
	silent = Argument(0, 'Do not output anything', ('-s', '--silent')),
177
	verbose = Argument(0, 'More info at response', ('-v', '--verbose')),
178
	version = VersionArgument(0, 'Print current version', ('-V', '--version')),
179
	options = CmdLineConfigArgument(_config_arg, 'Override a config value', ('-o', '--options'))
170
    debug = FlagArgument('Include debug output', ('-d', '--debug')),
171
    include = FlagArgument('Include protocol headers in the output', ('-i', '--include')),
172
    silent = FlagArgument('Do not output anything', ('-s', '--silent')),
173
    verbose = FlagArgument('More info at response', ('-v', '--verbose')),
174
    version = VersionArgument('Print current version', ('-V', '--version')),
175
    options = CmdLineConfigArgument(_config_arg, 'Override a config value', ('-o', '--options'))
180 176
)
181 177

  
182 178
def parse_known_args(parser):
183
	parsed, unparsed = parser.parse_known_args()
184
	for name, arg in _arguments.items():
185
		arg.value = getattr(parsed, name, arg.value)
186
	return parsed, unparsed
179
    parsed, unparsed = parser.parse_known_args()
180
    for name, arg in _arguments.items():
181
        arg.value = getattr(parsed, name, arg.value)
182
    return parsed, unparsed
187 183

  
188 184

  

Also available in: Unified diff