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

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2007-12-21 01:42:15 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:115
Deleted common/jail.py (bad cruft).

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
# It is called with at least one argument, which specifies which operation to
26
26
# take.
27
27
 
28
 
# setup.py listmake (for developer use only)
29
 
# Recurses through the source tree and builds a list of all files which should
30
 
# be copied upon installation. This should be run by the developer before
31
 
# cutting a distribution, and the listfile it generates should be included in
32
 
# the distribution, avoiding the administrator having to run it.
33
 
 
34
28
# setup.py conf [args]
35
29
# Configures IVLE with machine-specific details, most notably, various paths.
36
30
# Either prompts the administrator for these details or accepts them as
48
42
#   (eg. python and Python libs, ld.so, etc).
49
43
# Generates .pyc files for all the IVLE .py files.
50
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
51
# setup.py install [--nojail] [--dry|n]
52
52
# (Requires root)
53
53
# Create target install directory ($target).
57
57
# Copy www/ to $target.
58
58
# Copy jail/ to jails template directory (unless --nojail specified).
59
59
 
 
60
# TODO: List in help, and handle, args for the conf operation
 
61
 
60
62
import os
61
 
import stat
62
 
import shutil
63
63
import sys
64
64
import getopt
65
65
import string
66
66
import errno
67
 
import mimetypes
68
 
import compileall
69
 
import getopt
70
67
 
71
68
# Try importing existing conf, but if we can't just set up defaults
72
69
# The reason for this is that these settings are used by other phases
85
82
# Always defaults
86
83
allowed_uids = "0"
87
84
 
88
 
# Try importing install_list, but don't fail if we can't, because listmake can
89
 
# function without it.
90
 
try:
91
 
    import install_list
92
 
except:
93
 
    pass
94
 
 
95
 
# Mime types which will automatically be placed in the list by listmake.
96
 
# Note that listmake is not intended to be run by the final user (the system
97
 
# administrator who installs this), so the developers can customize the list
98
 
# as necessary, and include it in the distribution.
99
 
listmake_mimetypes = ['text/x-python', 'text/html',
100
 
    'application/x-javascript', 'application/javascript',
101
 
    'text/css', 'image/png']
102
 
 
103
85
# Main function skeleton from Guido van Rossum
104
86
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
105
87
 
 
88
class Usage(Exception):
 
89
    def __init__(self, msg):
 
90
        self.msg = msg
 
91
 
106
92
def main(argv=None):
107
93
    if argv is None:
108
94
        argv = sys.argv
128
114
 
129
115
    # Call the requested operation's function
130
116
    try:
131
 
        oper_func = {
 
117
        return {
132
118
            'help' : help,
133
119
            'conf' : conf,
134
120
            'build' : build,
135
121
            'listmake' : listmake,
136
122
            'install' : install,
137
 
        }[operation]
 
123
        }[operation](argv[2:])
138
124
    except KeyError:
139
125
        print >>sys.stderr, (
140
126
            """Invalid operation '%s'. Try python setup.py help."""
141
127
            % operation)
142
 
    return oper_func(argv[2:])
 
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
143
139
 
144
140
# Operation functions
145
141
 
162
158
    if operation == 'help':
163
159
        print """python setup.py help [operation]
164
160
Prints the usage message or detailed help on an operation, then exits."""
165
 
    elif operation == 'listmake':
166
 
        print """python setup.py listmake
167
 
(For developer use only)
168
 
Recurses through the source tree and builds a list of all files which should
169
 
be copied upon installation. This should be run by the developer before
170
 
cutting a distribution, and the listfile it generates should be included in
171
 
the distribution, avoiding the administrator having to run it."""
172
161
    elif operation == 'conf':
173
162
        print """python setup.py conf [args]
174
163
Configures IVLE with machine-specific details, most notably, various paths.
175
164
Either prompts the administrator for these details or accepts them as
176
 
command-line args. Will be interactive only if there are no arguments given.
177
 
Takes defaults from existing conf file if it exists.
 
165
command-line args.
178
166
Creates www/conf/conf.py and trampoline/conf.h.
179
167
Args are:
180
 
    --root_dir
181
 
    --ivle_install_dir
182
 
    --jail_base
183
 
    --allowed_uids
184
 
As explained in the interactive prompt or conf.py.
185
168
"""
186
169
    elif operation == 'build':
187
 
        print """python -O setup.py build [--dry|-n]
 
170
        print """python setup.py build
188
171
Compiles all files and sets up a jail template in the source directory.
189
 
-O is recommended to cause compilation to be optimised.
190
172
Details:
191
173
Compiles (GCC) trampoline/trampoline.c to trampoline/trampoline.
192
174
Creates jail/.
194
176
Copies console/ to a location within the jail.
195
177
Copies OS programs and files to corresponding locations within the jail
196
178
  (eg. python and Python libs, ld.so, etc).
197
 
Generates .pyc or .pyo files for all the IVLE .py files.
198
 
 
199
 
--dry | -n  Print out the actions but don't do anything."""
 
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."""
200
187
    elif operation == 'install':
201
188
        print """sudo python setup.py install [--nojail] [--dry|-n]
