Skip to content
Snippets Groups Projects
Commit 98a60864 authored by Seblu's avatar Seblu
Browse files

Improve commands loading

Commands loading is now done by crawling commands directory under cccli module.
All command which starts by Commmand_ and which is a son of Command class are candidate.
parent a98db606
No related branches found
No related tags found
No related merge requests found
Showing
with 144 additions and 214 deletions
......@@ -9,7 +9,7 @@ CloudControl CLI main module
import cccli
from cccli.exception import *
from cccli.printer import Printer, color
from cccli.commands import Commands, Aliases
from cccli.command import Commands, Aliases
from cccli.handler import CliHandler
from cccli.tagdisplay import TagDisplay
from sjrpc.core.exceptions import *
......
......@@ -4,11 +4,126 @@
'''
CloudControl CLI command module
'''
import re
import ConfigParser
import os
import shlex
import imp
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from optparse import OptionParser
import cccli.commands
class Commands(object):
'''Command manager'''
def __init__(self, cli):
# save cli context
self.cli = cli
# build command list
self.cmds = self.load_commands(cccli.commands.__path__[0], Command)
# build remote function list
try:
self.functions = set([ c["name"] for c in self.cli.rpc.call("functions") ])
except RpcError as e:
raise cliError("RPCError: Unable to retrieve remote commands: %s"%str(e))
# remove not available remote commands
for cname in tuple(self.cmds):
cobj = self.cmds[cname](self.cli, cname)
if isinstance(cobj, RemoteCommand):
try:
if len(cobj.remote_functions()) == 0:
raise NotImplementedError("No remote function")
if not cobj.remote_functions().issubset(self.functions):
del self.cmds[cname]
self.cli.printer.debug("Command %s not available"%cname)
except NotImplementedError as e:
self.cli.printer.debug("Command %s lack of remote_functions"%cname)
del self.cmds[cname]
def __len__(self):
return len(self.cmds)
def __contains__(self, item):
return item in self.cmds.keys()
def __iter__(self):
return iter(self.cmds.keys())
def __repr__(self):
return repr(self.cmds.keys())
def __call__(self, argv):
# check argv
if len(argv) == 0:
raise cmdBadName()
# find right commands to call
if argv[0] not in self:
matchlist = [ x for x in self if re.match("%s.+"%re.escape(argv[0]), x) ]
if len(matchlist) == 1:
argv[0] = matchlist[0]
else:
raise cmdBadName()
# create class and call it
cmd = self.cmds[argv[0]](self.cli, argv[0])
return cmd(argv)
def usage(self, argv0):
'''Return usage of a command'''
u = self.cmds[argv0](self.cli, argv0).usage()
return u if u is not None else ""
def help(self, argv0):
'''Return of a command'''
h = self.cmds[argv0](self.cli, argv0).help()
return h if h is not None else ""
def load_commands(self, path, cls):
'''Load sublasss of cls from package name'''
cmds=dict()
for name in os.listdir(path):
if name.endswith(".py") and not name.startswith("__"):
fpath = os.path.join(path, name)
module = imp.load_source(os.path.splitext(name)[0], fpath)
for key, entry in module.__dict__.items():
try:
if issubclass(entry, cls) and entry.__name__.startswith("Command_"):
cmds[entry.__name__[8:]] = entry
except TypeError:
continue
return cmds
class Aliases(dict):
''' Aliases manager'''
def load(self, filename):
'''load alias from file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
if fparser.has_section("alias"):
self.clear()
self.update(fparser.items("alias"))
def save(self, filename):
'''save alias on file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
fparser.remove_section("alias")
fparser.add_section("alias")
for n,v in self.items():
fparser.set("alias", n, v)
fparser.write(open(filename, "w"))
def substitute(self, argv):
if argv[0] in self:
oldargv = argv[1:]
argv = shlex.split(self[argv[0]])
argv.extend(oldargv)
return argv
class Command(object):
'''Base of all command class'''
......@@ -19,6 +134,11 @@ class Command(object):
self.name = argv0
def __call__(self, argv):
'''Code called when command is invoked'''
raise NotImplementedError
def name(self):
'''Name of the command'''
raise NotImplementedError
def usage(self):
......
#!/usr/bin/env python
#coding=utf8
'''
CloudControl CLI Commands Package
'''
__all__ = [
"Command",
"OptionCommand",
"RemoteCommand",
"TqlCommand",
"Command_addaccount",
"Command_addright",
"Command_addtag",
"Command_alias",
"Command_cancel",
"Command_clear",
"Command_clone",
"Command_close",
"Command_declose",
"Command_delaccount",
"Command_delright",
"Command_deltag",
"Command_destroy",
"Command_execute",
"Command_expert",
"Command_help",
"Command_history",
"Command_jobs",
"Command_kill",
"Command_list",
"Command_migrate",
"Command_passwd",
"Command_pause",
"Command_quit",
"Command_resume",
"Command_rights",
"Command_server",
"Command_shutdown",
"Command_start",
"Command_stop",
"Command_tagdisplay",
"Command_tags",
"Command_unalias",
"Command_undefine",
"Command_usage",
"Command_version",
"Command_whoami",
]
# importing
from cccli.command.command import Command, OptionCommand, RemoteCommand, TqlCommand
from cccli.command.account import Command_addaccount
from cccli.command.account import Command_close
from cccli.command.account import Command_declose
from cccli.command.account import Command_delaccount
from cccli.command.account import Command_passwd
from cccli.command.alias import Command_alias
from cccli.command.alias import Command_unalias
from cccli.command.cancel import Command_cancel
from cccli.command.execute import Command_execute
from cccli.command.expert import Command_expert
from cccli.command.jobs import Command_jobs
from cccli.command.kill import Command_kill
from cccli.command.list import Command_list
from cccli.command.migrate import Command_migrate
from cccli.command.right import Command_addright
from cccli.command.right import Command_delright
from cccli.command.right import Command_rights
from cccli.command.server import Command_server
from cccli.command.shell import Command_clear
from cccli.command.shell import Command_help
from cccli.command.shell import Command_history
from cccli.command.shell import Command_quit
from cccli.command.shell import Command_usage
from cccli.command.shell import Command_version
from cccli.command.shell import Command_whoami
from cccli.command.shutdown import Command_shutdown
from cccli.command.tag import Command_addtag
from cccli.command.tag import Command_deltag
from cccli.command.tag import Command_tags
from cccli.command.tagdisplay import Command_tagdisplay
from cccli.command.vm import Command_clone
from cccli.command.vm import Command_destroy
from cccli.command.vm import Command_pause
from cccli.command.vm import Command_resume
from cccli.command.vm import Command_start
from cccli.command.vm import Command_stop
from cccli.command.vm import Command_undefine
#!/usr/bin/env python
#coding=utf8
'''
CloudControl CLI commands module
'''
import re
import ConfigParser
import os
import shlex
from cccli.exception import *
from cccli.command import *
class Commands(object):
'''Command manager'''
def __init__(self, cli):
# save cli context
self.cli = cli
# build command list
self.cmds = dict()
for x in [ x for x in globals() if x.startswith("Command_") ]:
self.cmds[x[8:]] = globals()[x]
# build remote function list
try:
self.functions = set([ c["name"] for c in self.cli.rpc.call("functions") ])
except RpcError as e:
raise cliError("RPCError: Unable to retrieve remote commands: %s"%str(e))
# remove not available commands
for cname in tuple(self.cmds):
cobj = self.cmds[cname](self.cli, cname)
if isinstance(cobj, RemoteCommand):
try:
if len(cobj.remote_functions()) == 0:
raise NotImplementedError("No remote function")
if not cobj.remote_functions().issubset(self.functions):
del self.cmds[cname]
self.cli.printer.debug("Command %s not available"%cname)
except NotImplementedError as e:
self.cli.printer.debug("Command %s lack of remote_functions"%cname)
del self.cmds[cname]
def __len__(self):
return len(self.cmds)
def __contains__(self, item):
return item in self.cmds.keys()
def __iter__(self):
return iter(self.cmds.keys())
def __repr__(self):
return repr(self.cmds.keys())
def __call__(self, argv):
# check argv
if len(argv) == 0:
raise cmdBadName()
# find right commands to call
if argv[0] not in self:
matchlist = [ x for x in self if re.match("%s.+"%re.escape(argv[0]), x) ]
if len(matchlist) == 1:
argv[0] = matchlist[0]
else:
raise cmdBadName()
# create class and call it
cmd = self.cmds[argv[0]](self.cli, argv[0])
return cmd(argv)
def usage(self, argv0):
'''Return usage of a command'''
u = self.cmds[argv0](self.cli, argv0).usage()
return u if u is not None else ""
def help(self, argv0):
'''Return of a command'''
h = self.cmds[argv0](self.cli, argv0).help()
return h if h is not None else ""
class Aliases(dict):
''' Aliases manager'''
def load(self, filename):
'''load alias from file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
if fparser.has_section("alias"):
self.clear()
self.update(fparser.items("alias"))
def save(self, filename):
'''save alias on file'''
if filename is not None:
fparser = ConfigParser.RawConfigParser()
fparser.read(filename)
fparser.remove_section("alias")
fparser.add_section("alias")
for n,v in self.items():
fparser.set("alias", n, v)
fparser.write(open(filename, "w"))
def substitute(self, argv):
if argv[0] in self:
oldargv = argv[1:]
argv = shlex.split(self[argv[0]])
argv.extend(oldargv)
return argv
#!/usr/bin/env python
#coding=utf8
'''
CloudControl CLI Commands Package
'''
__all__ = []
......@@ -8,7 +8,7 @@ CloudControl accounts related commands
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_addaccount(TqlCommand):
'''Create an account'''
......
......@@ -6,7 +6,7 @@ CloudControl alias related command
'''
from cccli.exception import *
from cccli.command.command import OptionCommand
from cccli.command import OptionCommand
import re
class Command_alias(OptionCommand):
......
......@@ -8,7 +8,7 @@ CloudControl cancel command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import RemoteCommand
from cccli.command import RemoteCommand
class Command_cancel(RemoteCommand):
'''Cancel a job'''
......
......@@ -6,7 +6,7 @@ CloudControl execute command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_execute(TqlCommand):
'''Execute a command on the remote host'''
......
......@@ -6,7 +6,7 @@ CloudControl expert command
'''
from cccli.exception import *
from cccli.printer import Printer, color
from cccli.command.command import Command
from cccli.command import Command
from sjrpc.utils import ConnectionProxy
import code
......
......@@ -8,7 +8,7 @@ CloudControl jobs command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_jobs(TqlCommand):
'''List jobs'''
......
......@@ -8,7 +8,7 @@ CloudControl Connection related commands
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_kill(TqlCommand):
'''Kill a server connection'''
......
......@@ -8,7 +8,7 @@ CloudControl list command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
import math
import os
......
......@@ -8,7 +8,7 @@ CloudControl migrate command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_migrate(TqlCommand):
'''Migrate vm'''
......
......@@ -8,7 +8,7 @@ CloudControl right releated commands
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import Command, TqlCommand
from cccli.command import Command, TqlCommand
class Command_rights(TqlCommand):
'''List account rights'''
......
......@@ -7,7 +7,7 @@ CloudControl server command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import RemoteCommand
from cccli.command import RemoteCommand
class Command_server(RemoteCommand):
'''Server manipulation command'''
......
......@@ -7,7 +7,7 @@ CloudControl shells related commands
from cccli.exception import *
from cccli.printer import Printer, color
from cccli.command.command import Command
from cccli.command import Command
class Command_quit(Command):
'''Quit application with respect'''
......
......@@ -6,7 +6,7 @@ CloudControl physical host related commands
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
class Command_shutdown(TqlCommand):
'''Shutdown a physical host'''
......
......@@ -8,7 +8,7 @@ CloudControl tag releated commands
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import TqlCommand
from cccli.command import TqlCommand
from optparse import OptionParser
......
......@@ -7,7 +7,7 @@ CloudControl tagdisplay command
from cccli.exception import *
from sjrpc.core.exceptions import *
from cccli.printer import Printer, color
from cccli.command.command import OptionCommand
from cccli.command import OptionCommand
class Command_tagdisplay(OptionCommand):
'''Tagdisplay tool'''
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment