From 994ed27b6424d373e2dd37a8bec30b2c5797d6a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Luttringer?= Date: Tue, 2 Oct 2012 13:10:38 +0200 Subject: [PATCH] wip --- cccli/cli.py | 2 + cccli/commands/right.py | 130 +++++++++++++++++----------------------- cccli/printer.py | 46 +++++++++++++- 3 files changed, 100 insertions(+), 78 deletions(-) diff --git a/cccli/cli.py b/cccli/cli.py index 3fa267a..00df190 100644 --- a/cccli/cli.py +++ b/cccli/cli.py @@ -37,6 +37,8 @@ import shlex import StringIO class Cli(object): + '''Command Line Class''' + def __init__(self, settings): self.settings = settings self.rpc = None diff --git a/cccli/commands/right.py b/cccli/commands/right.py index 1be1654..8c82a8d 100644 --- a/cccli/commands/right.py +++ b/cccli/commands/right.py @@ -19,96 +19,74 @@ CloudControl right releated commands ''' -import tempfile -import subprocess +from cccli.command import RemoteCommand +from cccli.exception import * import os -import re -import pprint -from cccli.exception import * -from sjrpc.core.exceptions import * -from cccli.printer import Printer, color -from cccli.command import Command, RemoteCommand +class RightCommand(RemoteCommand): + '''Right Base Class''' + + @staticmethod + def obj2str(obj_rights): + '''Convert rights object to string''' + s = "" + col_len = "" + for r in obj_rights: + s += "%(match)s\t%(method)s\t%(tql)s\t%(action)s\n" % r + return s + + @staticmethod + def str2obj(str_rights): + '''Convert rigths string to object''' + obj = [] + for line in str_rights.split(os.linesep): + line = line.strip() + if len(line) == 0 or line.startswith("#"): + continue + #print line + match, method, tql, action = line.split(None, 4) + obj.append({"match": match, + "method": method, + "tql": tql, + "action": action}) + return obj + + def check_file(self, fo): + '''Check if fo is valid rights strings''' + try: + self.str2obj(fo.read()) + except Exception as e: + raise + self.printer.debug("Invalid format: %s" % e) + return False + return True -class Command_rights(RemoteCommand): - '''List account rights''' - def __init__(self, cli, argv0): - RemoteCommand.__init__(self, cli, argv0) - self.set_usage("%prog [options]") +class Command_rights(RightCommand): + '''List server rights''' def __call__(self, argv): # ask server - al = self.rpc.call("loadrights") + o_rights = self.rpc.call("loadrights") # display answer - for r in al: - self.printer.out("%(match)s\t%(method)s\t%(tql)s\t%(action)s" % r) + self.printer.out(self.obj2str(o_rights), nl=None) - def remote_functions(self): + @staticmethod + def remote_functions(): return set(('loadrights',)) -class Command_editrights(RemoteCommand): - ''' Edit rights ''' - - def __init__(self, cli, argv0): - RemoteCommand.__init__(self, cli, argv0) - self.set_usage("%prog [options]") - - def indent(self, rights, space): - indents = {} - fields = ('match', 'method', 'tql', 'action') - for f in fields: - cur = 0 - for r in rights: - cur = max(cur, len(r[f])) - indents[f] = cur + space - return indents - - def edit(self, out): - editor = os.environ.get('EDITOR', '/bin/nano') - subprocess.call([editor, out.name]) - out.seek(0) - new_rights = [] - nb = 1 - for line in out: - line = line.lstrip().rstrip() - if len(line) == 0 or line.startswith('#'): - continue - items = line.split() - if len(items) < 4 or (len(items) > 4 and not items[5].startswith('#')): - while True: - s = raw_input("Error: bad file format at line %d, do you want to reedit ? [yes/no] " % nb) - answer = s.lstrip().rstrip() - if answer == 'yes': - return self.edit(out) - elif answer == 'no': - raise cmdError('Bad file format at line %d' % nb) - else: - self.printer.out("Please answer by yes or no") - new_rights.append({'match': items[0], 'method': items[1], 'tql': items[2], 'action': items[3]}) - nb += 1 - return new_rights +class Command_editrights(RightCommand): + ''' Edit server rights ''' def __call__(self, argv): - with tempfile.NamedTemporaryFile(dir='/tmp') as temp: - al = self.rpc.call("loadrights") - indents = self.indent(al, 2) - temp.write("# match%smethod%stql%saction\n" % (' '*(indents['match'] - len('match') - 2), - ' '*(indents['method'] - len('method')), - ' '*(indents['tql'] - len('tql')))) - for r in al: - temp.write("%s%s%s%s%s%s%s\n" % (r['match'], - ' '*(indents['match'] - len(r['match'])), - r['method'], - ' '*(indents['method'] - len(r['method'])), - r['tql'], - ' '*(indents['tql'] - len(r['tql'])), - r['action'])) - temp.flush() - new_rights = self.edit(temp) - temp.close() - self.rpc.call('saverights', new_rights) + obj_rights = self.rpc.call("loadrights") + str_rights = self.obj2str(obj_rights) + new_rights = self.printer.editor(str_rights, self.check_file) + if new_rights is not None: + self.rpc.call('saverights', self.str2obj(new_rights)) + else: + self.printer.out("Nothing change.") def remote_functions(self): return set(('saverights',)) diff --git a/cccli/printer.py b/cccli/printer.py index b767337..3c288ec 100644 --- a/cccli/printer.py +++ b/cccli/printer.py @@ -19,15 +19,16 @@ CloudControl CLI Printer module ''' -import cccli from cccli.exception import * - +import cccli import fcntl import os +import shutil import signal import struct import subprocess import sys +import tempfile import termios import tty @@ -201,6 +202,8 @@ class Printer(object): def pager(self, data): '''Page data using PAGER''' + if self.readline is None: + return binary = os.environ.get("CC_PAGER", os.environ.get("PAGER", "more")) if isinstance(data, basestring): p = subprocess.Popen(binary, stdin=subprocess.PIPE, close_fds=True, @@ -211,6 +214,45 @@ class Printer(object): shell=True) p.wait() + def editor(self, data, checker=None): + ''' + Edit data using editor and verify validity with checker + Return edited files or None + ''' + if self.readline is None: + return False + binary = os.environ.get("CC_EDITOR", os.environ.get("EDITOR", "vi")) + # create tempory files + f_tmp = tempfile.NamedTemporaryFile() + # fullfill temp file with data + if isinstance(data, basestring): + f_tmp.write(data) + else: + shutil.copyfileobj(data, f_tmp) + f_tmp.flush() + # run editor + to_save = False + while True: + subprocess.Popen("%s '%s'" % (binary, f_tmp.name), shell=True).wait() + if checker is not None: + f_tmp.seek(0) + if checker(f_tmp): + to_save = True + break + else: + if self.ask("Invalid file format! Retry (Y/n)? ").lower() != "Y": + break + else: + to_save = True + break + if to_save: + f_tmp.seek(0) + ans = f_tmp.read() + else: + ans = None + f_tmp.close() + return ans + class History(object): '''History class''' -- GitLab