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.
33
# Determine which Python version (2.4 or 2.5, for example) we are running,
34
# and use that as the filename to the Python directory.
35
# Just get the first 3 characters of sys.version.
36
PYTHON_VERSION = sys.version[0:3]
38
# Location of standard programs
39
RSYNC = '/usr/bin/rsync'
41
# UID of the Webserver
44
def copy_file_to_jail(src, dry):
45
"""Copies a single file from an absolute location into the same location
46
within the jail. src must begin with a '/'. The jail will be located
47
in a 'jail' subdirectory of the current path."""
48
action_copyfile(src, 'jail' + src, dry)
50
# The actions call Python os functions but print actions and handle dryness.
51
# May still throw os exceptions if errors occur.
54
"""Represents an error when running a program (nonzero return)."""
55
def __init__(self, prog, retcode):
57
self.retcode = retcode
59
return str(self.prog) + " returned " + repr(self.retcode)
61
def action_runprog(prog, args, dry):
62
"""Runs a unix program. Searches in $PATH. Synchronous (waits for the
63
program to return). Runs in the current environment. First prints the
64
action as a "bash" line.
66
Throws a RunError with a retcode of the return value of the program,
67
if the program did not return 0.
69
prog: String. Name of the program. (No path required, if in $PATH).
70
args: [String]. Arguments to the program. (Note, this does not allow you to
71
set argv[0]; it will always be prog.)
72
dry: Bool. If True, prints but does not execute.
74
print prog, string.join(args, ' ')
76
ret = os.spawnvp(os.P_WAIT, prog, [prog] + args)
78
raise RunError(prog, ret)
80
def action_remove(path, dry):
81
"""Calls rmtree, deleting the target file if it exists."""
85
shutil.rmtree(path, True)
86
except OSError, (err, msg):
87
if err != errno.EEXIST:
89
# Otherwise, didn't exist, so we don't care
91
def action_rename(src, dst, dry):
92
"""Calls rename. Deletes the target if it already exists."""
93
action_remove(dst, dry)
98
except OSError, (err, msg):
99
if err != errno.EEXIST:
102
def action_mkdir(path, dry):
103
"""Calls mkdir. Silently ignored if the directory already exists.
104
Creates all parent directories as necessary."""
105
print "mkdir -p", path
109
except OSError, (err, msg):
110
if err != errno.EEXIST:
113
def action_copytree(src, dst, dry):
114
"""Copies an entire directory tree. Symlinks are seen as normal files and
115
copies of the entire file (not the link) are made. Creates all parent
116
directories as necessary.
118
See shutil.copytree."""
119
# Allow copying over itself
120
if (os.path.normpath(os.path.join(os.getcwd(),src)) ==
121
os.path.normpath(os.path.join(os.getcwd(),dst))):
124
# Try to do the copy with rsync, if that fails just copy
126
action_runprog(RSYNC, ['-a','--delete',src + '/',dst], dry)
129
action_remove(dst, dry)
130
print "cp -r", src, dst
131
shutil.copytree(src, dst, True)
133
def action_copylist(srclist, dst, dry, srcdir="."):
134
"""Copies all files in a list to a new location. The files in the list
135
are read relative to the current directory, and their destinations are the
136
same paths relative to dst. Creates all parent directories as necessary.
137
srcdir is "." by default, can be overridden.
139
for srcfile in srclist:
140
dstfile = os.path.join(dst, srcfile)
141
srcfile = os.path.join(srcdir, srcfile)
142
dstdir = os.path.split(dstfile)[0]
143
if not os.path.isdir(dstdir):
144
action_mkdir(dstdir, dry)
145
print "cp -f", srcfile, dstfile
148
shutil.copyfile(srcfile, dstfile)
149
shutil.copymode(srcfile, dstfile)
153
def action_copyfile(src, dst, dry):
154
"""Copies one file to a new location. Creates all parent directories
156
Warn if file not found.
158
dstdir = os.path.split(dst)[0]
159
if not os.path.isdir(dstdir):
160
action_mkdir(dstdir, dry)
161
print "cp -f", src, dst
164
shutil.copyfile(src, dst)
165
shutil.copymode(src, dst)
166
except (shutil.Error, IOError), e:
167
print "Warning: " + str(e)
169
def action_symlink(src, dst, dry):
170
"""Creates a symlink in a given location. Creates all parent directories
173
dstdir = os.path.split(dst)[0]
174
if not os.path.isdir(dstdir):
175
action_mkdir(dstdir, dry)
176
# Delete existing file
177
if os.path.exists(dst):
179
print "ln -fs", src, dst
183
def action_append(ivle_pth, ivle_www):
184
file = open(ivle_pth, 'a+')
185
file.write(ivle_www + '\n')
188
def action_chown_setuid(file, dry):
189
"""Chowns a file to root, and sets the setuid bit on the file.
190
Calling this function requires the euid to be root.
191
The actual mode of path is set to: rws--s--s
193
print "chown root:root", file
196
print "chmod a+xs", file
197
print "chmod u+rw", file
199
os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
200
| stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
202
def action_chmod_x(file, dry):
203
"""Chmod 755 a file (sets permissions to rwxr-xr-x)."""
204
print "chmod 755", file
206
os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
207
| stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
209
def action_make_private(file, dry):
210
"""Ensures that a file is private to IVLE (chowns to www-data and chmod to
212
print "chown %s:%s %s"%(wwwuid, wwwuid, file)
214
os.chown(file, wwwuid, wwwuid)
215
print "chmod 600", file
217
os.chmod(file, stat.S_IRUSR | stat.S_IWUSR)
219
def query_user(default, prompt):
220
"""Prompts the user for a string, which is read from a line of stdin.
221
Exits silently if EOF is encountered. Returns the string, with spaces
222
removed from the beginning and end.
224
Returns default if a 0-length line (after spaces removed) was read.
226
sys.stdout.write('%s\n (default: "%s")\n>' % (prompt, default))
228
val = sys.stdin.readline()
229
except KeyboardInterrupt:
231
sys.stdout.write("\n")
233
sys.stdout.write("\n")
235
if val == '': sys.exit(1)
236
# If empty line, return default
238
if val == '': return default
241
def filter_mutate(function, list):
242
"""Like built-in filter, but mutates the given list instead of returning a
243
new one. Returns None."""
246
# Delete elements which do not match
247
if not function(list[i]):
251
def get_svn_revision():
252
"""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: