~lutostag/ubuntu/trusty/maas/1.5.2+packagefix

« back to all changes in this revision

Viewing changes to src/maascli/api.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2014-03-28 10:43:53 UTC
  • mto: This revision was merged to the branch mainline in revision 57.
  • Revision ID: package-import@ubuntu.com-20140328104353-ekpolg0pm5xnvq2s
Tags: upstream-1.5+bzr2204
ImportĀ upstreamĀ versionĀ 1.5+bzr2204

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2012 Canonical Ltd.  This software is licensed under the
 
1
# Copyright 2012-2014 Canonical Ltd.  This software is licensed under the
2
2
# GNU Affero General Public License version 3 (see the file LICENSE).
3
3
 
4
4
"""Interact with a remote MAAS server."""
16
16
    "register_api_commands",
17
17
    ]
18
18
 
 
19
import argparse
19
20
from collections import defaultdict
20
21
from email.message import Message
21
22
import httplib
249
250
            file.write("\n")
250
251
 
251
252
 
 
253
class ActionHelp(argparse.Action):
 
254
    """Custom "help" function for an action `ArgumentParser`.
 
255
 
 
256
    We use the argument parser's "epilog" field for the action's detailed
 
257
    description.
 
258
 
 
259
    This class is stateless.
 
260
    """
 
261
 
 
262
    keyword_args_help = dedent("""\
 
263
        This method accepts keyword arguments.  Pass each argument as a
 
264
        key-value pair with an equals sign between the key and the value:
 
265
        key1=value1 key2=value key3=value3.  Keyword arguments must come after
 
266
        any positional arguments.
 
267
        """)
 
268
 
 
269
    @classmethod
 
270
    def get_positional_args(cls, parser):
 
271
        """Return an API action's positional arguments.
 
272
 
 
273
        Most typically, this holds a URL path fragment for the object that's
 
274
        being addressed, e.g. a physical zone's name.
 
275
 
 
276
        There will also be a "data" argument, representing the request's
 
277
        embedded data, but that's of no interest to end-users.  The CLI offers
 
278
        a more fine-grained interface to pass parameters, so as a special case,
 
279
        that one item is left out.
 
280
        """
 
281
        # Use private method on the parser.  The list of actions does not
 
282
        # seem to be publicly exposed.
 
283
        positional_actions = parser._get_positional_actions()
 
284
        names = [action.dest for action in positional_actions]
 
285
        if len(names) > 0 and names[-1] == 'data':
 
286
            names = names[:-1]
 
287
        return names
 
288
 
 
289
    @classmethod
 
290
    def get_optional_args(cls, parser):
 
291
        """Return an API action's optional arguments."""
 
292
        # Use private method on the parser.  The list of actions does not
 
293
        # seem to be publicly exposed.
 
294
        optional_args = parser._get_optional_actions()
 
295
        return optional_args
 
296
 
 
297
    @classmethod
 
298
    def compose_positional_args(cls, parser):
 
299
        """Describe positional arguments for `parser`, as a list of strings."""
 
300
        positional_args = cls.get_positional_args(parser)
 
301
        if len(positional_args) == 0:
 
302
            return []
 
303
        else:
 
304
            return [
 
305
                '',
 
306
                '',
 
307
                "Positional arguments:",
 
308
                ] + ["\t%s" % arg for arg in positional_args]
 
309
 
 
310
    @classmethod
 
311
    def compose_epilog(cls, parser):
 
312
        """Describe action in detail, as a list of strings."""
 
313
        epilog = parser.epilog
 
314
        if parser.epilog is None:
 
315
            return []
 
316
        epilog = epilog.rstrip()
 
317
        if epilog == '':
 
318
            return []
 
319
 
 
320
        lines = [
 
321
            '',
 
322
            '',
 
323
            ]
 
324
        if ':param ' in epilog:
 
325
            # This API action documents keyword arguments.  Explain to the
 
326
            # user how those work first.
 
327
            lines.append(cls.keyword_args_help)
 
328
        # Finally, include the actual documentation body.
 
329
        lines.append(epilog)
 
330
        return lines
 
331
 
 
332
    @classmethod
 
333
    def compose_optional_args(cls, parser):
 
334
        """Describe optional arguments for `parser`, as a list of strings."""
 
335
        optional_args = cls.get_optional_args(parser)
 
336
        if len(optional_args) == 0:
 
337
            return []
 
338
 
 
339
        lines = [
 
340
            '',
 
341
            '',
 
342
            "Common command-line options:",
 
343
            ]
 
344
        for arg in optional_args:
 
345
            # Minimal representation of options.  Doesn't show
 
346
            # arguments to the options, defaults, and so on.  But it's
 
347
            # all we need for now.
 
348
            lines.append('    %s' % ', '.join(arg.option_strings))
 
349
            lines.append('\t%s' % arg.help)
 
350
        return lines
 
351
 
 
352
    @classmethod
 
353
    def compose(cls, parser):
 
354
        """Put together, and return, help output for `parser`."""
 
355
        lines = [
 
356
            parser.format_usage().rstrip(),
 
357
            '',
 
358
            parser.description,
 
359
            ]
 
360
        lines += cls.compose_positional_args(parser)
 
361
        lines += cls.compose_epilog(parser)
 
362
        lines += cls.compose_optional_args(parser)
 
363
        return '\n'.join(lines)
 
364
 
 
365
    def __call__(self, parser, namespace, values, option_string):
 
366
        """Overridable as defined by the `argparse` API."""
 
367
        print(self.compose(parser))
 
368
        sys.exit(0)
 
369
 
 
370
 
252
371
def register_actions(profile, handler, parser):
253
372
    """Register a handler's actions."""
254
373
    for action in handler["actions"]:
263
382
        action_class = type(action_name, action_bases, action_ns)
264
383
        action_parser = parser.subparsers.add_parser(
265
384
            action_name, help=help_title, description=help_title,
266
 
            epilog=help_body)
267
 
        action_parser.set_defaults(
268
 
            execute=action_class(action_parser))
 
385
            epilog=help_body, add_help=False)
 
386
        action_parser.add_argument(
 
387
            '--help', '-h', action=ActionHelp, nargs=0,
 
388
            help="Show this help message and exit.")
 
389
        action_parser.set_defaults(execute=action_class(action_parser))
269
390
 
270
391
 
271
392
def register_handler(profile, handler, parser):