Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / argument.py @ 34e4cf61

History | View | Annotate | Download (13.7 kB)

1 b9331a9f Stavros Sachtouris
# Copyright 2012 GRNET S.A. All rights reserved.
2 b9331a9f Stavros Sachtouris
#
3 b9331a9f Stavros Sachtouris
# Redistribution and use in source and binary forms, with or
4 b9331a9f Stavros Sachtouris
# without modification, are permitted provided that the following
5 b9331a9f Stavros Sachtouris
# conditions are met:
6 b9331a9f Stavros Sachtouris
#
7 b9331a9f Stavros Sachtouris
#   1. Redistributions of source code must retain the above
8 b9331a9f Stavros Sachtouris
#     copyright notice, this list of conditions and the following
9 b9331a9f Stavros Sachtouris
#     disclaimer.
10 b9331a9f Stavros Sachtouris
#
11 b9331a9f Stavros Sachtouris
#   2. Redistributions in binary form must reproduce the above
12 b9331a9f Stavros Sachtouris
#     copyright notice, this list of conditions and the following
13 b9331a9f Stavros Sachtouris
#     disclaimer in the documentation and/or other materials
14 b9331a9f Stavros Sachtouris
#     provided with the distribution.
15 b9331a9f Stavros Sachtouris
#
16 b9331a9f Stavros Sachtouris
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 b9331a9f Stavros Sachtouris
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 b9331a9f Stavros Sachtouris
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 b9331a9f Stavros Sachtouris
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 b9331a9f Stavros Sachtouris
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 b9331a9f Stavros Sachtouris
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 b9331a9f Stavros Sachtouris
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 b9331a9f Stavros Sachtouris
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 b9331a9f Stavros Sachtouris
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 b9331a9f Stavros Sachtouris
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 b9331a9f Stavros Sachtouris
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 b9331a9f Stavros Sachtouris
# POSSIBILITY OF SUCH DAMAGE.
28 b9331a9f Stavros Sachtouris
#
29 b9331a9f Stavros Sachtouris
# The views and conclusions contained in the software and
30 b9331a9f Stavros Sachtouris
# documentation are those of the authors and should not be
31 b9331a9f Stavros Sachtouris
# interpreted as representing official policies, either expressed
32 b9331a9f Stavros Sachtouris
# or implied, of GRNET S.A.
33 9bdc89da Stavros Sachtouris
34 c270fe96 Stavros Sachtouris
from kamaki.cli.config import Config
35 b696ed2c Stavros Sachtouris
from kamaki.cli.errors import CLISyntaxError, raiseCLIError
36 e0f40c94 Stavros Sachtouris
from kamaki.cli.utils import split_input
37 db8d1766 Stavros Sachtouris
from logging import getLogger
38 db8d1766 Stavros Sachtouris
39 e0f40c94 Stavros Sachtouris
40 af6de846 Stavros Sachtouris
from argparse import ArgumentParser, ArgumentError
41 dfee2caf Stavros Sachtouris
42 fd1f1d96 Stavros Sachtouris
try:
43 365280ca Stavros Sachtouris
    from progress.bar import ShadyBar as KamakiProgressBar
44 fd1f1d96 Stavros Sachtouris
except ImportError:
45 fd1f1d96 Stavros Sachtouris
    # progress not installed - pls, pip install progress
46 fd1f1d96 Stavros Sachtouris
    pass
47 fd1f1d96 Stavros Sachtouris
48 b6a99832 Stavros Sachtouris
kloger = getLogger('kamaki')
49 db8d1766 Stavros Sachtouris
50 fd5db045 Stavros Sachtouris
51 dfee2caf Stavros Sachtouris
class Argument(object):
52 edb7fc1a Stavros Sachtouris
    """An argument that can be parsed from command line or otherwise.
53 edb7fc1a Stavros Sachtouris
    This is the general Argument class. It is suggested to extent this
54 edb7fc1a Stavros Sachtouris
    class into more specific argument types.
55 edb7fc1a Stavros Sachtouris
    """
56 dfee2caf Stavros Sachtouris
57 dfee2caf Stavros Sachtouris
    def __init__(self, arity, help=None, parsed_name=None, default=None):
58 606fe15f Stavros Sachtouris
        self.arity = int(arity)
59 606fe15f Stavros Sachtouris
60 dfee2caf Stavros Sachtouris
        if help is not None:
61 dfee2caf Stavros Sachtouris
            self.help = help
62 dfee2caf Stavros Sachtouris
        if parsed_name is not None:
63 dfee2caf Stavros Sachtouris
            self.parsed_name = parsed_name
64 dfee2caf Stavros Sachtouris
        if default is not None:
65 dfee2caf Stavros Sachtouris
            self.default = default
66 dfee2caf Stavros Sachtouris
67 fd5db045 Stavros Sachtouris
    @property
68 dfee2caf Stavros Sachtouris
    def parsed_name(self):
69 edb7fc1a Stavros Sachtouris
        """the string which will be recognised by the parser as an instance
70 edb7fc1a Stavros Sachtouris
            of this argument
71 edb7fc1a Stavros Sachtouris
        """
72 dfee2caf Stavros Sachtouris
        return getattr(self, '_parsed_name', None)
73 fd5db045 Stavros Sachtouris
74 dfee2caf Stavros Sachtouris
    @parsed_name.setter
75 dfee2caf Stavros Sachtouris
    def parsed_name(self, newname):
76 dfee2caf Stavros Sachtouris
        self._parsed_name = getattr(self, '_parsed_name', [])
77 dfee2caf Stavros Sachtouris
        if isinstance(newname, list) or isinstance(newname, tuple):
78 dfee2caf Stavros Sachtouris
            self._parsed_name += list(newname)
79 dfee2caf Stavros Sachtouris
        else:
80 dfee2caf Stavros Sachtouris
            self._parsed_name.append(unicode(newname))
81 dfee2caf Stavros Sachtouris
82 fd5db045 Stavros Sachtouris
    @property
83 dfee2caf Stavros Sachtouris
    def help(self):
84 edb7fc1a Stavros Sachtouris
        """a user friendly help message"""
85 dfee2caf Stavros Sachtouris
        return getattr(self, '_help', None)
86 fd5db045 Stavros Sachtouris
87 dfee2caf Stavros Sachtouris
    @help.setter
88 dfee2caf Stavros Sachtouris
    def help(self, newhelp):
89 dfee2caf Stavros Sachtouris
        self._help = unicode(newhelp)
90 dfee2caf Stavros Sachtouris
91 fd5db045 Stavros Sachtouris
    @property
92 dfee2caf Stavros Sachtouris
    def arity(self):
93 edb7fc1a Stavros Sachtouris
        """negative for repeating, 0 for flag, 1 or more for values"""
94 dfee2caf Stavros Sachtouris
        return getattr(self, '_arity', None)
95 fd5db045 Stavros Sachtouris
96 dfee2caf Stavros Sachtouris
    @arity.setter
97 dfee2caf Stavros Sachtouris
    def arity(self, newarity):
98 dfee2caf Stavros Sachtouris
        newarity = int(newarity)
99 dfee2caf Stavros Sachtouris
        self._arity = newarity
100 dfee2caf Stavros Sachtouris
101 fd5db045 Stavros Sachtouris
    @property
102 dfee2caf Stavros Sachtouris
    def default(self):
103 edb7fc1a Stavros Sachtouris
        """the value of this argument when not set"""
104 dfee2caf Stavros Sachtouris
        if not hasattr(self, '_default'):
105 dfee2caf Stavros Sachtouris
            self._default = False if self.arity == 0 else None
106 dfee2caf Stavros Sachtouris
        return self._default
107 fd5db045 Stavros Sachtouris
108 dfee2caf Stavros Sachtouris
    @default.setter
109 dfee2caf Stavros Sachtouris
    def default(self, newdefault):
110 dfee2caf Stavros Sachtouris
        self._default = newdefault
111 dfee2caf Stavros Sachtouris
112 fd5db045 Stavros Sachtouris
    @property
113 dfee2caf Stavros Sachtouris
    def value(self):
114 edb7fc1a Stavros Sachtouris
        """the value of the argument"""
115 dfee2caf Stavros Sachtouris
        return getattr(self, '_value', self.default)
116 fd5db045 Stavros Sachtouris
117 dfee2caf Stavros Sachtouris
    @value.setter
118 dfee2caf Stavros Sachtouris
    def value(self, newvalue):
119 dfee2caf Stavros Sachtouris
        self._value = newvalue
120 dfee2caf Stavros Sachtouris
121 dfee2caf Stavros Sachtouris
    def update_parser(self, parser, name):
122 edb7fc1a Stavros Sachtouris
        """Update argument parser with self info"""
123 0a0b9fb6 Stavros Sachtouris
        action = 'append' if self.arity < 0\
124 0a0b9fb6 Stavros Sachtouris
            else 'store_true' if self.arity == 0\
125 0a0b9fb6 Stavros Sachtouris
            else 'store'
126 dfee2caf Stavros Sachtouris
        parser.add_argument(*self.parsed_name, dest=name, action=action,
127 dfee2caf Stavros Sachtouris
            default=self.default, help=self.help)
128 dfee2caf Stavros Sachtouris
129 dfee2caf Stavros Sachtouris
    def main(self):
130 edb7fc1a Stavros Sachtouris
        """Overide this method to give functionality to your args"""
131 dfee2caf Stavros Sachtouris
        raise NotImplementedError
132 dfee2caf Stavros Sachtouris
133 fd5db045 Stavros Sachtouris
134 9bdc89da Stavros Sachtouris
class ConfigArgument(Argument):
135 439926dd Stavros Sachtouris
    """Manage a kamaki configuration (file)"""
136 edb7fc1a Stavros Sachtouris
137 e9a92550 Stavros Sachtouris
    _config_file = None
138 e9a92550 Stavros Sachtouris
139 fd5db045 Stavros Sachtouris
    @property
140 c41a86b2 Stavros Sachtouris
    def value(self):
141 439926dd Stavros Sachtouris
        """A Config object"""
142 d486baec Stavros Sachtouris
        super(self.__class__, self).value
143 c41a86b2 Stavros Sachtouris
        return super(self.__class__, self).value
144 fd5db045 Stavros Sachtouris
145 c41a86b2 Stavros Sachtouris
    @value.setter
146 c41a86b2 Stavros Sachtouris
    def value(self, config_file):
147 e9a92550 Stavros Sachtouris
        if config_file:
148 e9a92550 Stavros Sachtouris
            self._value = Config(config_file)
149 e9a92550 Stavros Sachtouris
            self._config_file = config_file
150 e9a92550 Stavros Sachtouris
        elif self._config_file:
151 e9a92550 Stavros Sachtouris
            self._value = Config(self._config_file)
152 e9a92550 Stavros Sachtouris
        else:
153 e9a92550 Stavros Sachtouris
            self._value = Config()
154 9bdc89da Stavros Sachtouris
155 c41a86b2 Stavros Sachtouris
    def get(self, group, term):
156 439926dd Stavros Sachtouris
        """Get a configuration setting from the Config object"""
157 c41a86b2 Stavros Sachtouris
        return self.value.get(group, term)
158 c41a86b2 Stavros Sachtouris
159 c41a86b2 Stavros Sachtouris
    def get_groups(self):
160 c41a86b2 Stavros Sachtouris
        return self.value.apis()
161 017d37ce Stavros Sachtouris
162 017d37ce Stavros Sachtouris
_config_arg = ConfigArgument(1, 'Path to configuration file', '--config')
163 017d37ce Stavros Sachtouris
164 fd5db045 Stavros Sachtouris
165 9bdc89da Stavros Sachtouris
class CmdLineConfigArgument(Argument):
166 edb7fc1a Stavros Sachtouris
    """Set a run-time setting option (not persistent)"""
167 edb7fc1a Stavros Sachtouris
168 c41a86b2 Stavros Sachtouris
    def __init__(self, config_arg, help='', parsed_name=None, default=None):
169 c41a86b2 Stavros Sachtouris
        super(self.__class__, self).__init__(1, help, parsed_name, default)
170 c41a86b2 Stavros Sachtouris
        self._config_arg = config_arg
171 c41a86b2 Stavros Sachtouris
172 fd5db045 Stavros Sachtouris
    @property
173 c41a86b2 Stavros Sachtouris
    def value(self):
174 439926dd Stavros Sachtouris
        """A key=val option"""
175 c41a86b2 Stavros Sachtouris
        return super(self.__class__, self).value
176 fd5db045 Stavros Sachtouris
177 c41a86b2 Stavros Sachtouris
    @value.setter
178 c41a86b2 Stavros Sachtouris
    def value(self, options):
179 c41a86b2 Stavros Sachtouris
        if options == self.default:
180 c41a86b2 Stavros Sachtouris
            return
181 fd5db045 Stavros Sachtouris
        if not isinstance(options, list):
182 fd5db045 Stavros Sachtouris
            options = [unicode(options)]
183 c41a86b2 Stavros Sachtouris
        for option in options:
184 c41a86b2 Stavros Sachtouris
            keypath, sep, val = option.partition('=')
185 c41a86b2 Stavros Sachtouris
            if not sep:
186 b696ed2c Stavros Sachtouris
                raiseCLIError(CLISyntaxError('Argument Syntax Error '),
187 b696ed2c Stavros Sachtouris
                    details=['%s is missing a "="',
188 b696ed2c Stavros Sachtouris
                    ' (usage: -o section.key=val)' % option]
189 b696ed2c Stavros Sachtouris
                )
190 c41a86b2 Stavros Sachtouris
            section, sep, key = keypath.partition('.')
191 0a0b9fb6 Stavros Sachtouris
        if not sep:
192 0a0b9fb6 Stavros Sachtouris
            key = section
193 0a0b9fb6 Stavros Sachtouris
            section = 'global'
194 0a0b9fb6 Stavros Sachtouris
        self._config_arg.value.override(
195 0a0b9fb6 Stavros Sachtouris
            section.strip(),
196 fd5db045 Stavros Sachtouris
            key.strip(),
197 fd5db045 Stavros Sachtouris
            val.strip())
198 fd5db045 Stavros Sachtouris
199 c41a86b2 Stavros Sachtouris
200 c41a86b2 Stavros Sachtouris
class FlagArgument(Argument):
201 edb7fc1a Stavros Sachtouris
    """
202 439926dd Stavros Sachtouris
    :value: true if set, false otherwise
203 edb7fc1a Stavros Sachtouris
    """
204 edb7fc1a Stavros Sachtouris
205 40a9c357 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=False):
206 c41a86b2 Stavros Sachtouris
        super(FlagArgument, self).__init__(0, help, parsed_name, default)
207 c41a86b2 Stavros Sachtouris
208 fd5db045 Stavros Sachtouris
209 c41a86b2 Stavros Sachtouris
class ValueArgument(Argument):
210 edb7fc1a Stavros Sachtouris
    """
211 edb7fc1a Stavros Sachtouris
    :value type: string
212 edb7fc1a Stavros Sachtouris
    :value returns: given value or default
213 edb7fc1a Stavros Sachtouris
    """
214 edb7fc1a Stavros Sachtouris
215 c41a86b2 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
216 c41a86b2 Stavros Sachtouris
        super(ValueArgument, self).__init__(1, help, parsed_name, default)
217 c41a86b2 Stavros Sachtouris
218 fd5db045 Stavros Sachtouris
219 e3d4d442 Stavros Sachtouris
class IntArgument(ValueArgument):
220 edb7fc1a Stavros Sachtouris
221 fd5db045 Stavros Sachtouris
    @property
222 e3d4d442 Stavros Sachtouris
    def value(self):
223 439926dd Stavros Sachtouris
        """integer (type checking)"""
224 e3d4d442 Stavros Sachtouris
        return getattr(self, '_value', self.default)
225 fd5db045 Stavros Sachtouris
226 e3d4d442 Stavros Sachtouris
    @value.setter
227 e3d4d442 Stavros Sachtouris
    def value(self, newvalue):
228 e3d4d442 Stavros Sachtouris
        if newvalue == self.default:
229 e3d4d442 Stavros Sachtouris
            self._value = self.default
230 e3d4d442 Stavros Sachtouris
            return
231 e3d4d442 Stavros Sachtouris
        try:
232 e3d4d442 Stavros Sachtouris
            self._value = int(newvalue)
233 e3d4d442 Stavros Sachtouris
        except ValueError:
