Statistics
| Branch: | Tag: | Revision:

root / kamaki / cli / argument / __init__.py @ 26413b0d

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

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

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

595 e0da0f90 Stavros Sachtouris
        :param arguments: if not given, update self.arguments instead
596 e0da0f90 Stavros Sachtouris
        """
597 631b7c35 Stavros Sachtouris
        arguments = arguments or self._arguments
598 e0da0f90 Stavros Sachtouris
599 e0da0f90 Stavros Sachtouris
        for name, arg in arguments.items():
600 e0da0f90 Stavros Sachtouris
            try:
601 e0da0f90 Stavros Sachtouris
                arg.update_parser(self.parser, name)
602 b3dd8f4b Stavros Sachtouris
                self._parser_modified = True
603 e0da0f90 Stavros Sachtouris
            except ArgumentError:
604 e0da0f90 Stavros Sachtouris
                pass
605 e0da0f90 Stavros Sachtouris
606 7c2247a0 Stavros Sachtouris
    def update_arguments(self, new_arguments):
607 7c2247a0 Stavros Sachtouris
        """Add to / update existing arguments
608 7c2247a0 Stavros Sachtouris

609 7c2247a0 Stavros Sachtouris
        :param new_arguments: (dict)
610 7c2247a0 Stavros Sachtouris
        """
611 7c2247a0 Stavros Sachtouris
        if new_arguments:
612 56d84a4e Stavros Sachtouris
            assert isinstance(new_arguments, dict), 'Arguments not in dict !!!'
613 7c2247a0 Stavros Sachtouris
            self._arguments.update(new_arguments)
614 7c2247a0 Stavros Sachtouris
            self.update_parser()
615 7c2247a0 Stavros Sachtouris
616 0b052394 Stavros Sachtouris
    def _parse_required_arguments(self, required, parsed_args):
617 9b3c8fd9 Stavros Sachtouris
        if not (self.check_required and required):
618 0b052394 Stavros Sachtouris
            return True
619 0b052394 Stavros Sachtouris
        if isinstance(required, tuple):
620 0b052394 Stavros Sachtouris
            for item in required:
621 0b052394 Stavros Sachtouris
                if not self._parse_required_arguments(item, parsed_args):
622 0b052394 Stavros Sachtouris
                    return False
623 0b052394 Stavros Sachtouris
            return True
624 0b052394 Stavros Sachtouris
        if isinstance(required, list):
625 0b052394 Stavros Sachtouris
            for item in required:
626 0b052394 Stavros Sachtouris
                if self._parse_required_arguments(item, parsed_args):
627 0b052394 Stavros Sachtouris
                    return True
628 0b052394 Stavros Sachtouris
            return False
629 0b052394 Stavros Sachtouris
        return required in parsed_args
630 0b052394 Stavros Sachtouris
631 120126f1 Stavros Sachtouris
    def parse(self, new_args=None):
632 320aac17 Stavros Sachtouris
        """Parse user input"""
633 c8e17a67 Stavros Sachtouris
        try:
634 320aac17 Stavros Sachtouris
            pkargs = (new_args,) if new_args else ()
635 320aac17 Stavros Sachtouris
            self._parsed, unparsed = self.parser.parse_known_args(*pkargs)
636 0b052394 Stavros Sachtouris
            parsed_args = [
637 0b052394 Stavros Sachtouris
                k for k, v in vars(self._parsed).items() if v not in (None, )]
638 0b052394 Stavros Sachtouris
            if not self._parse_required_arguments(self.required, parsed_args):
639 56d84a4e Stavros Sachtouris
                self.print_help()
640 0b052394 Stavros Sachtouris
                raise CLISyntaxError('Missing required arguments')
641 c8e17a67 Stavros Sachtouris
        except SystemExit:
642 c8e17a67 Stavros Sachtouris
            raiseCLIError(CLISyntaxError('Argument Syntax Error'))
643 b3dd8f4b Stavros Sachtouris
        for name, arg in self.arguments.items():
644 b3dd8f4b Stavros Sachtouris
            arg.value = getattr(self._parsed, name, arg.default)
645 b3dd8f4b Stavros Sachtouris
        self._unparsed = []
646 b3dd8f4b Stavros Sachtouris
        for term in unparsed:
647 b3dd8f4b Stavros Sachtouris
            self._unparsed += split_input(' \'%s\' ' % term)
648 b3dd8f4b Stavros Sachtouris
        self._parser_modified = False