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

« back to all changes in this revision

Viewing changes to setup.py

  • Committer: mattgiuca
  • Date: 2007-12-21 00:53:07 UTC
  • Revision ID: svn-v3-trunk0:2b9c9e99-6f39-0410-b283-7f802c844ae2:trunk:113
setup.py: Now loads defaults, if possible, from the existing conf.py.
Instead of printing examples, prints the defaults. Hitting return immediately
when faced with a query now chooses the default.

Show diffs side-by-side

added added

removed removed

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