Fix version output when missing.
[plcapi.git] / plcsh
1 #!/usr/bin/python
2 #
3 # Interactive shell for testing PLCAPI
4 #
5 # Mark Huang <mlhuang@cs.princeton.edu>
6 # Copyright (C) 2005 The Trustees of Princeton University
7 #
8 # $Id$
9 #
10
11 import os
12 import sys
13 from socket import gethostname
14 from optparse import OptionParser
15 from getpass import getpass
16 from traceback import print_exc
17
18 sys.path.append(os.path.dirname(os.path.realpath(sys.argv[0])))
19 from PLC.Shell import Shell
20
21 usage="""Usage: %prog [options]
22    runs an interactive shell
23 Usage: %prog [options] script script-arguments
24 Usage: %prog script [plcsh-options --] script arguments
25    run a script"""
26
27 parser = OptionParser(usage=usage,add_help_option = False)
28 parser.add_option("-f", "--config", help = "PLC configuration file")
29 parser.add_option("-h", "--url", help = "API URL")
30 parser.add_option("-c", "--cacert", help = "API SSL certificate")
31 parser.add_option("-k", "--insecure", help = "Do not check SSL certificate")
32 parser.add_option("-m", "--method", help = "API authentication method")
33 parser.add_option("-s", "--session", help = "API session key")
34 parser.add_option("-u", "--user", help = "API user name")
35 parser.add_option("-p", "--password", help = "API password")
36 parser.add_option("-r", "--role", help = "API role")
37 parser.add_option("-x", "--xmlrpc", action = "store_true", default = False, help = "Use XML-RPC interface")
38 # pass this to the invoked shell if any
39 parser.add_option("--help", action = "store_true", dest="help", default=False,
40                   help = "show this help message and exit")
41 (options, args) = parser.parse_args()
42
43 if not args and options.help:
44     parser.print_help()
45     sys.exit(1)    
46
47 # If user is specified but password is not
48 if options.user is not None and options.password is None:
49     try:
50         options.password = getpass()
51     except (EOFError, KeyboardInterrupt):
52         print
53         sys.exit(0)
54
55 # Initialize a single global instance (scripts may re-initialize
56 # this instance and/or create additional instances).
57 try:
58     shell = Shell(globals = globals(),
59                   config = options.config,
60                   url = options.url, xmlrpc = options.xmlrpc, cacert = options.cacert,
61                   method = options.method, role = options.role,
62                   user = options.user, password = options.password,
63                   session = options.session)
64     # Register a few more globals for backward compatibility
65     auth = shell.auth
66     api = shell.api
67     config = shell.config
68 except Exception, err:
69     print "Error:", err
70     print
71     parser.print_help()
72     sys.exit(1)
73
74 # If called by a script 
75 if args:
76     if not os.path.exists(args[0]):
77         print 'File %s not found'%args[0]
78         parser.print_help()
79         sys.exit(1)
80     else:
81         # re-append --help if provided
82         if options.help:
83             args.append('--help')
84         # use args as sys.argv for the next shell, so our own options get removed for the next script
85         sys.argv = args
86         script = sys.argv[0]
87         # Add of script to sys.path 
88         path = os.path.dirname(os.path.abspath(script))
89         sys.path.append(path)
90         execfile(script)
91
92 # Otherwise, run an interactive shell environment
93 else:
94     if shell.server is None:
95         print "PlanetLab Central Direct API Access"
96         prompt = ""
97     elif shell.auth['AuthMethod'] == "anonymous":
98         prompt = "[anonymous]"
99         print "Connected anonymously"
100     elif shell.auth['AuthMethod'] == "session":
101         # XXX No way to tell node and user sessions apart from the
102         # client point of view.
103         prompt = "[%s]" % gethostname()
104         print "%s connected using session authentication" % gethostname()
105     else:
106         prompt = "[%s]" % shell.auth['Username']
107         print "%s connected using %s authentication" % \
108               (shell.auth['Username'], shell.auth['AuthMethod'])
109
110     # Readline and tab completion support
111     import atexit
112     import readline
113     import rlcompleter
114
115     print 'Type "system.listMethods()" or "help(method)" for more information.'
116     # Load command history
117     history_path = os.path.join(os.environ["HOME"], ".plcapi_history")
118     try:
119         file(history_path, 'a').close()
120         readline.read_history_file(history_path)
121         atexit.register(readline.write_history_file, history_path)
122     except IOError:
123         pass
124
125     # Enable tab completion
126     readline.parse_and_bind("tab: complete")
127
128     try:
129         while True:
130             command = ""
131             while True:
132                 # Get line
133                 try:
134                     if command == "":
135                         sep = ">>> "
136                     else:
137                         sep = "... "
138                     line = raw_input(prompt + sep)
139                 # Ctrl-C
140                 except KeyboardInterrupt:
141                     command = ""
142                     print
143                     break
144
145                 # Build up multi-line command
146                 command += line
147
148                 # Blank line or first line does not end in :
149                 if line == "" or (command == line and line[-1] != ':'):
150                     break
151
152                 command += os.linesep
153
154             # Blank line
155             if command == "":
156                 continue
157             # Quit
158             elif command in ["q", "quit", "exit"]:
159                 break
160
161             try:
162                 try:
163                     # Try evaluating as an expression and printing the result
164                     result = eval(command)
165                     if result is not None:
166                         print result
167                 except SyntaxError:
168                     # Fall back to executing as a statement
169                     exec command
170             except Exception, err:
171                 print_exc()
172
173     except EOFError:
174         print
175         pass