Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / argument / __init__.py @ 94370709

History | View | Annotate | Download (22.8 kB)

1 e3f01d64 Stavros Sachtouris
# Copyright 2012-2013 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 c3d42104 Stavros Sachtouris
from kamaki.cli.errors import (
36 c3d42104 Stavros Sachtouris
    CLISyntaxError, raiseCLIError, CLIInvalidArgument)
37 7b109aa7 Stavros Sachtouris
from kamaki.cli.utils import split_input, to_bytes
38 7637d600 Stavros Sachtouris
39 04d01cd4 Stavros Sachtouris
from datetime import datetime as dtm
40 ea4a21b8 Stavros Sachtouris
from time import mktime
41 56d84a4e Stavros Sachtouris
from sys import stderr
42 db8d1766 Stavros Sachtouris
43 7637d600 Stavros Sachtouris
from logging import getLogger
44 af6de846 Stavros Sachtouris
from argparse import ArgumentParser, ArgumentError
45 2703cceb Stavros Sachtouris
from argparse import RawDescriptionHelpFormatter
46 67083ca0 Stavros Sachtouris
from progress.bar import ShadyBar as KamakiProgressBar
47 fd1f1d96 Stavros Sachtouris
48 7637d600 Stavros Sachtouris
log = getLogger(__name__)
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 5286e2c3 Stavros Sachtouris
    This is the top-level Argument class. It is suggested to extent this
54 edb7fc1a Stavros Sachtouris
    class into more specific argument types.
55 edb7fc1a Stavros Sachtouris
    """
56 eb647cfe Stavros Sachtouris
    lvalue_delimiter = '/'
57 dfee2caf Stavros Sachtouris
58 dfee2caf Stavros Sachtouris
    def __init__(self, arity, help=None, parsed_name=None, default=None):
59 606fe15f Stavros Sachtouris
        self.arity = int(arity)
60 5286e2c3 Stavros Sachtouris
        self.help = '%s' % help or ''
61 dfee2caf Stavros Sachtouris
62 f17d6cb5 Stavros Sachtouris
        assert parsed_name, 'No parsed name for argument %s' % self
63 f17d6cb5 Stavros Sachtouris
        self.parsed_name = list(parsed_name) if isinstance(
64 f17d6cb5 Stavros Sachtouris
            parsed_name, list) or isinstance(parsed_name, tuple) else (
65 f17d6cb5 Stavros Sachtouris
                '%s' % parsed_name).split()
66 f17d6cb5 Stavros Sachtouris
        for name in self.parsed_name:
67 f17d6cb5 Stavros Sachtouris
            assert name.count(' ') == 0, '%s: Invalid parse name "%s"' % (
68 f17d6cb5 Stavros Sachtouris
                self, name)
69 f17d6cb5 Stavros Sachtouris
            msg = '%s: Invalid parse name "%s" should start with a "-"' % (
70 f17d6cb5 Stavros Sachtouris
                    self, name)
71 f17d6cb5 Stavros Sachtouris
            assert name.startswith('-'), msg
72 f17d6cb5 Stavros Sachtouris
73 a6d2ad78 Stavros Sachtouris
        self.default = default or None
74 dfee2caf Stavros Sachtouris
75 fd5db045 Stavros Sachtouris
    @property
76 dfee2caf Stavros Sachtouris
    def value(self):
77 dfee2caf Stavros Sachtouris
        return getattr(self, '_value', self.default)
78 fd5db045 Stavros Sachtouris
79 dfee2caf Stavros Sachtouris
    @value.setter
80 dfee2caf Stavros Sachtouris
    def value(self, newvalue):
81 dfee2caf Stavros Sachtouris
        self._value = newvalue
82 dfee2caf Stavros Sachtouris
83 dfee2caf Stavros Sachtouris
    def update_parser(self, parser, name):
84 edb7fc1a Stavros Sachtouris
        """Update argument parser with self info"""
85 f17d6cb5 Stavros Sachtouris
        action = 'append' if self.arity < 0 else (
86 f17d6cb5 Stavros Sachtouris
            'store' if self.arity else 'store_true')
87 de73876b Stavros Sachtouris
        parser.add_argument(
88 de73876b Stavros Sachtouris
            *self.parsed_name,
89 f17d6cb5 Stavros Sachtouris
            dest=name, action=action, default=self.default, help=self.help)
90 dfee2caf Stavros Sachtouris
91 eb647cfe Stavros Sachtouris
    @property
92 eb647cfe Stavros Sachtouris
    def lvalue(self):
93 eb647cfe Stavros Sachtouris
        """A printable form of the left value when calling an argument e.g.,
94 eb647cfe Stavros Sachtouris
        --left-value=right-value"""
95 eb647cfe Stavros Sachtouris
        return (self.lvalue_delimiter or ' ').join(self.parsed_name or [])
96 eb647cfe Stavros Sachtouris
97 fd5db045 Stavros Sachtouris
98 9bdc89da Stavros Sachtouris
class ConfigArgument(Argument):
99 439926dd Stavros Sachtouris
    """Manage a kamaki configuration (file)"""
100 edb7fc1a Stavros Sachtouris
101 a7aacf12 Stavros Sachtouris
    def __init__(self, help, parsed_name=('-c', '--config')):
102 a7aacf12 Stavros Sachtouris
        super(ConfigArgument, self).__init__(1, help, parsed_name, None)
103 a7aacf12 Stavros Sachtouris
        self.file_path = None
104 e9a92550 Stavros Sachtouris
105 fd5db045 Stavros Sachtouris
    @property
106 c41a86b2 Stavros Sachtouris
    def value(self):
107 c22183b9 Stavros Sachtouris
        return getattr(self, '_value', None)
108 fd5db045 Stavros Sachtouris
109 c41a86b2 Stavros Sachtouris
    @value.setter
110 c41a86b2 Stavros Sachtouris
    def value(self, config_file):
111 e9a92550 Stavros Sachtouris
        if config_file:
112 e9a92550 Stavros Sachtouris
            self._value = Config(config_file)
113 a7aacf12 Stavros Sachtouris
            self.file_path = config_file
114 a7aacf12 Stavros Sachtouris
        elif self.file_path:
115 a7aacf12 Stavros Sachtouris
            self._value = Config(self.file_path)
116 e9a92550 Stavros Sachtouris
        else:
117 e9a92550 Stavros Sachtouris
            self._value = Config()
118 9bdc89da Stavros Sachtouris
119 c41a86b2 Stavros Sachtouris
    def get(self, group, term):
120 439926dd Stavros Sachtouris
        """Get a configuration setting from the Config object"""
121 c41a86b2 Stavros Sachtouris
        return self.value.get(group, term)
122 c41a86b2 Stavros Sachtouris
123 a7aacf12 Stavros Sachtouris
    @property
124 a7aacf12 Stavros Sachtouris
    def groups(self):
125 362adf50 Stavros Sachtouris
        suffix = '_cli'
126 362adf50 Stavros Sachtouris
        slen = len(suffix)
127 362adf50 Stavros Sachtouris
        return [term[:-slen] for term in self.value.keys('global') if (
128 362adf50 Stavros Sachtouris
            term.endswith(suffix))]
129 f724cd35 Stavros Sachtouris
130 a7aacf12 Stavros Sachtouris
    @property
131 a7aacf12 Stavros Sachtouris
    def cli_specs(self):
132 362adf50 Stavros Sachtouris
        suffix = '_cli'
133 362adf50 Stavros Sachtouris
        slen = len(suffix)
134 362adf50 Stavros Sachtouris
        return [(k[:-slen], v) for k, v in self.value.items('global') if (
135 362adf50 Stavros Sachtouris
            k.endswith(suffix))]
136 362adf50 Stavros Sachtouris
137 362adf50 Stavros Sachtouris
    def get_global(self, option):
138 534e7bbb Stavros Sachtouris
        return self.value.get('global', option)
139 362adf50 Stavros Sachtouris
140 144b3551 Stavros Sachtouris
    def get_cloud(self, cloud, option):
141 144b3551 Stavros Sachtouris
        return self.value.get_cloud(cloud, option)
142 017d37ce Stavros Sachtouris
143 f17d6cb5 Stavros Sachtouris
144 a7aacf12 Stavros Sachtouris
_config_arg = ConfigArgument('Path to config file')
145 017d37ce Stavros Sachtouris
146 fd5db045 Stavros Sachtouris
147 1bd4f765 Stavros Sachtouris
class RuntimeConfigArgument(Argument):
148 edb7fc1a Stavros Sachtouris
    """Set a run-time setting option (not persistent)"""
149 edb7fc1a Stavros Sachtouris
150 c41a86b2 Stavros Sachtouris
    def __init__(self, config_arg, help='', parsed_name=None, default=None):
151 c41a86b2 Stavros Sachtouris
        super(self.__class__, self).__init__(1, help, parsed_name, default)
152 c41a86b2 Stavros Sachtouris
        self._config_arg = config_arg
153 c41a86b2 Stavros Sachtouris
154 fd5db045 Stavros Sachtouris
    @property
155 c41a86b2 Stavros Sachtouris
    def value(self):
156 34c480f2 Stavros Sachtouris
        return super(RuntimeConfigArgument, self).value
157 fd5db045 Stavros Sachtouris
158 c41a86b2 Stavros Sachtouris
    @value.setter
159 c41a86b2 Stavros Sachtouris
    def value(self, options):
160 c41a86b2 Stavros Sachtouris
        if options == self.default:
161 c41a86b2 Stavros Sachtouris
            return
162 fd5db045 Stavros Sachtouris
        if not isinstance(options, list):
163 a517ff50 Stavros Sachtouris
            options = ['%s' % options]
164 c41a86b2 Stavros Sachtouris
        for option in options:
165 c41a86b2 Stavros Sachtouris
            keypath, sep, val = option.partition('=')
166 c41a86b2 Stavros Sachtouris
            if not sep:
167 de73876b Stavros Sachtouris
                raiseCLIError(
168 de73876b Stavros Sachtouris
                    CLISyntaxError('Argument Syntax Error '),
169 24ff0a35 Stavros Sachtouris
                    details=[
170 24ff0a35 Stavros Sachtouris
                        '%s is missing a "="',
171 24ff0a35 Stavros Sachtouris
                        ' (usage: -o section.key=val)' % option])
172 c41a86b2 Stavros Sachtouris
            section, sep, key = keypath.partition('.')
173 0a0b9fb6 Stavros Sachtouris
        if not sep:
174 0a0b9fb6 Stavros Sachtouris
            key = section
175 0a0b9fb6 Stavros Sachtouris
            section = 'global'
176 0a0b9fb6 Stavros Sachtouris
        self._config_arg.value.override(
177 0a0b9fb6 Stavros Sachtouris
            section.strip(),
178 fd5db045 Stavros Sachtouris
            key.strip(),
179 fd5db045 Stavros Sachtouris
            val.strip())
180 fd5db045 Stavros Sachtouris
181 c41a86b2 Stavros Sachtouris
182 c41a86b2 Stavros Sachtouris
class FlagArgument(Argument):
183 edb7fc1a Stavros Sachtouris
    """
184 439926dd Stavros Sachtouris
    :value: true if set, false otherwise
185 edb7fc1a Stavros Sachtouris
    """
186 edb7fc1a Stavros Sachtouris
187 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
188 c41a86b2 Stavros Sachtouris
        super(FlagArgument, self).__init__(0, help, parsed_name, default)
189 c41a86b2 Stavros Sachtouris
190 fd5db045 Stavros Sachtouris
191 c41a86b2 Stavros Sachtouris
class ValueArgument(Argument):
192 edb7fc1a Stavros Sachtouris
    """
193 edb7fc1a Stavros Sachtouris
    :value type: string
194 edb7fc1a Stavros Sachtouris
    :value returns: given value or default
195 edb7fc1a Stavros Sachtouris
    """
196 edb7fc1a Stavros Sachtouris
197 c41a86b2 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
198 c41a86b2 Stavros Sachtouris
        super(ValueArgument, self).__init__(1, help, parsed_name, default)
199 c41a86b2 Stavros Sachtouris
200 fd5db045 Stavros Sachtouris
201 0155548b Stavros Sachtouris
class CommaSeparatedListArgument(ValueArgument):
202 0155548b Stavros Sachtouris
    """
203 0155548b Stavros Sachtouris
    :value type: string
204 0155548b Stavros Sachtouris
    :value returns: list of the comma separated values
205 0155548b Stavros Sachtouris
    """
206 0155548b Stavros Sachtouris
207 0155548b Stavros Sachtouris
    @property
208 0155548b Stavros Sachtouris
    def value(self):
209 0155548b Stavros Sachtouris
        return self._value or list()
210 0155548b Stavros Sachtouris
211 0155548b Stavros Sachtouris
    @value.setter
212 0155548b Stavros Sachtouris
    def value(self, newvalue):
213 0155548b Stavros Sachtouris
        self._value = newvalue.split(',') if newvalue else list()
214 0155548b Stavros Sachtouris
215 0155548b Stavros Sachtouris
216 e3d4d442 Stavros Sachtouris
class IntArgument(ValueArgument):
217 edb7fc1a Stavros Sachtouris
218 fd5db045 Stavros Sachtouris
    @property
219 e3d4d442 Stavros Sachtouris
    def value(self):
220 439926dd Stavros Sachtouris
        """integer (type checking)"""
221 e3d4d442 Stavros Sachtouris
        return getattr(self, '_value', self.default)
222 fd5db045 Stavros Sachtouris
223 e3d4d442 Stavros Sachtouris
    @value.setter
224 e3d4d442 Stavros Sachtouris
    def value(self, newvalue):
225 4a25486d Stavros Sachtouris
        if newvalue == self.default:
226 4a25486d Stavros Sachtouris
            self._value = newvalue
227 4a25486d Stavros Sachtouris
            return
228 e3d4d442 Stavros Sachtouris
        try:
229 4a25486d Stavros Sachtouris
            if int(newvalue) == float(newvalue):
230 4a25486d Stavros Sachtouris
                self._value = int(newvalue)
231 4a25486d Stavros Sachtouris
            else:
232 4a25486d Stavros Sachtouris
                raise ValueError('Raise int argument error')
233 e3d4d442 Stavros Sachtouris
        except ValueError:
234 24ff0a35 Stavros Sachtouris
            raiseCLIError(CLISyntaxError(
235 24ff0a35 Stavros Sachtouris
                'IntArgument Error',
236 c8e17a67 Stavros Sachtouris
                details=['Value %s not an int' % newvalue]))
237 fd5db045 Stavros Sachtouris
238 e3d4d442 Stavros Sachtouris
239 7b109aa7 Stavros Sachtouris
class DataSizeArgument(ValueArgument):
240 7b109aa7 Stavros Sachtouris
    """Input: a string of the form <number><unit>
241 7b109aa7 Stavros Sachtouris
    Output: the number of bytes
242 7b109aa7 Stavros Sachtouris
    Units: B, KiB, KB, MiB, MB, GiB, GB, TiB, TB
