~azzar1/unity/add-show-desktop-key

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: Matt Giuca
  • Date: 2009-04-28 11:19:03 UTC
  • Revision ID: matt.giuca@gmail.com-20090428111903-murkoqeljahrp2d8
usrmgt-server: Removed all references to ivle.conf. Now uses the config
    object.
    (I created a global variable, config, just for the outermost functions to
    use. All of the other functions still use an argument version of config,
    for testing purposes).

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
# Date:   12/12/2007
22
22
 
23
23
# This is a command-line application, for use by the administrator.
24
 
# This program configures, builds and installs IVLE in three separate steps.
 
24
# This program is a frontend for the modules in the setup packages that 
 
25
# build and install IVLE in separate steps.
25
26
# It is called with at least one argument, which specifies which operation to
26
27
# take.
27
28
 
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
31
 
# command-line args.
32
 
# Creates www/conf/conf.py and trampoline/conf.h.
33
 
 
34
 
# setup.py build
35
 
# Compiles all files and sets up a jail template in the source directory.
36
 
# Details:
37
 
# Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
38
 
# Creates jail/.
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.
44
 
 
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.
50
 
 
51
 
# setup.py install [--nojail] [--dry|n]
52
 
# (Requires root)
53
 
# Create target install directory ($target).
54
 
# Create $target/bin.
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).
59
 
 
60
 
# TODO: List in help, and handle, args for the conf operation
61
 
 
62
 
import os
63
29
import sys
64
 
import getopt
65
 
import string
66
 
import errno
67
 
 
68
 
# Try importing existing conf, but if we can't just set up defaults
69
 
# The reason for this is that these settings are used by other phases
70
 
# of setup besides conf, so we need to know them.
71
 
# Also this allows you to hit Return to accept the existing value.
72
 
try:
73
 
    confmodule = __import__("www/conf/conf")
74
 
    root_dir = confmodule.root_dir
75
 
    ivle_install_dir = confmodule.ivle_install_dir
76
 
    jail_base = confmodule.jail_base
77
 
except ImportError:
78
 
    # Just set reasonable defaults
79
 
    root_dir = "/ivle"
80
 
    ivle_install_dir = "/opt/ivle"
81
 
    jail_base = "/home/informatics/jails"
82
 
# Always defaults
83
 
allowed_uids = "0"
84
 
 
85
 
# Main function skeleton from Guido van Rossum
86
 
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
87
 
 
88
 
class Usage(Exception):
89
 
    def __init__(self, msg):
90
 
        self.msg = msg
 
30
import setup.build
 
31
import setup.install
91
32
 
92
33
def main(argv=None):
93
34
    if argv is None:
96
37
    # Print the opening spiel including the GPL notice
97
38
 
98
39
    print """IVLE - Informatics Virtual Learning Environment Setup
99
 
Copyright (C) 2007-2008 The University of Melbourne
 
40
Copyright (C) 2007-2009 The University of Melbourne
100
41
IVLE comes with ABSOLUTELY NO WARRANTY.
101
42
This is free software, and you are welcome to redistribute it
102
43
under certain conditions. See LICENSE.txt for details.
112
53
        help([])
113
54
        return 1
114
55
 
 
56
    oper_func = call_operator(operation)
 
57
    return oper_func(argv[2:])
 
58
 
 
59
def help(args):
 
60
    if len(args)!=1:
 
61
        print """Usage: python setup.py operation [options]
 
62
Operation can be:
 
63
    help [operation]
 
64
    build
 
65
    install
 
66
 
 
67
    For help and options for a specific operation use 'help [operation]'."""
 
68
    else:
 
69
        operator = args[0]
 
70
        oper_func = call_operator(operator)
 
71
        oper_func(['operator','--help'])
 
72
 
 
73
def call_operator(operation):
115
74
    # Call the requested operation's function
116
75
    try:
117
 
        return {
 
76
        oper_func = {
118
77
            'help' : help,
119
 
            'conf' : conf,
120
 
            'build' : build,
121
 
            'listmake' : listmake,
122
 
            'install' : install,
123
 
        }[operation](argv[2:])
 
78
            'build' : setup.build.build,
 
79
            'install' : setup.install.install,
 
80
        }[operation]
124
81
    except KeyError:
125
82
        print >>sys.stderr, (
126
83
            """Invalid operation '%s'. Try python setup.py help."""
127
84
            % operation)
128
 
 
129
 
    try:
130
 
        try:
131
 
            opts, args = getopt.getopt(argv[1:], "h", ["help"])
132
 
        except getopt.error, msg:
133
 
            raise Usage(msg)
134
 
        # more code, unchanged
135
 
    except Usage, err:
136
 
        print >>sys.stderr, err.msg
137
 
        print >>sys.stderr, "for help use --help"
138
 
        return 2
139
 
 
140
 
# Operation functions
141
 
 
142
 
def help(args):
143
 
    if args == []:
144
 
        print """Usage: python setup.py operation [args]
145
 
Operation (and args) can be:
146
 
    help [operation]
147
 
    conf [args]
148
 
    build
149
 
    install [--nojail] [-n|--dry]
150
 
"""
151
 
        return 1
152
 
    elif len(args) != 1:
153
 
        print """Usage: python setup.py help [operation]"""
154
 
        return 2
155
 
    else:
156
 
        operation = args[0]
157
 
 
158
 
    if operation == 'help':
159
 
        print """python setup.py help [operation]
160
 
Prints the usage message or detailed help on an operation, then exits."""
161
 
    elif operation == 'conf':
162
 
        print """python setup.py conf [args]
163
 
Configures IVLE with machine-specific details, most notably, various paths.
164
 
Either prompts the administrator for these details or accepts them as
165
 
command-line args.
166
 
Creates www/conf/conf.py and trampoline/conf.h.
167
 
Args are:
168
 
"""
169
 
    elif operation == 'build':
170
 
        print """python setup.py build
171
 
Compiles all files and sets up a jail template in the source directory.
172
 
Details:
173
 
Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
174
 
Creates jail/.
175
 
Creates standard subdirs inside the jail, eg bin, opt, home, tmp.
176
 
Copies console/ to a location within the jail.
177
 
Copies OS programs and files to corresponding locations within the jail
178
 
  (eg. python and Python libs, ld.so, etc).
179
 
Generates .pyc files for all the IVLE .py files."""
180
 
    elif operation == 'listmake':
181
 
        print """python setup.py listmake
182
 
(For developer use only)
183
 
Recurses through the source tree and builds a list of all files which should
184
 
be copied upon installation. This should be run by the developer before
185
 
cutting a distribution, and the listfile it generates should be included in
186
 
the distribution, avoiding the administrator having to run it."""
187
 
    elif operation == 'install':
188
 
        print """sudo python setup.py install [--nojail] [--dry|-n]
189
 
(Requires root)
190
 
Create target install directory ($target).
191
 
Create $target/bin.
192
 
Copy trampoline/trampoline to $target/bin.
193
 
chown and chmod the installed trampoline.
194
 
Copy www/ to $target.
195
 
Copy jail/ to jails template directory (unless --nojail specified).
196
 
 
197
 
--nojail    Do not copy the jail.
198
 
--dry | -n  Print out the actions but don't do anything."""
199
 
    else:
200
 
        print >>sys.stderr, (
201
 
            """Invalid operation '%s'. Try python setup.py help."""
202
 
            % operation)
203
 
    return 1
204
 
 
205
 
def listmake(args):
206
 
    # We build two separate lists, by walking www and console
207
 
    list_www = build_list_py_files('www')
208
 
    list_console = build_list_py_files('console')
209
 
    # Make sure that the files generated by conf are in the list
210
 
    # (since listmake is typically run before conf)
211
 
    if "www/conf/conf.py" not in list_www:
212
 
        list_www.append("www/conf/conf.py")
213
 
    # Write these out to a file
214
 
    cwd = os.getcwd()
215
 
    # the files that will be created/overwritten
216
 
    listfile = os.path.join(cwd, "install_list.py")
217
 
 
218
 
    try:
219
 
        file = open(listfile, "w")
220
 
 
221
 
        file.write("""# IVLE Configuration File
222
 
# install_list.py
223
 
# Provides lists of all Python files to be installed by `setup.py install'.
224
 
 
225
 
# List of all installable Python files in www directory.
226
 
list_www = """)
227
 
        writelist_pretty(file, list_www)
228
 
        file.write("""
229
 
# List of all installable Python files in console directory.
230
 
list_console = """)
231
 
        writelist_pretty(file, list_console)
232
 
 
233
 
        file.close()
234
 
    except IOError, (errno, strerror):
235
 
        print "IO error(%s): %s" % (errno, strerror)
236
 
        sys.exit(1)
237
 
 
238
 
    print "Successfully wrote install_list.py"
239
 
 
240
 
    print
241
 
    print ("You may modify the set of installable files before cutting the "
242
 
            "distribution:")
243
 
    print listfile
244
 
    print
245
 
 
246
 
    return 0
247
 
 
248
 
def build_list_py_files(dir):
249
 
    """Builds a list of all py files found in a directory and its
250
 
    subdirectories. Returns this as a list of strings."""
251
 
    pylist = []
252
 
    for (dirpath, dirnames, filenames) in os.walk(dir):
253
 
        # Exclude directories beginning with a '.' (such as '.svn')
254
 
        filter_mutate(lambda x: x[0] != '.', dirnames)
255
 
        # All *.py files are added to the list
256
 
        pylist += [os.path.join(dirpath, item) for item in filenames
257
 
            if item.endswith('.py')]
258
 
    return pylist
259
 
 
260
 
def writelist_pretty(file, list):
261
 
    """Writes a list one element per line, to a file."""
262
 
    if list == []:
263
 
        file.write("[]\n")
264
 
    else:
265
 
        file.write('[\n')
266
 
        for elem in list:
267
 
            file.write('    %s,\n' % repr(elem))
268
 
        file.write(']\n')
269
 
 
270
 
def conf(args):
271
 
    global root_dir, ivle_install_dir, jail_base, allowed_uids
272
 
    # Set up some variables
273
 
 
274
 
    cwd = os.getcwd()
275
 
    # the files that will be created/overwritten
276
 
    conffile = os.path.join(cwd, "www/conf/conf.py")
277
 
    conf_hfile = os.path.join(cwd, "trampoline/conf.h")
278
 
 
279
 
    # Fixed config options that we don't ask the admin
280
 
 
281
 
    default_app = "dummy"
282
 
 
283
 
    print """This tool will create the following files:
284
 
    %s
285
 
    %s
286
 
prompting you for details about your configuration. The file will be
287
 
overwritten if it already exists. It will *not* install or deploy IVLE.
288
 
 
289
 
Please hit Ctrl+C now if you do not wish to do this.
290
 
""" % (conffile, conf_hfile)
291
 
 
292
 
    # Get information from the administrator
293
 
    # If EOF is encountered at any time during the questioning, just exit
294
 
    # silently
295
 
 
296
 
    root_dir = query_user(root_dir,
297
 
    """Root directory where IVLE is located (in URL space):""")
298
 
    ivle_install_dir = query_user(ivle_install_dir,
299
 
    'Root directory where IVLE will be installed (on the local file '
300
 
    'system):')
301
 
    jail_base = query_user(jail_base,
302
 
    """Root directory where the jails (containing user files) are stored
303
 
(on the local file system):""")
304
 
    allowed_uids = query_user(allowed_uids,
305
 
    """UID of the web server process which will run IVLE.
306
 
Only this user may execute the trampoline. May specify multiple users as
307
 
a comma-separated list.
308
 
    (eg. "1002,78")""")
309
 
 
310
 
    # Error handling on input values
311
 
 
312
 
    try:
313
 
        allowed_uids = map(int, allowed_uids.split(','))
314
 
    except ValueError:
315
 
        print >>sys.stderr, (
316
 
        "Invalid UID list (%s).\n"
317
 
        "Must be a comma-separated list of integers." % allowed_uids)
318
 
        return 1
319
 
 
320
 
    # Write www/conf/conf.py
321
 
 
322
 
    try:
323
 
        conf = open(conffile, "w")
324
 
 
325
 
        conf.write("""# IVLE Configuration File
326
 
# conf.py
327
 
# Miscellaneous application settings
328
 
 
329
 
 
330
 
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
331
 
# with this).
332
 
# eg. "/" or "/ivle".
333
 
root_dir = "%s"
334
 
 
335
 
# In the local file system, where IVLE is actually installed.
336
 
# This directory should contain the "www" and "bin" directories.
337
 
ivle_install_dir = "%s"
338
 
 
339
 
# In the local file system, where are the student/user file spaces located.
340
 
# The user jails are expected to be located immediately in subdirectories of
341
 
# this location.
342
 
jail_base = "%s"
343
 
 
344
 
# Which application to load by default (if the user navigates to the top level
345
 
# of the site). This is the app's URL name.
346
 
# Note that if this app requires authentication, the user will first be
347
 
# presented with the login screen.
348
 
default_app = "%s"
349
 
""" % (root_dir, ivle_install_dir, jail_base, default_app))
350
 
 
351
 
        conf.close()
352
 
    except IOError, (errno, strerror):
353
 
        print "IO error(%s): %s" % (errno, strerror)
354
 
        sys.exit(1)
355
 
 
356
 
    print "Successfully wrote www/conf/conf.py"
357
 
 
358
 
    # Write trampoline/conf.h
359
 
 
360
 
    try:
361
 
        conf = open(conf_hfile, "w")
362
 
 
363
 
        conf.write("""/* IVLE Configuration File
364
 
 * conf.h
365
 
 * Administrator settings required by trampoline.
366
 
 * Note: trampoline will have to be rebuilt in order for changes to this file
367
 
 * to take effect.
368
 
 */
369
 
 
370
 
/* In the local file system, where are the jails located.
371
 
 * The trampoline does not allow the creation of a jail anywhere besides
372
 
 * jail_base or a subdirectory of jail_base.
373
 
 */
374
 
static const char* jail_base = "%s";
375
 
 
376
 
/* Which user IDs are allowed to run the trampoline.
377
 
 * This list should be limited to the web server user.
378
 
 * (Note that root is an implicit member of this list).
379
 
 */
380
 
static const int allowed_uids[] = { %s };
381
 
""" % (jail_base, repr(allowed_uids)[1:-1]))
382
 
 
383
 
        conf.close()
384
 
    except IOError, (errno, strerror):
385
 
        print "IO error(%s): %s" % (errno, strerror)
386
 
        sys.exit(1)
387
 
 
388
 
    print "Successfully wrote trampoline/conf.h"
389
 
 
390
 
    print
391
 
    print "You may modify the configuration at any time by editing"
392
 
    print conffile
393
 
    print conf_hfile
394
 
    print
395
 
    return 0
396
 
 
397
 
def build(args):
398
 
    dry = False     # Set to True later if --dry
399
 
 
400
 
    # Compile the trampoline
401
 
    action_runprog('gcc', ['-Wall', '-o', 'trampoline/trampoline',
402
 
        'trampoline/trampoline.c'], dry)
403
 
 
404
 
    # Create the jail and its subdirectories
405
 
    action_mkdir('jail')
406
 
    action_mkdir('jail/bin')
407
 
    action_mkdir('jail/lib')
408
 
    action_mkdir('jail/usr/bin')
409
 
    action_mkdir('jail/usr/lib')
410
 
    action_mkdir('jail/opt/ivle')
411
 
    action_mkdir('jail/home')
412
 
    action_mkdir('jail/tmp')
413
 
 
414
 
    # TODO: Copy console into the jail
415
 
    # TODO: Copy operating system files into the jail
416
 
    # TODO: Compile .py files into .pyc files
417
 
 
418
 
    return 0
419
 
 
420
 
def install(args):
421
 
    print "Install"
422
 
    return 0
423
 
 
424
 
# The actions call Python os functions but print actions and handle dryness.
425
 
# May still throw os exceptions if errors occur.
426
 
 
427
 
class RunError:
428
 
    """Represents an error when running a program (nonzero return)."""
429
 
    def __init__(self, prog, retcode):
430
 
        self.prog = prog
431
 
        self.retcode = retcode
432
 
    def __str__(self):
433
 
        return str(self.prog) + " returned " + repr(self.retcode)
434
 
 
435
 
def action_runprog(prog, args, dry):
436
 
    """Runs a unix program. Searches in $PATH. Synchronous (waits for the
437
 
    program to return). Runs in the current environment. First prints the
438
 
    action as a "bash" line.
439
 
 
440
 
    Throws a RunError with a retcode of the return value of the program,
441
 
    if the program did not return 0.
442
 
 
443
 
    prog: String. Name of the program. (No path required, if in $PATH).
444
 
    args: [String]. Arguments to the program.
445
 
    dry: Bool. If True, prints but does not execute.
446
 
    """
447
 
    print prog, string.join(args, ' ')
448
 
    if dry: return
449
 
    ret = os.spawnvp(os.P_WAIT, prog, args)
450
 
    if ret != 0:
451
 
        raise RunError(prog, ret)
452
 
 
453
 
def action_mkdir(path):
454
 
    """Calls mkdir. Silently ignored if the directory already exists.
455
 
    Creates all parent directories as necessary."""
456
 
    print "mkdir -p", path
457
 
    if dry: return
458
 
    try:
459
 
        os.makedirs(path)
460
 
    except OSError, (err, msg):
461
 
        if err != errno.EEXIST:
462
 
            raise
463
 
 
464
 
def query_user(default, prompt):
465
 
    """Prompts the user for a string, which is read from a line of stdin.
466
 
    Exits silently if EOF is encountered. Returns the string, with spaces
467
 
    removed from the beginning and end.
468
 
 
469
 
    Returns default if a 0-length line (after spaces removed) was read.
470
 
    """
471
 
    sys.stdout.write('%s\n    (default: "%s")\n>' % (prompt, default))
472
 
    try:
473
 
        val = sys.stdin.readline()
474
 
    except KeyboardInterrupt:
475
 
        # Ctrl+C
476
 
        sys.stdout.write("\n")
477
 
        sys.exit(1)
478
 
    sys.stdout.write("\n")
479
 
    # If EOF, exit
480
 
    if val == '': sys.exit(1)
481
 
    # If empty line, return default
482
 
    val = val.strip()
483
 
    if val == '': return default
484
 
    return val
485
 
 
486
 
def filter_mutate(function, list):
487
 
    """Like built-in filter, but mutates the given list instead of returning a
488
 
    new one. Returns None."""
489
 
    i = len(list)-1
490
 
    while i >= 0:
491
 
        # Delete elements which do not match
492
 
        if not function(list[i]):
493
 
            del list[i]
494
 
        i -= 1
 
85
        sys.exit(1)
 
86
    return oper_func
495
87
 
496
88
if __name__ == "__main__":
497
89
    sys.exit(main())
 
90