#!/usr/bin/env python #coding=utf8 ''' CloudControl CLI main module ''' import os, os.path import sys import re import subprocess import shlex import StringIO from cccli import version, debug from cccli.command import Command, Alias from cccli.printer import Printer from cccli.exception import * from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, ConnectionProxy, pure from sjrpc.core.exceptions import * class Cli(object): def __init__(self, settings): self.settings = settings self.prompt = "" self.rpc = None self.printer = None self.alias = Alias() def start(self, line=""): '''Start a CLI''' # line stuff if line: sys.stdin = StringIO.StringIO(line) # set interactive mode self.interactive = sys.stderr.isatty() and sys.stdin.isatty() # start printer and load history self.printer = Printer(self.interactive) self.printer.history.load(self.settings.get("history", "")) self.printer.history.maxsize(self.settings.get("hsize", None)) # load alias self.alias.load(self.settings.get("alias", "")) # print debug self.printer.debug("Interactive: %s"%self.interactive) self.printer.debug("Alias: %s"%self.alias) self.printer.debug("Loaded history: %s"%len(self.printer.history)) # Connecting self._connect() # authentifications self._auth() # Parsing self._parse() # save history self.printer.history.save(self.settings.get("history", "")) def _connect(self): self.printer.debug("Connecting...") rpcc = SimpleRpcClient.from_addr(self.settings["server"], self.settings["port"], enable_ssl=True, default_handler=CliHandler(), on_disconnect="quit", timeout=self.settings["timeout"] ) rpcc.start(daemonize=True) self.rpc = ConnectionProxy(rpcc) def _auth(self): '''Handle server authentification''' self.printer.debug("Authenticating...") if self.rpc.authentify(self.settings["login"], self.settings["pass"]): self.printer.debug("Authenticated.") else: self.printer.fatal("Autentification failed!") def _parse(self): '''Parse a line''' prompt = "> " if self.interactive else "" while True: try: argv = shlex.split(self.printer.getline(prompt), comments=True) # alias subsitution if argv[0] in self.alias: argv[0] = self.alias[argv[0]] except ValueError, e: self.printer.error("Lexer: %s"%str(e)) continue except EOFError: break except SystemExit: break except KeyboardInterrupt: self.printer.out("") self._exec_command(argv) if self.interactive: self.printer.out("tcho!") def _exec_command(self, argv): '''Execute command''' try: if (argv[0] == "!"): p = subprocess.Popen(argv[1:], close_fds=True, shell=True) p.wait() ret = p.returncode elif (argv[0] == "?"): Command(["help"], self).call() else: Command(argv, self).call() except BadArgument, e: if str(e): self.printer.error("Bad argument: %s."%str(e)) else: self.printer.error("Bad argument.") usage = Command.usage(argv[0]) if usage != "": self.printer.out("usage: %s."%usage) except BadCommand, e: if str(e): self.printer.error("command: %s."%str(e)) else: self.printer.error("No command: %s."%argv[0]) except RpcError, e: if debug: raise self.printer.error("sjRPC: %s"%str(e)) except Exception, e: if debug: raise self.printer.error("%s: %s."%(argv[0], str(e))) class CliHandler(RpcHandler): '''Handle RPC incoming request''' @pure def get_tags(self, tags=()): if "version" in tags: return { "version": version } @pure def quit(self, rpc=None): self.printer.fatal("Disconnected from server!") class CliLexer(object): def __init__(self, fd): self.fd = fd def get_next_token(self): pass