cli: Use metaprogramming to generate code during runtime when new apis sync

- Fixes metaprogramming to inject methods during shell class object's runtime
- This enable new apis that are synced to come up with new verbs, docs etc.
- Fixes printing issue
- Fixes null bitfield parsing issue

Signed-off-by: Rohit Yadav <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/repo
Commit: 
http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/commit/a2e89c42
Tree: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/tree/a2e89c42
Diff: http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/diff/a2e89c42

Branch: refs/heads/vim51_win8
Commit: a2e89c42006d41fc7fd817664e89db80d76d4bb0
Parents: 6a601ba
Author: Rohit Yadav <[email protected]>
Authored: Mon Feb 4 17:55:11 2013 +0530
Committer: Rohit Yadav <[email protected]>
Committed: Mon Feb 4 17:57:08 2013 +0530

----------------------------------------------------------------------
 tools/cli/cloudmonkey/cachemaker.py  |    5 +-
 tools/cli/cloudmonkey/cloudmonkey.py |  133 +++++++++++++++--------------
 tools/cli/cloudmonkey/printer.py     |    2 +-
 3 files changed, 73 insertions(+), 67 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/a2e89c42/tools/cli/cloudmonkey/cachemaker.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/cachemaker.py 
b/tools/cli/cloudmonkey/cachemaker.py
index 5886c62..8827f29 100644
--- a/tools/cli/cloudmonkey/cachemaker.py
+++ b/tools/cli/cloudmonkey/cachemaker.py
@@ -56,6 +56,8 @@ def savecache(apicache, json_file):
     """
     Saves apicache dictionary as json_file, returns dictionary as indented str
     """
+    if isinstance(type(apicache), types.NoneType) or apicache is None or 
apicache is {}:
+      return ""
     apicachestr = json.dumps(apicache, indent=2)
     with open(json_file, 'w') as cache_file:
         cache_file.write(apicachestr)
@@ -81,8 +83,9 @@ def monkeycache(apis):
     """
     Feed this a dictionary of api bananas, it spits out processed cache
     """
-    if isinstance(type(apis), types.NoneType):
+    if isinstance(type(apis), types.NoneType) or apis is None:
         return {}
+
     responsekey = filter(lambda x: 'response' in x, apis.keys())
 
     if len(responsekey) == 0:

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/a2e89c42/tools/cli/cloudmonkey/cloudmonkey.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/cloudmonkey.py 
b/tools/cli/cloudmonkey/cloudmonkey.py
index 6ebeb6a..db7104a 100644
--- a/tools/cli/cloudmonkey/cloudmonkey.py
+++ b/tools/cli/cloudmonkey/cloudmonkey.py
@@ -28,20 +28,14 @@ try:
     import sys
     import types
 
-    from urllib2 import HTTPError, URLError
-    from httplib import BadStatusLine
-
+    from cachemaker import loadcache, savecache, monkeycache, splitverbsubject
     from config import __version__, cache_file
     from config import read_config, write_config
-
+    from prettytable import PrettyTable
     from printer import monkeyprint
     from requester import monkeyrequest
-    from cachemaker import loadcache, savecache, monkeycache
-    from cachemaker import splitverbsubject
-
-    from prettytable import PrettyTable
 except ImportError, e:
-    print "Import error in %s : %s" % (__name__, e)
+    print("Import error in %s : %s" % (__name__, e))
     import sys
     sys.exit()
 
@@ -50,11 +44,10 @@ try:
 except ImportError:
     apicache = {}
 
-# Fix autocompletion issue, can be put in .pythonstartup
 try:
     import readline
 except ImportError, e:
-    print "Module readline not found, autocompletions will fail", e
+    print("Module readline not found, autocompletions will fail", e)
 else:
     import rlcompleter
     if 'libedit' in readline.__doc__:
@@ -71,8 +64,6 @@ class CloudMonkeyShell(cmd.Cmd, object):
              ". Type help or ? to list commands.\n")
     ruler = "="
     cache_file = cache_file
-    ## datastructure {'verb': {cmd': ['api', [params], doc, required=[]]}}
-    #cache_verbs = apicache
     config_options = []
 
     def __init__(self, pname):
@@ -91,9 +82,9 @@ class CloudMonkeyShell(cmd.Cmd, object):
         try:
             if os.path.exists(self.history_file):
                 readline.read_history_file(self.history_file)
-            atexit.register(readline.write_history_file, self.history_file)
-        except IOError:
-            monkeyprint("Error: history support")
+        except IOError, e:
+            logger.debug("Error: Unable to read history. " + str(e))
+        atexit.register(readline.write_history_file, self.history_file)
 
     def get_attr(self, field):
         return getattr(self, field)
@@ -105,7 +96,7 @@ class CloudMonkeyShell(cmd.Cmd, object):
         pass
 
     def cmdloop(self, intro=None):
-        print self.intro
+        print(self.intro)
         while True:
             try:
                 super(CloudMonkeyShell, self).cmdloop(intro="")
@@ -118,7 +109,31 @@ class CloudMonkeyShell(cmd.Cmd, object):
             self.apicache = loadcache(self.cache_file)
         else:
             self.apicache = apicache
-        self.verbs = apicache['verbs']
+        if 'verbs' in self.apicache:
+            self.verbs = self.apicache['verbs']
+
+        for verb in self.verbs:
+            def add_grammar(verb):
+                def grammar_closure(self, args):
+                    if self.pipe_runner("%s %s" % (verb, args)):
+                        return
+                    if ' --help' in args or ' -h' in args:
+                        self.do_help("%s %s" % (verb, args))
+                        return
+                    try:
+                        args_partition = args.partition(" ")
+                        cmd = self.apicache[verb][args_partition[0]]['name']
+                        args = args_partition[2]
+                    except KeyError, e:
+                        self.monkeyprint("Error: invalid %s api arg" % verb, e)
+                        return
+                    self.default("%s %s" % (cmd, args))
+                return grammar_closure
+
+            grammar_handler = add_grammar(verb)
+            grammar_handler.__doc__ = "%ss resources" % verb.capitalize()
+            grammar_handler.__name__ = 'do_' + str(verb)
+            setattr(self.__class__, grammar_handler.__name__, grammar_handler)
 
     def monkeyprint(self, *args):
         output = ""
@@ -128,12 +143,12 @@ class CloudMonkeyShell(cmd.Cmd, object):
                     continue
                 output += str(arg)
         except Exception, e:
-            print e
+            print(e)
 
         if self.color == 'true':
             monkeyprint(output)
         else:
-            print output
+            print(output)
 
     def print_result(self, result, result_filter=None):
         if result is None or len(result) == 0:
@@ -219,7 +234,7 @@ class CloudMonkeyShell(cmd.Cmd, object):
             next_val = lexp.next()
             if next_val is None:
                 break
-            args.append(next_val)
+            args.append(next_val.replace('\x00', ''))
 
         args_dict = dict(map(lambda x: [x.partition("=")[0],
                                         x.partition("=")[2]],
@@ -230,15 +245,21 @@ class CloudMonkeyShell(cmd.Cmd, object):
                                   map(lambda x: x.strip(),
                                       args_dict.pop('filter').split(',')))
 
-        missing_args = filter(lambda x: x not in args_dict.keys(),
-                              self.apicache[verb][subject]['requiredparams'])
+        missing_args = []
+        if verb in self.apicache:
+            missing_args = filter(lambda x: x not in args_dict.keys(),
+                           self.apicache[verb][subject]['requiredparams'])
 
         if len(missing_args) > 0:
             self.monkeyprint("Missing arguments: ", ' '.join(missing_args))
             return
 
-        result = self.make_request(apiname, args_dict,
-                                   apiname in self.apicache['asyncapis'])
+        isasync = False
+        if 'asyncapis' in self.apicache:
+            isasync = apiname in self.apicache['asyncapis']
+
+        result = self.make_request(apiname, args_dict, isasync)
+
         if result is None:
             return
         try:
@@ -285,6 +306,9 @@ class CloudMonkeyShell(cmd.Cmd, object):
         """
         response = self.make_request("listApis")
         self.apicache = monkeycache(response)
+        if response is None:
+            monkeyprint("Failed to sync apis, check your config")
+            return
         savecache(self.apicache, self.cache_file)
         self.loadcache()
 
@@ -361,9 +385,19 @@ class CloudMonkeyShell(cmd.Cmd, object):
         else:
             verb = fields[0]
             subject = fields[2].partition(" ")[0]
-
-            if subject in self.cache_verbs[verb]:
-                self.monkeyprint(self.cache_verbs[verb][subject][2])
+            if subject in self.apicache[verb]:
+                api = self.apicache[verb][subject]
+                helpdoc = "(%s) %s" % (api['name'], api['description'])
+                helpdoc = api['description']
+                if api['isasync']:
+                    helpdoc += "\nThis API is asynchronous."
+                required = api['requiredparams']
+                if len(required) > 0:
+                    helpdoc += "\nRequired params are %s" % ' '.join(required)
+                helpdoc += "\nParameters\n" + "=" * 10
+                for param in api['params']:
+                    helpdoc += "\n%s = (%s) %s" % (param['name'], 
param['type'], param['description'])
+                self.monkeyprint(helpdoc)
             else:
                 self.monkeyprint("Error: no such api (%s) on %s" %
                                  (subject, verb))
@@ -379,6 +413,12 @@ class CloudMonkeyShell(cmd.Cmd, object):
             text = subfields[2]
             return self.completedefault(text, line, begidx, endidx)
 
+    def do_EOF(self, args):
+        """
+        Quit on Ctrl+d or EOF
+        """
+        sys.exit()
+
     def do_exit(self, args):
         """
         Quit CloudMonkey CLI
@@ -392,45 +432,8 @@ class CloudMonkeyShell(cmd.Cmd, object):
         self.monkeyprint("Bye!")
         return self.do_EOF(args)
 
-    def do_EOF(self, args):
-        """
-        Quit on Ctrl+d or EOF
-        """
-        sys.exit()
-
 
 def main():
-    verbs = []
-    if os.path.exists(cache_file):
-        verbs = loadcache(cache_file)['verbs']
-    elif 'verbs' in apicache:
-        verbs = apicache['verbs']
-
-    for verb in verbs:
-        def add_grammar(verb):
-            def grammar_closure(self, args):
-                if self.pipe_runner("%s %s" % (verb, args)):
-                    return
-                try:
-                    args_partition = args.partition(" ")
-                    api = self.apicache[verb][args_partition[0]]
-                    cmd = api['name']
-                    helpdoc = api['description']
-                    args = args_partition[2]
-                except KeyError, e:
-                    self.monkeyprint("Error: invalid %s api arg" % verb, e)
-                    return
-                if ' --help' in args or ' -h' in args:
-                    self.monkeyprint(helpdoc)
-                    return
-                self.default("%s %s" % (cmd, args))
-            return grammar_closure
-
-        grammar_handler = add_grammar(verb)
-        grammar_handler.__doc__ = "%ss resources" % verb.capitalize()
-        grammar_handler.__name__ = 'do_' + str(verb)
-        setattr(CloudMonkeyShell, grammar_handler.__name__, grammar_handler)
-
     shell = CloudMonkeyShell(sys.argv[0])
     if len(sys.argv) > 1:
         shell.onecmd(' '.join(sys.argv[1:]))

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/a2e89c42/tools/cli/cloudmonkey/printer.py
----------------------------------------------------------------------
diff --git a/tools/cli/cloudmonkey/printer.py b/tools/cli/cloudmonkey/printer.py
index dd2b8d2..925e765 100644
--- a/tools/cli/cloudmonkey/printer.py
+++ b/tools/cli/cloudmonkey/printer.py
@@ -69,10 +69,10 @@ class MonkeyLexer(RegexLexer):
             (r'(?:\b\d+\b(?:-\b\d+|%)?)', Number),
             (r'^[-=]*\n', Operator.Word),
             (r'Error', Error),
-            (makelistre(keywords), Keyword),
             (makelistre(attributes), Literal),
             (makelistre(params) + r'( = )(.*)', bygroups(Name, Operator,
                                                          String)),
+            (makelistre(keywords), Keyword),
             (makelistre(params), Name),
             (r'(^[a-zA-Z]* )(=)', bygroups(Name, Operator)),
             (r'\S+', Text),

Reply via email to