243 7b109aa7 Stavros Sachtouris
    """
244 7b109aa7 Stavros Sachtouris
245 7b109aa7 Stavros Sachtouris
    @property
246 7b109aa7 Stavros Sachtouris
    def value(self):
247 7b109aa7 Stavros Sachtouris
        return getattr(self, '_value', self.default)
248 7b109aa7 Stavros Sachtouris
249 7b109aa7 Stavros Sachtouris
    def _calculate_limit(self, user_input):
250 7b109aa7 Stavros Sachtouris
        limit = 0
251 7b109aa7 Stavros Sachtouris
        try:
252 7b109aa7 Stavros Sachtouris
            limit = int(user_input)
253 7b109aa7 Stavros Sachtouris
        except ValueError:
254 7b109aa7 Stavros Sachtouris
            index = 0
255 7b109aa7 Stavros Sachtouris
            digits = [str(num) for num in range(0, 10)] + ['.']
256 7b109aa7 Stavros Sachtouris
            while user_input[index] in digits:
257 7b109aa7 Stavros Sachtouris
                index += 1
258 7b109aa7 Stavros Sachtouris
            limit = user_input[:index]
259 7b109aa7 Stavros Sachtouris
            format = user_input[index:]
260 7b109aa7 Stavros Sachtouris
            try:
261 7b109aa7 Stavros Sachtouris
                return to_bytes(limit, format)
262 7b109aa7 Stavros Sachtouris
            except Exception as qe:
263 7b109aa7 Stavros Sachtouris
                msg = 'Failed to convert %s to bytes' % user_input,
264 7b109aa7 Stavros Sachtouris
                raiseCLIError(qe, msg, details=[
265 7b109aa7 Stavros Sachtouris
                    'Syntax: containerlimit set <limit>[format] [container]',
266 7b109aa7 Stavros Sachtouris
                    'e.g.,: containerlimit set 2.3GB mycontainer',
267 7b109aa7 Stavros Sachtouris
                    'Valid formats:',
268 7b109aa7 Stavros Sachtouris
                    '(*1024): B, KiB, MiB, GiB, TiB',
269 7b109aa7 Stavros Sachtouris
                    '(*1000): B, KB, MB, GB, TB'])
270 7b109aa7 Stavros Sachtouris
        return limit
271 7b109aa7 Stavros Sachtouris
272 7b109aa7 Stavros Sachtouris
    @value.setter
273 7b109aa7 Stavros Sachtouris
    def value(self, new_value):
274 7b109aa7 Stavros Sachtouris
        if new_value:
275 7b109aa7 Stavros Sachtouris
            self._value = self._calculate_limit(new_value)
276 7b109aa7 Stavros Sachtouris
277 7b109aa7 Stavros Sachtouris
278 04d01cd4 Stavros Sachtouris
class DateArgument(ValueArgument):
279 04d01cd4 Stavros Sachtouris
280 b7ff6e0c Stavros Sachtouris
    DATE_FORMAT = '%a %b %d %H:%M:%S %Y'
281 04d01cd4 Stavros Sachtouris
282 b7ff6e0c Stavros Sachtouris
    INPUT_FORMATS = [DATE_FORMAT, '%d-%m-%Y', '%H:%M:%S %d-%m-%Y']
283 04d01cd4 Stavros Sachtouris
284 04d01cd4 Stavros Sachtouris
    @property
285 ea4a21b8 Stavros Sachtouris
    def timestamp(self):
286 ea4a21b8 Stavros Sachtouris
        v = getattr(self, '_value', self.default)
287 ea4a21b8 Stavros Sachtouris
        return mktime(v.timetuple()) if v else None
288 ea4a21b8 Stavros Sachtouris
289 ea4a21b8 Stavros Sachtouris
    @property
290 ea4a21b8 Stavros Sachtouris
    def formated(self):
291 ea4a21b8 Stavros Sachtouris
        v = getattr(self, '_value', self.default)
292 b7ff6e0c Stavros Sachtouris
        return v.strftime(self.DATE_FORMAT) if v else None
293 ea4a21b8 Stavros Sachtouris
294 ea4a21b8 Stavros Sachtouris
    @property
295 04d01cd4 Stavros Sachtouris
    def value(self):
296 ea4a21b8 Stavros Sachtouris
        return self.timestamp
297 04d01cd4 Stavros Sachtouris
298 04d01cd4 Stavros Sachtouris
    @value.setter
299 04d01cd4 Stavros Sachtouris
    def value(self, newvalue):
300 2af87afc Stavros Sachtouris
        self._value = self.format_date(newvalue) if newvalue else self.default
301 04d01cd4 Stavros Sachtouris
302 04d01cd4 Stavros Sachtouris
    def format_date(self, datestr):
303 04d01cd4 Stavros Sachtouris
        for format in self.INPUT_FORMATS:
304 04d01cd4 Stavros Sachtouris
            try:
305 04d01cd4 Stavros Sachtouris
                t = dtm.strptime(datestr, format)
306 04d01cd4 Stavros Sachtouris
            except ValueError:
307 04d01cd4 Stavros Sachtouris
                continue
308 b7ff6e0c Stavros Sachtouris
            return t  # .strftime(self.DATE_FORMAT)
309 b7ff6e0c Stavros Sachtouris
        raiseCLIError(None, 'Date Argument Error', details=[
310 b7ff6e0c Stavros Sachtouris
            '%s not a valid date' % datestr,
311 b7ff6e0c Stavros Sachtouris
            'Correct formats:\n\t%s' % self.INPUT_FORMATS])
312 04d01cd4 Stavros Sachtouris
313 04d01cd4 Stavros Sachtouris
314 c41a86b2 Stavros Sachtouris
class VersionArgument(FlagArgument):
315 edb7fc1a Stavros Sachtouris
    """A flag argument with that prints current version"""
316 edb7fc1a Stavros Sachtouris
317 fd5db045 Stavros Sachtouris
    @property
318 c41a86b2 Stavros Sachtouris
    def value(self):
319 439926dd Stavros Sachtouris
        """bool"""
320 c41a86b2 Stavros Sachtouris
        return super(self.__class__, self).value
321 fd5db045 Stavros Sachtouris
322 c41a86b2 Stavros Sachtouris
    @value.setter
323 c41a86b2 Stavros Sachtouris
    def value(self, newvalue):
324 c41a86b2 Stavros Sachtouris
        self._value = newvalue
325 f17d6cb5 Stavros Sachtouris
        if newvalue:
326 c41a86b2 Stavros Sachtouris
            import kamaki
327 fd5db045 Stavros Sachtouris
            print('kamaki %s' % kamaki.__version__)
328 fd5db045 Stavros Sachtouris
329 9bdc89da Stavros Sachtouris
330 ca5528f1 Stavros Sachtouris
class RepeatableArgument(Argument):
331 ca5528f1 Stavros Sachtouris
    """A value argument that can be repeated"""
332 ca5528f1 Stavros Sachtouris
333 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
334 ca5528f1 Stavros Sachtouris
        super(RepeatableArgument, self).__init__(
335 ca5528f1 Stavros Sachtouris
            -1, help, parsed_name, default)
336 ca5528f1 Stavros Sachtouris
337 a6d2ad78 Stavros Sachtouris
    @property
338 a6d2ad78 Stavros Sachtouris
    def value(self):
339 a6d2ad78 Stavros Sachtouris
        return getattr(self, '_value', [])
340 a6d2ad78 Stavros Sachtouris
341 a6d2ad78 Stavros Sachtouris
    @value.setter
342 a6d2ad78 Stavros Sachtouris
    def value(self, newvalue):
343 a6d2ad78 Stavros Sachtouris
        self._value = newvalue
344 a6d2ad78 Stavros Sachtouris
345 ca5528f1 Stavros Sachtouris
346 0a0b9fb6 Stavros Sachtouris
class KeyValueArgument(Argument):
347 ca5528f1 Stavros Sachtouris
    """A Key=Value Argument that can be repeated
348 edb7fc1a Stavros Sachtouris

349 439926dd Stavros Sachtouris
    :syntax: --<arg> key1=value1 --<arg> key2=value2 ...
350 edb7fc1a Stavros Sachtouris
    """
351 edb7fc1a Stavros Sachtouris
352 a6d2ad78 Stavros Sachtouris
    def __init__(self, help='', parsed_name=None, default=None):
353 0a0b9fb6 Stavros Sachtouris
        super(KeyValueArgument, self).__init__(-1, help, parsed_name, default)
354 f3e94e06 Stavros Sachtouris
355 fd5db045 Stavros Sachtouris
    @property
356 f3e94e06 Stavros Sachtouris
    def value(self):
357 439926dd Stavros Sachtouris
        """
358 8d427cb9 Stavros Sachtouris
        :returns: (dict) {key1: val1, key2: val2, ...}
359 439926dd Stavros Sachtouris
        """
360 a6d2ad78 Stavros Sachtouris
        return getattr(self, '_value', {})
361 fd5db045 Stavros Sachtouris
362 fd5db045 Stavros Sachtouris
    @value.setter
363 f3e94e06 Stavros Sachtouris
    def value(self, keyvalue_pairs):
364 8d427cb9 Stavros Sachtouris
        """
365 8d427cb9 Stavros Sachtouris
        :param keyvalue_pairs: (str) ['key1=val1', 'key2=val2', ...]
366 8d427cb9 Stavros Sachtouris
        """
367 a6d2ad78 Stavros Sachtouris
        if keyvalue_pairs:
368 a6d2ad78 Stavros Sachtouris
            self._value = self.value
369 a6d2ad78 Stavros Sachtouris
            try:
370 a6d2ad78 Stavros Sachtouris
                for pair in keyvalue_pairs:
371 a6d2ad78 Stavros Sachtouris
                    key, sep, val = pair.partition('=')
372 a6d2ad78 Stavros Sachtouris
                    assert sep, ' %s misses a "=" (usage: key1=val1 )\n' % (
373 a6d2ad78 Stavros Sachtouris
                        pair)
374 a6d2ad78 Stavros Sachtouris
                    self._value[key] = val
375 a6d2ad78 Stavros Sachtouris
            except Exception as e:
376 a6d2ad78 Stavros Sachtouris
                raiseCLIError(e, 'KeyValueArgument Syntax Error')
377 f3e94e06 Stavros Sachtouris
378 fd1f1d96 Stavros Sachtouris
379 c3d42104 Stavros Sachtouris
class StatusArgument(ValueArgument):
380 c3d42104 Stavros Sachtouris
    """Initialize with valid_states=['list', 'of', 'states']
381 c3d42104 Stavros Sachtouris
    First state is the default"""
382 c3d42104 Stavros Sachtouris
383 c3d42104 Stavros Sachtouris
    def __init__(self, *args, **kwargs):
384 c3d42104 Stavros Sachtouris
        self.valid_states = kwargs.pop('valid_states', ['BUILD', ])
385 c3d42104 Stavros Sachtouris
        super(StatusArgument, self).__init__(*args, **kwargs)
386 c3d42104 Stavros Sachtouris
387 c3d42104 Stavros Sachtouris
    @property
388 c3d42104 Stavros Sachtouris
    def value(self):
389 c3d42104 Stavros Sachtouris
        return getattr(self, '_value', None)
390 c3d42104 Stavros Sachtouris
391 c3d42104 Stavros Sachtouris
    @value.setter
392 c3d42104 Stavros Sachtouris
    def value(self, new_status):
393 c3d42104 Stavros Sachtouris
        if new_status:
394 c3d42104 Stavros Sachtouris
            new_status = new_status.upper()
395 c3d42104 Stavros Sachtouris
            if new_status not in self.valid_states:
396 c3d42104 Stavros Sachtouris
                raise CLIInvalidArgument(
397 c3d42104 Stavros Sachtouris
                    'Invalid argument %s' % new_status, details=[
398 c3d42104 Stavros Sachtouris
                    'Usage: '
399 c3d42104 Stavros Sachtouris
                    '%s=[%s]' % (self.lvalue, '|'.join(self.valid_states))])
400 c3d42104 Stavros Sachtouris
            self._value = new_status
401 c3d42104 Stavros Sachtouris
402 c3d42104 Stavros Sachtouris
403 fd1f1d96 Stavros Sachtouris
class ProgressBarArgument(FlagArgument):
404 439926dd Stavros Sachtouris
    """Manage a progress bar"""
405 fd1f1d96 Stavros Sachtouris
406 fd1f1d96 Stavros Sachtouris
    def __init__(self, help='', parsed_name='', default=True):
407 fd1f1d96 Stavros Sachtouris
        self.suffix = '%(percent)d%%'
408 fd1f1d96 Stavros Sachtouris
        super(ProgressBarArgument, self).__init__(help, parsed_name, default)
409 fd1f1d96 Stavros Sachtouris
410 852a22e7 Stavros Sachtouris
    def clone(self):
411 439926dd Stavros Sachtouris
        """Get a modifiable copy of this bar"""
412 852a22e7 Stavros Sachtouris
        newarg = ProgressBarArgument(
413 c0fbf04c Stavros Sachtouris
            self.help, self.parsed_name, self.default)
414 852a22e7 Stavros Sachtouris
        newarg._value = self._value
415 852a22e7 Stavros Sachtouris
        return newarg
416 852a22e7 Stavros Sachtouris
417 8547cd19 Stavros Sachtouris
    def get_generator(
418 8547cd19 Stavros Sachtouris
            self, message, message_len=25, countdown=False, timeout=100):
419 439926dd Stavros Sachtouris
        """Get a generator to handle progress of the bar (gen.next())"""
420 fd1f1d96 Stavros Sachtouris
        if self.value:
421 fd1f1d96 Stavros Sachtouris
            return None
422 fd1f1d96 Stavros Sachtouris
        try:
423 1df445fe Stavros Sachtouris
            self.bar = KamakiProgressBar(
424 1df445fe Stavros Sachtouris
                message.ljust(message_len), max=timeout or 100)
425 fd1f1d96 Stavros Sachtouris
        except NameError:
426 329753ae Stavros Sachtouris
            self.value = None
427 329753ae Stavros Sachtouris
            return self.value
428 8547cd19 Stavros Sachtouris
        if countdown:
429 e9c73313 Stavros Sachtouris
            bar_phases = list(self.bar.phases)
430 8547cd19 Stavros Sachtouris
            self.bar.empty_fill, bar_phases[0] = bar_phases[-1], ''
431 8547cd19 Stavros Sachtouris
            bar_phases.reverse()
432 e9c73313 Stavros Sachtouris
            self.bar.phases = bar_phases
433 8547cd19 Stavros Sachtouris
            self.bar.bar_prefix = ' '
434 e9c73313 Stavros Sachtouris
            self.bar.bar_suffix = ' '
435 8547cd19 Stavros Sachtouris
            self.bar.suffix = '%(remaining)ds to timeout'
436 e9c73313 Stavros Sachtouris
        else:
437 e9c73313 Stavros Sachtouris
            self.bar.suffix = '%(percent)d%% - %(eta)ds'
438 a10f5561 Stavros Sachtouris
        self.bar.start()
439 fd1f1d96 Stavros Sachtouris
440 852a22e7 Stavros Sachtouris
        def progress_gen(n):
441 852a22e7 Stavros Sachtouris
            for i in self.bar.iter(range(int(n))):
442 852a22e7 Stavros Sachtouris
                yield
443 852a22e7 Stavros Sachtouris
            yield
444 852a22e7 Stavros Sachtouris
        return progress_gen
445 fd1f1d96 Stavros Sachtouris
446 852a22e7 Stavros Sachtouris
    def finish(self):
447 439926dd Stavros Sachtouris
        """Stop progress bar, return terminal cursor to user"""
448 852a22e7 Stavros Sachtouris
        if self.value:
449 852a22e7 Stavros Sachtouris
            return
450 852a22e7 Stavros Sachtouris
        mybar = getattr(self, 'bar', None)
451 852a22e7 Stavros Sachtouris
        if mybar:
452 852a22e7 Stavros Sachtouris
            mybar.finish()
453 fd1f1d96 Stavros Sachtouris
454 fd1f1d96 Stavros Sachtouris
455 de73876b Stavros Sachtouris
_arguments = dict(
456 de73876b Stavros Sachtouris
    config=_config_arg,
457 144b3551 Stavros Sachtouris
    cloud=ValueArgument('Chose a cloud to connect to', ('--cloud')),
458 fd5db045 Stavros Sachtouris
    help=Argument(0, 'Show help message', ('-h', '--help')),
459 fd5db045 Stavros Sachtouris
    debug=FlagArgument('Include debug output', ('-d', '--debug')),
460 f6822a26 Stavros Sachtouris
    #include=FlagArgument(
461 f6822a26 Stavros Sachtouris
    #    'Include raw connection data in the output', ('-i', '--include')),
462 fd5db045 Stavros Sachtouris
    silent=FlagArgument('Do not output anything', ('-s', '--silent')),
463 fd5db045 Stavros Sachtouris
    verbose=FlagArgument('More info at response', ('-v', '--verbose')),
464 fd5db045 Stavros Sachtouris
    version=VersionArgument('Print current version', ('-V', '--version')),
465 1bd4f765 Stavros Sachtouris
    options=RuntimeConfigArgument(
466 cb4a5d9c Stavros Sachtouris
        _config_arg, 'Override a config value', ('-o', '--options'))
467 9bdc89da Stavros Sachtouris
)
468 cb4a5d9c Stavros Sachtouris
469 cb4a5d9c Stavros Sachtouris
470 cb4a5d9c Stavros Sachtouris
#  Initial command line interface arguments
471 439926dd Stavros Sachtouris
472 439926dd Stavros Sachtouris
473 7c2247a0 Stavros Sachtouris
class ArgumentParseManager(object):
474 e0da0f90 Stavros Sachtouris
    """Manage (initialize and update) an ArgumentParser object"""
475 e0da0f90 Stavros Sachtouris
476 49e85ee2 Stavros Sachtouris
    def __init__(
477 49e85ee2 Stavros Sachtouris
            self, exe,
478 9b3c8fd9 Stavros Sachtouris
            arguments=None, required=None, syntax=None, description=None,
479 9b3c8fd9 Stavros Sachtouris
            check_required=True):
480 e0da0f90 Stavros Sachtouris
        """
481 e0da0f90 Stavros Sachtouris
        :param exe: (str) the basic command (e.g. 'kamaki')
482 e0da0f90 Stavros Sachtouris

483 e0da0f90 Stavros Sachtouris
        :param arguments: (dict) if given, overrides the global _argument as
484 e0da0f90 Stavros Sachtouris
            the parsers arguments specification
485 56d84a4e Stavros Sachtouris
        :param required: (list or tuple) an iterable of argument keys, denoting
486 56d84a4e Stavros Sachtouris
            which arguments are required. A tuple denoted an AND relation,
487 56d84a4e Stavros Sachtouris
            while a list denotes an OR relation e.g., ['a', 'b'] means that
488 56d84a4e Stavros Sachtouris
            either 'a' or 'b' is required, while ('a', 'b') means that both 'a'
489 56d84a4e Stavros Sachtouris
            and 'b' ar required.
490 56d84a4e Stavros Sachtouris
            Nesting is allowed e.g., ['a', ('b', 'c'), ['d', 'e']] means that
491 56d84a4e Stavros Sachtouris
            this command required either 'a', or both 'b' and 'c', or one of
492 56d84a4e Stavros Sachtouris
            'd', 'e'.
493 56d84a4e Stavros Sachtouris
            Repeated arguments are also allowed e.g., [('a', 'b'), ('a', 'c'),
494 56d84a4e Stavros Sachtouris
            ['b', 'c']] means that the command required either 'a' and 'b' or
495 56d84a4e Stavros Sachtouris
            'a' and 'c' or at least one of 'b', 'c' and could be written as
496 56d84a4e Stavros Sachtouris
            [('a', ['b', 'c']), ['b', 'c']]
497 49e85ee2 Stavros Sachtouris
        :param syntax: (str) The basic syntax of the arguments. Default:
498 49e85ee2 Stavros Sachtouris
            exe <cmd_group> [<cmd_subbroup> ...] <cmd>
499 49e85ee2 Stavros Sachtouris
        :param description: (str) The description of the commands or ''
500 9b3c8fd9 Stavros Sachtouris
        :param check_required: (bool) Set to False inorder not to check for
501 9b3c8fd9 Stavros Sachtouris
            required argument values while parsing
502 e0da0f90 Stavros Sachtouris
        """
503 de73876b Stavros Sachtouris
        self.parser = ArgumentParser(
504 320aac17 Stavros Sachtouris
            add_help=False, formatter_class=RawDescriptionHelpFormatter)
505 56d84a4e Stavros Sachtouris
        self._exe = exe
506 49e85ee2 Stavros Sachtouris
        self.syntax = syntax or (
507 49e85ee2 Stavros Sachtouris
            '%s <cmd_group> [<cmd_subbroup> ...] <cmd>' % exe)
508 9b3c8fd9 Stavros Sachtouris
        self.required, self.check_required = required, check_required
509 49e85ee2 Stavros Sachtouris
        self.parser.description = description or ''
510 e0da0f90 Stavros Sachtouris
        if arguments:
511 e0da0f90 Stavros Sachtouris
            self.arguments = arguments
512 e0da0f90 Stavros Sachtouris
        else:
513 e0da0f90 Stavros Sachtouris
            global _arguments
514 e0da0f90 Stavros Sachtouris
            self.arguments = _arguments
515 631b7c35 Stavros Sachtouris
        self._parser_modified, self._parsed, self._unparsed = False, None, None
516 7c2247a0 Stavros Sachtouris
        self.parse()
517 e0da0f90 Stavros Sachtouris
518 56d84a4e Stavros Sachtouris
    @staticmethod
519 56d84a4e Stavros Sachtouris
    def required2list(required):
520 56d84a4e Stavros Sachtouris
        if isinstance(required, list) or isinstance(required, tuple):
521 56d84a4e Stavros Sachtouris
            terms = []
522 56d84a4e Stavros Sachtouris
            for r in required:
523 56d84a4e Stavros Sachtouris
                terms.append(ArgumentParseManager.required2list(r))
524 56d84a4e Stavros Sachtouris
            return list(set(terms).union())
525 56d84a4e Stavros Sachtouris
        return required
526 56d84a4e Stavros Sachtouris
527 56d84a4e Stavros Sachtouris
    @staticmethod
528 56d84a4e Stavros Sachtouris
    def required2str(required, arguments, tab=''):
529 56d84a4e Stavros Sachtouris
        if isinstance(required, list):
530 a6d2ad78 Stavros Sachtouris
            return ' %sat least one of the following:\n%s' % (tab, ''.join(
531 56d84a4e Stavros Sachtouris
                [ArgumentParseManager.required2str(
532 56d84a4e Stavros Sachtouris
                    r, arguments, tab + '  ') for r in required]))
533 56d84a4e Stavros Sachtouris
        elif isinstance(required, tuple):
534 a6d2ad78 Stavros Sachtouris
            return ' %sall of the following:\n%s' % (tab, ''.join(
535 56d84a4e Stavros Sachtouris
                [ArgumentParseManager.required2str(
536 56d84a4e Stavros Sachtouris
                    r, arguments, tab + '  ') for r in required]))
537 56d84a4e Stavros Sachtouris
        else:
538 56d84a4e Stavros Sachtouris
            lt_pn, lt_all, arg = 23, 80, arguments[required]
539 56d84a4e Stavros Sachtouris
            tab2 = ' ' * lt_pn
540 56d84a4e Stavros Sachtouris
            ret = '%s%s' % (tab, ', '.join(arg.parsed_name))
541 56d84a4e Stavros Sachtouris
            if arg.arity != 0:
542 56d84a4e Stavros Sachtouris
                ret += ' %s' % required.upper()
543 56d84a4e Stavros Sachtouris
            ret = ('{:<%s}' % lt_pn).format(ret)
544 264a13f7 Stavros Sachtouris
            prefix = ('\n%s' % tab2) if len(ret) > lt_pn else ' '
545 264a13f7 Stavros Sachtouris
            cur = 0
546 56d84a4e Stavros Sachtouris
            while arg.help[cur:]:
547 264a13f7 Stavros Sachtouris
                next = cur + lt_all - lt_pn
548 56d84a4e Stavros Sachtouris
                ret += prefix
549 56d84a4e Stavros Sachtouris
                ret += ('{:<%s}' % (lt_all - lt_pn)).format(arg.help[cur:next])
550 56d84a4e Stavros Sachtouris
                cur, finish = next, '\n%s' % tab2
551 56d84a4e Stavros Sachtouris
            return ret + '\n'
552 56d84a4e Stavros Sachtouris
553 320af781 Stavros Sachtouris
    @staticmethod
554 320af781 Stavros Sachtouris
    def _patch_with_required_args(arguments, required):
555 320af781 Stavros Sachtouris
        if isinstance(required, tuple):
556 320af781 Stavros Sachtouris
            return ' '.join([ArgumentParseManager._patch_with_required_args(
557 320af781 Stavros Sachtouris
                arguments, k) for k in required])
558 320af781 Stavros Sachtouris
        elif isinstance(required, list):
559 320af781 Stavros Sachtouris
            return '< %s >' % ' | '.join([
560 320af781 Stavros Sachtouris
                ArgumentParseManager._patch_with_required_args(
561 320af781 Stavros Sachtouris
                    arguments, k) for k in required])
562 320af781 Stavros Sachtouris
        arg = arguments[required]
563 320af781 Stavros Sachtouris
        return '/'.join(arg.parsed_name) + (
564 320af781 Stavros Sachtouris
            ' %s [...]' % required.upper() if arg.arity < 0 else (
565 320af781 Stavros Sachtouris
                ' %s' % required.upper() if arg.arity else ''))
566 320af781 Stavros Sachtouris
567 56d84a4e Stavros Sachtouris
    def print_help(self, out=stderr):
568 56d84a4e Stavros Sachtouris
        if self.required:
569 56d84a4e Stavros Sachtouris
            tmp_args = dict(self.arguments)
570 56d84a4e Stavros Sachtouris
            for term in self.required2list(self.required):
571 56d84a4e Stavros Sachtouris
                tmp_args.pop(term)
572 56d84a4e Stavros Sachtouris
            tmp_parser = ArgumentParseManager(self._exe, tmp_args)
573 320af781 Stavros Sachtouris
            tmp_parser.syntax = self.syntax + self._patch_with_required_args(
574 320af781 Stavros Sachtouris
                self.arguments, self.required)
575 56d84a4e Stavros Sachtouris
            tmp_parser.parser.description = '%s\n\nrequired arguments:\n%s' % (
576 56d84a4e Stavros Sachtouris
                self.parser.description,
577 56d84a4e Stavros Sachtouris
                self.required2str(self.required, self.arguments))
578 56d84a4e Stavros Sachtouris
            tmp_parser.update_parser()
579 56d84a4e Stavros Sachtouris
            tmp_parser.parser.print_help()
580 56d84a4e Stavros Sachtouris
        else:
581 56d84a4e Stavros Sachtouris
            self.parser.print_help()
582 56d84a4e Stavros Sachtouris
583 e0da0f90 Stavros Sachtouris
    @property
584 e0da0f90 Stavros Sachtouris
    def syntax(self):
585 b3dd8f4b Stavros Sachtouris
        """The command syntax (useful for help messages, descriptions, etc)"""
586 e0da0f90 Stavros Sachtouris
        return self.parser.prog
587 e0da0f90 Stavros Sachtouris
588 e0da0f90 Stavros Sachtouris
    @syntax.setter
589 e0da0f90 Stavros Sachtouris
    def syntax(self, new_syntax):
590 e0da0f90 Stavros Sachtouris
        self.parser.prog = new_syntax
591 e0da0f90 Stavros Sachtouris
592 b3dd8f4b Stavros Sachtouris
    @property
593 b3dd8f4b Stavros Sachtouris
    def arguments(self):
594 631b7c35 Stavros Sachtouris
        """:returns: (dict) arguments the parser should be aware of"""
595 b3dd8f4b Stavros Sachtouris
        return self._arguments
596 b3dd8f4b Stavros Sachtouris
597 b3dd8f4b Stavros Sachtouris
    @arguments.setter
598 b3dd8f4b Stavros Sachtouris
    def arguments(self, new_arguments):
599 631b7c35 Stavros Sachtouris
        assert isinstance(new_arguments, dict), 'Arguments must be in a dict'
600 b3dd8f4b Stavros Sachtouris
        self._arguments = new_arguments
601 b3dd8f4b Stavros Sachtouris
        self.update_parser()
602 b3dd8f4b Stavros Sachtouris
603 7c2247a0 Stavros Sachtouris
    @property
604 b3dd8f4b Stavros Sachtouris
    def parsed(self):
605 7c2247a0 Stavros Sachtouris
        """(Namespace) parser-matched terms"""
606 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
607 b3dd8f4b Stavros Sachtouris
            self.parse()
608 b3dd8f4b Stavros Sachtouris
        return self._parsed
609 b3dd8f4b Stavros Sachtouris
610 b3dd8f4b Stavros Sachtouris
    @property
611 b3dd8f4b Stavros Sachtouris
    def unparsed(self):
612 b3dd8f4b Stavros Sachtouris
        """(list) parser-unmatched terms"""
613 b3dd8f4b Stavros Sachtouris
        if self._parser_modified:
614 b3dd8f4b Stavros Sachtouris
            self.parse()
615 b3dd8f4b Stavros Sachtouris
        return self._unparsed
616 b3dd8f4b Stavros Sachtouris
617 e0da0f90 Stavros Sachtouris
    def update_parser(self, arguments=None):
618 e0da0f90 Stavros Sachtouris
        """Load argument specifications to parser
619 e0da0f90 Stavros Sachtouris

620 e0da0f90 Stavros Sachtouris
        :param arguments: if not given, update self.arguments instead
621 e0da0f90 Stavros Sachtouris
        """
622 631b7c35 Stavros Sachtouris
        arguments = arguments or self._arguments
623 e0da0f90 Stavros Sachtouris
624 e0da0f90 Stavros Sachtouris
        for name, arg in arguments.items():
625 e0da0f90 Stavros Sachtouris
            try:
626 e0da0f90 Stavros Sachtouris
                arg.update_parser(self.parser, name)
627 b3dd8f4b Stavros Sachtouris
                self._parser_modified = True
628 e0da0f90 Stavros Sachtouris
            except ArgumentError:
629 e0da0f90 Stavros Sachtouris
                pass
630 e0da0f90 Stavros Sachtouris
631 7c2247a0 Stavros Sachtouris
    def update_arguments(self, new_arguments):
632 7c2247a0 Stavros Sachtouris
        """Add to / update existing arguments
633 7c2247a0 Stavros Sachtouris

634 7c2247a0 Stavros Sachtouris
        :param new_arguments: (dict)
635 7c2247a0 Stavros Sachtouris
        """
636 7c2247a0 Stavros Sachtouris
        if new_arguments:
637 56d84a4e Stavros Sachtouris
            assert isinstance(new_arguments, dict), 'Arguments not in dict !!!'
638 7c2247a0 Stavros Sachtouris
            self._arguments.update(new_arguments)
639 7c2247a0 Stavros Sachtouris
            self.update_parser()
640 7c2247a0 Stavros Sachtouris
641 0b052394 Stavros Sachtouris
    def _parse_required_arguments(self, required, parsed_args):
642 9b3c8fd9 Stavros Sachtouris
        if not (self.check_required and required):
643 0b052394 Stavros Sachtouris
            return True
644 0b052394 Stavros Sachtouris
        if isinstance(required, tuple):
645 0b052394 Stavros Sachtouris
            for item in required:
646 0b052394 Stavros Sachtouris
                if not self._parse_required_arguments(item, parsed_args):
647 0b052394 Stavros Sachtouris
                    return False
648 0b052394 Stavros Sachtouris
            return True
649 05ecf3a3 Stavros Sachtouris
        elif isinstance(required, list):
650 0b052394 Stavros Sachtouris
            for item in required:
651 0b052394 Stavros Sachtouris
                if self._parse_required_arguments(item, parsed_args):
652 0b052394 Stavros Sachtouris
                    return True
653 0b052394 Stavros Sachtouris
            return False
654 0b052394 Stavros Sachtouris
        return required in parsed_args
655 0b052394 Stavros Sachtouris
656 120126f1 Stavros Sachtouris
    def parse(self, new_args=None):
657 320aac17 Stavros Sachtouris
        """Parse user input"""
658 c8e17a67 Stavros Sachtouris
        try:
659 320aac17 Stavros Sachtouris
            pkargs = (new_args,) if new_args else ()
660 320aac17 Stavros Sachtouris
            self._parsed, unparsed = self.parser.parse_known_args(*pkargs)
661 0b052394 Stavros Sachtouris
            parsed_args = [
662 0b052394 Stavros Sachtouris
                k for k, v in vars(self._parsed).items() if v not in (None, )]
663 0b052394 Stavros Sachtouris
            if not self._parse_required_arguments(self.required, parsed_args):
664 56d84a4e Stavros Sachtouris
                self.print_help()
665 0b052394 Stavros Sachtouris
                raise CLISyntaxError('Missing required arguments')
666 c8e17a67 Stavros Sachtouris
        except SystemExit:
667 c8e17a67 Stavros Sachtouris
            raiseCLIError(CLISyntaxError('Argument Syntax Error'))
668 b3dd8f4b Stavros Sachtouris
        for name, arg in self.arguments.items():
669 b3dd8f4b Stavros Sachtouris
            arg.value = getattr(self._parsed, name, arg.default)
670 b3dd8f4b Stavros Sachtouris
        self._unparsed = []
671 b3dd8f4b Stavros Sachtouris
        for term in unparsed:
672 b3dd8f4b Stavros Sachtouris
            self._unparsed += split_input(' \'%s\' ' % term)
673 b3dd8f4b Stavros Sachtouris
        self._parser_modified = False