17
17
# along with this program; if not, write to the Free Software
18
18
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20
# Author: David Coles, Will Grant
23
A script for generating a Subversion diff. It is intended to be run via
24
trampoline by ivle.webapp.filesystem.diff.DiffView.
24
# A CGI script for generating a diff report page in HTML. It is intended to be
25
# run from the trampoline by the Diff application.
32
from ivle import cgirequest
38
locale.setlocale(locale.LC_CTYPE, "en_US.UTF-8")
35
def htmlfy_diff(difftext):
36
"""Adds HTML markup to a udiff string"""
37
output = cgi.escape(difftext)
39
r'^([\+\-]{3})\s(\S+)\s\((.+)\)$':
40
r'<span class="diff-files">\1 \2 <em>(\3)</em></span>',
42
r'<span class="diff-range">@@ \1 @@</span>',
44
r'<span class="diff-add">+\1</span>',
46
r'<span class="diff-sub">-\1</span>',
48
r'<span class="diff-special">\\\1</span>'
52
output = re.compile(match, re.MULTILINE).sub(subs[match], output)
56
# Use a CGIRequest object to make the CGI environment look like the normal
57
# IVLE handler environment.
59
req = cgirequest.CGIRequest()
60
req.install_error_handler()
61
req.content_type = "text/html"
63
# Beginning of the page
64
req.write('<div id="ivle_padding">\n')
65
req.write('<h1>Diff</h1>\n')
40
67
# Default revisions
41
68
revs = [pysvn.Revision(x) for x in [pysvn.opt_revision_kind.base,
42
69
pysvn.opt_revision_kind.working]]
44
# Override revisions from argv.
45
for ri in range(len(sys.argv[2:4])):
46
r = ivle.svn.revision_from_string(sys.argv[2 + ri])
70
# Override revisions from query string
71
fields = req.get_fieldstorage()
72
field_r = fields.getlist("r")
73
for ri in range(len(field_r)):
74
r = ivle.svn.revision_from_string(field_r[ri])
50
78
# Attempt to get the diff for these revisons
52
svnclient = ivle.svn.create_auth_svn_client(username=ivle.conf.login,
53
password=ivle.conf.svn_pass)
54
svnclient.exception_style = 1
80
svnclient = pysvn.Client()
55
81
diff = svnclient.diff
57
# pysvn's diff tempfile behaviour changes with Subversion 1.6.x.
58
# < 1.6 wants a filename, >= 1.6 wants a directory.
59
if pysvn.svn_version > (1, 6):
62
tmp_path = '/tmp/svndiff'
64
diff_text = diff(tmp_path,
65
os.path.join('/home', sys.argv[1]),
82
diff_text = diff( '/tmp/svndiff',
83
os.path.join('/home', req.path),
69
print cjson.encode({'diff': diff_text.decode('utf-8')})
70
except pysvn.ClientError, e:
75
# See subversion/include/svn_error_codes.h.
76
# 150000: ERR_ENTRY_NOT_FOUND
77
# 155007: WC_NOT_DIRECTORY.
78
# 160013: FS_NOT_FOUND
79
# 200005: UNVERSIONED_RESOURCE
80
if code in (150000, 155007, 160013, 200005):
83
error = '%s (code %d)' % (error, code)
87
print cjson.encode({'error': error})
88
# Split up the udiff into individual files
89
diff_matcher = re.compile(
90
r'^Index: (.*)\n\=+\n((?:[^I].*\n)*)',re.MULTILINE
92
split_diff = diff_matcher.findall(diff_text)
95
for filediff in split_diff:
96
filename = filediff[0]
97
diffbody = htmlfy_diff(filediff[1])
98
req.write('<p><b>File:</b> %s</p>\n'
99
% cgi.escape(filename))
100
req.write('<pre class="diff">%s</pre>\n' % diffbody)
102
except pysvn._pysvn_2_5.ClientError, e:
103
req.write('<p><b>Error:</b></p>\n')
104
req.write('<pre class="diff">%s</pre>\n' % cgi.escape(str(e)))
106
req.write('</div>\n')