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

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2008-02-03 11:38:23 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:387
Implemented file uploads.
fileservice: Added "putfiles" action (slightly different to putfile action;
    see comments at top which discuss the difference).
browser/listing: Added "upload" button to side panel, which opens an upload
    panel with a file selection dialog. This uses a little trick (documented
    in the code) to get the upload to work without refreshing the page.

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
# cutting a distribution, and the listfile it generates should be included in
32
32
# the distribution, avoiding the administrator having to run it.
33
33
 
34
 
# setup.py conf [args]
 
34
# setup.py config [args]
35
35
# Configures IVLE with machine-specific details, most notably, various paths.
36
36
# Either prompts the administrator for these details or accepts them as
37
37
# command-line args.
74
74
import conf
75
75
import common.makeuser
76
76
 
 
77
# Determine which Python version (2.4 or 2.5, for example) we are running,
 
78
# and use that as the filename to the Python directory.
 
79
# Just get the first 3 characters of sys.version.
 
80
PYTHON_VERSION = sys.version[0:3]
 
81
 
77
82
# Operating system files to copy over into the jail.
78
83
# These will be copied from the given place on the OS file system into the
79
84
# same place within the jail.
94
99
    '/bin/ls',
95
100
    '/bin/echo',
96
101
    # Needed by python
97
 
    '/usr/bin/python2.5',
 
102
    '/usr/bin/python%s' % PYTHON_VERSION,
98
103
    # Needed by matplotlib
99
104
    '/usr/lib/i686/cmov/libssl.so.0.9.8',
100
105
    '/usr/lib/i686/cmov/libcrypto.so.0.9.8',
118
123
]
119
124
# Symlinks to make within the jail. Src mapped to dst.
120
125
JAIL_LINKS = {
121
 
    'python2.5': 'jail/usr/bin/python',
 
126
    'python%s' % PYTHON_VERSION: 'jail/usr/bin/python',
122
127
}
123
128
# Trees to copy. Src mapped to dst (these will be passed to action_copytree).
124
129
JAIL_COPYTREES = {
125
 
    '/usr/lib/python2.5': 'jail/usr/lib/python2.5',
 
130
    '/usr/lib/python%s' % PYTHON_VERSION:
 
131
        'jail/usr/lib/python%s' % PYTHON_VERSION,
126
132
    '/usr/share/matplotlib': 'jail/usr/share/matplotlib',
127
133
    '/etc/ld.so.conf.d': 'jail/etc/ld.so.conf.d',
128
134
}
129
135
 
 
136
class ConfigOption:
 
137
    """A configuration option; one of the things written to conf.py."""
 
138
    def __init__(self, option_name, default, prompt, comment):
 
139
        """Creates a configuration option.
 
140
        option_name: Name of the variable in conf.py. Also name of the
 
141
            command-line argument to setup.py conf.
 
142
        default: Default value for this variable.
 
143
        prompt: (Short) string presented during the interactive prompt in
 
144
            setup.py conf.
 
145
        comment: (Long) comment string stored in conf.py. Each line of this
 
146
            string should begin with a '#'.
 
147
        """
 
148
        self.option_name = option_name
 
149
        self.default = default
 
150
        self.prompt = prompt
 
151
        self.comment = comment
 
152
 
 
153
# Configuration options, defaults and descriptions
 
154
config_options = []
 
155
config_options.append(ConfigOption("root_dir", "/ivle",
 
156
    """Root directory where IVLE is located (in URL space):""",
 
157
    """
 
158
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
 
159
# with this).
 
160
# eg. "/" or "/ivle"."""))
 
161
config_options.append(ConfigOption("ivle_install_dir", "/opt/ivle",
 
162
    'Root directory where IVLE will be installed (on the local file '
 
163
    'system):',
 
164
    """
 
165
# In the local file system, where IVLE is actually installed.
 
166
# This directory should contain the "www" and "bin" directories."""))
 
167
config_options.append(ConfigOption("jail_base", "/home/informatics/jails",
 
168
    """Root directory where the jails (containing user files) are stored
 
169
(on the local file system):""",
 
170
    """
 
171
# In the local file system, where are the student/user file spaces located.
 
172
# The user jails are expected to be located immediately in subdirectories of
 
173
# this location."""))
 
174
config_options.append(ConfigOption("subjects_base",
 
175
    "/home/informatics/subjects",
 
176
    """Root directory where the subject directories (containing worksheets
 
177
and other per-subject files) are stored (on the local file system):""",
 
178
    """
 
179
# In the local file system, where are the per-subject file spaces located.
 
180
# The individual subject directories are expected to be located immediately
 
181
# in subdirectories of this location."""))
 
182
config_options.append(ConfigOption("public_host", "public.localhost",
 
183
    """Hostname which will cause the server to go into "public mode",
 
184
providing login-free access to student's published work:""",
 
185
    """
 
186
# The server goes into "public mode" if the browser sends a request with this
 
187
# host. This is for security reasons - we only serve public student files on a
 
188
# separate domain to the main IVLE site.
 
189
# Public mode does not use cookies, and serves only public content.
 
190
# Private mode (normal mode) requires login, and only serves files relevant to
 
191
# the logged-in user."""))
 
192
config_options.append(ConfigOption("allowed_uids", "33",
 
193
    """UID of the web server process which will run IVLE.
 
194
Only this user may execute the trampoline. May specify multiple users as
 
195
a comma-separated list.
 
196
    (eg. "1002,78")""",
 
197
    """
 
198
# The User-ID of the web server process which will run IVLE, and any other
 
199
# users who are allowed to run the trampoline. This is stores as a string of
 
200
# comma-separated integers, simply because it is not used within Python, only
 
201
# used by the setup program to write to conf.h (see setup.py config)."""))
 
202
config_options.append(ConfigOption("db_host", "localhost",
 
203
    """PostgreSQL Database config
 
204
==========================
 
205
Hostname of the DB server:""",
 
206
    """
 
207
### PostgreSQL Database config ###
 
208
# Database server hostname"""))
 
209
config_options.append(ConfigOption("db_port", "5432",
 
210
    """Port of the DB server:""",
 
211
    """
 
212
# Database server port"""))
 
213
config_options.append(ConfigOption("db_dbname", "ivle",
 
214
    """Database name:""",
 
215
    """
 
216
# Database name"""))
 
217
config_options.append(ConfigOption("db_user", "postgres",
 
218
    """Username for DB server login:""",
 
219
    """
 
220
# Database username"""))
 
221
config_options.append(ConfigOption("db_password", "",
 
222
    """Password for DB server login:
 
223
    (Caution: This password is stored in plaintext in www/conf/conf.py)""",
 
224
    """
 
225
# Database password"""))
 
226
 
130
227
# Try importing existing conf, but if we can't just set up defaults
131
228
# The reason for this is that these settings are used by other phases
132
229
# of setup besides conf, so we need to know them.
133
230
# Also this allows you to hit Return to accept the existing value.
134
231
try:
135
232
    confmodule = __import__("www/conf/conf")
136
 
    try:
137
 
        root_dir = confmodule.root_dir
138
 
    except:
139
 
        root_dir = "/ivle"
140
 
    try:
141
 
        ivle_install_dir = confmodule.ivle_install_dir
142
 
    except:
143
 
        ivle_install_dir = "/opt/ivle"
144
 
    try:
145
 
        jail_base = confmodule.jail_base
146
 
    except:
147
 
        jail_base = "/home/informatics/jails"
 
233
    for opt in config_options:
 
234
        try:
 
235
            globals()[opt.option_name] = confmodule.__dict__[opt.option_name]
 
236
        except:
 
237
            globals()[opt.option_name] = opt.default
148
238
except ImportError:
149
239
    # Just set reasonable defaults
150
 
    root_dir = "/ivle"
151
 
    ivle_install_dir = "/opt/ivle"
152
 
    jail_base = "/home/informatics/jails"
153
 
# Always defaults
154
 
allowed_uids = "0"
 
240
    for opt in config_options:
 
241
        globals()[opt.option_name] = opt.default
155
242
 
156
243
# Try importing install_list, but don't fail if we can't, because listmake can
157
244
# function without it.
166
253
# as necessary, and include it in the distribution.
167
254
listmake_mimetypes = ['text/x-python', 'text/html',
168
255
    'application/x-javascript', 'application/javascript',
169
 
    'text/css', 'image/png']
 
256
    'text/css', 'image/png', 'application/xml']
170
257
 
171
258
# Main function skeleton from Guido van Rossum
172
259
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
204
291
    try:
205
292
        oper_func = {
206
293
            'help' : help,
207
 
            'conf' : conf,
 
294
            'config' : conf,
208
295
            'build' : build,
209
296
            'listmake' : listmake,
210
297
            'install' : install,
225
312
Operation (and args) can be:
226
313
    help [operation]
227
314
    listmake (developer use only)
228
 
    conf [args]
 
315
    config [args]
229
316
    build
230
 
    install [--nojail] [-n|--dry]
 
317
    install [--nojail] [--nosubjects] [-n|--dry]
231
318
"""
232
319
        return 1
233
320
    elif len(args) != 1:
246
333
be copied upon installation. This should be run by the developer before
247
334
cutting a distribution, and the listfile it generates should be included in
248
335
the distribution, avoiding the administrator having to run it."""
249
 
    elif operation == 'conf':
250
 
        print """python setup.py conf [args]
 
336
    elif operation == 'config':
 
337
        print """python setup.py config [args]
251
338
Configures IVLE with machine-specific details, most notably, various paths.
252
339
Either prompts the administrator for these details or accepts them as
253
340
command-line args. Will be interactive only if there are no arguments given.
259
346
 
260
347
Creates www/conf/conf.py and trampoline/conf.h.
261
348
 
262
 
Args are:
263
 
    --root_dir
264
 
    --ivle_install_dir
265
 
    --jail_base
266
 
    --allowed_uids
267
 
As explained in the interactive prompt or conf.py.
 
349
Args are:"""
 
350
        for opt in config_options:
 
351
            print "    --" + opt.option_name
 
352
        print """As explained in the interactive prompt or conf.py.
268
353
"""
269
354
    elif operation == 'build':
270
355
        print """python -O setup.py build [--dry|-n]
281
366
 
282
367
--dry | -n  Print out the actions but don't do anything."""
283
368
    elif operation == 'install':
284
 
        print """sudo python setup.py install [--nojail] [--dry|-n]
 
369
        print """sudo python setup.py install [--nojail] [--nosubjects][--dry|-n]
285
370
(Requires root)
286
371
Create target install directory ($target).
287
372
Create $target/bin.
289
374
chown and chmod the installed trampoline.
290
375
Copy www/ to $target.
291
376
Copy jail/ to jails template directory (unless --nojail specified).
 
377
Copy subjects/ to subjects directory (unless --nosubjects specified).
292
378
 
293
 
--nojail    Do not copy the jail.
 
379
--nojail        Do not copy the jail.
 
380
--nosubjects    Do not copy the subjects.
294
381
--dry | -n  Print out the actions but don't do anything."""
295
382
    elif operation == 'updatejails':
296
383
        print """sudo python setup.py updatejails [--dry|-n]
308
395
    # We build two separate lists, by walking www and console
309
396
    list_www = build_list_py_files('www')
310
397
    list_console = build_list_py_files('console')
 
398
    list_subjects = build_list_py_files('subjects', no_top_level=True)
311
399
    # Make sure that the files generated by conf are in the list
312
400
    # (since listmake is typically run before conf)
313
401
    if "www/conf/conf.py" not in list_www:
337
425
# List of all installable files in console directory.
338
426
list_console = """)
339
427
        writelist_pretty(file, list_console)
 
428
        file.write("""
 
429
# List of all installable files in subjects directory.
 
430
# This is to install sample subjects and material.
 
431
list_subjects = """)
 
432
        writelist_pretty(file, list_subjects)
340
433
 
341
434
        file.close()
342
435
    except IOError, (errno, strerror):
353
446
 
354
447
    return 0
355
448
 
356
 
def build_list_py_files(dir):
 
449
def build_list_py_files(dir, no_top_level=False):
357
450
    """Builds a list of all py files found in a directory and its
358
 
    subdirectories. Returns this as a list of strings."""
 
451
    subdirectories. Returns this as a list of strings.
 
452
    no_top_level=True means the file paths will not include the top-level
 
453
    directory.
 
454
    """
359
455
    pylist = []
360
456
    for (dirpath, dirnames, filenames) in os.walk(dir):
361
457
        # Exclude directories beginning with a '.' (such as '.svn')
363
459
        # All *.py files are added to the list
364
460
        pylist += [os.path.join(dirpath, item) for item in filenames
365
461
            if mimetypes.guess_type(item)[0] in listmake_mimetypes]
 
462
    if no_top_level:
 
463
        for i in range(0, len(pylist)):
 
464
            _, pylist[i] = pylist[i].split(os.sep, 1)
366
465
    return pylist
367
466
 
368
467
def writelist_pretty(file, list):
376
475
        file.write(']\n')
377
476
 
378
477
def conf(args):
379
 
    global root_dir, ivle_install_dir, jail_base, allowed_uids
 
478
    global db_port
380
479
    # Set up some variables
381
480
 
382
481
    cwd = os.getcwd()
386
485
 
387
486
    # Get command-line arguments to avoid asking questions.
388
487
 
389
 
    (opts, args) = getopt.gnu_getopt(args, "", ['root_dir=',
390
 
                    'ivle_install_dir=', 'jail_base=', 'allowed_uids='])
 
488
    optnames = []
 
489
    for opt in config_options:
 
490
        optnames.append(opt.option_name + "=")
 
491
    (opts, args) = getopt.gnu_getopt(args, "", optnames)
391
492
 
392
493
    if args != []:
393
494
        print >>sys.stderr, "Invalid arguments:", string.join(args, ' ')
409
510
        # If EOF is encountered at any time during the questioning, just exit
410
511
        # silently
411
512
 
412
 
        root_dir = query_user(root_dir,
413
 
        """Root directory where IVLE is located (in URL space):""")
414
 
        ivle_install_dir = query_user(ivle_install_dir,
415
 
        'Root directory where IVLE will be installed (on the local file '
416
 
        'system):')
417
 
        jail_base = query_user(jail_base,
418
 
        """Root directory where the jails (containing user files) are stored
419
 
(on the local file system):""")
420
 
        allowed_uids = query_user(allowed_uids,
421
 
        """UID of the web server process which will run IVLE.
422
 
Only this user may execute the trampoline. May specify multiple users as
423
 
a comma-separated list.
424
 
    (eg. "1002,78")""")
425
 
 
 
513
        for opt in config_options:
 
514
            globals()[opt.option_name] = \
 
515
                query_user(globals()[opt.option_name], opt.prompt)
426
516
    else:
427
517
        opts = dict(opts)
428
518
        # Non-interactive mode. Parse the options.
429
 
        if '--root_dir' in opts:
430
 
            root_dir = opts['--root_dir']
431
 
        if '--ivle_install_dir' in opts:
432
 
            ivle_install_dir = opts['--ivle_install_dir']
433
 
        if '--jail_base' in opts:
434
 
            jail_base = opts['--jail_base']
435
 
        if '--allowed_uids' in opts:
436
 
            allowed_uids = opts['--allowed_uids']
 
519
        for opt in config_options:
 
520
            if '--' + opt.option_name in opts:
 
521
                globals()[opt.option_name] = opts['--' + opt.option_name]
437
522
 
438
523
    # Error handling on input values
439
524
    try:
440
 
        allowed_uids = map(int, allowed_uids.split(','))
 
525
        allowed_uids_list = map(int, allowed_uids.split(','))
441
526
    except ValueError:
442
527
        print >>sys.stderr, (
443
528
        "Invalid UID list (%s).\n"
444
529
        "Must be a comma-separated list of integers." % allowed_uids)
445
530
        return 1
 
531
    try:
 
532
        db_port = int(db_port)
 
533
        if db_port < 0 or db_port >= 65536: raise ValueError()
 
534
    except ValueError:
 
535
        print >>sys.stderr, (
 
536
        "Invalid DB port (%s).\n"
 
537
        "Must be an integer between 0 and 65535." % repr(db_port))
 
538
        return 1
446
539
 
447
540
    # Write www/conf/conf.py
448
541
 
453
546
# conf.py
454
547
# Miscellaneous application settings
455
548
 
456
 
 
457
 
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
458
 
# with this).
459
 
# eg. "/" or "/ivle".
460
 
root_dir = "%s"
461
 
 
462
 
# In the local file system, where IVLE is actually installed.
463
 
# This directory should contain the "www" and "bin" directories.
464
 
ivle_install_dir = "%s"
465
 
 
466
 
# In the local file system, where are the student/user file spaces located.
467
 
# The user jails are expected to be located immediately in subdirectories of
468
 
# this location.
469
 
jail_base = "%s"
470
 
""" % (root_dir, ivle_install_dir, jail_base))
 
549
""")
 
550
        for opt in config_options:
 
551
            conf.write('%s\n%s = %s\n' % (opt.comment, opt.option_name,
 
552
                repr(globals()[opt.option_name])))
471
553
 
472
554
        conf.close()
473
555
    except IOError, (errno, strerror):
499
581
 * (Note that root is an implicit member of this list).
500
582
 */
501
583
static const int allowed_uids[] = { %s };
502
 
""" % (jail_base, repr(allowed_uids)[1:-1]))
 
584
""" % (jail_base, repr(allowed_uids_list)[1:-1]))
503
585
 
504
586
        conf.close()
505
587
    except IOError, (errno, strerror):
525
607
        print "Dry run (no actions will be executed\n"
526
608
 
527
609
    # Compile the trampoline
528
 
    action_runprog('gcc', ['-Wall', '-o', 'trampoline/trampoline',
529
 
        'trampoline/trampoline.c'], dry)
 
610
    curdir = os.getcwd()
 
611
    os.chdir('trampoline')
 
612
    action_runprog('make', [], dry)
 
613
    os.chdir(curdir)
530
614
 
531
615
    # Create the jail and its subdirectories
532
616
    # Note: Other subdirs will be made by copying files
566
650
 
567
651
def install(args):
568
652
    # Get "dry" and "nojail" variables from command line
569
 
    (opts, args) = getopt.gnu_getopt(args, "n", ['dry', 'nojail'])
 
653
    (opts, args) = getopt.gnu_getopt(args, "n",
 
654
        ['dry', 'nojail', 'nosubjects'])
570
655
    opts = dict(opts)
571
656
    dry = '-n' in opts or '--dry' in opts
572
657
    nojail = '--nojail' in opts
 
658
    nosubjects = '--nosubjects' in opts
573
659
 
574
660
    if dry:
575
661
        print "Dry run (no actions will be executed\n"
597
683
        # to the jails template directory (it will be used as a template
598
684
        # for all the students' jails).
599
685
        action_copytree('jail', os.path.join(jail_base, 'template'), dry)
 
686
    if not nosubjects:
 
687
        # Copy the subjects directory across
 
688
        action_copylist(install_list.list_subjects, subjects_base, dry,
 
689
            srcdir="./subjects")
600
690
 
601
691
    # Append IVLE path to ivle.pth in python site packages
602
692
    # (Unless it's already there)
603
693
    ivle_pth = os.path.join(sys.prefix,
604
 
        "lib/python2.5/site-packages/ivle.pth")
 
694
        "lib/python%s/site-packages/ivle.pth" % PYTHON_VERSION)
605
695
    ivle_www = os.path.join(ivle_install_dir, "www")
606
696
    write_ivle_pth = True
607
697
    try:
732
822
    if dry: return
733
823
    common.makeuser.linktree(src, dst)
734
824
 
735
 
def action_copylist(srclist, dst, dry):
 
825
def action_copylist(srclist, dst, dry, srcdir="."):
736
826
    """Copies all files in a list to a new location. The files in the list
737
827
    are read relative to the current directory, and their destinations are the
738
828
    same paths relative to dst. Creates all parent directories as necessary.
 
829
    srcdir is "." by default, can be overridden.
739
830
    """
740
831
    for srcfile in srclist:
741
832
        dstfile = os.path.join(dst, srcfile)
 
833
        srcfile = os.path.join(srcdir, srcfile)
742
834
        dstdir = os.path.split(dstfile)[0]
743
835
        if not os.path.isdir(dstdir):
744
836
            action_mkdir(dstdir, dry)
753
845
def action_copyfile(src, dst, dry):
754
846
    """Copies one file to a new location. Creates all parent directories
755
847
    as necessary.
 
848
    Warn if file not found.
756
849
    """
757
850
    dstdir = os.path.split(dst)[0]
758
851
    if not os.path.isdir(dstdir):
762
855
        try:
763
856
            shutil.copyfile(src, dst)
764
857
            shutil.copymode(src, dst)
765
 
        except shutil.Error:
766
 
            pass
 
858
        except (shutil.Error, IOError), e:
 
859
            print "Warning: " + str(e)
767
860
 
768
861
def action_symlink(src, dst, dry):
769
862
    """Creates a symlink in a given location. Creates all parent directories
799
892
            | stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
800
893
 
801
894
def action_chmod_x(file, dry):
802
 
    """Chmod +xs a file (sets execute permission)."""
803
 
    print "chmod u+rwx", file
 
895
    """Chmod 755 a file (sets permissions to rwxr-xr-x)."""
 
896
    print "chmod 755", file
804
897
    if not dry:
805
 
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
 
898
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
 
899
            | stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
806
900
 
807
901
def query_user(default, prompt):
808
902
    """Prompts the user for a string, which is read from a line of stdin.