23
23
# This is a command-line application, for use by the administrator.
24
# This program is a frontend for the modules in the setup packages that
25
# build and install IVLE in separate steps.
24
# This program configures, builds and installs IVLE in three separate steps.
26
25
# It is called with at least one argument, which specifies which operation to
28
# setup.py conf [args]
29
# Configures IVLE with machine-specific details, most notably, various paths.
30
# Either prompts the administrator for these details or accepts them as
32
# Creates www/conf/conf.py and trampoline/conf.h.
35
# Compiles all files and sets up a jail template in the source directory.
37
# Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
39
# Creates standard subdirs inside the jail, eg bin, opt, home, tmp.
40
# Copies console/ to a location within the jail.
41
# Copies OS programs and files to corresponding locations within the jail
42
# (eg. python and Python libs, ld.so, etc).
43
# Generates .pyc files for all the IVLE .py files.
45
# setup.py listmake (for developer use only)
46
# Recurses through the source tree and builds a list of all files which should
47
# be copied upon installation. This should be run by the developer before
48
# cutting a distribution, and the listfile it generates should be included in
49
# the distribution, avoiding the administrator having to run it.
51
# setup.py install [--nojail] [--dry|n]
53
# Create target install directory ($target).
55
# Copy trampoline/trampoline to $target/bin.
56
# chown and chmod the installed trampoline.
57
# Copy www/ to $target.
58
# Copy jail/ to jails template directory (unless --nojail specified).
60
# TODO: List in help, and handle, args for the conf operation
68
# Main function skeleton from Guido van Rossum
69
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
71
class Usage(Exception):
72
def __init__(self, msg):
33
75
def main(argv=None):
56
oper_func = call_operator(operation)
57
return oper_func(argv[2:])
98
# Call the requested operation's function
104
'listmake' : listmake,
106
}[operation](argv[2:])
108
print >>sys.stderr, (
109
"""Invalid operation '%s'. Try python setup.py help."""
114
opts, args = getopt.getopt(argv[1:], "h", ["help"])
115
except getopt.error, msg:
117
# more code, unchanged
119
print >>sys.stderr, err.msg
120
print >>sys.stderr, "for help use --help"
123
# Operation functions
61
print """Usage: python setup.py operation [options]
127
print """Usage: python setup.py operation [args]
128
Operation (and args) can be:
67
For help and options for a specific operation use 'help [operation]'."""
70
oper_func = call_operator(operator)
71
oper_func(['operator','--help'])
73
def call_operator(operation):
74
# Call the requested operation's function
78
'build' : setup.build.build,
79
'install' : setup.install.install,
132
install [--nojail] [-n|--dry]
136
print """Usage: python setup.py help [operation]"""
141
if operation == 'help':
142
print """python setup.py help [operation]
143
Prints the usage message or detailed help on an operation, then exits."""
144
elif operation == 'conf':
145
print """python setup.py conf [args]
146
Configures IVLE with machine-specific details, most notably, various paths.
147
Either prompts the administrator for these details or accepts them as
149
Creates www/conf/conf.py and trampoline/conf.h.
152
elif operation == 'build':
153
print """python setup.py build
154
Compiles all files and sets up a jail template in the source directory.
156
Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
158
Creates standard subdirs inside the jail, eg bin, opt, home, tmp.
159
Copies console/ to a location within the jail.
160
Copies OS programs and files to corresponding locations within the jail
161
(eg. python and Python libs, ld.so, etc).
162
Generates .pyc files for all the IVLE .py files."""
163
elif operation == 'listmake':
164
print """python setup.py listmake
165
(For developer use only)
166
Recurses through the source tree and builds a list of all files which should
167
be copied upon installation. This should be run by the developer before
168
cutting a distribution, and the listfile it generates should be included in
169
the distribution, avoiding the administrator having to run it."""
170
elif operation == 'install':
171
print """sudo python setup.py install [--nojail] [--dry|-n]
173
Create target install directory ($target).
175
Copy trampoline/trampoline to $target/bin.
176
chown and chmod the installed trampoline.
177
Copy www/ to $target.
178
Copy jail/ to jails template directory (unless --nojail specified).
180
--nojail Do not copy the jail.
181
--dry | -n Print out the actions but don't do anything."""
82
183
print >>sys.stderr, (
83
184
"""Invalid operation '%s'. Try python setup.py help."""
189
# Set up some variables
192
# the files that will be created/overwritten
193
conffile = os.path.join(cwd, "www/conf/conf.py")
194
conf_hfile = os.path.join(cwd, "trampoline/conf.h")
196
# Fixed config options that we don't ask the admin
198
default_app = "dummy"
200
print """This tool will create the following files:
203
prompting you for details about your configuration. The file will be
204
overwritten if it already exists. It will *not* install or deploy IVLE.
206
Please hit Ctrl+C now if you do not wish to do this.
207
""" % (conffile, conf_hfile)
209
# Get information from the administrator
210
# If EOF is encountered at any time during the questioning, just exit
213
root_dir = query_user(
214
"""Root directory where IVLE is located (in URL space):
215
(eg. "/" or "/ivle")""")
216
ivle_install_dir = query_user(
217
'Root directory where IVLE is located (on the local file system):\n'
218
'(eg. "/home/informatics/ivle")')
219
jail_base = query_user(
220
"""Root directory where user files are stored (on the local file system):
221
(eg. "/home/informatics/jails")""")
222
allowed_uid = query_user(
223
"""UID of the web server process which will run IVLE.
224
Only this user may execute the trampoline. You can configure multiple users
225
by manually editing conf.h.
228
# Error handling on input values
231
allowed_uid = int(allowed_uid)
233
print >>sys.stderr, "Invalid UID (%s)." % allowed_uid
236
# Write www/conf/conf.py
239
conf = open(conffile, "w")
241
conf.write("""# IVLE Configuration File
243
# Miscellaneous application settings
246
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
248
# eg. "/" or "/ivle".
251
# In the local file system, where IVLE is actually installed.
252
# This directory should contain the "www" and "bin" directories.
253
ivle_install_dir = "%s"
255
# In the local file system, where are the student/user file spaces located.
256
# The user jails are expected to be located immediately in subdirectories of
260
# Which application to load by default (if the user navigates to the top level
261
# of the site). This is the app's URL name.
262
# Note that if this app requires authentication, the user will first be
263
# presented with the login screen.
265
""" % (root_dir, ivle_install_dir, jail_base, default_app))
268
except IOError, (errno, strerror):
269
print "IO error(%s): %s" % (errno, strerror)
272
print "Successfully wrote www/conf/conf.py"
274
# Write trampoline/conf.h
277
conf = open(conf_hfile, "w")
279
conf.write("""/* IVLE Configuration File
281
* Administrator settings required by trampoline.
282
* Note: trampoline will have to be rebuilt in order for changes to this file
286
/* In the local file system, where are the jails located.
287
* The trampoline does not allow the creation of a jail anywhere besides
288
* jail_base or a subdirectory of jail_base.
290
static const char* jail_base = "%s";
292
/* Which user IDs are allowed to run the trampoline.
293
* This list should be limited to the web server user.
294
* (Note that root is an implicit member of this list).
296
static const int allowed_uids[] = { %d };
297
""" % (jail_base, allowed_uid))
300
except IOError, (errno, strerror):
301
print "IO error(%s): %s" % (errno, strerror)
304
print "Successfully wrote trampoline/conf.h"
307
print "You may modify the configuration at any time by editing"
314
dry = False # Set to True later if --dry
316
# Compile the trampoline
317
action_runprog('gcc', ['-Wall', '-o', 'trampoline/trampoline',
318
'trampoline/trampoline.c'], dry)
320
# Create the jail and its subdirectories
322
action_mkdir('jail/bin')
323
action_mkdir('jail/lib')
324
action_mkdir('jail/usr')
325
action_mkdir('jail/usr/bin')
326
action_mkdir('jail/usr/lib')
327
action_mkdir('jail/opt')
328
action_mkdir('jail/home')
329
action_mkdir('jail/tmp')
331
# TODO: Copy console into the jail
332
# TODO: Copy operating system files into the jail
333
# TODO: Compile .py files into .pyc files
345
# The actions call Python os functions but print actions and handle dryness.
346
# May still throw os exceptions if errors occur.
349
"""Represents an error when running a program (nonzero return)."""
350
def __init__(self, prog, retcode):
352
self.retcode = retcode
354
return str(self.prog) + " returned " + repr(self.retcode)
356
def action_runprog(prog, args, dry):
357
"""Runs a unix program. Searches in $PATH. Synchronous (waits for the
358
program to return). Runs in the current environment. First prints the
359
action as a "bash" line.
361
Throws a RunError with a retcode of the return value of the program,
362
if the program did not return 0.
364
prog: String. Name of the program. (No path required, if in $PATH).
365
args: [String]. Arguments to the program.
366
dry: Bool. If True, prints but does not execute.
368
print prog, string.join(args, ' ')
370
ret = os.spawnvp(os.P_WAIT, prog, args)
372
raise RunError(prog, ret)
374
def action_mkdir(path):
375
"""Calls mkdir. Silently ignored if the directory already exists."""
379
except OSError, (err, msg):
380
if err != errno.EEXIST:
383
def query_user(prompt):
384
"""Prompts the user for a string, which is read from a line of stdin.
385
Exits silently if EOF is encountered. Returns the string, with spaces
386
removed from the beginning and end.
388
sys.stdout.write(prompt)
389
sys.stdout.write("\n>")
391
val = sys.stdin.readline()
392
except KeyboardInterrupt:
394
sys.stdout.write("\n")
396
sys.stdout.write("\n")
397
if val == '': sys.exit(1)
88
400
if __name__ == "__main__":