234 b696ed2c Stavros Sachtouris
            raiseCLIError(CLISyntaxError('IntArgument Error'),
235 fd5db045 Stavros Sachtouris
                details='Value %s not an int' % newvalue)
236 fd5db045 Stavros Sachtouris
237 e3d4d442 Stavros Sachtouris
238 c41a86b2 Stavros Sachtouris
class VersionArgument(FlagArgument):
239 edb7fc1a Stavros Sachtouris
    """A flag argument with that prints current version"""
240 edb7fc1a Stavros Sachtouris
241 fd5db045 Stavros Sachtouris
    @property
242 c41a86b2 Stavros Sachtouris
    def value(self):
243 439926dd Stavros Sachtouris
        """bool"""
244 c41a86b2 Stavros Sachtouris
        return super(self.__class__, self).value
245 fd5db045 Stavros Sachtouris
246 c41a86b2 Stavros Sachtouris
    @value.setter
247 c41a86b2 Stavros Sachtouris
    def value(self, newvalue):
248 c41a86b2 Stavros Sachtouris
        self._value = newvalue
249 c41a86b2 Stavros Sachtouris
        self.main()
250 c41a86b2 Stavros Sachtouris
251 c41a86b2 Stavros Sachtouris
    def main(self):
252 439926dd Stavros Sachtouris
        """Print current version"""
253 c41a86b2 Stavros Sachtouris
        if self.value:
254 c41a86b2 Stavros Sachtouris
            import kamaki
255 fd5db045 Stavros Sachtouris
            print('kamaki %s' % kamaki.__version__)
256 fd5db045 Stavros Sachtouris
257 9bdc89da Stavros Sachtouris
258 0a0b9fb6 Stavros Sachtouris
class KeyValueArgument(Argument):
259 edb7fc1a Stavros Sachtouris
    """A Value Argument that can be repeated
260 edb7fc1a Stavros Sachtouris

261 439926dd Stavros Sachtouris
    :syntax: --<arg> key1=value1 --<arg> key2=value2 ...
262 edb7fc1a Stavros Sachtouris
    """
263 edb7fc1a Stavros Sachtouris
264 0a0b9fb6 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=[]):
265 0a0b9fb6 Stavros Sachtouris
        super(KeyValueArgument, self).__init__(-1, help, parsed_name, default)
266 f3e94e06 Stavros Sachtouris
267 fd5db045 Stavros Sachtouris
    @property
268 f3e94e06 Stavros Sachtouris
    def value(self):
269 439926dd Stavros Sachtouris
        """
270 439926dd Stavros Sachtouris
        :input: key=value
271 439926dd Stavros Sachtouris
        :output: {'key1':'value1', 'key2':'value2', ...}
272 439926dd Stavros Sachtouris
        """
273 f3e94e06 Stavros Sachtouris
        return super(KeyValueArgument, self).value
274 fd5db045 Stavros Sachtouris
275 fd5db045 Stavros Sachtouris
    @value.setter
276 f3e94e06 Stavros Sachtouris
    def value(self, keyvalue_pairs):
277 0a0b9fb6 Stavros Sachtouris
        self._value = {}
278 f3e94e06 Stavros Sachtouris
        for pair in keyvalue_pairs:
279 fd5db045 Stavros Sachtouris
            key, sep, val = pair.partition('=')
280 f3e94e06 Stavros Sachtouris
            if not sep:
281 b696ed2c Stavros Sachtouris
                raiseCLIError(CLISyntaxError('Argument syntax error '),
282 0a0b9fb6 Stavros Sachtouris
                    details='%s is missing a "=" (usage: key1=val1 )\n' % pair)
283 23803b28 Stavros Sachtouris
            self._value[key.strip()] = val.strip()
284 f3e94e06 Stavros Sachtouris
285 fd1f1d96 Stavros Sachtouris
286 fd1f1d96 Stavros Sachtouris
class ProgressBarArgument(FlagArgument):
287 439926dd Stavros Sachtouris
    """Manage a progress bar"""
288 fd1f1d96 Stavros Sachtouris
289 fd1f1d96 Stavros Sachtouris
    def __init__(self, help='', parsed_name='', default=True):
290 fd1f1d96 Stavros Sachtouris
        self.suffix = '%(percent)d%%'
291 fd1f1d96 Stavros Sachtouris
        super(ProgressBarArgument, self).__init__(help, parsed_name, default)
292 fd1f1d96 Stavros Sachtouris
        try:
293 1d329d27 Stavros Sachtouris
            KamakiProgressBar
294 fd1f1d96 Stavros Sachtouris
        except NameError:
295 db8d1766 Stavros Sachtouris
            kloger.warning('no progress bar functionality')
296 fd1f1d96 Stavros Sachtouris
297 852a22e7 Stavros Sachtouris
    def clone(self):
298 439926dd Stavros Sachtouris
        """Get a modifiable copy of this bar"""
299 852a22e7 Stavros Sachtouris
        newarg = ProgressBarArgument(
300 852a22e7 Stavros Sachtouris
            self.help,
301 852a22e7 Stavros Sachtouris
            self.parsed_name,
302 852a22e7 Stavros Sachtouris
            self.default)
303 852a22e7 Stavros Sachtouris
        newarg._value = self._value
304 852a22e7 Stavros Sachtouris
        return newarg
305 852a22e7 Stavros Sachtouris
306 fd1f1d96 Stavros Sachtouris
    def get_generator(self, message, message_len=25):
307 439926dd Stavros Sachtouris
        """Get a generator to handle progress of the bar (gen.next())"""
308 fd1f1d96 Stavros Sachtouris
        if self.value:
309 fd1f1d96 Stavros Sachtouris
            return None
310 fd1f1d96 Stavros Sachtouris
        try:
311 1d329d27 Stavros Sachtouris
            self.bar = KamakiProgressBar()
312 fd1f1d96 Stavros Sachtouris
        except NameError:
313 329753ae Stavros Sachtouris
            self.value = None
314 329753ae Stavros Sachtouris
            return self.value
315 329753ae Stavros Sachtouris
        self.bar.message = message.ljust(message_len)
316 852a22e7 Stavros Sachtouris
        self.bar.suffix = '%(percent)d%% - %(eta)ds'
317 a10f5561 Stavros Sachtouris
        self.bar.start()
318 fd1f1d96 Stavros Sachtouris
319 852a22e7 Stavros Sachtouris
        def progress_gen(n):
320 852a22e7 Stavros Sachtouris
            for i in self.bar.iter(range(int(n))):
321 852a22e7 Stavros Sachtouris
                yield
322 852a22e7 Stavros Sachtouris
            yield
323 852a22e7 Stavros Sachtouris
        return progress_gen
324 fd1f1d96 Stavros Sachtouris
325 852a22e7 Stavros Sachtouris
    def finish(self):
326 439926dd Stavros Sachtouris
        """Stop progress bar, return terminal cursor to user"""
327 852a22e7 Stavros Sachtouris
        if self.value:
328 852a22e7 Stavros Sachtouris
            return
329 852a22e7 Stavros Sachtouris
        mybar = getattr(self, 'bar', None)
330 852a22e7 Stavros Sachtouris
        if mybar:
331 852a22e7 Stavros Sachtouris
            mybar.finish()
332 fd1f1d96 Stavros Sachtouris
333 fd1f1d96 Stavros Sachtouris
334 fd5db045 Stavros Sachtouris
_arguments = dict(config=_config_arg,
335 fd5db045 Stavros Sachtouris
    help=Argument(0, 'Show help message', ('-h', '--help')),
336 fd5db045 Stavros Sachtouris
    debug=FlagArgument('Include debug output', ('-d', '--debug')),
337 fd5db045 Stavros Sachtouris
    include=FlagArgument('Include protocol headers in the output',
338 fd5db045 Stavros Sachtouris
        ('-i', '--include')),
339 fd5db045 Stavros Sachtouris
    silent=FlagArgument('Do not output anything', ('-s', '--silent')),
340 fd5db045 Stavros Sachtouris
    verbose=FlagArgument('More info at response', ('-v', '--verbose')),
341 fd5db045 Stavros Sachtouris
    version=VersionArgument('Print current version', ('-V', '--version')),
342 fd5db045 Stavros Sachtouris
    options=CmdLineConfigArgument(_config_arg,
343 fd5db045 Stavros Sachtouris
        'Override a config value',
344 fd5db045 Stavros Sachtouris
        ('-o', '--options'))
345 9bdc89da Stavros Sachtouris
)
346 439926dd Stavros Sachtouris
"""Initial command line interface arguments"""
347 439926dd Stavros Sachtouris
348 439926dd Stavros Sachtouris
349 439926dd Stavros Sachtouris
"""
350 439926dd Stavros Sachtouris
Mechanism:
351 439926dd Stavros Sachtouris
    init_parser
352 439926dd Stavros Sachtouris
    parse_known_args
353 439926dd Stavros Sachtouris
    manage top-level user arguments input
354 439926dd Stavros Sachtouris
    find user-requested command
355 439926dd Stavros Sachtouris
    add command-specific arguments to dict
356 439926dd Stavros Sachtouris
    update_arguments
357 439926dd Stavros Sachtouris
"""
358 439926dd Stavros Sachtouris
359 439926dd Stavros Sachtouris
360 7c2247a0 Stavros Sachtouris
class ArgumentParseManager(object):
361 e0da0f90 Stavros Sachtouris
    """Manage (initialize and update) an ArgumentParser object"""
362 e0da0f90 Stavros Sachtouris
363 5ad77121 Stavros Sachtouris
    parser = None
364 7c2247a0 Stavros Sachtouris
    _arguments = {}
365 b3dd8f4b Stavros Sachtouris
    _parser_modified = False
366 b3dd8f4b Stavros Sachtouris
    _parsed = None
367 b3dd8f4b Stavros Sachtouris
    _unparsed = None
368 e0da0f90 Stavros Sachtouris
369 e0da0f90 Stavros Sachtouris
    def __init__(self, exe, arguments=None):
370 e0da0f90 Stavros Sachtouris
        """
371 e0da0f90 Stavros Sachtouris
        :param exe: (str) the basic command (e.g. 'kamaki')
372 e0da0f90 Stavros Sachtouris

373 e0da0f90 Stavros Sachtouris
        :param arguments: (dict) if given, overrides the global _argument as
374 e0da0f90 Stavros Sachtouris
            the parsers arguments specification
375 e0da0f90 Stavros Sachtouris
        """
376 5ad77121 Stavros Sachtouris
        self.parser = ArgumentParser(add_help=False)
377 b3dd8f4b Stavros Sachtouris
        self.syntax = '%s <cmd_group> [<cmd_subbroup> ...] <cmd>' % exe
378 e0da0f90 Stavros Sachtouris
        if arguments:
379 e0da0f90 Stavros Sachtouris
            self.arguments = arguments
380 e0da0f90 Stavros Sachtouris
        else:
381 e0da0f90 Stavros Sachtouris
            global _arguments
382 e0da0f90 Stavros Sachtouris
            self.arguments = _arguments
383 7c2247a0 Stavros Sachtouris
        self.parse()
384 e0da0f90 Stavros Sachtouris
385 e0da0f90 Stavros Sachtouris
    @property
386 e0da0f90 Stavros Sachtouris
    def syntax(self):
387 b3dd8f4b Stavros Sachtouris
        """The command syntax (useful for help messages, descriptions, etc)"""
388 e0da0f90 Stavros Sachtouris
        return self.parser.prog
389 e0da0f90 Stavros Sachtouris
390 e0da0f90 Stavros Sachtouris
    @syntax.setter
391 e0da0f90 Stavros Sachtouris
    def syntax(self, new_syntax):
392 e0da0f90 Stavros Sachtouris
        self.parser.prog = new_syntax
393 e0da0f90 Stavros Sachtouris
394 b3dd8f4b Stavros Sachtouris
    @property
395 b3dd8f4b Stavros Sachtouris
    def arguments(self):
396 b3dd8f4b Stavros Sachtouris
        """(dict) arguments the parser should be aware of"""
397 b3dd8f4b Stavros Sachtouris
        return self._arguments
398 b3dd8f4b Stavros Sachtouris
399 b3dd8f4b Stavros Sachtouris
    @arguments.setter
400 b3dd8f4b Stavros Sachtouris
    def arguments(self, new_arguments):
401 b3dd8f4b Stavros Sachtouris
        if new_arguments:
402 b3dd8f4b Stavros Sachtouris
            assert isinstance(new_arguments, dict)
403 b3dd8f4b Stavros Sachtouris
        self._arguments = new_arguments
404 b3dd8f4b Stavros Sachtouris
        self.update_parser()
405 b3dd8f4b Stavros Sachtouris
406 7c2247a0 Stavros Sachtouris
    @property
407 b3dd8f4b Stavros Sachtouris
    def parsed(self):
408 7c2247a0 Stavros Sachtouris
        """(Namespace) parser-matched terms"""
409 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
410 b3dd8f4b Stavros Sachtouris
            self.parse()
411 b3dd8f4b Stavros Sachtouris
        return self._parsed
412 b3dd8f4b Stavros Sachtouris
413 b3dd8f4b Stavros Sachtouris
    @property
414 b3dd8f4b Stavros Sachtouris
    def unparsed(self):
415 b3dd8f4b Stavros Sachtouris
        """(list) parser-unmatched terms"""
416 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
417 b3dd8f4b Stavros Sachtouris
            self.parse()
418 b3dd8f4b Stavros Sachtouris
        return self._unparsed
419 b3dd8f4b Stavros Sachtouris
420 e0da0f90 Stavros Sachtouris
    def update_parser(self, arguments=None):
421 e0da0f90 Stavros Sachtouris
        """Load argument specifications to parser
422 e0da0f90 Stavros Sachtouris

423 e0da0f90 Stavros Sachtouris
        :param arguments: if not given, update self.arguments instead
424 e0da0f90 Stavros Sachtouris
        """
425 e0da0f90 Stavros Sachtouris
        if not arguments:
426 b3dd8f4b Stavros Sachtouris
            arguments = self._arguments
427 e0da0f90 Stavros Sachtouris
428 e0da0f90 Stavros Sachtouris
        for name, arg in arguments.items():
429 e0da0f90 Stavros Sachtouris
            try:
430 e0da0f90 Stavros Sachtouris
                arg.update_parser(self.parser, name)
431 b3dd8f4b Stavros Sachtouris
                self._parser_modified = True
432 e0da0f90 Stavros Sachtouris
            except ArgumentError:
433 e0da0f90 Stavros Sachtouris
                pass
434 e0da0f90 Stavros Sachtouris
435 7c2247a0 Stavros Sachtouris
    def update_arguments(self, new_arguments):
436 7c2247a0 Stavros Sachtouris
        """Add to / update existing arguments
437 7c2247a0 Stavros Sachtouris

438 7c2247a0 Stavros Sachtouris
        :param new_arguments: (dict)
439 7c2247a0 Stavros Sachtouris
        """
440 7c2247a0 Stavros Sachtouris
        if new_arguments:
441 7c2247a0 Stavros Sachtouris
            assert isinstance(new_arguments, dict)
442 7c2247a0 Stavros Sachtouris
            self._arguments.update(new_arguments)
443 7c2247a0 Stavros Sachtouris
            self.update_parser()
444 7c2247a0 Stavros Sachtouris
445 120126f1 Stavros Sachtouris
    def parse(self, new_args=None):
446 7c2247a0 Stavros Sachtouris
        """Do parse user input"""
447 120126f1 Stavros Sachtouris
        if new_args:
448 120126f1 Stavros Sachtouris
            self._parsed, unparsed = self.parser.parse_known_args(new_args)
449 120126f1 Stavros Sachtouris
        else:
450 120126f1 Stavros Sachtouris
            self._parsed, unparsed = self.parser.parse_known_args()
451 b3dd8f4b Stavros Sachtouris
        for name, arg in self.arguments.items():
452 b3dd8f4b Stavros Sachtouris
            arg.value = getattr(self._parsed, name, arg.default)
453 b3dd8f4b Stavros Sachtouris
        self._unparsed = []
454 b3dd8f4b Stavros Sachtouris
        for term in unparsed:
455 b3dd8f4b Stavros Sachtouris
            self._unparsed += split_input(' \'%s\' ' % term)
456 b3dd8f4b Stavros Sachtouris
        self._parser_modified = False