202
189
(Requires root)
223
210
    # (since listmake is typically run before conf)
224
211
    if "www/conf/conf.py" not in list_www:
225
212
        list_www.append("www/conf/conf.py")
226
 
    # Make sure that console/python-console is in the list
227
 
    if "console/python-console" not in list_console:
228
 
        list_console.append("console/python-console")
229
213
    # Write these out to a file
230
214
    cwd = os.getcwd()
231
215
    # the files that will be created/overwritten
236
220
 
237
221
        file.write("""# IVLE Configuration File
238
222
# install_list.py
239
 
# Provides lists of all files to be installed by `setup.py install' from
240
 
# certain directories.
241
 
# Note that any files with the given filename plus 'c' or 'o' (that is,
242
 
# compiled .pyc or .pyo files) will be copied as well.
 
223
# Provides lists of all Python files to be installed by `setup.py install'.
243
224
 
244
 
# List of all installable files in www directory.
 
225
# List of all installable Python files in www directory.
245
226
list_www = """)
246
227
        writelist_pretty(file, list_www)
247
228
        file.write("""
248
 
# List of all installable files in console directory.
 
229
# List of all installable Python files in console directory.
249
230
list_console = """)
250
231
        writelist_pretty(file, list_console)
251
232
 
273
254
        filter_mutate(lambda x: x[0] != '.', dirnames)
274
255
        # All *.py files are added to the list
275
256
        pylist += [os.path.join(dirpath, item) for item in filenames
276
 
            if mimetypes.guess_type(item)[0] in listmake_mimetypes]
 
257
            if item.endswith('.py')]
277
258
    return pylist
278
259
 
279
260
def writelist_pretty(file, list):
296
277
    conf_hfile = os.path.join(cwd, "trampoline/conf.h")
297
278
 
298
279
    # Fixed config options that we don't ask the admin
 
280
 
299
281
    default_app = "dummy"
300
282
 
301
 
    # Get command-line arguments to avoid asking questions.
302
 
 
303
 
    (opts, args) = getopt.gnu_getopt(args, "", ['root_dir=',
304
 
                    'ivle_install_dir=', 'jail_base=', 'allowed_uids='])
305
 
 
306
 
    if args != []:
307
 
        print >>sys.stderr, "Invalid arguments:", string.join(args, ' ')
308
 
        return 2
309
 
 
310
 
    if opts == []:
311
 
        # Interactive mode. Prompt the user for all the values.
312
 
 
313
 
        print """This tool will create the following files:
 
283
    print """This tool will create the following files:
314
284
    %s
315
285
    %s
316
286
prompting you for details about your configuration. The file will be
319
289
Please hit Ctrl+C now if you do not wish to do this.
320
290
""" % (conffile, conf_hfile)
321
291
 
322
 
        # Get information from the administrator
323
 
        # If EOF is encountered at any time during the questioning, just exit
324
 
        # silently
 
292
    # Get information from the administrator
 
293
    # If EOF is encountered at any time during the questioning, just exit
 
294
    # silently
325
295
 
326
 
        root_dir = query_user(root_dir,
327
 
        """Root directory where IVLE is located (in URL space):""")
328
 
        ivle_install_dir = query_user(ivle_install_dir,
329
 
        'Root directory where IVLE will be installed (on the local file '
330
 
        'system):')
331
 
        jail_base = query_user(jail_base,
332
 
        """Root directory where the jails (containing user files) are stored
 
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
333
303
(on the local file system):""")
334
 
        allowed_uids = query_user(allowed_uids,
335
 
        """UID of the web server process which will run IVLE.
 
304
    allowed_uids = query_user(allowed_uids,
 
305
    """UID of the web server process which will run IVLE.
336
306
Only this user may execute the trampoline. May specify multiple users as
337
307
a comma-separated list.
338
308
    (eg. "1002,78")""")
339
309
 
340
 
    else:
341
 
        opts = dict(opts)
342
 
        # Non-interactive mode. Parse the options.
343
 
        if '--root_dir' in opts:
344
 
            root_dir = opts['--root_dir']
345
 
        if '--ivle_install_dir' in opts:
346
 
            ivle_install_dir = opts['--ivle_install_dir']
347
 
        if '--jail_base' in opts:
348
 
            jail_base = opts['--jail_base']
349
 
        if '--allowed_uids' in opts:
350
 
            allowed_uids = opts['--allowed_uids']
351
 
 
352
310
    # Error handling on input values
 
311
 
353
312
    try:
354
313
        allowed_uids = map(int, allowed_uids.split(','))
355
314
    except ValueError:
443
402
        'trampoline/trampoline.c'], dry)
444
403
 
445
404
    # Create the jail and its subdirectories
446
 
    action_mkdir('jail', dry)
447
 
    action_mkdir('jail/bin', dry)
448
 
    action_mkdir('jail/lib', dry)
449
 
    action_mkdir('jail/usr/bin', dry)
450
 
    action_mkdir('jail/usr/lib', dry)
451
 
    action_mkdir('jail/opt/ivle', dry)
452
 
    action_mkdir('jail/home', dry)
453
 
    action_mkdir('jail/tmp', dry)
454
 
 
455
 
    # Copy all console files into the jail
456
 
    action_copylist(install_list.list_console, 'jail/opt/ivle', dry)
457
 
 
 
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
458
415
    # TODO: Copy operating system files into the jail
459
 
 
460
 
    # Compile .py files into .pyc or .pyo files
461
 
    compileall.compile_dir('www', quiet=True)
462
 
    compileall.compile_dir('console', quiet=True)
 
416
    # TODO: Compile .py files into .pyc files
463
417
 
464
418
    return 0
465
419
 
466
420
def install(args):
467
 
    # Create the target directory
468
 
    nojail = False  # Set to True later if --nojail
469
 
    dry = False     # Set to True later if --dry
470
 
 
471
 
    if not dry and os.geteuid() != 0:
472
 
        print >>sys.stderr, "Must be root to run install"
473
 
        print >>sys.stderr, "(I need to chown some files)."
474
 
        return 1
475
 
 
476
 
    # Create the target (install) directory
477
 
    action_mkdir(ivle_install_dir, dry)
478
 
 
479
 
    # Create bin and copy the compiled files there
480
 
    action_mkdir(os.path.join(ivle_install_dir, 'bin'), dry)
481
 
    tramppath = os.path.join(ivle_install_dir, 'bin/trampoline')
482
 
    action_copyfile('trampoline/trampoline', tramppath, dry)
483
 
    # chown trampoline to root and set setuid bit
484
 
    action_chown_setuid(tramppath, dry)
485
 
 
486
 
    # Copy the www directory using the list
487
 
    action_copylist(install_list.list_www, ivle_install_dir, dry)
488
 
 
489
 
    if not nojail:
490
 
        # Copy the local jail directory built by the build action
491
 
        # to the jails template directory (it will be used as a template
492
 
        # for all the students' jails).
493
 
        action_copytree('jail', os.path.join(jail_base, 'template'), dry)
494
 
 
 
421
    print "Install"
495
422
    return 0
496
423
 
497
424
# The actions call Python os functions but print actions and handle dryness.
523
450
    if ret != 0:
524
451
        raise RunError(prog, ret)
525
452
 
526
 
def action_mkdir(path, dry):
 
453
def action_mkdir(path):
527
454
    """Calls mkdir. Silently ignored if the directory already exists.
528
455
    Creates all parent directories as necessary."""
529
456
    print "mkdir -p", path
534
461
        if err != errno.EEXIST:
535
462
            raise
536
463
 
537
 
def action_copytree(src, dst, dry):
538
 
    """Copies an entire directory tree. Symlinks are seen as normal files and
539
 
    copies of the entire file (not the link) are made. Creates all parent
540
 
    directories as necessary.
541
 
 
542
 
    See shutil.copytree."""
543
 
    if os.access(dst, os.F_OK):
544
 
        print "rm -r", dst
545
 
        if not dry:
546
 
            shutil.rmtree(dst, True)
547
 
    print "cp -r", src, dst
548
 
    if dry: return
549
 
    shutil.copytree(src, dst)
550
 
 
551
 
def action_copylist(srclist, dst, dry):
552
 
    """Copies all files in a list to a new location. The files in the list
553
 
    are read relative to the current directory, and their destinations are the
554
 
    same paths relative to dst. Creates all parent directories as necessary.
555
 
    """
556
 
    for srcfile in srclist:
557
 
        dstfile = os.path.join(dst, srcfile)
558
 
        dstdir = os.path.split(dstfile)[0]
559
 
        if not os.path.isdir(dstdir):
560
 
            action_mkdir(dstdir, dry)
561
 
        print "cp -f", srcfile, dstfile
562
 
        if not dry:
563
 
            shutil.copyfile(srcfile, dstfile)
564
 
 
565
 
def action_copyfile(src, dst, dry):
566
 
    """Copies one file to a new location. Creates all parent directories
567
 
    as necessary.
568
 
    """
569
 
    dstdir = os.path.split(dst)[0]
570
 
    if not os.path.isdir(dstdir):
571
 
        action_mkdir(dstdir, dry)
572
 
    print "cp -f", src, dst
573
 
    if not dry:
574
 
        shutil.copyfile(src, dst)
575
 
 
576
 
def action_chown_setuid(file, dry):
577
 
    """Chowns a file to root, and sets the setuid bit on the file.
578
 
    Calling this function requires the euid to be root.
579
 
    The actual mode of path is set to: rws--s--s
580
 
    """
581
 
    print "chown root:root", file
582
 
    if not dry:
583
 
        os.chown(file, 0, 0)
584
 
    print "chmod a+xs", file
585
 
    print "chmod u+rw", file
586
 
    if not dry:
587
 
        os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
588
 
            | stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
589
 
 
590
464
def query_user(default, prompt):
591
465
    """Prompts the user for a string, which is read from a line of stdin.
592
466
    Exits silently if EOF is encountered. Returns the string, with spaces