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

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2008-01-22 00:05:54 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:258
interpret.py: CGI handler does some checks before deleting env vars, to avoid
exceptions if they are missing.

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 config [args]
 
34
# setup.py conf [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.
38
 
# Creates lib/conf/conf.py and trampoline/conf.h.
 
38
# Creates www/conf/conf.py and trampoline/conf.h.
39
39
 
40
40
# setup.py build
41
41
# Compiles all files and sets up a jail template in the source directory.
70
70
 
71
71
# Import modules from the website is tricky since they're in the www
72
72
# directory.
73
 
sys.path.append(os.path.join(os.getcwd(), 'lib'))
 
73
sys.path.append(os.path.join(os.getcwd(), 'www'))
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
 
 
82
77
# Operating system files to copy over into the jail.
83
78
# These will be copied from the given place on the OS file system into the
84
79
# same place within the jail.
99
94
    '/bin/ls',
100
95
    '/bin/echo',
101
96
    # Needed by python
102
 
    '/usr/bin/python%s' % PYTHON_VERSION,
103
 
    # Needed by fileservice
104
 
    '/lib/libcom_err.so.2',
105
 
    '/lib/libcrypt.so.1',
106
 
    '/lib/libkeyutils.so.1',
107
 
    '/lib/libresolv.so.2',
108
 
    '/lib/librt.so.1',
109
 
    '/lib/libuuid.so.1',
110
 
    '/usr/lib/libapr-1.so.0',
111
 
    '/usr/lib/libaprutil-1.so.0',
112
 
    '/usr/lib/libdb-4.4.so',
113
 
    '/usr/lib/libexpat.so.1',
114
 
    '/usr/lib/libgcrypt.so.11',
115
 
    '/usr/lib/libgnutls.so.13',
116
 
    '/usr/lib/libgpg-error.so.0',
117
 
    '/usr/lib/libgssapi_krb5.so.2',
118
 
    '/usr/lib/libk5crypto.so.3',
119
 
    '/usr/lib/libkrb5.so.3',
120
 
    '/usr/lib/libkrb5support.so.0',
121
 
    '/usr/lib/liblber.so.2',
122
 
    '/usr/lib/libldap_r.so.2',
123
 
    '/usr/lib/libneon.so.26',
124
 
    '/usr/lib/libpq.so.5',
125
 
    '/usr/lib/libsasl2.so.2',
126
 
    '/usr/lib/libsqlite3.so.0',
127
 
    '/usr/lib/libsvn_client-1.so.1',
128
 
    '/usr/lib/libsvn_delta-1.so.1',
129
 
    '/usr/lib/libsvn_diff-1.so.1',
130
 
    '/usr/lib/libsvn_fs-1.so.1',
131
 
    '/usr/lib/libsvn_fs_base-1.so.1',
132
 
    '/usr/lib/libsvn_fs_fs-1.so.1',
133
 
    '/usr/lib/libsvn_ra-1.so.1',
134
 
    '/usr/lib/libsvn_ra_dav-1.so.1',
135
 
    '/usr/lib/libsvn_ra_local-1.so.1',
136
 
    '/usr/lib/libsvn_ra_svn-1.so.1',
137
 
    '/usr/lib/libsvn_repos-1.so.1',
138
 
    '/usr/lib/libsvn_subr-1.so.1',
139
 
    '/usr/lib/libsvn_wc-1.so.1',
140
 
    '/usr/lib/libtasn1.so.3',
141
 
    '/usr/lib/libxml2.so.2',
 
97
    '/usr/bin/python2.5',
142
98
    # Needed by matplotlib
143
99
    '/usr/lib/i686/cmov/libssl.so.0.9.8',
144
100
    '/usr/lib/i686/cmov/libcrypto.so.0.9.8',
159
115
    '/usr/lib/libXdmcp.so.6',
160
116
    '/lib/libgcc_s.so.1',
161
117
    '/etc/matplotlibrc',
162
 
    # Needed for resolv
163
 
    '/lib/libnss_dns.so.2',
164
 
    #'/lib/libnss_mdns4.so',
165
 
    '/etc/hosts',
166
 
    '/etc/resolv.conf',
167
 
    #'/etc/hosts.conf',
168
 
    #'/etc/hostname',
169
 
    '/etc/nsswitch.conf',
170
 
    '/lib/libnss_files.so.2',
171
118
]
172
119
# Symlinks to make within the jail. Src mapped to dst.
173
120
JAIL_LINKS = {
174
 
    'python%s' % PYTHON_VERSION: 'jail/usr/bin/python',
 
121
    'python2.5': 'jail/usr/bin/python',
175
122
}
176
123
# Trees to copy. Src mapped to dst (these will be passed to action_copytree).
177
124
JAIL_COPYTREES = {
178
 
    '/usr/lib/python%s' % PYTHON_VERSION:
179
 
        'jail/usr/lib/python%s' % PYTHON_VERSION,
 
125
    '/usr/lib/python2.5': 'jail/usr/lib/python2.5',
180
126
    '/usr/share/matplotlib': 'jail/usr/share/matplotlib',
181
127
    '/etc/ld.so.conf.d': 'jail/etc/ld.so.conf.d',
182
128
}
183
129
 
184
 
class ConfigOption:
185
 
    """A configuration option; one of the things written to conf.py."""
186
 
    def __init__(self, option_name, default, prompt, comment):
187
 
        """Creates a configuration option.
188
 
        option_name: Name of the variable in conf.py. Also name of the
189
 
            command-line argument to setup.py conf.
190
 
        default: Default value for this variable.
191
 
        prompt: (Short) string presented during the interactive prompt in
192
 
            setup.py conf.
193
 
        comment: (Long) comment string stored in conf.py. Each line of this
194
 
            string should begin with a '#'.
195
 
        """
196
 
        self.option_name = option_name
197
 
        self.default = default
198
 
        self.prompt = prompt
199
 
        self.comment = comment
200
 
 
201
 
# Configuration options, defaults and descriptions
202
 
config_options = []
203
 
config_options.append(ConfigOption("root_dir", "/",
204
 
    """Root directory where IVLE is located (in URL space):""",
205
 
    """
206
 
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
207
 
# with this).
208
 
# eg. "/" or "/ivle"."""))
209
 
config_options.append(ConfigOption("ivle_install_dir", "/opt/ivle",
210
 
    'Root directory where IVLE will be installed (on the local file '
211
 
    'system):',
212
 
    """
213
 
# In the local file system, where IVLE is actually installed.
214
 
# This directory should contain the "www" and "bin" directories."""))
215
 
config_options.append(ConfigOption("jail_base", "/home/informatics/jails",
216
 
    """Location of Directories
217
 
=======================
218
 
Root directory where the jails (containing user files) are stored
219
 
(on the local file system):""",
220
 
    """
221
 
# In the local file system, where are the student/user file spaces located.
222
 
# The user jails are expected to be located immediately in subdirectories of
223
 
# this location."""))
224
 
config_options.append(ConfigOption("subjects_base",
225
 
    "/home/informatics/subjects",
226
 
    """Root directory where the subject directories (containing worksheets
227
 
and other per-subject files) are stored (on the local file system):""",
228
 
    """
229
 
# In the local file system, where are the per-subject file spaces located.
230
 
# The individual subject directories are expected to be located immediately
231
 
# in subdirectories of this location."""))
232
 
config_options.append(ConfigOption("exercises_base",
233
 
    "/home/informatics/exercises",
234
 
    """Root directory where the exercise directories (containing
235
 
subject-independent exercise sheets) are stored (on the local file
236
 
system):""",
237
 
    """
238
 
# In the local file system, where are the subject-independent exercise sheet
239
 
# file spaces located."""))
240
 
config_options.append(ConfigOption("public_host", "public.localhost",
241
 
    """Hostname which will cause the server to go into "public mode",
242
 
providing login-free access to student's published work:""",
243
 
    """
244
 
# The server goes into "public mode" if the browser sends a request with this
245
 
# host. This is for security reasons - we only serve public student files on a
246
 
# separate domain to the main IVLE site.
247
 
# Public mode does not use cookies, and serves only public content.
248
 
# Private mode (normal mode) requires login, and only serves files relevant to
249
 
# the logged-in user."""))
250
 
config_options.append(ConfigOption("allowed_uids", "33",
251
 
    """UID of the web server process which will run IVLE.
252
 
Only this user may execute the trampoline. May specify multiple users as
253
 
a comma-separated list.
254
 
    (eg. "1002,78")""",
255
 
    """
256
 
# The User-ID of the web server process which will run IVLE, and any other
257
 
# users who are allowed to run the trampoline. This is stores as a string of
258
 
# comma-separated integers, simply because it is not used within Python, only
259
 
# used by the setup program to write to conf.h (see setup.py config)."""))
260
 
config_options.append(ConfigOption("db_host", "localhost",
261
 
    """PostgreSQL Database config
262
 
==========================
263
 
Hostname of the DB server:""",
264
 
    """
265
 
### PostgreSQL Database config ###
266
 
# Database server hostname"""))
267
 
config_options.append(ConfigOption("db_port", "5432",
268
 
    """Port of the DB server:""",
269
 
    """
270
 
# Database server port"""))
271
 
config_options.append(ConfigOption("db_dbname", "ivle",
272
 
    """Database name:""",
273
 
    """
274
 
# Database name"""))
275
 
config_options.append(ConfigOption("db_forumdbname", "ivle_forum",
276
 
    """Forum Database name:""",
277
 
    """
278
 
# Forum Database name"""))
279
 
config_options.append(ConfigOption("db_user", "postgres",
280
 
    """Username for DB server login:""",
281
 
    """
282
 
# Database username"""))
283
 
config_options.append(ConfigOption("db_password", "",
284
 
    """Password for DB server login:
285
 
    (Caution: This password is stored in plaintext in lib/conf/conf.py)""",
286
 
    """
287
 
# Database password"""))
288
 
