# Mark Huang <mlhuang@cs.princeton.edu>
# Copyright (C) 2005 The Trustees of Princeton University
#
-# $Id: Shell.py,v 1.5 2006/10/03 19:34:05 mlhuang Exp $
+# $Id: Shell.py,v 1.12 2006/11/02 22:07:22 mlhuang Exp $
#
import os, sys
import xmlrpclib
import getpass
+# Append PLC to the system path
+sys.path.append(os.path.dirname(os.path.realpath(sys.argv[0])))
+
from PLC.API import PLCAPI
from PLC.Parameter import Mixed
from PLC.Auth import Auth
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
if role == "anonymous" or method == "anonymous":
auth = {'AuthMethod': "anonymous"}
else:
- if role is None:
- print "Error: must specify a role with -r"
- usage()
-
if user is None:
print "Error: must specify a username with -u"
usage()
auth = {'AuthMethod': method,
'Username': user,
- 'AuthString': password,
- 'Role': role}
+ 'AuthString': password}
+
+ 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:
"""
# Figure out if the function requires an authentication
# structure as its first argument.
self.auth = False
- func = api.callable(method)
try:
- #func = api.callable(method)
+ func = api.callable(method)
if func.accepts and \
(isinstance(func.accepts[0], Auth) or \
(isinstance(func.accepts[0], Mixed) and \
filter(lambda param: isinstance(param, Auth), func.accepts[0]))):
self.auth = True
except:
+ traceback.print_exc()
# XXX Ignore undefined methods for now
pass
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')):
- return self.func(auth, *args, **kwds)
+ (not args or not isinstance(args[0], dict) or \
+ (not args[0].has_key('AuthMethod') and \
+ not args[0].has_key('session'))):
+ args = (auth,) + args
+
+ if multi:
+ calls.append({'methodName': self.name, 'params': list(args)})
+ return None
else:
- return self.func(*args)
-
-if server is not None:
- methods = server.system.listMethods()
-else:
- methods = api.call(None, "system.listMethods")
+ return self.func(*args, **kwds)
# 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)
# 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
prompt = "[anonymous]"
print "Connected anonymously"
else:
- prompt = "[%s %s]" % (auth['Username'], auth['Role'])
- print "%s connected as %s using %s authentication" % \
- (auth['Username'], auth['Role'], auth['AuthMethod'])
+ prompt = "[%s]" % auth['Username']
+ print "%s connected using %s authentication" % \
+ (auth['Username'], auth['AuthMethod'])
print 'Type "system.listMethods()" or "help(method)" for more information.'
# Readline and tab completion support
result = eval(command)
if result is not None:
print result
- except:
+ except SyntaxError:
# Fall back to executing as a statement
exec command
except Exception, err: