At the bottom of this page are two Python scripts, history.cgi and diff.cgi. These are CGI scripts that pull data from the C2 wiki and generate a somewhat friendly history listing and version diff, respectively. To use them,
Observations
Samples
You can see a sample snapshot of history.cgi at http://andstuff.org/wiki/history.html?WardCunningham. The "Compare" button for the snapshot is hard-wired to a comparison of revisions 688 and 689, which shows some of the capabilities of the color-coded diff (borrowed from JotEngine and MoinMoin).
history.cgi
#!/usr/bin/python
# This script is public domain
import urllib
import os
import re
try :
page = os.environ['QUERY_STRING']
except :
page = ""
if page == "" :
print "Content-type: text/plain"
print
print "Please indicate a page name"
exit()
stream = urllib.urlopen('http://c2.com/wiki/history/' + page)
history = stream.read()
stream.close()
stream = urllib.urlopen('http://c2.com/cgi/quickDiff?' + page)
diff = stream.read()
stream.close()
versions = []
re.sub(r'(HREF="(\d+)">\d+ +([-0-9A-Za-z]+ [0-9:]+))', lambda match: versions.insert(0, [int(match.group(2)), match.group(3), "http://c2.com/wiki/history/" + page + '/' + match.group(2)]), history)
re.sub(r'(Revision (\d+) made ([0-9]+ [a-z]+ ago))', lambda match: versions.insert(0, [int(match.group(2)), match.group(3), "http://c2.com/cgi/wiki?" + page]), diff)
versions.sort()
versions.reverse()
print "Content-type: text/html"
print
print "History of " + page + " "
print "History of " + page + "
"
print ""
print ""
diff.cgi
#!/usr/bin/python
# This script is public domain.
import re
import cgi, cgitb; cgitb.enable()
import urllib
def getcur(page) :
stream = urllib.urlopen('http://c2.com/cgi/wiki?edit=' + page)
text = stream.read()
stream.close()
match = re.search(r'', text, re.DOTALL)
if match is None : result = ""
else : result = match.group(1)
result = result.replace('<', '<')
result = result.replace('>', '>')
result = result.replace('"', '"')
result = result.replace('&', '&')
return result
def diff(s1, s2) :
from difflib import SequenceMatcher
s1 = s1.replace('&', '&')
s1 = s1.replace('<', '<')
s2 = s2.replace('&', '&')
s2 = s2.replace('<', '<')
seq1 = s1.splitlines()
seq2 = s2.splitlines()
seqobj = SequenceMatcher(None, seq1, seq2)
linematch = seqobj.get_matching_blocks()
if len(seq1) == len(seq2) and linematch[0] == (0, 0, len(seq1)) : # No differences.
return 'No differences.'
lastmatch = (0, 0)
end = (len(seq1), len(seq2))
result = "\n"
for match in linematch : # Print all differences.
if lastmatch == match[0:2] : # Starts of pages identical.
lastmatch = (match[0] + match[2], match[1] + match[2])
continue
result = result + "" + "Line " + str(lastmatch[0] + 1) + ", removed:" + " " + "Line " + str(lastmatch[1] + 1) + ", added:" + " \n"
leftpane = ""
rightpane = ""
linecount = max(match[0] - lastmatch[0], match[1] - lastmatch[1])
for line in range(linecount) :
if line < match[0] - lastmatch[0] :
if line > 0 :
leftpane += '\n'
leftpane += seq1[lastmatch[0] + line]
if line < match[1] - lastmatch[1] :
if line > 0 :
rightpane += '\n'
rightpane += seq2[lastmatch[1] + line]
charobj = SequenceMatcher(None, leftpane, rightpane)
charmatch = charobj.get_matching_blocks()
if leftpane == "" and rightpane == "" :
ratio = 1.0
else :
ratio = charobj.ratio()
if ratio < 0.5 : # Insufficient similarity.
if len(leftpane) != 0 :
leftresult = "" + leftpane + ""
else :
leftresult = ""
if len(rightpane) != 0 :
rightresult = "" + rightpane + ""
else :
rightresult = ""
else : # Some similarities; markup changes.
charlast = (0, 0)
charend = (len(leftpane), len(rightpane))
leftresult = ""
rightresult = ""
for thismatch in charmatch :
if thismatch[0] - charlast[0] != 0 :
leftresult = leftresult + "" + leftpane[charlast[0]:thismatch[0]] + ""
if thismatch[1] - charlast[1] != 0 :
rightresult = rightresult + "" + rightpane[charlast[1]:thismatch[1]] + ""
leftresult = leftresult + leftpane[thismatch[0]:thismatch[0] + thismatch[2]]
rightresult = rightresult + rightpane[thismatch[1]:thismatch[1] + thismatch[2]]
charlast = (thismatch[0] + thismatch[2], thismatch[1] + thismatch[2])
leftpane = leftresult.replace('\n', '
\n')
rightpane = rightresult.replace('\n', '
\n')
result = result + "" + leftpane + " " + rightpane + " \n"
lastmatch = (match[0] + match[2], match[1] + match[2])
result = result + '
\n'
return result
form = cgi.FieldStorage()
page = form.getfirst('page', "")
v1 = form.getfirst('v1', "")
v2 = form.getfirst('v2', "")
stream = urllib.urlopen('http://c2.com/wiki/history/' + page + '/' + v1)
v1 = stream.read()
stream.close()
stream = urllib.urlopen('http://c2.com/wiki/history/' + page + '/' + v2)
v2 = stream.read()
stream.close()
if not re.search(r'404 Not Found ', v1) is None : v1 = getcur(page)
if not re.search(r'404 Not Found ', v2) is None : v2 = getcur(page)
print "Content-type: text/html"
print
print "Differences for " + page + " "
print "Differences for " + page + "
"
print diff(v1, v2)
print ""