15
15
# along with this program; if not, write to the Free Software
16
16
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22
# This app is a wrapper around the diff script run through the trampoline
18
# Author: David Coles, Will Grant
27
28
import ivle.interpret
30
# handle_with_trampoline controls the way in which fileservice_lib is invoked.
31
# If False, it will simply be called directly by this handler.
32
# If True, the request will get marshalled into a CGI environment and the
33
# trampoline will invoke services/fileservices within the user's jail (SetUID'd
34
# to them). This script will then wrap the CGI environment in a replica of the
35
# original environment and handle it that way.
36
# This is a lot of overhead but it's the only way to properly ensure we are
37
# acting "as" that user and therefore we don't run into permissions problems.
38
# If set to True, it will be a lot more efficient, but there will be
39
# permissions issues unless all user's files are owned by the web server user.
40
HANDLE_WITH_TRAMPOLINE = True
29
from ivle.webapp.base.xhtml import XHTMLView
30
from ivle.webapp.base.plugins import BasePlugin
31
from ivle.webapp.errors import NotFound
42
33
diffservice_path = os.path.join(ivle.conf.share_path, 'services/diffservice')
45
"""Handler for the File Services application."""
46
req.styles = ["media/diff/diff.css"] # CSS styles
47
req.write_html_head_foot = True # Have dispatch print head and foot
50
if not HANDLE_WITH_TRAMPOLINE:
54
req.throw_redirect(os.path.join(req.uri,req.user.login));
55
interp_object = ivle.interpret.interpreter_objects["cgi-python"]
35
class DiffView(XHTMLView):
36
template = 'template.html'
38
def populate(self, req, ctx):
39
req.styles = ["/media/diff/diff.css"] # CSS styles
41
revfields = req.get_fieldstorage().getlist("r")
42
if len(revfields) > 2:
43
raise BadRequest('A maximum of two revisions can be given.')
45
revs = [revfield.value for revfield in revfields]
56
47
user_jail_dir = os.path.join(ivle.conf.jail_base, req.user.login)
57
ivle.interpret.interpret_file(req, req.user, user_jail_dir,
58
diffservice_path, interp_object)
48
(out, err) = ivle.interpret.execute_raw(req.user, user_jail_dir,
49
'/home', diffservice_path, [self.path] + revs)
52
response = cjson.decode(out)
53
if 'error' in response:
54
if response['error'] == 'notfound':
57
raise AssertionError('Unknown error from diffservice: %s' %
60
# No error. We must be safe.
61
diff = response['diff']
63
# Split up the udiff into individual files
64
diff_matcher = re.compile(
65
r'^Index: (.*)\n\=+\n((?:[^I].*\n)*)',re.MULTILINE
68
# Create a dict with (name, HTMLdiff) pairs for each non-empty diff.
69
ctx['files'] = dict([(fd[0], genshi.XML(htmlfy_diff(fd[1])))
70
for fd in diff_matcher.findall(diff)
74
def htmlfy_diff(difftext):
75
"""Adds HTML markup to a udiff string"""
76
output = cgi.escape(difftext)
78
r'^([\+\-]{3})\s(\S+)\s\((.+)\)$':
79
r'<span class="diff-files">\1 \2 <em>(\3)</em></span>',
81
r'<span class="diff-range">@@ \1 @@</span>',
83
r'<span class="diff-add">+\1</span>',
85
r'<span class="diff-sub">-\1</span>',
87
r'<span class="diff-special">\\\1</span>'
91
output = re.compile(match, re.MULTILINE).sub(subs[match], output)
93
return '<pre class="diff">%s</pre>' % output
95
class Plugin(BasePlugin):
97
('diff/', DiffView, {'path': ''}),
98
('diff/*(path)', DiffView),