diff --git a/bin/cc-cli b/bin/cc-cli index 14f11f7a5f5a94c51871a23ecdeba645f9a36836..4d09a8168b27604be8366da238bd7d18478c7980 100755 --- a/bin/cc-cli +++ b/bin/cc-cli @@ -24,6 +24,7 @@ settings = { "timeout": "30", "hsize": "100", "alias": "%s/alias"%BaseDirectory.save_config_path(cccli.canonical_name), + "tag": "%s/tag"%BaseDirectory.save_config_path(cccli.canonical_name), "history": "%s/history"%BaseDirectory.save_data_path(cccli.canonical_name), "expert": "%s/expert"%BaseDirectory.save_data_path(cccli.canonical_name), } diff --git a/cccli/cli.py b/cccli/cli.py index 6a579b45e34a980d3d70677254b57f403183a092..8afa740141dca4308d53d9b0da5ec803ca7a34dd 100644 --- a/cccli/cli.py +++ b/cccli/cli.py @@ -5,29 +5,30 @@ CloudControl CLI main module ''' -import os, os.path -import sys -import re -import subprocess -import platform -import shlex -import StringIO import cccli from cccli.exception import * from cccli.printer import Printer, color from cccli.commands import Commands, Alias from cccli.handler import CliHandler - +from cccli.tagdisplay import TagDisplay +from sjrpc.core.exceptions import * from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, pure -from sjrpc.core.exceptions import * +import os, os.path +import sys +import re +import subprocess +import platform +import shlex +import StringIO class Cli(object): def __init__(self, settings): self.settings = settings self.rpc = None self.alias = Alias() + self.tagdisplay = TagDisplay() self.prompt = "" def start(self, line=""): @@ -60,6 +61,8 @@ class Cli(object): # load alias self.alias.load(self.settings.get("alias", "")) self.printer.debug("Loaded aliases: %d"%len(self.alias)) + # load tagdisplay + self.tagdisplay.load(self.settings.get("tag", "")) # connecting self._connect() # auth diff --git a/cccli/command/list.py b/cccli/command/list.py index 2f520ae126bed261cb47a75a6a816c025bfe0abe..de5394bb75c72744297e3dc1c8cd94537ff16cd1 100644 --- a/cccli/command/list.py +++ b/cccli/command/list.py @@ -15,17 +15,25 @@ class Command_list(OptionCommand): def __init__(self, cli, argv0): OptionCommand.__init__(self, cli, argv0) - self.option.set_usage("%prog [options] <tql>") - self.option.add_option("-c", action="store_true", dest="table", + self.option.set_usage("%prog [options] [tql]") + self.option.add_option("-t", action="store_true", dest="table", help="column aligment display") self.option.add_option("-l", action="store_true", dest="align", help="line aligment display") + self.option.add_option("-n", "--no-tagdisplay", action="store_false", dest="tagdisplay", default=True, + help="No tag display system") def __call__(self, argv): try: (options, args) = self.option.parse_args(argv[1:]) except SystemExit: return + if options.tagdisplay: + self.td = self.cli.tagdisplay.resolve + self.tc = self.cli.tagdisplay.color + else: + self.td = lambda tagname, tagvalue: tagvalue + self.tc = lambda tagname: color["reset"] if len(args) == 0: args.append("") try: @@ -39,48 +47,65 @@ class Command_list(OptionCommand): elif options.table: self._list_table(objs) else: - self._list(objs) + self._trivial_list(objs) - def _list(self, objs): + def _trivial_list(self, objs): + '''Trivial listing of tag''' for o in objs: - id = o.pop("id") - tags = " ".join([ "%s%s:%s%s"%(color["green"], t, color["reset"], v) for (t,v) in o.items() ]) - self.printer.out("%sid:%s%s%s %s"%(color["green"], color["yellow"], id, color["reset"], tags)) + id = self.td("id", o.pop("id")) + tags = " ".join([ "%s%s:%s%s"%(color["green"], + t, + self.tc(t), + self.td(t, v)) + for (t,v) in o.items() ]) + self.printer.out("%sid:%s%s %s%s"%(color["green"], color["lblue"], id, tags, color["reset"])) def _list_align(self, objs): - # get all tag list + '''Listing line aligned''' + # get max size by tag tags = dict() for o in objs: for t,v in o.items(): - tags[t] = max(len(str(v)), tags.get(t, len(str(t)))) + tags[t] = max(len(self.td(t, v)), tags.get(t, len(str(t)))) + # extract id size + idsize = tags.pop("id") + # dislay each object by line for o in objs: - id = str(o.pop("id")) - line = "%sid:%s%s%s"%(color["green"], color["yellow"], id.ljust(tags["id"] + 2), color["reset"]) - taglist = o.keys() - taglist.sort() - for tagname in taglist: - line += "%s%s:%s%s"%(color["green"], tagname, color["reset"], - str(o[tagname]).ljust(tags[tagname] + 1)) - self.printer.out(line) + # show id tag + line = "%sid:%s%s"%(color["green"], + self.tc("id"), + self.td("id", o.pop("id")).ljust(idsize + 2)) + # show others tags + for tagname in sorted(tags.keys()): + line += "%s%s:%s%s"%(color["green"], + tagname, + self.tc(tagname), + self.td(tagname, o.get(tagname, "")).ljust(tags[tagname] + 1)) + self.printer.out("%s%s"%(line, color["reset"])) def _list_table(self, objs): - # get all tag list + '''Listing table style''' + # get max size by tag tags = dict() for o in objs: for t,v in o.items(): - tags[t] = max(len(str(v)), tags.get(t, len(str(t)))) - # extract id info + tags[t] = max(len(self.td(t, v)), tags.get(t, len(str(t)))) + # extract id size idsize = tags.pop("id") - # print titles + # print id title self.printer.out(color["green"], nl="") self.printer.out("id".ljust(idsize+1), nl=" ") + # print others titles for t,v in tags.items(): self.printer.out(t.ljust(v), nl=" ") self.printer.out(color["reset"]) # print obj for obj in objs: - self.printer.out("%s%s%s"%(color["yellow"], obj.pop("id").ljust(idsize+1), color["reset"]) ,nl=" ") + # print id first + self.printer.out(self.tc("id"), nl="") + self.printer.out(self.td("id", obj.pop("id")).ljust(idsize+1), nl=" ") + # print others tags for (t, v) in tags.items(): - self.printer.out(str(obj.get(t, "")).ljust(v) ,nl=" ") - self.printer.out() - + self.printer.out(self.tc(t), nl="") + self.printer.out(self.td(t, obj.get(t, "")).ljust(v) ,nl=" ") + self.printer.out(color["reset"]) diff --git a/cccli/commands.py b/cccli/commands.py index 3d3bb574ede64bc31e88d3487d6f2d0778d7e11d..31c7fb1a8f3c263e0edc0f8fa21567eeab0c3511 100644 --- a/cccli/commands.py +++ b/cccli/commands.py @@ -11,6 +11,7 @@ import os from cccli.exception import * class Commands(object): + '''Command manager''' def __init__(self, cli): # save cli context diff --git a/cccli/handler.py b/cccli/handler.py index 24b09c0df599ef795fe602fcca0ca6b460ac921d..f31b696fe9abe1987f4fe9e702ee72dc59e8a14c 100644 --- a/cccli/handler.py +++ b/cccli/handler.py @@ -5,17 +5,15 @@ CloudControl CLI RPC Handler ''' -import os, os.path -import subprocess -import platform - -import cccli from cccli.exception import * from cccli.printer import Printer, color - from sjrpc.client import SimpleRpcClient from sjrpc.utils import RpcHandler, pure from sjrpc.core.exceptions import * +import cccli +import os, os.path +import subprocess +import platform class CliHandler(RpcHandler): diff --git a/cccli/tagdisplay.py b/cccli/tagdisplay.py new file mode 100644 index 0000000000000000000000000000000000000000..a00b3adea9ea84207260dad3a1c3c18ee535d9a8 --- /dev/null +++ b/cccli/tagdisplay.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +#coding=utf8 + +''' +CloudControl Tag displaying stuff +''' + +from cccli.exception import * +from cccli.printer import Printer, color +import os +import re +import math +import ConfigParser +import time + +class TagDisplay(object): + '''Handle tagdisplay stuff''' + + def __init__(self): + self.option = dict() + self.tagtype = dict() + self.tagcolor = { "id": "lblue" } + self.types = [ x[5:] for x in dir(self) if x.startswith("type_") ] + + def load(self, filename): + '''load tagdisplay settings from file''' + if os.access(filename, os.R_OK): + fparser = ConfigParser.RawConfigParser() + fparser.read(filename) + self.__init__() + if fparser.has_section("option"): + self.option.update(fparser.items("option")) + if fparser.has_section("type"): + self.tagtype.update(fparser.items("type")) + if fparser.has_section("color"): + self.tagcolor.update(fparser.items("color")) + + def save(self, filename): + '''save tagdisplay settings on file''' + if os.access(filename, os.R_OK or os.W_OK): + fparser = ConfigParser.RawConfigParser() + fparser.read(filename) + for n,d in (("type", self.tagtype), ("color", self.tagcolor), ("option", self.option)): + fparser.remove_section(n) + fparser.add_section(n) + for k,v in d.items(): + fparser.set(n, k, v) + fparser.write(open(filename, "w")) + + def color(self, tagname): + '''Return the current tag color''' + if tagname in self.tagcolor and self.tagcolor[tagname] in color: + return color[self.tagcolor[tagname]] + return color["reset"] + + def resolve(self, tagname, tagvalue): + '''Transform a tagvalue respecting custom display settings''' + tagname = unicode(tagname) + tagvalue = unicode(tagvalue) + if bool(self.option.get("quotespace", False)): + if re.search("\s", tagvalue) is not None: + tagvalue = "'%s'"%re.sub("'", "\'", tagvalue) + if tagname in self.tagtype and self.tagtype[tagname] in self.types: + return getattr(self, "type_%s"%self.tagtype[tagname])(tagvalue) + return tagvalue + + def type_lower(self, value): + '''Lower case type''' + return value.lower() + + def type_upper(self, value): + '''Upper case type''' + return value.upper() + + def type_si(self, value): + '''System International type''' + if value.isdecimal(): + v = float(value) + if v >= 1000: + si = "KMGTPEZY" + p = min(math.floor(math.log10(abs(v))/3.0), len(si)) + d = v / pow(10, 3*p) + u = si[int(p-1)] + value = "%.1f%s"%(d, u) + return value + + def type_bit(self, value): + '''Bit type''' + if value.isdecimal(): + v = float(value) + if v >= 1000: + si = "KMGTPEZY" + p = min(math.floor(math.log(abs(v), 2)/10.0), pow(2, len(si))) + d = v / pow(2, 10*p) + u = si[int(p-1)] + value = "%.1f%si"%(d, u) + return value + + def type_second(self, value): + '''Second type''' + if value.isdecimal(): + v = long(value) + if v < 60: + return "%ss"%value + elif v < 3600: + return "%dm%ds"%(v/60, v%60) + elif v < 86400: + return "%dh%dm%ds"%(v/3600, v/60%60, v%60) + else: + return "%dd%dh%dm%ds"%(v/86400, v/3600%3600, v/60%60, v%60) + return value