Commit 6303e22f authored by Seblu's avatar Seblu
Browse files

add history system

parent 40535698
Loading
Loading
Loading
Loading
+22 −19
Original line number Diff line number Diff line
@@ -19,13 +19,15 @@ import getpass

settings = {
    "port": "1984",
    "timeout": "5"
    "timeout": "5",
    "hsize": "100"
    }

try:
    # parse rc file
    if "HOME" in os.environ:
        settings["alias"] = "%s/.cc-cli.conf"%os.environ["HOME"]
        settings["history"] = "%s/.cc-cli.history"%os.environ["HOME"]
        if os.access("%s/.cc-cli.conf"%os.environ["HOME"], os.R_OK):
            fparser = ConfigParser.SafeConfigParser()
            fparser.read("%s/.cc-cli.conf"%os.environ["HOME"])
@@ -72,13 +74,20 @@ try:
                       dest="timeout",
                       default="10",
                       help="connection timeout")



    oparser.add_option("--history-file",
                       action="store",
                       dest="history",
                       default="",
                       help="History file")
    oparser.add_option("--history-size",
                       action="store",
                       dest="hsize",
                       default="",
                       help="History max entry count")
    (options, args) = oparser.parse_args()

    # options handling
    for i in ("debug", "login", "server", "port", "timeout"):
    for i in ("debug", "login", "server", "port", "timeout", "history", "hsize"):
        if hasattr(options, i):
            o = getattr(options, i)
            if o:
@@ -96,18 +105,12 @@ try:
    if "server" not in settings:
        raise BadArgument("No server address")

    # check port value
    # check int values
    for i in "port", "timeout", "hsize":
        try:
        settings["port"] = int(settings["port"])
            settings[i] = int(settings[i])
        except:
        raise BadArgument("Invalid port number")

    # check timeout value
    try:
        settings["timeout"] = int(settings["timeout"])
    except:
        raise BadArgument("Invalid timeout")

            raise BadArgument("Invalid %s number"%i)
    # check login
    if "login" not in settings:
        settings["login"] = raw_input("Login: ")
@@ -117,8 +120,8 @@ try:
        settings["pass"] = getpass.getpass("Password: ")

    # start cli
    cli = cli.Cli(settings, args)
    cli.start()
    cli = cli.Cli(settings)
    cli.start(" ".join(args))
except BadArgument, e:
    printer.error("Bad Argument: %s"%str(e))
    oparser.print_help()
+92 −55
Original line number Diff line number Diff line
@@ -12,67 +12,74 @@ import ssl
import threading
import subprocess
import ConfigParser
import cccli
from cccli import printer, command
from cccli.clierror import *
import re

from cccli import printer, command, version, debug
from cccli.command import Command
from cccli.clierror import *
from sjrpc.core.exceptions import *
from sjrpc.client import SimpleRpcClient
from sjrpc.utils import RpcHandler, ConnectionProxy, pure
import sjrpc.core.exceptions

import re
import readline

class Cli(object):
    def __init__(self, settings, args):
        self._settings = settings
        self.alias = Alias(settings.get("alias", ""))
        self.alias.load()
        self.interactive = sys.stderr.isatty() and sys.stdin.isatty()
        self._prompt = "> "
        self._commands = args
    def __init__(self, settings):
        self.isinteractive = sys.stderr.isatty() and sys.stdin.isatty()
        self.settings = settings
        self.prompt = "> "
        self.rpc = None
        self.alias = Alias()
        self.history = History()

    def start(self):
    def start(self, line=""):
        '''Start a CLI'''
        # not interactive is command line
        if line:
            self.isinteractive = False
        # start readline and load history
        if self.isinteractive:
            import readline
            self.history.readline = readline
            self.history.load(self.settings.get("history", ""))
            self.history.maxsize(self.settings.get("hsize", None))
        # load alias
        self.alias.load(self.settings.get("alias", ""))
        printer.debug("Alias: %s"%self.alias)
        # Connecting
        self._connect()
        # authentifications
        self._auth()
        # run parsing args
        if len(self._commands) > 0:
            self._parse_line(" ".join(self._commands))
        elif self.interactive:
            self._interactive_parser()
        if line:
            self._parse_line(line)
        else:
            self._parser()
            self._shell()
        self.history.save(self.settings.get("history", ""))


    def _connect(self):
        printer.debug("Connecting...")
        rpcc = SimpleRpcClient.from_addr(self._settings["server"],
                                         self._settings["port"],
        rpcc = SimpleRpcClient.from_addr(self.settings["server"],
                                         self.settings["port"],
                                         enable_ssl=True,
                                         default_handler=CliHandler(),
                                         on_disconnect="quit",
                                         timeout=self._settings["timeout"]
                                         timeout=self.settings["timeout"]
                                        )
        rpcc.start(daemonize=True)
        self.rpc = ConnectionProxy(rpcc)

    def _auth(self):
        printer.debug("Authenticating...")
        if self.rpc.authentify(self._settings["login"], self._settings["pass"]):
        if self.rpc.authentify(self.settings["login"], self.settings["pass"]):
            printer.debug("Authenticated.")
        else:
            printer.fatal("Autentification failed!")

    def _interactive_parser(self):
        '''Interactive shell parser'''
        # init readline

    def _shell(self):
        '''Shell parser'''
        while True:
            try:
                line = raw_input(self._prompt)
                line = raw_input(self.prompt)
                self._parse_line(line)
            except EOFError:
                printer.out("")
@@ -81,19 +88,8 @@ class Cli(object):
                break
            except KeyboardInterrupt:
                printer.out("")
        try:
            pass
            #readline.write_history_file(self._settings["histfile"])
        except IOError:
            pass
        printer.out("Tcho!")

    def _parser(self):
        '''Non interactive parser'''
        while True:
            line = raw_input(self._prompt)
            self._parse_line(line)

    def _parse_line(self, line):
        '''Parse a line (more than one command)'''
        for cmd in line.split(";"):
@@ -130,11 +126,11 @@ class Cli(object):
                printer.error("command: %s."%str(e))
            else:
                printer.error("No command: %s."%argv[0])
        except sjrpc.core.exceptions.RpcError, e:
            if cccli.debug: raise
        except RpcError, e:
            if debug: raise
            printer.error("sjRPC: %s"%str(e))
        except Exception, e:
            if cccli.debug: raise
            if debug: raise
            printer.error("%s: %s."%(argv[0], str(e)))

    def _lex_argv(self, string):
@@ -143,28 +139,70 @@ class Cli(object):

class Alias(dict):
    ''' Alias wrapper'''
    def __init__(self, filename):
        self._filename = filename

    def load(self):
    def load(self, filename):
        '''load alias from file'''
        if os.access(self._filename, os.R_OK):
        if os.access(filename, os.R_OK):
            fparser = ConfigParser.SafeConfigParser()
            fparser.read(self._filename)
            fparser.read(filename)
            if fparser.has_section("alias"):
                self.clear()
                self.update(fparser.items("alias"))

    def save(self):
    def save(self, filename):
        '''save alias on file'''
        if os.access(self._filename, os.R_OK or os.W_OK):
        if os.access(filename, os.R_OK or os.W_OK):
            fparser = ConfigParser.SafeConfigParser()
            fparser.read(self._filename)
            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(self._filename, "w"))
            fparser.write(open(filename, "w"))


class History(object):
    '''History class'''
    def __init__(self, readline=None):
        self.readline = readline

    def __nonzero__(self):
        return not self.readline is None

    def __getattribute__(self, name):
        r = object.__getattribute__(self, "readline")
        if name == "readline":
            return r
        if r is None:
            return lambda *a,**k: None
        return object.__getattribute__(self, name)

    def __iter__(self):
        for i in range(1, len(self)):
            yield self.readline.get_history_item(i)

    def __len__(self):
        return self.readline.get_current_history_length()

    def load(self, path):
        '''Load history from a file'''
        try:
            self.readline.read_history_file(path)
        except IOError:
            pass

    def save(self, path):
        '''Save history into path'''
        try:
            self.readline.write_history_file(path)
        except IOError:
            pass

    def maxsize(self, size=None):
        '''Set or return max history size'''
        if size is not None:
            self.readline.set_history_length(size)
        return self.readline.get_history_length()


class CliHandler(RpcHandler):
    '''Handle RPC incoming request'''
@@ -172,9 +210,8 @@ class CliHandler(RpcHandler):
    @pure
    def get_tags(self, tags=()):
        if "version" in tags:
            return { "version": cccli.version }
            return { "version": version }

    @pure
    def quit(self, rpc=None):
        printer.fatal("Disconnected from server!")
+11 −2
Original line number Diff line number Diff line
@@ -126,7 +126,7 @@ class Command(object):
            printer.out("%s=%s"%(argv[1], self.cli.alias[argv[1]]))
        elif len(argv) == 3:
            self.cli.alias[argv[1]] = argv[2]
            self.cli.alias.save()
            self.cli.alias.save(self.cli.settings.get("alias", ""))
        else:
            raise BadArgument()
    cmd_alias.usage = "alias [name] [value]"
@@ -139,7 +139,7 @@ class Command(object):
        if argv[1] not in self.cli.alias:
            raise BadArgument("%s: No such alias"%argv[1])
        del self.cli.alias[argv[1]]
        self.cli.alias.save()
        self.cli.alias.save(self.cli.settings.get("alias", ""))
    cmd_unalias.usage = "unalias [name]"
    cmd_unalias.desc = "Remove an aliases"

@@ -150,6 +150,15 @@ class Command(object):
    cmd_rcmd.usage = "rcmd"
    cmd_rcmd.desc = "Print remote command list"

    def cmd_history(self, argv):
        '''Show history of commands'''
        if not self.cli.history:
            raise Exception("History is disabled")
        for l in self.cli.history:
            printer.out(l)
    cmd_history.usage = "history"
    cmd_history.desc = "Show commands history"

    def cmd_list(self, argv):
        '''List objects'''
        if len(argv) == 1: