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
# Import modules from the website is tricky since they're in the www
35
sys.path.append('../lib')
36
import common.makeuser
38
# Determine which Python version (2.4 or 2.5, for example) we are running,
39
# and use that as the filename to the Python directory.
40
# Just get the first 3 characters of sys.version.
41
PYTHON_VERSION = sys.version[0:3]
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.
70
dry: Bool. If True, prints but does not execute.
72
print prog, string.join(args, ' ')
74
ret = os.spawnvp(os.P_WAIT, prog, args)
76
raise RunError(prog, ret)
78
def action_remove(path, dry):
79
"""Calls rmtree, deleting the target file if it exists."""
83
shutil.rmtree(path, True)
84
except OSError, (err, msg):
85
if err != errno.EEXIST:
87
# Otherwise, didn't exist, so we don't care
89
def action_rename(src, dst, dry):
90
"""Calls rename. Deletes the target if it already exists."""
91
action_remove(dst, dry)
96
except OSError, (err, msg):
97
if err != errno.EEXIST:
100
def action_mkdir(path, dry):
101
"""Calls mkdir. Silently ignored if the directory already exists.
102
Creates all parent directories as necessary."""
103
print "mkdir -p", path
107
except OSError, (err, msg):
108
if err != errno.EEXIST:
111
def action_copytree(src, dst, dry):
112
"""Copies an entire directory tree. Symlinks are seen as normal files and
113
copies of the entire file (not the link) are made. Creates all parent
114
directories as necessary.
116
See shutil.copytree."""
117
# Allow copying over itself
118
if (os.path.normpath(os.path.join(os.getcwd(),src)) ==
119
os.path.normpath(os.path.join(os.getcwd(),dst))):
121
action_remove(dst, dry)
122
print "cp -r", src, dst
124
shutil.copytree(src, dst, True)
126
def action_linktree(src, dst, dry):
127
"""Hard-links an entire directory tree. Same as copytree but the created
128
files are hard-links not actual copies. Removes the existing destination.
130
action_remove(dst, dry)
131
print "<cp with hardlinks> -r", src, dst
133
common.makeuser.linktree(src, dst)
135
def action_copylist(srclist, dst, dry, srcdir="."):
136
"""Copies all files in a list to a new location. The files in the list
137
are read relative to the current directory, and their destinations are the
138
same paths relative to dst. Creates all parent directories as necessary.
139
srcdir is "." by default, can be overridden.
141
for srcfile in srclist:
142
dstfile = os.path.join(dst, srcfile)
143
srcfile = os.path.join(srcdir, srcfile)
144
dstdir = os.path.split(dstfile)[0]
145
if not os.path.isdir(dstdir):
146
action_mkdir(dstdir, dry)
147
print "cp -f", srcfile, dstfile
150
shutil.copyfile(srcfile, dstfile)
151
shutil.copymode(srcfile, dstfile)
155
def action_copyfile(src, dst, dry):
156
"""Copies one file to a new location. Creates all parent directories
158
Warn if file not found.
160
dstdir = os.path.split(dst)[0]
161
if not os.path.isdir(dstdir):
162
action_mkdir(dstdir, dry)
163
print "cp -f", src, dst
166
shutil.copyfile(src, dst)
167
shutil.copymode(src, dst)
168
except (shutil.Error, IOError), e:
169
print "Warning: " + str(e)
171
def action_symlink(src, dst, dry):
172
"""Creates a symlink in a given location. Creates all parent directories
175
dstdir = os.path.split(dst)[0]
176
if not os.path.isdir(dstdir):
177
action_mkdir(dstdir, dry)
178
# Delete existing file
179
if os.path.exists(dst):
181
print "ln -fs", src, dst
185
def action_append(ivle_pth, ivle_www):
186
file = open(ivle_pth, 'a+')
187
file.write(ivle_www + '\n')
190
def action_chown_setuid(file, dry):
191
"""Chowns a file to root, and sets the setuid bit on the file.
192
Calling this function requires the euid to be root.
193
The actual mode of path is set to: rws--s--s
195
print "chown root:root", file
198
print "chmod a+xs", file
199
print "chmod u+rw", file
201
os.chmod(file, stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
202
| stat.S_ISUID | stat.S_IRUSR | stat.S_IWUSR)
204
def action_chmod_x(file, dry):
205
"""Chmod 755 a file (sets permissions to rwxr-xr-x)."""
206
print "chmod 755", file
208
os.chmod(file, stat.S_IXUSR | stat.S_IRUSR | stat.S_IWUSR
209
| stat.S_IXGRP | stat.S_IRGRP | stat.S_IXOTH | stat.S_IROTH)
211
def query_user(default, prompt):
212
"""Prompts the user for a string, which is read from a line of stdin.
213
Exits silently if EOF is encountered. Returns the string, with spaces
214
removed from the beginning and end.
216
Returns default if a 0-length line (after spaces removed) was read.
218
sys.stdout.write('%s\n (default: "%s")\n>' % (prompt, default))
220
val = sys.stdin.readline()
221
except KeyboardInterrupt:
223
sys.stdout.write("\n")
225
sys.stdout.write("\n")
227
if val == '': sys.exit(1)
228
# If empty line, return default
230
if val == '': return default
233
def filter_mutate(function, list):
234
"""Like built-in filter, but mutates the given list instead of returning a
235
new one. Returns None."""
238
# Delete elements which do not match
239
if not function(list[i]):
243
def get_svn_revision():
244
"""Returns either the current SVN revision of this build, or None"""
247
entry = svn.info('.')
248
revnum = entry.revision.number
249
except pysvn.ClientError, e: