- order queried events by event_id
[plcapi.git] / Shell.py
index 613d40a..a649e84 100755 (executable)
--- a/Shell.py
+++ b/Shell.py
@@ -5,7 +5,7 @@
 # Mark Huang <mlhuang@cs.princeton.edu>
 # Copyright (C) 2005 The Trustees of Princeton University
 #
-# $Id: Shell.py,v 1.8 2006/10/20 18:25:39 mlhuang Exp $
+# $Id: Shell.py,v 1.12 2006/11/02 22:07:22 mlhuang Exp $
 #
 
 import os, sys
@@ -33,56 +33,61 @@ method = None
 user = None
 password = None
 role = None
-
-def usage():
-    print "Usage: %s [OPTION]..." % sys.argv[0]
-    print "Options:"
-    print "     -f, --config=FILE       PLC configuration file"
-    print "     -h, --url=URL           API URL"
-    print "     -m, --method=METHOD     API authentication method"
-    print "     -u, --user=EMAIL        API user name"
-    print "     -p, --password=STRING   API password"
-    print "     -r, --role=ROLE         API role"
-    print "     -x, --xmlrpc            Use XML-RPC interface"
-    print "     --help                  This message"
-    sys.exit(1)
-
-# Get options
-try:
-    (opts, argv) = getopt.getopt(sys.argv[1:],
-                                 "f:h:m:u:p:r:x",
-                                 ["config=", "cfg=", "file=",
-                                  "host=",
-                                  "method=",
-                                  "username=", "user=",
-                                  "password=", "pass=", "authstring=",
-                                  "role=",
-                                  "xmlrpc",
-                                  "help"])
-except getopt.GetoptError, err:
-    print "Error: " + err.msg
-    usage()
-
-for (opt, optval) in opts:
-    if opt == "-f" or opt == "--config" or opt == "--cfg" or opt == "--file":
-        config = optval
-    elif opt == "-h" or opt == "--host" or opt == "--url":
-        url = optval
-    elif opt == "-m" or opt == "--method":
-        method = optval
-    elif opt == "-u" or opt == "--username" or opt == "--user":
-        user = optval
-    elif opt == "-p" or opt == "--password" or opt == "--pass" or opt == "--authstring":
-        password = optval
-    elif opt == "-r" or opt == "--role":
-        role = optval
-    elif opt == "--help":
+xmlrpc = False
+
+if len(sys.argv) < 2 or not os.path.exists(sys.argv[1]):
+    # Parse options if called interactively
+    def usage():
+        print "Usage: %s [OPTION]..." % sys.argv[0]
+        print "Options:"
+        print "     -f, --config=FILE       PLC configuration file"
+        print "     -h, --url=URL           API URL"
+        print "     -m, --method=METHOD     API authentication method"
+        print "     -u, --user=EMAIL        API user name"
+        print "     -p, --password=STRING   API password"
+        print "     -r, --role=ROLE         API role"
+        print "     -x, --xmlrpc            Use XML-RPC interface"
+        print "     --help                  This message"
+        sys.exit(1)
+
+    try:
+        (opts, argv) = getopt.getopt(sys.argv[1:],
+                                     "f:h:m:u:p:r:x",
+                                     ["config=", "cfg=", "file=",
+                                      "host=",
+                                      "method=",
+                                      "username=", "user=",
+                                      "password=", "pass=", "authstring=",
+                                      "role=",
+                                      "xmlrpc",
+                                      "help"])
+    except getopt.GetoptError, err:
+        print "Error: ", err.msg
         usage()
 
+    for (opt, optval) in opts:
+        if opt == "-f" or opt == "--config" or opt == "--cfg" or opt == "--file":
+            config = optval
+        elif opt == "-h" or opt == "--host" or opt == "--url":
+            url = optval
+        elif opt == "-m" or opt == "--method":
+            method = optval
+        elif opt == "-u" or opt == "--username" or opt == "--user":
+            user = optval
+        elif opt == "-p" or opt == "--password" or opt == "--pass" or opt == "--authstring":
+            password = optval
+        elif opt == "-r" or opt == "--role":
+            role = optval
+        elif opt == "-x" or opt == "--xmlrpc":
+            xmlrpc = True
+        elif opt == "--help":
+            usage()
+
 try:
     # If any XML-RPC options have been specified, do not try
     # connecting directly to the DB.
-    if opts:
+    if (url, method, user, password, role, xmlrpc) != \
+       (None, None, None, None, None, False):
         raise Exception
         
     # Otherwise, first try connecting directly to the DB. If this
@@ -141,6 +146,40 @@ else:
     if role is not None:
         auth['Role'] = role
 
+# More convenient multicall support
+multi = False
+calls = []
+
+def begin():
+    global multi, calls
+
+    if calls:
+        raise Exception, "multicall already in progress"
+
+    multi = True
+
+def commit():
+    global multi, calls
+
+    if calls:
+        ret = []
+        multi = False
+        results = system.multicall(calls)
+        for result in results:
+            if type(result) == type({}):
+                raise xmlrpclib.Fault(item['faultCode'], item['faultString'])
+            elif type(result) == type([]):
+                ret.append(result[0])
+            else:
+                raise ValueError, "unexpected type in multicall result"
+    else:
+        ret = None
+
+    calls = []
+    multi = False
+
+    return ret
+
 class Callable:
     """
     Wrapper to call a method either directly or remotely. Initialize
@@ -180,21 +219,22 @@ class Callable:
         requires it and it has not been specified.
         """
 
+        global multi, calls
+
         if self.auth and \
            (not args or not isinstance(args[0], dict) or \
             (not args[0].has_key('AuthMethod') and \
              not args[0].has_key('session'))):
-            return self.func(auth, *args, **kwds)
+            args = (auth,) + args
+
+        if multi:
+            calls.append({'methodName': self.name, 'params': list(args)})
+            return None
         else:
             return self.func(*args, **kwds)
 
-if server is not None:
-    methods = server.system.listMethods()
-else:
-    methods = api.call(None, "system.listMethods")
-
 # Define all methods in the global namespace to support tab completion
-for method in methods:
+for method in PLC.Methods.methods:
     paths = method.split(".")
     if len(paths) > 1:
         first = paths.pop(0)
@@ -229,9 +269,11 @@ def help(thing):
     # help(...)
     pyhelp(thing)
 
-# If a file is specified
-if argv:
-    execfile(argv[0])
+# If called by a script
+if len(sys.argv) > 1 and os.path.exists(sys.argv[1]):
+    # Pop us off the argument stack
+    sys.argv.pop(0)
+    execfile(sys.argv[0])
     sys.exit(0)
 
 # Otherwise, create an interactive shell environment