-#!/usr/bin/env python
-# Copyright 2011-2012 GRNET S.A. All rights reserved.
+# Copyright 2012-2013 GRNET S.A. All rights reserved.
#
# Redistribution and use in source and binary forms, with or
# without modification, are permitted provided that the following
# The views and conclusions contained in the software and
# documentation are those of the authors and should not be
# interpreted as representing official policies, either expressed
-# or implied, of GRNET S.A.
-
-#from __future__ import print_function
+# or implied, of GRNET S.A.command
import logging
-
-from inspect import getargspec
-from argparse import ArgumentParser, ArgumentError
+from sys import argv, exit, stdout
from os.path import basename
-from sys import exit, stdout, argv
+from inspect import getargspec
-from kamaki.cli.errors import CLIError, CLICmdSpecError
-from kamaki.cli.utils import magenta, red, yellow, print_dict, print_list,\
- remove_colors
-from kamaki.cli.command_tree import CommandTree
-from kamaki.cli.argument import _arguments, parse_known_args
+from kamaki.cli.argument import _arguments, parse_known_args, init_parser,\
+ update_arguments
from kamaki.cli.history import History
+from kamaki.cli.utils import print_dict, print_list, red, magenta, yellow
+from kamaki.cli.errors import CLIError
-cmd_spec_locations = [
- 'kamaki.cli.commands',
- 'kamaki.commands',
- 'kamaki.cli',
- 'kamaki',
- '']
-_commands = CommandTree(name='kamaki',
- description='A command line tool for poking clouds')
-
-# If empty, all commands are loaded, if not empty, only commands in this list
-# e.g. [store, lele, list, lolo] is good to load store_list but not list_store
-# First arg should always refer to a group
-candidate_command_terms = []
-allow_no_commands = False
-allow_all_commands = False
-allow_subclass_signatures = False
-
-
-def _allow_class_in_cmd_tree(cls):
- global allow_all_commands
- if allow_all_commands:
- return True
- global allow_no_commands
- if allow_no_commands:
- return False
-
- term_list = cls.__name__.split('_')
- global candidate_command_terms
- index = 0
- for term in candidate_command_terms:
- try:
- index += 1 if term_list[index] == term else 0
- except IndexError: # Whole term list matched!
- return True
- if allow_subclass_signatures:
- if index == len(candidate_command_terms) and len(term_list) > index:
- try: # is subterm already in _commands?
- _commands.get_command('_'.join(term_list[:index + 1]))
- except KeyError: # No, so it must be placed there
- return True
- return False
-
- return True if index == len(term_list) else False
-
-
-def command():
- """Class decorator that registers a class as a CLI command"""
-
- def decorator(cls):
- """Any class with name of the form cmd1_cmd2_cmd3_... is accepted"""
+_help = False
+_debug = False
+_verbose = False
+_colors = False
- if not _allow_class_in_cmd_tree(cls):
- return cls
-
- cls.description, sep, cls.long_description\
- = cls.__doc__.partition('\n')
- # Generate a syntax string based on main's arguments
+def _construct_command_syntax(cls):
spec = getargspec(cls.main.im_func)
args = spec.args[1:]
n = len(args) - len(spec.defaults or ())
if spec.varargs:
cls.syntax += ' <%s ...>' % spec.varargs
- # store each term, one by one, first
- _commands.add_command(cls.__name__, cls.description, cls)
- return cls
- return decorator
+def _get_cmd_tree_from_spec(spec, cmd_tree_list):
+ for tree in cmd_tree_list:
+ if tree.name == spec:
+ return tree
+ return None
-def _update_parser(parser, arguments):
- for name, argument in arguments.items():
- try:
- argument.update_parser(parser, name)
- except ArgumentError:
- pass
+_best_match = []
-def _init_parser(exe):
- parser = ArgumentParser(add_help=False)
- parser.prog = '%s <cmd_group> [<cmd_subbroup> ...] <cmd>' % exe
- _update_parser(parser, _arguments)
- return parser
+def _num_of_matching_terms(basic_list, attack_list):
+ if not attack_list:
+ return 1
+ matching_terms = 0
+ for i, term in enumerate(basic_list):
+ try:
+ if term != attack_list[i]:
+ break
+ except IndexError:
+ break
+ matching_terms += 1
+ return matching_terms
-def _print_error_message(cli_err):
- errmsg = '%s' % cli_err
- if cli_err.importance == 1:
- errmsg = magenta(errmsg)
- elif cli_err.importance == 2:
- errmsg = yellow(errmsg)
- elif cli_err.importance > 2:
- errmsg = red(errmsg)
- stdout.write(errmsg)
- print_list(cli_err.details)
+def _update_best_match(name_terms, prefix=[]):
+ if prefix:
+ pref_list = prefix if isinstance(prefix, list) else prefix.split('_')
+ else:
+ pref_list = []
-def get_command_group(unparsed):
- groups = _arguments['config'].get_groups()
- for grp_candidate in unparsed:
- if grp_candidate in groups:
- unparsed.remove(grp_candidate)
- return grp_candidate
- return None
+ num_of_matching_terms = _num_of_matching_terms(name_terms, pref_list)
+ global _best_match
+ if num_of_matching_terms and len(_best_match) <= num_of_matching_terms:
+ if len(_best_match) < num_of_matching_terms:
+ _best_match = name_terms[:num_of_matching_terms]
+ return True
+ return False
+
+
+def command(cmd_tree, prefix='', descedants_depth=1):
+ """Load a class as a command
+ spec_cmd0_cmd1 will be command spec cmd0
+ @cmd_tree is initialized in cmd_spec file and is the structure
+ where commands are loaded. Var name should be _commands
+ @param prefix if given, load only commands prefixed with prefix,
+ @param descedants_depth is the depth of the tree descedants of the
+ prefix command. It is used ONLY if prefix and if prefix is not
+ a terminal command
+ """
+
+ def wrap(cls):
+ cls_name = cls.__name__
+
+ if not cmd_tree:
+ if _debug:
+ print('Warning: command %s found but not loaded' % cls_name)
+ return cls
-def load_command(group, unparsed, reload_package=False):
- global candidate_command_terms
- candidate_command_terms = [group] + unparsed
- load_group_package(group, reload_package)
+ name_terms = cls_name.split('_')
+ if not _update_best_match(name_terms, prefix):
+ return None
- #From all possible parsed commands, chose the first match in user string
- final_cmd = _commands.get_command(group)
- for term in unparsed:
- cmd = final_cmd.get_subcmd(term)
- if cmd is not None:
- final_cmd = cmd
- unparsed.remove(cmd.name)
- return final_cmd
+ global _best_match
+ max_len = len(_best_match) + descedants_depth
+ if len(name_terms) > max_len:
+ partial = '_'.join(name_terms[:max_len])
+ if not cmd_tree.has_command(partial): # add partial path
+ cmd_tree.add_command(partial)
+ return None
+ cls.description, sep, cls.long_description\
+ = cls.__doc__.partition('\n')
+ _construct_command_syntax(cls)
-def shallow_load():
- """Load only group names and descriptions"""
- global allow_no_commands
- allow_no_commands = True # load only descriptions
- for grp in _arguments['config'].get_groups():
- load_group_package(grp)
- allow_no_commands = False
+ cmd_tree.add_command(cls_name, cls.description, cls)
+ return cls
+ return wrap
-def load_group_package(group, reload_package=False):
- spec_pkg = _arguments['config'].value.get(group, 'cli')
- if spec_pkg is None:
- return None
- for location in cmd_spec_locations:
- location += spec_pkg if location == '' else ('.' + spec_pkg)
- try:
- package = __import__(location, fromlist=['API_DESCRIPTION'])
- except ImportError:
- continue
- if reload_package:
- reload(package)
- for grp, descr in package.API_DESCRIPTION.items():
- _commands.add_command(grp, descr)
- return package
- raise CLICmdSpecError(details='Cmd Spec Package %s load failed' % spec_pkg)
-
-
-def print_commands(prefix=None, full_depth=False):
- cmd_list = _commands.get_groups() if prefix is None\
- else _commands.get_subcommands(prefix)
- cmds = {}
- for subcmd in cmd_list:
- if subcmd.sublen() > 0:
- sublen_str = '( %s more terms ... )' % subcmd.sublen()
- cmds[subcmd.name] = [subcmd.help, sublen_str]\
- if subcmd.has_description else sublen_str
- else:
- cmds[subcmd.name] = subcmd.help
- if len(cmds) > 0:
- print('\nOptions:')
- print_dict(cmds, ident=12)
- if full_depth:
- _commands.pretty_print()
+def get_cmd_terms():
+ global command
+ return [term for term in command.func_defaults[0]\
+ if not term.startswith('-')]
+
+cmd_spec_locations = [
+ 'kamaki.cli.commands',
+ 'kamaki.commands',
+ 'kamaki.cli',
+ 'kamaki',
+ '']
-def setup_logging(silent=False, debug=False, verbose=False, include=False):
+def _setup_logging(silent=False, debug=False, verbose=False, include=False):
"""handle logging for clients package"""
def add_handler(name, level, prefix=''):
add_handler('', logging.WARNING)
+def _init_session(arguments):
+ global _help
+ _help = arguments['help'].value
+ global _debug
+ _debug = arguments['debug'].value
+ global _verbose
+ _verbose = arguments['verbose'].value
+ global _colors
+ _colors = arguments['config'].get('global', 'colors')
+ _silent = arguments['silent'].value
+ _include = arguments['include'].value
+ _setup_logging(_silent, _debug, _verbose, _include)
+
+
+def get_command_group(unparsed, arguments):
+ groups = arguments['config'].get_groups()
+ for term in unparsed:
+ if term.startswith('-'):
+ continue
+ if term in groups:
+ unparsed.remove(term)
+ return term
+ return None
+ return None
+
+
+def _load_spec_module(spec, arguments, module):
+ spec_name = arguments['config'].get(spec, 'cli')
+ if spec_name is None:
+ return None
+ pkg = None
+ for location in cmd_spec_locations:
+ location += spec_name if location == '' else '.%s' % spec_name
+ try:
+ pkg = __import__(location, fromlist=[module])
+ return pkg
+ except ImportError:
+ continue
+ return pkg
+
+
+def _groups_help(arguments):
+ global _debug
+ descriptions = {}
+ for spec in arguments['config'].get_groups():
+ pkg = _load_spec_module(spec, arguments, '_commands')
+ if pkg:
+ cmds = None
+ try:
+ cmds = [
+ cmd for cmd in getattr(pkg, '_commands')\
+ if arguments['config'].get(cmd.name, 'cli')
+ ]
+ except AttributeError:
+ if _debug:
+ print('Warning: No description for %s' % spec)
+ try:
+ for cmd in cmds:
+ descriptions[cmd.name] = cmd.description
+ except TypeError:
+ if _debug:
+ print('Warning: no cmd specs in module %s' % spec)
+ elif _debug:
+ print('Warning: Loading of %s cmd spec failed' % spec)
+ print('\nOptions:\n - - - -')
+ print_dict(descriptions)
+
+
+def _print_subcommands_help(cmd):
+ printout = {}
+ for subcmd in cmd.get_subcommands():
+ printout[subcmd.path.replace('_', ' ')] = subcmd.description
+ if printout:
+ print('\nOptions:\n - - - -')
+ print_dict(printout)
+
+
+def _update_parser_help(parser, cmd):
+ global _best_match
+ parser.prog = parser.prog.split('<')[0]
+ parser.prog += ' '.join(_best_match)
+
+ if cmd.is_command:
+ cls = cmd.get_class()
+ parser.prog += ' ' + cls.syntax
+ arguments = cls().arguments
+ update_arguments(parser, arguments)
+ else:
+ parser.prog += ' <...>'
+ if cmd.has_description:
+ parser.description = cmd.help
+
+
+def _print_error_message(cli_err):
+ errmsg = '%s' % cli_err
+ if cli_err.importance == 1:
+ errmsg = magenta(errmsg)
+ elif cli_err.importance == 2:
+ errmsg = yellow(errmsg)
+ elif cli_err.importance > 2:
+ errmsg = red(errmsg)
+ stdout.write(errmsg)
+ print_list(cli_err.details)
+
+
+def _get_best_match_from_cmd_tree(cmd_tree, unparsed):
+ matched = [term for term in unparsed if not term.startswith('-')]
+ while matched:
+ try:
+ return cmd_tree.get_command('_'.join(matched))
+ except KeyError:
+ matched = matched[:-1]
+ return None
+
+
def _exec_cmd(instance, cmd_args, help_method):
try:
return instance.main(*cmd_args)
except TypeError as err:
if err.args and err.args[0].startswith('main()'):
print(magenta('Syntax error'))
- if instance.get_argument('verbose'):
+ if _debug:
+ raise err
+ if _verbose:
print(unicode(err))
help_method()
else:
raise
except CLIError as err:
- if instance.get_argument('debug'):
- raise
+ if _debug:
+ raise err
_print_error_message(err)
return 1
-def one_command():
- _debug = False
- _help = False
- _verbose = False
- try:
- exe = basename(argv[0])
- parser = _init_parser(exe)
- parsed, unparsed = parse_known_args(parser, _arguments)
- _colors = _arguments['config'].get('global', 'colors')
- if _colors != 'on':
- remove_colors()
- _history = History(_arguments['config'].get('history', 'file'))
- _history.add(' '.join([exe] + argv[1:]))
- _debug = _arguments['debug'].value
- _help = _arguments['help'].value
- _verbose = _arguments['verbose'].value
- if _arguments['version'].value:
- exit(0)
-
- group = get_command_group(unparsed)
- if group is None:
- parser.print_help()
- shallow_load()
- print_commands(full_depth=_debug)
- exit(0)
-
- cmd = load_command(group, unparsed)
- # Find the most specific subcommand
- for term in list(unparsed):
- if cmd.is_command:
- break
- if cmd.contains(term):
- cmd = cmd.get_subcmd(term)
- unparsed.remove(term)
-
- if _help or not cmd.is_command:
- if cmd.has_description:
- parser.description = cmd.help
- else:
- try:
- parser.description =\
- _commands.get_closest_ancestor_command(cmd.path).help
- except KeyError:
- parser.description = ' '
- parser.prog = '%s %s ' % (exe, cmd.path.replace('_', ' '))
- if cmd.is_command:
- cli = cmd.get_class()
- parser.prog += cli.syntax
- _update_parser(parser, cli().arguments)
- else:
- parser.prog += '[...]'
- parser.print_help()
-
- # load one more level just to see what is missing
- global allow_subclass_signatures
- allow_subclass_signatures = True
- load_command(group, cmd.path.split('_')[1:], reload_package=True)
-
- print_commands(cmd.path, full_depth=_debug)
- exit(0)
-
- setup_logging(silent=_arguments['silent'].value,
- debug=_debug,
- verbose=_verbose,
- include=_arguments['include'].value)
- cli = cmd.get_class()
- executable = cli(_arguments)
- _update_parser(parser, executable.arguments)
- parser.prog = '%s %s %s'\
- % (exe, cmd.path.replace('_', ' '), cli.syntax)
- parsed, new_unparsed = parse_known_args(parser, _arguments)
- unparsed = [term for term in unparsed if term in new_unparsed]
- ret = _exec_cmd(executable, unparsed, parser.print_help)
- exit(ret)
- except Exception as err:
- if _debug:
- from traceback import print_stack
- print_stack()
- raise
- err = err if isinstance(err, CLIError)\
- else CLIError('Unexpected Error (%s): %s' % (type(err), err))
- _print_error_message(err)
+def set_command_param(param, value):
+ if param == 'prefix':
+ pos = 0
+ elif param == 'descedants_depth':
+ pos = 1
+ else:
+ return
+ global command
+ def_params = list(command.func_defaults)
+ def_params[pos] = value
+ command.func_defaults = tuple(def_params)
+
+
+def one_cmd(parser, unparsed, arguments):
+ group = get_command_group(list(unparsed), arguments)
+ if not group:
+ parser.print_help()
+ _groups_help(arguments)
+ exit(0)
+
+ set_command_param(
+ 'prefix',
+ [term for term in unparsed if not term.startswith('-')]
+ )
+ global _best_match
+ _best_match = []
+
+ spec_module = _load_spec_module(group, arguments, '_commands')
+
+ cmd_tree = _get_cmd_tree_from_spec(group, spec_module._commands)
+
+ if _best_match:
+ cmd = cmd_tree.get_command('_'.join(_best_match))
+ else:
+ cmd = _get_best_match_from_cmd_tree(cmd_tree, unparsed)
+ _best_match = cmd.path.split('_')
+ if cmd is None:
+ if _debug or _verbose:
+ print('Unexpected error: failed to load command')
exit(1)
+ _update_parser_help(parser, cmd)
+
+ if _help or not cmd.is_command:
+ parser.print_help()
+ _print_subcommands_help(cmd)
+ exit(0)
+
+ cls = cmd.get_class()
+ executable = cls(arguments)
+ parsed, unparsed = parse_known_args(parser, executable.arguments)
+ for term in _best_match:
+ unparsed.remove(term)
+ _exec_cmd(executable, unparsed, parser.print_help)
+
+
from command_shell import _fix_arguments, Shell
return shell
-def run_shell():
+def run_shell(arguments):
_fix_arguments()
shell = _start_shell()
_config = _arguments['config']
- _config.value = None
- for grp in _config.get_groups():
- global allow_all_commands
- allow_all_commands = True
- load_group_package(grp)
- setup_logging(silent=_arguments['silent'].value,
- debug=_arguments['debug'].value,
- verbose=_arguments['verbose'].value,
- include=_arguments['include'].value)
- shell.cmd_tree = _commands
+ from kamaki.cli.command_tree import CommandTree
+ shell.cmd_tree = CommandTree(
+ 'kamaki', 'A command line tool for poking clouds')
+ for spec in [spec for spec in _config.get_groups()\
+ if arguments['config'].get(spec, 'cli')]:
+ try:
+ spec_module = _load_spec_module(spec, arguments, '_commands')
+ spec_commands = getattr(spec_module, '_commands')
+ except AttributeError:
+ if _debug:
+ print('Warning: No valid description for %s' % spec)
+ continue
+ for spec_tree in spec_commands:
+ if spec_tree.name == spec:
+ shell.cmd_tree.add_tree(spec_tree)
+ break
shell.run()
def main():
+ exe = basename(argv[0])
+ parser = init_parser(exe, _arguments)
+ parsed, unparsed = parse_known_args(parser, _arguments)
+
+ if _arguments['version'].value:
+ exit(0)
- if len(argv) <= 1:
- run_shell()
+ _init_session(_arguments)
+
+ if unparsed:
+ _history = History(_arguments['config'].get('history', 'file'))
+ _history.add(' '.join([exe] + argv[1:]))
+ one_cmd(parser, unparsed, _arguments)
+ elif _help:
+ parser.print_help()
+ _groups_help(_arguments)
else:
- one_command()
+ run_shell(_arguments)
class ConfigArgument(Argument):
@property
def value(self):
+ super(self.__class__, self).value
return super(self.__class__, self).value
@value.setter
from cmd import Cmd
from os import popen
-from argparse import ArgumentParser
-from kamaki.cli import _update_parser, _exec_cmd
-from .argument import _arguments
-from .utils import print_dict
from sys import stdout
-from .history import History
+from argparse import ArgumentParser
+
+from kamaki.cli import _exec_cmd
+from kamaki.cli.argument import _arguments, update_arguments
+from kamaki.cli.utils import print_dict
+from kamaki.cli.history import History
def _fix_arguments():
instance = cls(dict(_arguments))
cmd_parser.prog = '%s %s' % (cmd_parser.prog.replace('_', ' '),
cls.syntax)
- _update_parser(cmd_parser, instance.arguments)
+ update_arguments(cmd_parser, instance.arguments)
+ #_update_parser(cmd_parser, instance.arguments)
if '-h' in cmd_args or '--help' in cmd_args:
cmd_parser.print_help()
return
from kamaki.cli.commands import _command_init
from kamaki.cli.command_tree import CommandTree
-astakos_commands = CommandTree('astakos', 'Astakos API commands')
-_commands = [astakos_commands]
+astakos_cmds = CommandTree('astakos', 'Astakos API commands')
+_commands = [astakos_cmds]
class _astakos_init(_command_init):
self.client = AstakosClient(base_url=base_url, token=token)
-@command(_commands)
+@command(astakos_cmds)
class astakos_authenticate(_astakos_init):
"""Authenticate a user"""
def main(self, custom_token=None):
- super(astakos_authenticate, self).main()
+ super(self.__class__, self).main()
try:
reply = self.client.authenticate(custom_token)
except ClientError as err:
from kamaki.cli import command
from kamaki.cli.argument import FlagArgument
from kamaki.cli.commands import _command_init
+from kamaki.cli.command_tree import CommandTree
+config_cmds = CommandTree('config', 'Configuration commands')
+_command = [config_cmds]
-API_DESCRIPTION = {'config': 'Configuration commands'}
-
-@command()
+@command(config_cmds)
class config_list(_command_init):
"""List configuration options"""
print('%s.%s = %s' % (section, key, val))
-@command()
+@command(config_cmds)
class config_get(_command_init):
"""Show a configuration option"""
print(value)
-@command()
+@command(config_cmds)
class config_set(_command_init):
"""Set a configuration option"""
self.config.write()
-@command()
+@command(config_cmds)
class config_delete(_command_init):
"""Delete a configuration option (and use the default value)"""
# or implied, of GRNET S.A.
from kamaki.cli import command
+from kamaki.cli.command_tree import CommandTree
from kamaki.cli.utils import print_dict, print_items, print_list, bold
from kamaki.cli.errors import CLIError, raiseCLIError, CLISyntaxError
from kamaki.clients.cyclades import CycladesClient, ClientError
from os.path import exists
-API_DESCRIPTION = {'server': 'Compute/Cyclades API server commands',
- 'flavor': 'Compute/Cyclades API flavor commands',
- 'image': 'Compute/Cyclades or Glance API image commands',
- 'network': 'Compute/Cyclades API network commands'}
+server_cmds = CommandTree('server',
+ 'Compute/Cyclades API server commands')
+flavor_cmds = CommandTree('flavor',
+ 'Compute/Cyclades API flavor commands')
+image_cmds = CommandTree('image',
+ 'Compute/Cyclades or Glance API image commands')
+network_cmds = CommandTree('network',
+ 'Compute/Cyclades API network commands')
+_commands = [server_cmds, flavor_cmds, image_cmds, network_cmds]
class _init_cyclades(_command_init):
self.client = CycladesClient(base_url=base_url, token=token)
-@command()
+@command(server_cmds)
class server_list(_init_cyclades):
"""List servers"""
raiseCLIError(err)
-@command()
+@command(server_cmds)
class server_info(_init_cyclades):
"""Get server details"""
pass
-@command()
+@command(server_cmds)
class server_create(_init_cyclades):
"""Create a server"""
print_dict(reply)
-@command()
+@command(server_cmds)
class server_rename(_init_cyclades):
"""Update a server's name"""
importance=1)
-@command()
+@command(server_cmds)
class server_delete(_init_cyclades):
"""Delete a server"""
importance=1)
-@command()
+@command(server_cmds)
class server_reboot(_init_cyclades):
"""Reboot a server"""
importance=1)
-@command()
+@command(server_cmds)
class server_start(_init_cyclades):
"""Start a server"""
importance=1)
-@command()
+@command(server_cmds)
class server_shutdown(_init_cyclades):
"""Shutdown a server"""
importance=1)
-@command()
+@command(server_cmds)
class server_console(_init_cyclades):
"""Get a VNC console"""
print_dict(reply)
-@command()
+@command(server_cmds)
class server_firewall(_init_cyclades):
"""Set the server's firewall profile"""
importance=1)
-@command()
+@command(server_cmds)
class server_addr(_init_cyclades):
"""List a server's nic address"""
print_list(reply)
-@command()
+@command(server_cmds)
class server_meta(_init_cyclades):
"""Get a server's metadata"""
print_dict(reply)
-@command()
+@command(server_cmds)
class server_addmeta(_init_cyclades):
"""Add server metadata"""
print_dict(reply)
-@command()
+@command(server_cmds)
class server_setmeta(_init_cyclades):
"""Update server's metadata"""
print_dict(reply)
-@command()
+@command(server_cmds)
class server_delmeta(_init_cyclades):
"""Delete server metadata"""
importance=1)
-@command()
+@command(server_cmds)
class server_stats(_init_cyclades):
"""Get server statistics"""
print_dict(reply, exclude=('serverRef',))
-@command()
+@command(server_cmds)
class server_wait(_init_cyclades):
"""Wait for server to finish [BUILD, STOPPED, REBOOT, ACTIVE]"""
print('\nTime out')
-@command()
+@command(flavor_cmds)
class flavor_list(_init_cyclades):
"""List flavors"""
print_items(flavors)
-@command()
+@command(flavor_cmds)
class flavor_info(_init_cyclades):
"""Get flavor details"""
print_dict(flavor)
-@command()
+@command(network_cmds)
class network_list(_init_cyclades):
"""List networks"""
self.print_networks(networks)
-@command()
+@command(network_cmds)
class network_create(_init_cyclades):
"""Create a network"""
print_dict(reply)
-@command()
+@command(network_cmds)
class network_info(_init_cyclades):
"""Get network details"""
network_info.print_network(network)
-@command()
+@command(network_cmds)
class network_rename(_init_cyclades):
"""Update network name"""
raiseCLIError(err)
-@command()
+@command(network_cmds)
class network_delete(_init_cyclades):
"""Delete a network"""
raiseCLIError(err)
-@command()
+@command(network_cmds)
class network_connect(_init_cyclades):
"""Connect a server to a network"""
raiseCLIError(err)
-@command()
+@command(network_cmds)
class network_disconnect(_init_cyclades):
"""Disconnect a nic that connects a server to a network"""
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.
+from kamaki.cli.command_tree import CommandTree
from kamaki.cli.argument import IntArgument, ValueArgument
from kamaki.cli.history import History
from kamaki.cli import command
from kamaki.cli.commands import _command_init
-API_DESCRIPTION = {'history': 'Command history'}
+history_cmds = CommandTree('history', 'Command history')
class _init_history(_command_init):
self.history = History(self.config.get('history', 'file'))
-@command()
+@command(history_cmds)
class history(_init_history):
"""Show history [containing terms...]"""
print(''.join(ret))
-@command()
+@command(history_cmds)
class history_clean(_init_history):
"""Clean up history"""
# or implied, of GRNET S.A.command
from kamaki.cli import command
+from kamaki.cli.command_tree import CommandTree
from kamaki.cli.errors import raiseCLIError
from kamaki.cli.utils import print_dict, print_items, bold
from kamaki.clients.image import ImageClient, ClientError
from kamaki.cli.commands import _command_init
-API_DESCRIPTION = {'image': 'Compute/Cyclades or Glance API image commands'}
+image_cmds = CommandTree('image',
+ 'Compute/Cyclades or Glance API image commands')
+_commands = [image_cmds]
class _init_image(_command_init):
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_public(_init_image):
"""List public images"""
print_items(images, title=('name',))
-@command()
+@command(image_cmds)
class image_meta(_init_image):
"""Get image metadata"""
print_dict(image)
-@command()
+@command(image_cmds)
class image_test(_init_image):
"""Test stuff"""
print('OK...')
-@command()
+@command(image_cmds)
class image_register(_init_image):
"""Register an image"""
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_members(_init_image):
"""Get image members"""
print(member['member_id'])
-@command()
+@command(image_cmds)
class image_shared(_init_image):
"""List shared images"""
print(image['image_id'])
-@command()
+@command(image_cmds)
class image_addmember(_init_image):
"""Add a member to an image"""
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_delmember(_init_image):
"""Remove a member from an image"""
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_setmembers(_init_image):
"""Set the members of an image"""
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_list(_init_cyclades):
"""List images"""
self._print(images)
-@command()
+@command(image_cmds)
class image_info(_init_cyclades):
"""Get image details"""
self._print(image)
-@command()
+@command(image_cmds)
class image_delete(_init_cyclades):
"""Delete image"""
raiseCLIError(err)
-@command()
+@command(image_cmds)
class image_properties(_init_cyclades):
"""Get image properties"""
print_dict(reply)
-@command()
+@command(image_cmds)
class image_addproperty(_init_cyclades):
"""Add an image property"""
print_dict(reply)
-@command()
+@command(image_cmds)
class image_setproperty(_init_cyclades):
"""Update an image property"""
print_dict(reply)
-@command()
+@command(image_cmds)
class image_delproperty(_init_cyclades):
"""Delete an image property"""
# or implied, of GRNET S.A.command
from kamaki.cli import command
+from kamaki.cli.command_tree import CommandTree
from kamaki.cli.errors import CLIError, raiseCLIError
from kamaki.cli.utils import format_size, print_dict, pretty_keys
from kamaki.cli.argument import FlagArgument, ValueArgument, IntArgument
from datetime import datetime as dtm
-API_DESCRIPTION = dict(store='Pithos+ storage commands')
+pithos_cmds = CommandTree('store', 'Pithos+ storage commands')
+_commands = [pithos_cmds]
# Argument functionality
self.container = self.client.container
-@command()
+@command(pithos_cmds)
class store_list(_store_container_command):
"""List containers, object trees or objects in a directory
"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_mkdir(_store_container_command):
"""Create a directory"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_create(_store_container_command):
"""Create a container or a directory object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_copy(_store_container_command):
"""Copy an object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_move(_store_container_command):
"""Copy an object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_append(_store_container_command):
"""Append local file to (existing) remote object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_truncate(_store_container_command):
"""Truncate remote file up to a size"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_overwrite(_store_container_command):
"""Overwrite part (from start to end) of a remote file"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_manifest(_store_container_command):
"""Create a remote file with uploaded parts by manifestation"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_upload(_store_container_command):
"""Upload a file"""
print 'Upload completed'
-@command()
+@command(pithos_cmds)
class store_cat(_store_container_command):
"""Print a file to console"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_download(_store_container_command):
"""Download a file"""
print
-@command()
+@command(pithos_cmds)
class store_hashmap(_store_container_command):
"""Get the hashmap of an object"""
print_dict(data)
-@command()
+@command(pithos_cmds)
class store_delete(_store_container_command):
"""Delete a container [or an object]"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_purge(_store_container_command):
"""Purge a container"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_publish(_store_container_command):
"""Publish an object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_unpublish(_store_container_command):
"""Unpublish an object"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_permissions(_store_container_command):
"""Get object read/write permissions """
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_setpermissions(_store_container_command):
"""Set sharing permissions """
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_delpermissions(_store_container_command):
"""Delete all sharing permissions"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_info(_store_container_command):
"""Get information for account [, container [or object]]"""
print_dict(reply)
-@command()
+@command(pithos_cmds)
class store_meta(_store_container_command):
"""Get custom meta-content for account [, container [or object]]"""
detail = self.get_argument('detail')
try:
+ until = self.get_argument('until')
if self.container is None:
print(bold(self.client.account))
- until = self.get_argument('until')
if detail:
reply = self.client.get_account_info(until=until)
else:
reply = self.client.get_account_meta(until=until)
reply = pretty_keys(reply, '-')
elif self.path is None:
- print(bold('%s: %s' % self.client.account, self.container))
+ print(bold('%s: %s' % (self.client.account, self.container)))
if detail:
reply = self.client.get_container_info(until=until)
else:
reply = {'container-meta': pretty_keys(cmeta, '-'),
'object-meta': pretty_keys(ometa, '-')}
else:
- print('%s: %s:%s'\
- % (bold(self.client.account, self.container, self.path)))
+ print(bold('%s: %s:%s'\
+ % (self.client.account, self.container, self.path)))
version = self.get_argument('object_version')
if detail:
reply = self.client.get_object_info(self.path,
print_dict(reply)
-@command()
+@command(pithos_cmds)
class store_setmeta(_store_container_command):
"""Set a new metadatum for account [, container [or object]]"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_delmeta(_store_container_command):
"""Delete an existing metadatum of account [, container [or object]]"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_quota(_store_account_command):
"""Get quota for account [or container]"""
print_dict(reply)
-@command()
+@command(pithos_cmds)
class store_setquota(_store_account_command):
"""Set new quota (in KB) for account [or container]"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_versioning(_store_account_command):
"""Get versioning for account [or container ]"""
print_dict(reply)
-@command()
+@command(pithos_cmds)
class store_setversioning(_store_account_command):
"""Set new versioning (auto, none) for account [or container]"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_group(_store_account_command):
"""Get user groups details for account"""
print_dict(reply)
-@command()
+@command(pithos_cmds)
class store_setgroup(_store_account_command):
"""Create/update a new user group on account"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_delgroup(_store_account_command):
"""Delete a user group on an account"""
raiseCLIError(err)
-@command()
+@command(pithos_cmds)
class store_sharers(_store_account_command):
"""List the accounts that share objects with default account"""
print
-@command()
+@command(pithos_cmds)
class store_versions(_store_container_command):
"""Get the version list of an object"""
# interpreted as representing official policies, either expressed
# or implied, of GRNET S.A.command
-from kamaki.cli.new import get_cmd_terms # , command
+from kamaki.cli import get_cmd_terms, command
from kamaki.cli.commands import _command_init
from kamaki.cli.command_tree import CommandTree
from kamaki.cli.argument import FlagArgument
-#API_DESCRIPTION = dict(test='Test sample')
-
-_commands = [
- CommandTree('sample', 'Sample commands for developing your own'),
- CommandTree('test', 'Test commands for testing clients')
-]
+sample_cmds = CommandTree(
+ 'sample',
+ 'Sample commands for developing your own')
+test_cmds = CommandTree(
+ 'test',
+ 'Test commands for testing clients')
+_commands = [sample_cmds, test_cmds]
print('Command Terms: ', get_cmd_terms())
-def command(cmd_tree_list, prefix='', descedants_depth=1):
- def wrap(cls):
- cls_name = cls.__name__
-
- cmd_tree = _commands[0] if cls_name.startswith('sample')\
- else _commands[1]
- if not cmd_tree:
- return cls
-
- cls.description, sep, cls.long_description\
- = cls.__doc__.partition('\n')
- from kamaki.cli.new import _construct_command_syntax
- _construct_command_syntax(cls)
-
- cmd_tree.add_command(cls_name, cls.description, cls)
- return cls
- return wrap
-
-
class _test_init(_command_init):
def main(self, *args, **kwargs):
print('\t\tkwarg: %s: %s' % (k, v))
-@command(cmd_tree_list=_commands)
+@command(sample_cmds)
class sample_cmd0(_test_init):
""" test cmd
This is the zero command test and this is the long description of it
super(self.__class__, self).main(mant)
-@command(cmd_tree_list=_commands)
+@command(sample_cmds)
class sample_cmd_all(_test_init):
"""test cmd all"""
super(self.__class__, self).main()
-@command(cmd_tree_list=_commands)
+@command(sample_cmds)
class sample_cmd_some(_test_init):
"""test_cmd_some"""
super(self.__class__, self).main(opt=opt)
-@command(cmd_tree_list=_commands)
+@command(test_cmds)
class test_cmd0(_test_init):
""" test cmd"""
super(self.__class__, self).main(mant)
-@command(cmd_tree_list=_commands)
+@command(test_cmds)
class test_cmd_all(_test_init):
"""test cmd all"""
super(self.__class__, self).main()
-@command(cmd_tree_list=_commands)
+@command(test_cmds)
class test_cmdion(_test_init):
"""test_cmd_some"""
super(self.__class__, self).main(opt=opt)
-@command(cmd_tree_list=_commands)
+@command(test_cmds)
class test_cmd_cmdion_comedian(_test_init):
"""test_cmd_some"""
+++ /dev/null
-# Copyright 2012-2013 GRNET S.A. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or
-# without modification, are permitted provided that the following
-# conditions are met:
-#
-# 1. Redistributions of source code must retain the above
-# copyright notice, this list of conditions and the following
-# disclaimer.
-#
-# 2. Redistributions in binary form must reproduce the above
-# copyright notice, this list of conditions and the following
-# disclaimer in the documentation and/or other materials
-# provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
-# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
-# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
-# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
-# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-# POSSIBILITY OF SUCH DAMAGE.
-#
-# The views and conclusions contained in the software and
-# documentation are those of the authors and should not be
-# interpreted as representing official policies, either expressed
-# or implied, of GRNET S.A.command
-
-import logging
-from sys import argv, exit, stdout
-from os.path import basename
-from inspect import getargspec
-
-from kamaki.cli.argument import _arguments, parse_known_args, init_parser,\
- update_arguments
-from kamaki.cli.history import History
-from kamaki.cli.utils import print_dict, print_list, red, magenta, yellow
-from kamaki.cli.errors import CLIError
-
-_help = False
-_debug = False
-_verbose = False
-_colors = False
-
-
-def _construct_command_syntax(cls):
- spec = getargspec(cls.main.im_func)
- args = spec.args[1:]
- n = len(args) - len(spec.defaults or ())
- required = ' '.join('<%s>' % x\
- .replace('____', '[:')\
- .replace('___', ':')\
- .replace('__', ']').\
- replace('_', ' ') for x in args[:n])
- optional = ' '.join('[%s]' % x\
- .replace('____', '[:')\
- .replace('___', ':')\
- .replace('__', ']').\
- replace('_', ' ') for x in args[n:])
- cls.syntax = ' '.join(x for x in [required, optional] if x)
- if spec.varargs:
- cls.syntax += ' <%s ...>' % spec.varargs
-
-
-def _get_cmd_tree_from_spec(spec, cmd_tree_list):
- for tree in cmd_tree_list:
- if tree.name == spec:
- return tree
- return None
-
-
-_best_match = []
-
-
-def _num_of_matching_terms(basic_list, attack_list):
- if not attack_list:
- return 1
-
- matching_terms = 0
- for i, term in enumerate(basic_list):
- try:
- if term != attack_list[i]:
- break
- except IndexError:
- break
- matching_terms += 1
- return matching_terms
-
-
-def _update_best_match(name_terms, prefix=[]):
- if prefix:
- pref_list = prefix if isinstance(prefix, list) else prefix.split('_')
- else:
- pref_list = []
-
- num_of_matching_terms = _num_of_matching_terms(name_terms, pref_list)
- global _best_match
-
- if num_of_matching_terms and len(_best_match) <= num_of_matching_terms:
- if len(_best_match) < num_of_matching_terms:
- _best_match = name_terms[:num_of_matching_terms]
- return True
- return False
-
-
-def command(cmd_tree_list, prefix='', descedants_depth=1):
- """Load a class as a command
- spec_cmd0_cmd1 will be command spec cmd0
- @cmd_tree_list is initialized in cmd_spec file and is the structure
- where commands are loaded. Var name should be _commands
- @param prefix if given, load only commands prefixed with prefix,
- @param descedants_depth is the depth of the tree descedants of the
- prefix command. It is used ONLY if prefix and if prefix is not
- a terminal command
- """
-
- def wrap(cls):
- cls_name = cls.__name__
-
- spec = cls_name.split('_')[0]
- cmd_tree = _get_cmd_tree_from_spec(spec, cmd_tree_list)
- if not cmd_tree:
- if _debug:
- print('Warning: command %s found but not loaded' % cls_name)
- return cls
-
- name_terms = cls_name.split('_')
- if not _update_best_match(name_terms, prefix):
- return None
-
- global _best_match
- max_len = len(_best_match) + descedants_depth
- if len(name_terms) > max_len:
- partial = '_'.join(name_terms[:max_len])
- if not cmd_tree.has_command(partial): # add partial path
- cmd_tree.add_command(partial)
- return None
-
- cls.description, sep, cls.long_description\
- = cls.__doc__.partition('\n')
- _construct_command_syntax(cls)
-
- cmd_tree.add_command(cls_name, cls.description, cls)
- return cls
- return wrap
-
-
-def get_cmd_terms():
- global command
- return [term for term in command.func_defaults[0]\
- if not term.startswith('-')]
-
-cmd_spec_locations = [
- 'kamaki.cli.commands',
- 'kamaki.commands',
- 'kamaki.cli',
- 'kamaki',
- '']
-
-
-def _setup_logging(silent=False, debug=False, verbose=False, include=False):
- """handle logging for clients package"""
-
- def add_handler(name, level, prefix=''):
- h = logging.StreamHandler()
- fmt = logging.Formatter(prefix + '%(message)s')
- h.setFormatter(fmt)
- logger = logging.getLogger(name)
- logger.addHandler(h)
- logger.setLevel(level)
-
- if silent:
- add_handler('', logging.CRITICAL)
- elif debug:
- add_handler('requests', logging.INFO, prefix='* ')
- add_handler('clients.send', logging.DEBUG, prefix='> ')
- add_handler('clients.recv', logging.DEBUG, prefix='< ')
- elif verbose:
- add_handler('requests', logging.INFO, prefix='* ')
- add_handler('clients.send', logging.INFO, prefix='> ')
- add_handler('clients.recv', logging.INFO, prefix='< ')
- elif include:
- add_handler('clients.recv', logging.INFO)
- else:
- add_handler('', logging.WARNING)
-
-
-def _init_session(arguments):
- global _help
- _help = arguments['help'].value
- global _debug
- _debug = arguments['debug'].value
- global _verbose
- _verbose = arguments['verbose'].value
- global _colors
- _colors = arguments['config'].get('global', 'colors')
- _silent = arguments['silent'].value
- _include = arguments['include'].value
- _setup_logging(_silent, _debug, _verbose, _include)
-
-
-def get_command_group(unparsed, arguments):
- groups = arguments['config'].get_groups()
- for term in unparsed:
- if term.startswith('-'):
- continue
- if term in groups:
- unparsed.remove(term)
- return term
- return None
- return None
-
-
-def _load_spec_module(spec, arguments, module):
- spec_name = arguments['config'].get(spec, 'cli')
- if spec_name is None:
- return None
- pkg = None
- for location in cmd_spec_locations:
- location += spec_name if location == '' else '.%s' % spec_name
- try:
- print('\t-- %s' % location)
- pkg = __import__(location, fromlist=[module])
- print('SO COOL')
- return pkg
- except ImportError:
- continue
- return pkg
-
-
-def _groups_help(arguments):
- global _debug
- descriptions = {}
- for spec in arguments['config'].get_groups():
- pkg = _load_spec_module(spec, arguments, '_commands')
- if pkg:
- cmds = None
- try:
- cmds = [
- cmd for cmd in getattr(pkg, '_commands')\
- if arguments['config'].get(cmd.name, 'cli')
- ]
- except AttributeError:
- if _debug:
- print('Warning: No description for %s' % spec)
- try:
- for cmd in cmds:
- descriptions[cmd.name] = cmd.description
- except TypeError:
- if _debug:
- print('Warning: no cmd specs in module %s' % spec)
- elif _debug:
- print('Warning: Loading of %s cmd spec failed' % spec)
- print('\nOptions:\n - - - -')
- print_dict(descriptions)
-
-
-def _print_subcommands_help(cmd):
- printout = {}
- for subcmd in cmd.get_subcommands():
- printout[subcmd.path.replace('_', ' ')] = subcmd.description
- if printout:
- print('\nOptions:\n - - - -')
- print_dict(printout)
-
-
-def _update_parser_help(parser, cmd):
- global _best_match
- parser.prog = parser.prog.split('<')[0]
- parser.prog += ' '.join(_best_match)
-
- if cmd.is_command:
- cls = cmd.get_class()
- parser.prog += ' ' + cls.syntax
- arguments = cls().arguments
- update_arguments(parser, arguments)
- else:
- parser.prog += ' <...>'
- if cmd.has_description:
- parser.description = cmd.help
-
-
-def _print_error_message(cli_err):
- errmsg = '%s' % cli_err
- if cli_err.importance == 1:
- errmsg = magenta(errmsg)
- elif cli_err.importance == 2:
- errmsg = yellow(errmsg)
- elif cli_err.importance > 2:
- errmsg = red(errmsg)
- stdout.write(errmsg)
- print_list(cli_err.details)
-
-
-def _get_best_match_from_cmd_tree(cmd_tree, unparsed):
- matched = [term for term in unparsed if not term.startswith('-')]
- while matched:
- try:
- return cmd_tree.get_command('_'.join(matched))
- except KeyError:
- matched = matched[:-1]
- return None
-
-
-def _exec_cmd(instance, cmd_args, help_method):
- try:
- return instance.main(*cmd_args)
- except TypeError as err:
- if err.args and err.args[0].startswith('main()'):
- print(magenta('Syntax error'))
- if _debug:
- raise err
- if _verbose:
- print(unicode(err))
- help_method()
- else:
- raise
- except CLIError as err:
- if _debug:
- raise err
- _print_error_message(err)
- return 1
-
-
-def set_command_param(param, value):
- if param == 'prefix':
- pos = 0
- elif param == 'descedants_depth':
- pos = 1
- else:
- return
- global command
- def_params = list(command.func_defaults)
- def_params[pos] = value
- command.func_defaults = tuple(def_params)
-
-
-def one_cmd(parser, unparsed, arguments):
- group = get_command_group(list(unparsed), arguments)
- if not group:
- parser.print_help()
- _groups_help(arguments)
- exit(0)
-
- set_command_param(
- 'prefix',
- [term for term in unparsed if not term.startswith('-')]
- )
- global _best_match
- _best_match = []
-
- spec_module = _load_spec_module(group, arguments, '_commands')
-
- cmd_tree = _get_cmd_tree_from_spec(group, spec_module._commands)
-
- if _best_match:
- cmd = cmd_tree.get_command('_'.join(_best_match))
- else:
- cmd = _get_best_match_from_cmd_tree(cmd_tree, unparsed)
- _best_match = cmd.path.split('_')
- if cmd is None:
- if _debug or _verbose:
- print('Unexpected error: failed to load command')
- exit(1)
-
- _update_parser_help(parser, cmd)
-
- if _help or not cmd.is_command:
- parser.print_help()
- _print_subcommands_help(cmd)
- exit(0)
-
- cls = cmd.get_class()
- executable = cls(arguments)
- parsed, unparsed = parse_known_args(parser, executable.arguments)
- for term in _best_match:
- unparsed.remove(term)
- _exec_cmd(executable, unparsed, parser.print_help)
-
-
-from command_shell import _fix_arguments, Shell
-
-
-def _start_shell():
- shell = Shell()
- shell.set_prompt(basename(argv[0]))
- from kamaki import __version__ as version
- shell.greet(version)
- shell.do_EOF = shell.do_exit
- return shell
-
-
-def run_shell(arguments):
- _fix_arguments()
- shell = _start_shell()
- _config = _arguments['config']
- from kamaki.cli.command_tree import CommandTree
- shell.cmd_tree = CommandTree(
- 'kamaki', 'A command line tool for poking clouds')
- for spec in [spec for spec in _config.get_groups()\
- if arguments['config'].get(spec, 'cli')]:
- print('SPEC NAME: %s' % spec)
- try:
- print('\t1')
- spec_module = _load_spec_module(spec, arguments, '_commands')
- print('\t2 %s' % spec_module)
- spec_commands = getattr(spec_module, '_commands')
- print('\t3')
- except AttributeError:
- if _debug:
- print('Warning: No valid description for %s' % spec)
- continue
- for spec_tree in spec_commands:
- if spec_tree.name == spec:
- shell.cmd_tree.add_tree(spec_tree)
- break
- shell.run()
-
-
-def main():
- exe = basename(argv[0])
- parser = init_parser(exe, _arguments)
- parsed, unparsed = parse_known_args(parser, _arguments)
-
- if _arguments['version'].value:
- exit(0)
-
- _init_session(_arguments)
- print(_arguments['config'].value.sections())
-
- if unparsed:
- _history = History(_arguments['config'].get('history', 'file'))
- _history.add(' '.join([exe] + argv[1:]))
- one_cmd(parser, unparsed, _arguments)
- elif _help:
- parser.print_help()
- _groups_help(_arguments)
- else:
- run_shell(_arguments)
packages=['kamaki', 'kamaki.clients', 'kamaki.clients.connection', 'kamaki.cli', 'kamaki.cli.commands'],
include_package_data=True,
entry_points={
- 'console_scripts': ['kamaki = kamaki.cli:main', 'newmaki = kamaki.cli.new:main']
+ 'console_scripts': ['kamaki = kamaki.cli:main']
},
install_requires=required
)