1
# IVLE - Informatics Virtual Learning Environment
2
# Copyright (C) 2007-2008 The University of Melbourne
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
# Module: setup/setuputil
19
# Author: Matt Giuca, Refactored by David Coles
23
# Contains a set of functions useful for the setup program.
32
# Determine which Python version (2.4 or 2.5, for example) we are running,
33
# and use that as the filename to the Python directory.
34
# Just get the first 3 characters of sys.version.
35
PYTHON_VERSION = sys.version[0:3]
37
# Location of standard programs
38
RSYNC = '/usr/bin/rsync'
40
# UID of the Webserver
43
def copy_file_to_jail(src, dry):
44
"""Copies a single file from an absolute location into the same location
45
within the jail. src must begin with a '/'. The jail will be located
46
in a 'jail' subdirectory of the current path."""
47
action_copyfile(src, 'jail' + src, dry)
49
# The actions call Python os functions but print actions and handle dryness.
50
# May still throw os exceptions if errors occur.
53
"""Represents an error when running a program (nonzero return)."""
54
def __init__(self, prog, retcode):
56
self.retcode = retcode
58
return str(self.prog) + " returned " + repr(self.retcode)
60
def action_runprog(prog, args, dry):
61
"""Runs a unix program. Searches in $PATH. Synchronous (waits for the
62
program to return). Runs in the current environment. First prints the
63
action as a "bash" line.
65
Throws a RunError with a retcode of the return value of the program,
66
if the program did not return 0.
68
prog: String. Name of the program. (No path required, if in $PATH).
69
args: [String]. Arguments to the program. (Note, this does not allow you to
70
set argv[0]; it will always be prog.)
71
dry: Bool. If True, prints but does not execute.
73
print prog, string.join(args, ' ')
75
ret = os.spawnvp(os.P_WAIT, prog, [prog] + args)
77
raise RunError(prog, ret)
79
def action_remove(path, dry):
80
"""Calls rmtree, deleting the target file if it exists."""
84
shutil.rmtree(path, True)
85
except OSError, (err, msg):
86
if err != errno.EEXIST:
88
# Otherwise, didn't exist, so we don't care
90
def action_rename(src, dst, dry):
91
"""Calls rename. Deletes the target if it already exists."""
92
action_remove(dst, dry)
97
except OSError, (err, msg):
98
if err != errno.EEXIST:
101
def action_mkdir(path, dry):
102
"""Calls mkdir. Silently ignored if the directory already exists.
103
Creates all parent directories as necessary."""
104
print "mkdir -p", path
108
except OSError, (err, msg):
109
if err != errno.EEXIST:
112
def action_copytree(src, dst, dry):
113
"""Copies an entire directory tree. Symlinks are seen as normal files and
114
copies of the entire file (not the link) are made. Creates all parent
115
directories as necessary.
117
See shutil.copytree."""
118
# Allow copying over itself
119
if (os.path.normpath(os.path.join(os.getcwd(),src)) ==
120
os.path.normpath(os.path.join(os.getcwd(),dst))):
123
# Try to do the copy with rsync, if that fails just copy
125
action_runprog(RSYNC, ['-a','--delete',src + '/',dst], dry)
128
action_remove(dst, dry)
129
print "cp -r", src, dst
130
shutil.copytree(src, dst, True)
132
def action_copylist(srclist, dst, dry, srcdir="."):
133
"""Copies all files in a list to a new location. The files in the list
134
are read relative to the current directory, and their destinations are the
135
same paths relative to dst. Creates all parent directories as necessary.
136
srcdir is "." by default, can be overridden.
138
for srcfile in srclist:
139
dstfile = os.path.join(dst, srcfile)
140
srcfile = os.path.join(srcdir, srcfile)
141
dstdir = os.path.split(dstfile)[0]
142
if not os.path.isdir(dstdir):
143
action_mkdir(dstdir, dry)
144
print "cp -f", srcfile, dstfile
147
shutil.copyfile(srcfile, dstfile)
148
shutil.copymode(srcfile, dstfile)
152
def action_copyfile(src, dst, dry):
153
"""Copies one file to a new location. Creates all parent directories
155
Warn if file not found.
157
dstdir = os.path.split(dst)[0]
158
if not os.path.isdir(dstdir):
159
action_mkdir(dstdir, dry)
160
print "cp -f", src, dst
163
shutil.copyfile(src, dst)
164
shutil.copymode(src, dst)
165
except (shutil.Error, IOError), e:
166
print "Warning: " + str(e)
168
def action_symlink(src, dst, dry):
169
"""Creates a symlink in a given location. Creates all parent directories
172
dstdir = os.path.split(dst)[0]
173
if not os.path.isdir(dstdir):
174
action_mkdir(dstdir, dry)
175
# Delete existing file
176
if os.path.exists(dst):
178
print "ln -fs", src, dst
182
def action_append(ivle_pth, ivle_www):
183
file = open(ivle_pth, 'a+')
184
file.write(ivle_www + '\n')
187
def action_chown_setuid(file, dry):
188
"""Chowns a file to root, and sets the setuid bit on the file.
189
Calling this function requires the euid to be root.
190
The actual mode of path is set to: rws--s--s
192
print "chown root:root", file
195
print "chmod a+xs", file
196
print "chmod u+rw", file
198
os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
199
| stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
201
def action_chmod_x(file, dry):
202
"""Chmod 755 a file (sets permissions to rwxr-xr-x)."""
203
print "chmod 755", file
205
os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
206
| stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
208
def action_make_private(file, dry):
209
"""Ensures that a file is private to IVLE (chowns to www-data and chmod to
211
print "chown %s:%s %s"%(wwwuid, wwwuid, file)
213
os.chown(file, wwwuid, wwwuid)
214
print "chmod 600", file
216
os.chmod(file, stat.S_IRUSR | stat.S_IWUSR)
218
def query_user(default, prompt):
219
"""Prompts the user for a string, which is read from a line of stdin.
220
Exits silently if EOF is encountered. Returns the string, with spaces
221
removed from the beginning and end.
223
Returns default if a 0-length line (after spaces removed) was read.
225
sys.stdout.write('%s\n (default: "%s")\n>' % (prompt, default))
227
val = sys.stdin.readline()
228
except KeyboardInterrupt:
230
sys.stdout.write("\n")
232
sys.stdout.write("\n")
234
if val == '': sys.exit(1)
235
# If empty line, return default
237
if val == '': return default
240
def filter_mutate(function, list):
241
"""Like built-in filter, but mutates the given list instead of returning a
242
new one. Returns None."""
245
# Delete elements which do not match
246
if not function(list[i]):
250
def get_svn_revision():
251
"""Returns either the current SVN revision of this build, or None"""
255
entry = svn.info('.')
256
revnum = entry.revision.number
257
except pysvn.ClientError, e: