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

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2008-01-31 01:44:30 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:345
Global CSS change: ivlebody no longer has 1em of padding (it has none).
This is because most apps were disabling it (and it had to change anyway for
other reasons -- see below).

Hence, all apps which WERE disabling the padding have had that removed, and
just work by default. (console, browser, tutorial)
All apps which WEREN'T disabling the padding (very few) now have to manually
include an extra div. This has been done on all such apps, and has been
heavily documented (both in the CSS file and doc/app_howto). (help, dummy,
debuginfo).

media/common/ivle.css: 
    The real change here (which isn't yet being used) is that ivlebody is now
    positioned absolutely and takes up all the space on the canvas. This is
    to be used for full-page layouts in console and browser.

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.
68
68
import compileall
69
69
import getopt
70
70
 
 
71
# Import modules from the website is tricky since they're in the www
 
72
# directory.
 
73
sys.path.append(os.path.join(os.getcwd(), 'www'))
 
74
import conf
 
75
import common.makeuser
 
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
# Operating system files to copy over into the jail.
 
83
# These will be copied from the given place on the OS file system into the
 
84
# same place within the jail.
 
85
JAIL_FILES = [
 
86
    '/lib/ld-linux.so.2',
 
87
    '/lib/tls/i686/cmov/libc.so.6',
 
88
    '/lib/tls/i686/cmov/libdl.so.2',
 
89
    '/lib/tls/i686/cmov/libm.so.6',
 
90
    '/lib/tls/i686/cmov/libpthread.so.0',
 
91
    '/lib/tls/i686/cmov/libutil.so.1',
 
92
    '/etc/ld.so.conf',
 
93
    '/etc/ld.so.cache',
 
94
    # These 2 files do not exist in Ubuntu
 
95
    #'/etc/ld.so.preload',
 
96
    #'/etc/ld.so.nohwcap',
 
97
    # UNIX commands
 
98
    '/usr/bin/strace',
 
99
    '/bin/ls',
 
100
    '/bin/echo',
 
101
    # Needed by python
 
102
    '/usr/bin/python%s' % PYTHON_VERSION,
 
103
    # Needed by matplotlib
 
104
    '/usr/lib/i686/cmov/libssl.so.0.9.8',
 
105
    '/usr/lib/i686/cmov/libcrypto.so.0.9.8',
 
106
    '/lib/tls/i686/cmov/libnsl.so.1',
 
107
    '/usr/lib/libz.so.1',
 
108
    '/usr/lib/atlas/liblapack.so.3',
 
109
    '/usr/lib/atlas/libblas.so.3',
 
110
    '/usr/lib/libg2c.so.0',
 
111
    '/usr/lib/libstdc++.so.6',
 
112
    '/usr/lib/libfreetype.so.6',
 
113
    '/usr/lib/libpng12.so.0',
 
114
    '/usr/lib/libBLT.2.4.so.8.4',
 
115
    '/usr/lib/libtk8.4.so.0',
 
116
    '/usr/lib/libtcl8.4.so.0',
 
117
    '/usr/lib/tcl8.4/init.tcl',
 
118
    '/usr/lib/libX11.so.6',
 
119
    '/usr/lib/libXau.so.6',
 
120
    '/usr/lib/libXdmcp.so.6',
 
121
    '/lib/libgcc_s.so.1',
 
122
    '/etc/matplotlibrc',
 
123
]
 
124
# Symlinks to make within the jail. Src mapped to dst.
 
125
JAIL_LINKS = {
 
126
    'python%s' % PYTHON_VERSION: 'jail/usr/bin/python',
 
127
}
 
128
# Trees to copy. Src mapped to dst (these will be passed to action_copytree).
 
129
JAIL_COPYTREES = {
 
130
    '/usr/lib/python%s' % PYTHON_VERSION:
 
131
        'jail/usr/lib/python%s' % PYTHON_VERSION,
 
132
    '/usr/share/matplotlib': 'jail/usr/share/matplotlib',
 
133
    '/etc/ld.so.conf.d': 'jail/etc/ld.so.conf.d',
 
134
}
 
135
 
71
136
# Try importing existing conf, but if we can't just set up defaults
72
137
# The reason for this is that these settings are used by other phases
73
138
# of setup besides conf, so we need to know them.
74
139
# Also this allows you to hit Return to accept the existing value.
75
140
try:
76
141
    confmodule = __import__("www/conf/conf")
77
 
    root_dir = confmodule.root_dir
78
 
    ivle_install_dir = confmodule.ivle_install_dir
79
 
    jail_base = confmodule.jail_base
 
142
    try:
 
143
        root_dir = confmodule.root_dir
 
144
    except:
 
145
        root_dir = "/ivle"
 
146
    try:
 
147
        ivle_install_dir = confmodule.ivle_install_dir
 
148
    except:
 
149
        ivle_install_dir = "/opt/ivle"
 
150
    try:
 
151
        public_host = confmodule.public_host
 
152
    except:
 
153
        public_host = "public.localhost"
 
154
    try:
 
155
        jail_base = confmodule.jail_base
 
156
    except:
 
157
        jail_base = "/home/informatics/jails"
 
158
    try:
 
159
        subjects_base = confmodule.subjects_base
 
160
    except:
 
161
        subjects_base = "/home/informatics/subjects"
80
162
except ImportError:
81
163
    # Just set reasonable defaults
82
164
    root_dir = "/ivle"
83
165
    ivle_install_dir = "/opt/ivle"
 
166
    public_host = "public.localhost"
84
167
    jail_base = "/home/informatics/jails"
 
168
    subjects_base = "/home/informatics/subjects"
85
169
# Always defaults
86
170
allowed_uids = "0"
87
171
 
98
182
# as necessary, and include it in the distribution.
99
183
listmake_mimetypes = ['text/x-python', 'text/html',
100
184
    'application/x-javascript', 'application/javascript',
101
 
    'text/css', 'image/png']
 
185
    'text/css', 'image/png', 'application/xml']
102
186
 
103
187
# Main function skeleton from Guido van Rossum
104
188
# http://www.artima.com/weblogs/viewpost.jsp?thread=4829
127
211
        return 1
128
212
 
129
213
    # Disallow run as root unless installing
130
 
    if operation != 'install' and os.geteuid() == 0:
 
214
    if (operation != 'install' and operation != 'updatejails'
 
215
        and os.geteuid() == 0):
131
216
        print >>sys.stderr, "I do not want to run this stage as root."
132
217
        print >>sys.stderr, "Please run as a normal user."
133
218
        return 1
135
220
    try:
136
221
        oper_func = {
137
222
            'help' : help,
138
 
            'conf' : conf,
 
223
            'config' : conf,
139
224
            'build' : build,
140
225
            'listmake' : listmake,
141
226
            'install' : install,
 
227
            'updatejails' : updatejails,
142
228
        }[operation]
143
229
    except KeyError:
144
230
        print >>sys.stderr, (
155
241
Operation (and args) can be:
156
242
    help [operation]
157
243
    listmake (developer use only)
158
 
    conf [args]
 
244
    config [args]
159
245
    build
160
 
    install [--nojail] [-n|--dry]
 
246
    install [--nojail] [--nosubjects] [-n|--dry]
161
247
"""
162
248
        return 1
163
249
    elif len(args) != 1:
176
262
be copied upon installation. This should be run by the developer before
177
263
cutting a distribution, and the listfile it generates should be included in
178
264
the distribution, avoiding the administrator having to run it."""
179
 
    elif operation == 'conf':
180
 
        print """python setup.py conf [args]
 
265
    elif operation == 'config':
 
266
        print """python setup.py config [args]
181
267
Configures IVLE with machine-specific details, most notably, various paths.
182
268
Either prompts the administrator for these details or accepts them as
183
269
command-line args. Will be interactive only if there are no arguments given.
192
278
Args are:
193
279
    --root_dir
194
280
    --ivle_install_dir
 
281
    --public_host
195
282
    --jail_base
 
283
    --subjects_base
196
284
    --allowed_uids
197
285
As explained in the interactive prompt or conf.py.
198
286
"""
211
299
 
212
300
--dry | -n  Print out the actions but don't do anything."""
213
301
    elif operation == 'install':
214
 
        print """sudo python setup.py install [--nojail] [--dry|-n]
 
302
        print """sudo python setup.py install [--nojail] [--nosubjects][--dry|-n]
215
303
(Requires root)
216
304
Create target install directory ($target).
217
305
Create $target/bin.
219
307
chown and chmod the installed trampoline.
220
308
Copy www/ to $target.
221
309
Copy jail/ to jails template directory (unless --nojail specified).
222
 
 
223
 
--nojail    Do not copy the jail.
 
310
Copy subjects/ to subjects directory (unless --nosubjects specified).
 
311
 
 
312
--nojail        Do not copy the jail.
 
313
--nosubjects    Do not copy the subjects.
 
314
--dry | -n  Print out the actions but don't do anything."""
 
315
    elif operation == 'updatejails':
 
316
        print """sudo python setup.py updatejails [--dry|-n]
 
317
(Requires root)
 
318
Copy jail/ to each subdirectory in jails directory.
 
319
 
224
320
--dry | -n  Print out the actions but don't do anything."""
225
321
    else:
226
322
        print >>sys.stderr, (
232
328
    # We build two separate lists, by walking www and console
233
329
    list_www = build_list_py_files('www')
234
330
    list_console = build_list_py_files('console')
 
331
    list_subjects = build_list_py_files('subjects', no_top_level=True)
235
332
    # Make sure that the files generated by conf are in the list
236
333
    # (since listmake is typically run before conf)
237
334
    if "www/conf/conf.py" not in list_www:
261
358
# List of all installable files in console directory.
262
359
list_console = """)
263
360
        writelist_pretty(file, list_console)
 
361
        file.write("""
 
362
# List of all installable files in subjects directory.
 
363
# This is to install sample subjects and material.
 
364
list_subjects = """)
 
365
        writelist_pretty(file, list_subjects)
264
366
 
265
367
        file.close()
266
368
    except IOError, (errno, strerror):
277
379
 
278
380
    return 0
279
381
 
280
 
def build_list_py_files(dir):
 
382
def build_list_py_files(dir, no_top_level=False):
281
383
    """Builds a list of all py files found in a directory and its
282
 
    subdirectories. Returns this as a list of strings."""
 
384
    subdirectories. Returns this as a list of strings.
 
385
    no_top_level=True means the file paths will not include the top-level
 
386
    directory.
 
387
    """
283
388
    pylist = []
284
389
    for (dirpath, dirnames, filenames) in os.walk(dir):
285
390
        # Exclude directories beginning with a '.' (such as '.svn')
287
392
        # All *.py files are added to the list
288
393
        pylist += [os.path.join(dirpath, item) for item in filenames
289
394
            if mimetypes.guess_type(item)[0] in listmake_mimetypes]
 
395
    if no_top_level:
 
396
        for i in range(0, len(pylist)):
 
397
            _, pylist[i] = pylist[i].split(os.sep, 1)
290
398
    return pylist
291
399
 
292
400
def writelist_pretty(file, list):
300
408
        file.write(']\n')
301
409
 
302
410
def conf(args):
303
 
    global root_dir, ivle_install_dir, jail_base, allowed_uids
 
411
    global root_dir, ivle_install_dir, jail_base, subjects_base
 
412
    global public_host, allowed_uids
304
413
    # Set up some variables
305
414
 
306
415
    cwd = os.getcwd()
308
417
    conffile = os.path.join(cwd, "www/conf/conf.py")
309
418
    conf_hfile = os.path.join(cwd, "trampoline/conf.h")
310
419
 
311
 
    # Fixed config options that we don't ask the admin
312
 
    default_app = "dummy"
313
 
 
314
420
    # Get command-line arguments to avoid asking questions.
315
421
 
316
422
    (opts, args) = getopt.gnu_getopt(args, "", ['root_dir=',
344
450
        jail_base = query_user(jail_base,
345
451
        """Root directory where the jails (containing user files) are stored
346
452
(on the local file system):""")
 
453
        subjects_base = query_user(subjects_base,
 
454
        """Root directory where the subject directories (containing worksheets
 
455
and other per-subject files) are stored (on the local file system):""")
 
456
        public_host = query_user(public_host,
 
457
        """Hostname which will cause the server to go into "public mode",
 
458
providing login-free access to student's published work:""")
347
459
        allowed_uids = query_user(allowed_uids,
348
460
        """UID of the web server process which will run IVLE.
349
461
Only this user may execute the trampoline. May specify multiple users as
359
471
            ivle_install_dir = opts['--ivle_install_dir']
360
472
        if '--jail_base' in opts:
361
473
            jail_base = opts['--jail_base']
 
474
        if '--subjects_base' in opts:
 
475
            jail_base = opts['--subjects_base']
 
476
        if '--public_host' in opts:
 
477
            public_host = opts['--public_host']
362
478
        if '--allowed_uids' in opts:
363
479
            allowed_uids = opts['--allowed_uids']
364
480
 
390
506
# This directory should contain the "www" and "bin" directories.
391
507
ivle_install_dir = "%s"
392
508
 
 
509
# The server goes into "public mode" if the browser sends a request with this
 
510
# host. This is for security reasons - we only serve public student files on a
 
511
# separate domain to the main IVLE site.
 
512
# Public mode does not use cookies, and serves only public content.
 
513
# Private mode (normal mode) requires login, and only serves files relevant to
 
514
# the logged-in user.
 
515
public_host = "%s"
 
516
 
393
517
# In the local file system, where are the student/user file spaces located.
394
518
# The user jails are expected to be located immediately in subdirectories of
395
519
# this location.
396
520
jail_base = "%s"
397
521
 
398
 
# Which application to load by default (if the user navigates to the top level
399
 
# of the site). This is the app's URL name.
400
 
# Note that if this app requires authentication, the user will first be
401
 
# presented with the login screen.
402
 
default_app = "%s"
403
 
""" % (root_dir, ivle_install_dir, jail_base, default_app))
 
522
# In the local file system, where are the per-subject file spaces located.
 
523
# The individual subject directories are expected to be located immediately
 
524
# in subdirectories of this location.
 
525
subjects_base = "%s"
 
526
""" % (root_dir, ivle_install_dir, public_host, jail_base, subjects_base))
404
527
 
405
528
        conf.close()
406
529
    except IOError, (errno, strerror):
470
593
    # Copy all console and operating system files into the jail
471
594
    action_copylist(install_list.list_console, 'jail/opt/ivle', dry)
472
595
    copy_os_files_jail(dry)
 
596
    # Chmod the python console
 
597
    action_chmod_x('jail/opt/ivle/console/python-console', dry)
 
598
    
473
599
 
474
600
    # Compile .py files into .pyc or .pyo files
475
601
    compileall.compile_dir('www', quiet=True)
481
607
    """Copies necessary Operating System files from their usual locations
482
608
    into the jail/ directory of the cwd."""
483
609
    # Currently source paths are configured for Ubuntu.
484
 
    copy_file_to_jail('/lib/ld-linux.so.2', dry)
485
 
    copy_file_to_jail('/lib/tls/i686/cmov/libc.so.6', dry)
486
 
    copy_file_to_jail('/lib/tls/i686/cmov/libdl.so.2', dry)
487
 
    copy_file_to_jail('/lib/tls/i686/cmov/libm.so.6', dry)
488
 
    copy_file_to_jail('/lib/tls/i686/cmov/libpthread.so.0', dry)
489
 
    copy_file_to_jail('/lib/tls/i686/cmov/libutil.so.1', dry)
490
 
    copy_file_to_jail('/usr/bin/python2.5', dry)
491
 
    action_symlink('python2.5', 'jail/usr/bin/python', dry)
492
 
    action_copytree('/usr/lib/python2.5', 'jail/usr/lib/python2.5', dry)
 
610
    for filename in JAIL_FILES:
 
611
        copy_file_to_jail(filename, dry)
 
612
    for src, dst in JAIL_LINKS.items():
 
613
        action_symlink(src, dst, dry)
 
614
    for src, dst in JAIL_COPYTREES.items():
 
615
        action_copytree(src, dst, dry)
493
616
 
494
617
def copy_file_to_jail(src, dry):
495
618
    """Copies a single file from an absolute location into the same location
499
622
 
500
623
def install(args):
501
624
    # Get "dry" and "nojail" variables from command line
502
 
    (opts, args) = getopt.gnu_getopt(args, "n", ['dry', 'nojail'])
 
625
    (opts, args) = getopt.gnu_getopt(args, "n",
 
626
        ['dry', 'nojail', 'nosubjects'])
503
627
    opts = dict(opts)
504
628
    dry = '-n' in opts or '--dry' in opts
505
629
    nojail = '--nojail' in opts
 
630
    nosubjects = '--nosubjects' in opts
506
631
 
507
632
    if dry:
508
633
        print "Dry run (no actions will be executed\n"
530
655
        # to the jails template directory (it will be used as a template
531
656
        # for all the students' jails).
532
657
        action_copytree('jail', os.path.join(jail_base, 'template'), dry)
 
658
    if not nosubjects:
 
659
        # Copy the subjects directory across
 
660
        action_copylist(install_list.list_subjects, subjects_base, dry,
 
661
            srcdir="./subjects")
 
662
 
 
663
    # Append IVLE path to ivle.pth in python site packages
 
664
    # (Unless it's already there)
 
665
    ivle_pth = os.path.join(sys.prefix,
 
666
        "lib/python%s/site-packages/ivle.pth" % PYTHON_VERSION)
 
667
    ivle_www = os.path.join(ivle_install_dir, "www")
 
668
    write_ivle_pth = True
 
669
    try:
 
670
        file = open(ivle_pth, 'r')
 
671
        for line in file:
 
672
            if line.strip() == ivle_www:
 
673
                write_ivle_pth = False
 
674
                break
 
675
    except (IOError, OSError):
 
676
        pass
 
677
    if write_ivle_pth:
 
678
        action_append(ivle_pth, ivle_www)
 
679
 
 
680
    return 0
 
681
 
 
682
def updatejails(args):
 
683
    # Get "dry" variable from command line
 
684
    (opts, args) = getopt.gnu_getopt(args, "n", ['dry'])
 
685
    opts = dict(opts)
 
686
    dry = '-n' in opts or '--dry' in opts
 
687
 
 
688
    if dry:
 
689
        print "Dry run (no actions will be executed\n"
 
690
 
 
691
    if not dry and os.geteuid() != 0:
 
692
        print >>sys.stderr, "Must be root to run install"
 
693
        print >>sys.stderr, "(I need to chown some files)."
 
694
        return 1
 
695
 
 
696
    # Update the template jail directory in case it hasn't been installed
 
697
    # recently.
 
698
    action_copytree('jail', os.path.join(jail_base, 'template'), dry)
 
699
 
 
700
    # Re-link all the files in all students jails.
 
701
    for dir in os.listdir(jail_base):
 
702
        if dir == 'template': continue
 
703
        # First back up the student's home directory
 
704
        temp_home = os.tmpnam()
 
705
        action_rename(os.path.join(jail_base, dir, 'home'), temp_home, dry)
 
706
        # Delete the student's jail and relink the jail files
 
707
        action_linktree(os.path.join(jail_base, 'template'),
 
708
            os.path.join(jail_base, dir), dry)
 
709
        # Restore the student's home directory
 
710
        action_rename(temp_home, os.path.join(jail_base, dir, 'home'), dry)
 
711
        # Set up the user's home directory just in case they don't have a
 
712
        # directory for this yet
 
713
        action_mkdir(os.path.join(jail_base, dir, 'home', dir), dry)
533
714
 
534
715
    return 0
535
716
 
562
743
    if ret != 0:
563
744
        raise RunError(prog, ret)
564
745
 
 
746
def action_rename(src, dst, dry):
 
747
    """Calls rename. Deletes the target if it already exists."""
 
748
    if os.access(dst, os.F_OK):
 
749
        print "rm -r", dst
 
750
        if not dry:
 
751
            shutil.rmtree(dst, True)
 
752
    print "mv ", src, dst
 
753
    if dry: return
 
754
    try:
 
755
        os.rename(src, dst)
 
756
    except OSError, (err, msg):
 
757
        if err != errno.EEXIST:
 
758
            raise
 
759
 
565
760
def action_mkdir(path, dry):
566
761
    """Calls mkdir. Silently ignored if the directory already exists.
567
762
    Creates all parent directories as necessary."""
587
782
    if dry: return
588
783
    shutil.copytree(src, dst, True)
589
784
 
590
 
def action_copylist(srclist, dst, dry):
 
785
def action_linktree(src, dst, dry):
 
786
    """Hard-links an entire directory tree. Same as copytree but the created
 
787
    files are hard-links not actual copies. Removes the existing destination.
 
788
    """
 
789
    if os.access(dst, os.F_OK):
 
790
        print "rm -r", dst
 
791
        if not dry:
 
792
            shutil.rmtree(dst, True)
 
793
    print "<cp with hardlinks> -r", src, dst
 
794
    if dry: return
 
795
    common.makeuser.linktree(src, dst)
 
796
 
 
797
def action_copylist(srclist, dst, dry, srcdir="."):
591
798
    """Copies all files in a list to a new location. The files in the list
592
799
    are read relative to the current directory, and their destinations are the
593
800
    same paths relative to dst. Creates all parent directories as necessary.
 
801
    srcdir is "." by default, can be overridden.
594
802
    """
595
803
    for srcfile in srclist:
596
804
        dstfile = os.path.join(dst, srcfile)
 
805
        srcfile = os.path.join(srcdir, srcfile)
597
806
        dstdir = os.path.split(dstfile)[0]
598
807
        if not os.path.isdir(dstdir):
599
808
            action_mkdir(dstdir, dry)
608
817
def action_copyfile(src, dst, dry):
609
818
    """Copies one file to a new location. Creates all parent directories
610
819
    as necessary.
 
820
    Warn if file not found.
611
821
    """
612
822
    dstdir = os.path.split(dst)[0]
613
823
    if not os.path.isdir(dstdir):
617
827
        try:
618
828
            shutil.copyfile(src, dst)
619
829
            shutil.copymode(src, dst)
620
 
        except shutil.Error:
621
 
            pass
 
830
        except (shutil.Error, IOError), e:
 
831
            print "Warning: " + str(e)
622
832
 
623
833
def action_symlink(src, dst, dry):
624
834
    """Creates a symlink in a given location. Creates all parent directories
634
844
    if not dry:
635
845
        os.symlink(src, dst)
636
846
 
 
847
def action_append(ivle_pth, ivle_www):
 
848
    file = open(ivle_pth, 'a+')
 
849
    file.write(ivle_www + '\n')
 
850
    file.close()
 
851
 
637
852
def action_chown_setuid(file, dry):
638
853
    """Chowns a file to root, and sets the setuid bit on the file.
639
854
    Calling this function requires the euid to be root.
648
863
        os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
649
864
            | stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
650
865
 
 
866
def action_chmod_x(file, dry):
 
867
    """Chmod +xs a file (sets execute permission)."""
 
868
    print "chmod u+rwx", file
 
869
    if not dry:
 
870
        os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR)
 
871
 
651
872
def query_user(default, prompt):
652
873
    """Prompts the user for a string, which is read from a line of stdin.
653
874
    Exits silently if EOF is encountered. Returns the string, with spaces