config_options.append(ConfigOption("auth_modules", "ldap_auth",
289
 
    """Authentication config
290
 
=====================
291
 
Comma-separated list of authentication modules. Only "ldap" is available
292
 
by default.""",
293
 
    """
294
 
# Comma-separated list of authentication modules.
295
 
# These refer to importable Python modules in the www/auth directory.
296
 
# Modules "ldap" and "guest" are available in the source tree, but
297
 
# other modules may be plugged in to auth against organisation-specific
298
 
# auth backends."""))
299
 
config_options.append(ConfigOption("ldap_url", "ldaps://www.example.com",
300
 
    """(LDAP options are only relevant if "ldap" is included in the list of
301
 
auth modules).
302
 
URL for LDAP authentication server:""",
303
 
    """
304
 
# URL for LDAP authentication server"""))
305
 
config_options.append(ConfigOption("ldap_format_string",
306
 
    "uid=%s,ou=users,o=example",
307
 
    """Format string for LDAP auth request:
308
 
    (Must contain a single "%s" for the user's login name)""",
309
 
    """
310
 
# Format string for LDAP auth request
311
 
# (Must contain a single "%s" for the user's login name)"""))
312
 
config_options.append(ConfigOption("svn_addr", "http://svn.localhost/",
313
 
    """Subversion config
314
 
=================
315
 
The base url for accessing subversion repositories:""",
316
 
    """
317
 
# The base url for accessing subversion repositories."""))
318
 
config_options.append(ConfigOption("svn_conf", "/opt/ivle/svn/svn.conf",
319
 
    """The location of the subversion configuration file used by apache
320
 
to host the user repositories:""",
321
 
    """
322
 
# The location of the subversion configuration file used by
323
 
# apache to host the user repositories."""))
324
 
config_options.append(ConfigOption("svn_repo_path", "/home/informatics/repositories",
325
 
    """The root directory for the subversion repositories:""",
326
 
    """
327
 
# The root directory for the subversion repositories."""))
328
 
config_options.append(ConfigOption("svn_auth_ivle", "/opt/ivle/svn/ivle.auth",
329
 
    """The location of the password file used to authenticate users
330
 
of the subversion repository from the ivle server:""",
331
 
    """
332
 
# The location of the password file used to authenticate users
333
 
# of the subversion repository from the ivle server."""))
334
 
config_options.append(ConfigOption("svn_auth_local", "/opt/ivle/svn/local.auth",
335
 
    """The location of the password file used to authenticate local users
336
 
of the subversion repository:""",
337
 
    """
338
 
# The location of the password file used to authenticate local users
339
 
# of the subversion repository."""))
340
 
config_options.append(ConfigOption("usrmgt_host", "localhost",
341
 
    """User Management Server config
342
 
============================
343
 
The hostname where the usrmgt-server runs:""",
344
 
    """
345
 
# The hostname where the usrmgt-server runs."""))
346
 
config_options.append(ConfigOption("usrmgt_port", "2178",
347
 
    """The port where the usrmgt-server runs:""",
348
 
    """
349
 
# The port where the usrmgt-server runs."""))
350
 
config_options.append(ConfigOption("usrmgt_magic", "",
351
 
    """The password for the usrmgt-server:""",
352
 
    """
353
 
# The password for the usrmgt-server."""))
354
 
 
355
130
# Try importing existing conf, but if we can't just set up defaults
356
131
# The reason for this is that these settings are used by other phases
357
132
# of setup besides conf, so we need to know them.
358
133
# Also this allows you to hit Return to accept the existing value.
359
134
try:
360
 
    confmodule = __import__("lib/conf/conf")
361
 
    for opt in config_options:
362
 
        try:
363
 
            globals()[opt.option_name] = confmodule.__dict__[opt.option_name]
364
 
        except:
365
 
            globals()[opt.option_name] = opt.default
 
135
    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"
366
148
except ImportError:
367
149
    # Just set reasonable defaults
368
 
    for opt in config_options:
369
 
        globals()[opt.option_name] = opt.default
 
150
    root_dir = "/ivle"
 
151
    ivle_install_dir = "/opt/ivle"
 
152
    jail_base = "/home/informatics/jails"
 
153
# Always defaults
 
154
allowed_uids = "0"
370
155
 
371
156
# Try importing install_list, but don't fail if we can't, because listmake can
372
157
# function without it.
381
166
# as necessary, and include it in the distribution.
382
167
listmake_mimetypes = ['text/x-python', 'text/html',
383
168
    'application/x-javascript', 'application/javascript',
384
 
    'text/css', 'image/png', 'image/gif', 'application/xml']
 
169
    'text/css', 'image/png']
385
170
 
386
171
# Main function skeleton from Guido van Rossum
387
172
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
419
204
    try:
420
205
        oper_func = {
421
206
            'help' : help,
422
 
            'config' : conf,
 
207
            'conf' : conf,
423
208
            'build' : build,
424
209
            'listmake' : listmake,
425
210
            'install' : install,
440
225
Operation (and args) can be:
441
226
    help [operation]
442
227
    listmake (developer use only)
443
 
    config [args]
 
228
    conf [args]
444
229
    build
445
 
    install [--nojail] [--nosubjects] [-n|--dry]
 
230
    install [--nojail] [-n|--dry]
446
231
"""
447
232
        return 1
448
233
    elif len(args) != 1:
461
246
be copied upon installation. This should be run by the developer before
462
247
cutting a distribution, and the listfile it generates should be included in
463
248
the distribution, avoiding the administrator having to run it."""
464
 
    elif operation == 'config':
465
 
        print """python setup.py config [args]
 
249
    elif operation == 'conf':
 
250
        print """python setup.py conf [args]
466
251
Configures IVLE with machine-specific details, most notably, various paths.
467
252
Either prompts the administrator for these details or accepts them as
468
253
command-line args. Will be interactive only if there are no arguments given.
472
257
to rebuild/install), just provide ivle_install_dir as the IVLE trunk
473
258
directory, and run build/install one time.
474
259
 
475
 
Creates lib/conf/conf.py and trampoline/conf.h.
 
260
Creates www/conf/conf.py and trampoline/conf.h.
476
261
 
477
 
Args are:"""
478
 
        for opt in config_options:
479
 
            print "    --" + opt.option_name
480
 
        print """As explained in the interactive prompt or conf.py.
 
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.
481
268
"""
482
269
    elif operation == 'build':
483
270
        print """python -O setup.py build [--dry|-n]
494
281
 
495
282
--dry | -n  Print out the actions but don't do anything."""
496
283
    elif operation == 'install':
497
 
        print """sudo python setup.py install [--nojail] [--nosubjects][--dry|-n]
 
284
        print """sudo python setup.py install [--nojail] [--dry|-n]
498
285
(Requires root)
499
286
Create target install directory ($target).
500
287
Create $target/bin.
502
289
chown and chmod the installed trampoline.
503
290
Copy www/ to $target.
504
291
Copy jail/ to jails template directory (unless --nojail specified).
505
 
Copy subjects/ to subjects directory (unless --nosubjects specified).
506
292
 
507
 
--nojail        Do not copy the jail.
508
 
--nosubjects    Do not copy the subjects and exercises directories.
 
293
--nojail    Do not copy the jail.
509
294
--dry | -n  Print out the actions but don't do anything."""
510
295
    elif operation == 'updatejails':
511
296
        print """sudo python setup.py updatejails [--dry|-n]
522
307
def listmake(args):
523
308
    # We build two separate lists, by walking www and console
524
309
    list_www = build_list_py_files('www')
525
 
    list_lib = build_list_py_files('lib')
526
 
    list_subjects = build_list_py_files('subjects', no_top_level=True)
527
 
    list_exercises = build_list_py_files('exercises', no_top_level=True)
528
 
    list_scripts = [
529
 
        "scripts/python-console",
530
 
        "scripts/fileservice",
531
 
        "scripts/usrmgt-server",
532
 
        "scripts/diffservice",
533
 
    ]
 
310
    list_console = build_list_py_files('console')
534
311
    # Make sure that the files generated by conf are in the list
535
312
    # (since listmake is typically run before conf)
536
 
    if "lib/conf/conf.py" not in list_lib:
537
 
        list_lib.append("lib/conf/conf.py")
 
313
    if "www/conf/conf.py" not in list_www:
 
314
        list_www.append("www/conf/conf.py")
 
315
    # Make sure that console/python-console is in the list
 
316
    if "console/python-console" not in list_console:
 
317
        list_console.append("console/python-console")
538
318
    # Write these out to a file
539
319
    cwd = os.getcwd()
540
320
    # the files that will be created/overwritten
554
334
list_www = """)
555
335
        writelist_pretty(file, list_www)
556
336
        file.write("""
557
 
# List of all installable files in lib directory.
558
 
list_lib = """)
559
 
        writelist_pretty(file, list_lib)
560
 
        file.write("""
561
 
# List of all installable files in scripts directory.
562
 
list_scripts = """)
563
 
        writelist_pretty(file, list_scripts)
564
 
        file.write("""
565
 
# List of all installable files in subjects directory.
566
 
# This is to install sample subjects and material.
567
 
list_subjects = """)
568
 
        writelist_pretty(file, list_subjects)
569
 
        file.write("""
570
 
# List of all installable files in exercises directory.
571
 
# This is to install sample exercise material.
572
 
list_exercises = """)
573
 
        writelist_pretty(file, list_exercises)
 
337
# List of all installable files in console directory.
 
338
list_console = """)
 
339
        writelist_pretty(file, list_console)
574
340
 
575
341
        file.close()
576
342
    except IOError, (errno, strerror):
587
353
 
588
354
    return 0
589
355
 
590
 
def build_list_py_files(dir, no_top_level=False):
 
356
def build_list_py_files(dir):
591
357
    """Builds a list of all py files found in a directory and its
592
 
    subdirectories. Returns this as a list of strings.
593
 
    no_top_level=True means the file paths will not include the top-level
594
 
    directory.
595
 
    """
 
358
    subdirectories. Returns this as a list of strings."""
596
359
    pylist = []
597
360
    for (dirpath, dirnames, filenames) in os.walk(dir):
598
361
        # Exclude directories beginning with a '.' (such as '.svn')
600
363
        # All *.py files are added to the list
601
364
        pylist += [os.path.join(dirpath, item) for item in filenames
602
365
            if mimetypes.guess_type(item)[0] in listmake_mimetypes]
603
 
    if no_top_level:
604
 
        for i in range(0, len(pylist)):
605
 
            _, pylist[i] = pylist[i].split(os.sep, 1)
606
366
    return pylist
607
367
 
608
368
def writelist_pretty(file, list):
616
376
        file.write(']\n')
617
377
 
618
378
def conf(args):
619
 
    global db_port, usrmgt_port
 
379
    global root_dir, ivle_install_dir, jail_base, allowed_uids
620
380
    # Set up some variables
621
381
 
622
382
    cwd = os.getcwd()
623
383
    # the files that will be created/overwritten
624
 
    conffile = os.path.join(cwd, "lib/conf/conf.py")
625
 
    jailconffile = os.path.join(cwd, "lib/conf/jailconf.py")
 
384
    conffile = os.path.join(cwd, "www/conf/conf.py")
626
385
    conf_hfile = os.path.join(cwd, "trampoline/conf.h")
627
 
    phpBBconffile = os.path.join(cwd, "www/php/phpBB3/config.php")
628
386
 
629
387
    # Get command-line arguments to avoid asking questions.
630
388
 
631
 
    optnames = []
632
 
    for opt in config_options:
633
 
        optnames.append(opt.option_name + "=")
634
 
    (opts, args) = getopt.gnu_getopt(args, "", optnames)
 
389
    (opts, args) = getopt.gnu_getopt(args, "", ['root_dir=',
 
390
                    'ivle_install_dir=', 'jail_base=', 'allowed_uids='])
635
391
 
636
392
    if args != []:
637
393
        print >>sys.stderr, "Invalid arguments:", string.join(args, ' ')
643
399
        print """This tool will create the following files:
644
400
    %s
645
401
    %s
646
 
    %s
647
402
prompting you for details about your configuration. The file will be
648
403
overwritten if it already exists. It will *not* install or deploy IVLE.
649
404
 
650
405
Please hit Ctrl+C now if you do not wish to do this.
651
 
""" % (conffile, jailconffile, conf_hfile)
 
406
""" % (conffile, conf_hfile)
652
407
 
653
408
        # Get information from the administrator
654
409
        # If EOF is encountered at any time during the questioning, just exit
655
410
        # silently
656
411
 
657
 
        for opt in config_options:
658
 
            globals()[opt.option_name] = \
659
 
                query_user(globals()[opt.option_name], opt.prompt)
 
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
 
660
426
    else:
661
427
        opts = dict(opts)
662
428
        # Non-interactive mode. Parse the options.
663
 
        for opt in config_options:
664
 
            if '--' + opt.option_name in opts:
665
 
                globals()[opt.option_name] = opts['--' + opt.option_name]
 
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']
666
437
 
667
438
    # Error handling on input values
668
439
    try:
669
 
        allowed_uids_list = map(int, allowed_uids.split(','))
 
440
        allowed_uids = map(int, allowed_uids.split(','))
670
441
    except ValueError:
671
442
        print >>sys.stderr, (
672
443
        "Invalid UID list (%s).\n"
673
444
        "Must be a comma-separated list of integers." % allowed_uids)
674
445
        return 1
675
 
    try:
676
 
        db_port = int(db_port)
677
 
        if db_port < 0 or db_port >= 65536: raise ValueError()
678
 
    except ValueError:
679
 
        print >>sys.stderr, (
680
 
        "Invalid DB port (%s).\n"
681
 
        "Must be an integer between 0 and 65535." % repr(db_port))
682
 
        return 1
683
 
    try:
684
 
        usrmgt_port = int(usrmgt_port)
685
 
        if usrmgt_port < 0 or usrmgt_port >= 65536: raise ValueError()
686
 
    except ValueError:
687
 
        print >>sys.stderr, (
688
 
        "Invalid user management port (%s).\n"
689
 
        "Must be an integer between 0 and 65535." % repr(usrmgt_port))
690
 
        return 1
691
446
 
692
 
    # Write lib/conf/conf.py
 
447
    # Write www/conf/conf.py
693
448
 
694
449
    try:
695
450
        conf = open(conffile, "w")
698
453
# conf.py
699
454
# Miscellaneous application settings
700
455
 
701
 
""")
702
 
        for opt in config_options:
703
 
            conf.write('%s\n%s = %s\n' % (opt.comment, opt.option_name,
704
 
                repr(globals()[opt.option_name])))
705
 
 
706
 
        conf.close()
707
 
    except IOError, (errno, strerror):
708
 
        print "IO error(%s): %s" % (errno, strerror)
709
 
        sys.exit(1)
710
 
 
711
 
    print "Successfully wrote lib/conf/conf.py"
712
 
 
713
 
    # Write conf/jailconf.py
714
 
 
715
 
    try:
716
 
        conf = open(jailconffile, "w")
717
 
 
718
 
        # In the "in-jail" version of conf, we don't need MOST of the details
719
 
        # (it would be a security risk to have them here).
720
 
        # So we just write root_dir, and jail_base is "/".
721
 
        # (jail_base being "/" means "jail-relative" paths are relative to "/"
722
 
        # when inside the jail.)
723
 
        conf.write("""# IVLE Configuration File
724
 
# conf.py
725
 
# Miscellaneous application settings
726
 
# (User jail version)
727
 
 
728
456
 
729
457
# In URL space, where in the site is IVLE located. (All URLs will be prefixed
730
458
# with this).
731
459
# eg. "/" or "/ivle".
732
 
root_dir = %s
 
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"
733
465
 
734
466
# In the local file system, where are the student/user file spaces located.
735
467
# The user jails are expected to be located immediately in subdirectories of
736
468
# this location.
737
 
jail_base = '/'
738
 
 
739
 
# The hostname for serving publicly accessible pages
740
 
public_host = %s
741
 
""" % (repr(root_dir),repr(public_host)))
 
469
jail_base = "%s"
 
470
""" % (root_dir, ivle_install_dir, jail_base))
742
471
 
743
472
        conf.close()
744
473
    except IOError, (errno, strerror):
745
474
        print "IO error(%s): %s" % (errno, strerror)
746
475
        sys.exit(1)
747
476
 
748
 
    print "Successfully wrote lib/conf/jailconf.py"
 
477
    print "Successfully wrote www/conf/conf.py"
749
478
 
750
479
    # Write trampoline/conf.h
751
480
 
770
499
 * (Note that root is an implicit member of this list).
771
500
 */
772
501
static const int allowed_uids[] = { %s };
773
 
""" % (repr(jail_base)[1:-1], repr(allowed_uids_list)[1:-1]))
774
 
    # Note: The above uses PYTHON reprs, not C reprs
775
 
    # However they should be the same with the exception of the outer
776
 
    # characters, which are stripped off and replaced
 
502
""" % (jail_base, repr(allowed_uids)[1:-1]))
777
503
 
778
504
        conf.close()
779
505
    except IOError, (errno, strerror):
782
508
 
783
509
    print "Successfully wrote trampoline/conf.h"
784
510
 
785
 
    # Write www/php/phpBB3/config.php
786
 
 
787
 
    try:
788
 
        conf = open(phpBBconffile, "w")
789
 
        
790
 
        # php-pg work around
791
 
        if db_host == 'localhost':
792
 
            forumdb_host = '127.0.0.1'
793
 
        else:
794
 
            forumdb_host = db_host
795
 
 
796
 
        conf.write( """<?php
797
 
// phpBB 3.0.x auto-generated configuration file
798
 
// Do not change anything in this file!
799
 
$dbms = 'postgres';
800
 
$dbhost = '""" + forumdb_host + """';
801
 
$dbport = '""" + str(db_port) + """';
802
 
$dbname = '""" + db_forumdbname + """';
803
 
$dbuser = '""" + db_user + """';
804
 
$dbpasswd = '""" + db_password + """';
805
 
 
806
 
$table_prefix = 'phpbb_';
807
 
$acm_type = 'file';
808
 
$load_extensions = '';
809
 
@define('PHPBB_INSTALLED', true);
810
 
// @define('DEBUG', true);
811
 
//@define('DEBUG_EXTRA', true);
812
 
?>"""   )
813
 
    
814
 
        conf.close()
815
 
    except IOError, (errno, strerror):
816
 
        print "IO error(%s): %s" % (errno, strerror)
817
 
        sys.exit(1)
818
 
 
819
 
    print "Successfully wrote www/php/phpBB3/config.php"
820
 
 
821
511
    print
822
512
    print "You may modify the configuration at any time by editing"
823
513
    print conffile
824
 
    print jailconffile
825
514
    print conf_hfile
826
 
    print phpBBconffile
827
515
    print
828
516
    return 0
829
517
 
837
525
        print "Dry run (no actions will be executed\n"
838
526
 
839
527
    # Compile the trampoline
840
 
    curdir = os.getcwd()
841
 
    os.chdir('trampoline')
842
 
    action_runprog('make', [], dry)
843
 
    os.chdir(curdir)
 
528
    action_runprog('gcc', ['-Wall', '-o', 'trampoline/trampoline',
 
529
        'trampoline/trampoline.c'], dry)
844
530
 
845
531
    # Create the jail and its subdirectories
846
532
    # Note: Other subdirs will be made by copying files
848
534
    action_mkdir('jail/home', dry)
849
535
    action_mkdir('jail/tmp', dry)
850
536
 
851
 
    # Chmod the tmp directory to world writable
852
 
    action_chmod_w('jail/tmp', dry)
853
 
 
854
537
    # Copy all console and operating system files into the jail
855
 
    action_copylist(install_list.list_scripts, 'jail/opt/ivle', dry)
 
538
    action_copylist(install_list.list_console, 'jail/opt/ivle', dry)
856
539
    copy_os_files_jail(dry)
857
540
    # Chmod the python console
858
 
    action_chmod_x('jail/opt/ivle/scripts/python-console', dry)
859
 
    action_chmod_x('jail/opt/ivle/scripts/fileservice', dry)
 
541
    action_chmod_x('jail/opt/ivle/console/python-console', dry)
860
542
    
861
 
    # Also copy the IVLE lib directory into the jail
862
 
    # This is necessary for running certain scripts
863
 
    action_copylist(install_list.list_lib, 'jail/opt/ivle', dry)
864
 
    # IMPORTANT: The file jail/opt/ivle/lib/conf/conf.py contains details
865
 
    # which could compromise security if left in the jail (such as the DB
866
 
    # password).
867
 
    # The "safe" version is in jailconf.py. Delete conf.py and replace it with
868
 
    # jailconf.py.
869
 
    action_copyfile('lib/conf/jailconf.py',
870
 
        'jail/opt/ivle/lib/conf/conf.py', dry)
871
543
 
872
544
    # Compile .py files into .pyc or .pyo files
873
545
    compileall.compile_dir('www', quiet=True)
874
 
    compileall.compile_dir('lib', quiet=True)
875
 
    compileall.compile_dir('scripts', quiet=True)
876
 
    compileall.compile_dir('jail/opt/ivle/lib', quiet=True)
877
 
 
878
 
    # Set up ivle.pth inside the jail
879
 
    # Need to set /opt/ivle/lib to be on the import path
880
 
    ivle_pth = \
881
 
        "jail/usr/lib/python%s/site-packages/ivle.pth" % PYTHON_VERSION
882
 
    f = open(ivle_pth, 'w')
883
 
    f.write('/opt/ivle/lib\n')
884
 
    f.close()
 
546
    compileall.compile_dir('console', quiet=True)
885
547
 
886
548
    return 0
887
549
 
904
566
 
905
567
def install(args):
906
568
    # Get "dry" and "nojail" variables from command line
907
 
    (opts, args) = getopt.gnu_getopt(args, "n",
908
 
        ['dry', 'nojail', 'nosubjects'])
 
569
    (opts, args) = getopt.gnu_getopt(args, "n", ['dry', 'nojail'])
909
570
    opts = dict(opts)
910
571
    dry = '-n' in opts or '--dry' in opts
911
572
    nojail = '--nojail' in opts
912
 
    nosubjects = '--nosubjects' in opts
913
573
 
914
574
    if dry:
915
575
        print "Dry run (no actions will be executed\n"
929
589
    # chown trampoline to root and set setuid bit
930
590
    action_chown_setuid(tramppath, dry)
931
591
 
932
 
    # Create a scripts directory to put the usrmgt-server in.
933
 
    action_mkdir(os.path.join(ivle_install_dir, 'scripts'), dry)
934
 
    usrmgtpath = os.path.join(ivle_install_dir, 'scripts/usrmgt-server')
935
 
    action_copyfile('scripts/usrmgt-server', usrmgtpath, dry)
936
 
    action_chmod_x(usrmgtpath, dry)
937
 
 
938
 
    # Copy the www and lib directories using the list
 
592
    # Copy the www directory using the list
939
593
    action_copylist(install_list.list_www, ivle_install_dir, dry)
940
 
    action_copylist(install_list.list_lib, ivle_install_dir, dry)
941
 
    
942
 
    # Copy the php directory
943
 
    action_copytree('www/php/phpBB3',os.path.join(ivle_install_dir,'www/php/phpBB3'), 
944
 
    dry)
945
594
 
946
595
    if not nojail:
947
596
        # Copy the local jail directory built by the build action
948
597
        # to the jails template directory (it will be used as a template
949
598
        # for all the students' jails).
950
599
        action_copytree('jail', os.path.join(jail_base, 'template'), dry)
951
 
    if not nosubjects:
952
 
        # Copy the subjects and exercises directories across
953
 
        action_copylist(install_list.list_subjects, subjects_base, dry,
954
 
            srcdir="./subjects")
955
 
        action_copylist(install_list.list_exercises, exercises_base, dry,
956
 
            srcdir="./exercises")
957
600
 
958
601
    # Append IVLE path to ivle.pth in python site packages
959
602
    # (Unless it's already there)
960
603
    ivle_pth = os.path.join(sys.prefix,
961
 
        "lib/python%s/site-packages/ivle.pth" % PYTHON_VERSION)
 
604
        "lib/python2.5/site-packages/ivle.pth")
962
605
    ivle_www = os.path.join(ivle_install_dir, "www")
963
 
    ivle_lib = os.path.join(ivle_install_dir, "lib")
964
606
    write_ivle_pth = True
965
 
    write_ivle_lib_pth = True
966
607
    try:
967
608
        file = open(ivle_pth, 'r')
968
609
        for line in file:
969
610
            if line.strip() == ivle_www:
970
611
                write_ivle_pth = False
971
 
            elif line.strip() == ivle_lib:
972
 
                write_ivle_lib_pth = False
973
 
        file.close()
 
612
                break
974
613
    except (IOError, OSError):
975
614
        pass
976
615
    if write_ivle_pth:
977
616
        action_append(ivle_pth, ivle_www)
978
 
    if write_ivle_lib_pth:
979
 
        action_append(ivle_pth, ivle_lib)
980
617
 
981
618
    return 0
982
619
 
1044
681
    if ret != 0:
1045
682
        raise RunError(prog, ret)
1046
683
 
1047
 
def action_remove(path, dry):
1048
 
    """Calls rmtree, deleting the target file if it exists."""
1049
 
    try:
1050
 
        print "rm -r", path
1051
 
        if not dry:
1052
 
            shutil.rmtree(path, True)
1053
 
    except OSError, (err, msg):
1054
 
        if err != errno.EEXIST:
1055
 
            raise
1056
 
        # Otherwise, didn't exist, so we don't care
1057
 
 
1058
684
def action_rename(src, dst, dry):
1059
685
    """Calls rename. Deletes the target if it already exists."""
1060
 
    action_remove(dst, dry)
 
686
    if os.access(dst, os.F_OK):
 
687
        print "rm -r", dst
 
688
        if not dry:
 
689
            shutil.rmtree(dst, True)
1061
690
    print "mv ", src, dst
1062
691
    if dry: return
1063
692
    try:
1083
712
    directories as necessary.
1084
713
 
1085
714
    See shutil.copytree."""
1086
 
    # Allow copying over itself
1087
 
    if (os.path.normpath(os.path.join(os.getcwd(),src)) ==
1088
 
        os.path.normpath(os.path.join(os.getcwd(),dst))):
1089
 
        return
1090
 
    action_remove(dst, dry)
 
715
    if os.access(dst, os.F_OK):
 
716
        print "rm -r", dst
 
717
        if not dry:
 
718
            shutil.rmtree(dst, True)
1091
719
    print "cp -r", src, dst
1092
720
    if dry: return
1093
721
    shutil.copytree(src, dst, True)
1096
724
    """Hard-links an entire directory tree. Same as copytree but the created
1097
725
    files are hard-links not actual copies. Removes the existing destination.
1098
726
    """
1099
 
    action_remove(dst, dry)
 
727
    if os.access(dst, os.F_OK):
 
728
        print "rm -r", dst
 
729
        if not dry:
 
730
            shutil.rmtree(dst, True)
1100
731
    print "<cp with hardlinks> -r", src, dst
1101
732
    if dry: return
1102
733
    common.makeuser.linktree(src, dst)
1103
734
 
1104
 
def action_copylist(srclist, dst, dry, srcdir="."):
 
735
def action_copylist(srclist, dst, dry):
1105
736
    """Copies all files in a list to a new location. The files in the list
1106
737
    are read relative to the current directory, and their destinations are the
1107
738
    same paths relative to dst. Creates all parent directories as necessary.
1108
 
    srcdir is "." by default, can be overridden.
1109
739
    """
1110
740
    for srcfile in srclist:
1111
741
        dstfile = os.path.join(dst, srcfile)
1112
 
        srcfile = os.path.join(srcdir, srcfile)
1113
742
        dstdir = os.path.split(dstfile)[0]
1114
743
        if not os.path.isdir(dstdir):
1115
744
            action_mkdir(dstdir, dry)
1124
753
def action_copyfile(src, dst, dry):
1125
754
    """Copies one file to a new location. Creates all parent directories
1126
755
    as necessary.
1127
 
    Warn if file not found.
1128
756
    """
1129
757
    dstdir = os.path.split(dst)[0]
1130
758
    if not os.path.isdir(dstdir):
1134
762
        try:
1135
763
            shutil.copyfile(src, dst)
1136
764
            shutil.copymode(src, dst)
1137
 
        except (shutil.Error, IOError), e:
1138
 
            print "Warning: " + str(e)
 
765
        except shutil.Error:
 
766
            pass
1139
767
 
1140
768
def action_symlink(src, dst, dry):
1141
769
    """Creates a symlink in a given location. Creates all parent directories
1171
799
            | stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
1172
800
 
1173
801
def action_chmod_x(file, dry):
1174
 
    """Chmod 755 a file (sets permissions to rwxr-xr-x)."""
1175
 
    print "chmod 755", file
1176
 
    if not dry:
1177
 
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
1178
 
            | stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
1179
 
 
1180
 
 
1181
 
def action_chmod_w(file, dry):
1182
 
    """Chmod 777 a file (sets permissions to rwxrwxrwx)."""
1183
 
    print "chmod 777", file
1184
 
    if not dry:
1185
 
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
1186
 
            | stat.S_IXGRP | stat.S_IWGRP | stat.S_IRGRP | stat.S_IXOTH
1187
 
            | stat.S_IWOTH | stat.S_IROTH)
 
802
    """Chmod +xs a file (sets execute permission)."""
 
803
    print "chmod u+rwx", file
 
804
    if not dry:
 
805
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
1188
806
 
1189
807
def query_user(default, prompt):
1190
808
    """Prompts the user for a string, which is read from a line of stdin.