/stuff/changes/index.cgi
#!/usr/bin/env python
"""
index.cgi - Serve Changes
Author: Sean B. Palmer, inamidst.com
"""
import cgitb; cgitb.enable()
import sys, os, re, tarfile
import changes
r_month = re.compile(r'^\d{4}-\d{2}$')
def header(status=200, mime='text/html', other={}):
if status != 200:
print 'Status:', status
for (key, value) in other.iteritems():
print key + ':', value
print 'Content-Type:', mime
print
def template(mappings):
f = open('template.txt')
bytes = f.read()
f.close()
for (key, value) in mappings.iteritems():
bytes = bytes.replace('$' + key, value)
return bytes
def listMonths():
months = []
for month in changes.monthLogsBackwards():
if changes.monthExists(month):
months.append(month)
months = sorted(months)
def generator():
yield '<p>Access all of the archives:</p>'
yield ''
yield '<ul>'
oldyear = None
for month in months:
year = month[:4]
if year != oldyear:
if oldyear is not None:
yield '</li>'
yield '<li>' + year + ': '
if year == '2005':
yield '01 · 02 · 03 · 04 · 05 ·'
oldyear = year
else: yield ' · '
yield ' <a href="%s">%s</a>' % (month, month[-2:])
yield '</ul>'
return '\n'.join(generator()) + '\n'
def homepage(method, path, match):
header()
print template({
'title': 'Changes and Updates',
'changes': changes.latestAsHTML(15),
'months': listMonths()
})
def generateSummary(n=250):
oldmonth = None
for (day, time, message) in changes.genchanges(n):
month = day[:7]
if month != oldmonth:
if oldmonth is not None:
yield '</ul>'
yield '<h2>%s</h2>' % month
yield '<ul>'
oldmonth = month
link = '<a href="/changes/%s#T%s">%s</a>' % (day[:7], day, message)
yield '<li>%s</li>' % link
yield '</ul>'
def summary(method, path, match):
header()
msg = '<p>These are the 250 most recent change summaries:</p>\n\n'
print template({
'title': 'Change Summaries',
'changes': msg + '\n'.join(generateSummary()),
'months': listMonths()
})
def month(method, path, match, template=template):
header()
month = path[1:]
assert r_month.match(month)
print template({
'title': 'Changes and Updates for %s' % month,
'changes': changes.changesByMonth(month),
'months': ''
})
def diff(method, path, match):
filename = match.group(1)
lines = changes.getdiff(filename)
if lines is not False:
header(mime='text/plain')
for line in lines:
sys.stdout.write(line)
else:
header(status=404, mime='text/plain')
print "Not found:", filename
def diffget(method, path, match):
header()
hmm = match.group(1)
if len(hmm) > 1:
hmm = hmm.lstrip('/')
date, abspath = hmm.split('/', 1)
abspath = '/' + abspath
date = date.replace('T', ' ')
else: date, abspath = '', ''
print """
<form method="post">
<p><input type="text" name="date" value="%s" />
<input type="text" name="path" value="%s" />
<input type="submit" value="Get Diff" /></p>
</form>
""" % (date, abspath)
def diffpost(method, path, match):
import cgi
form = cgi.FieldStorage()
form.__call__ = lambda s: form[s].value
if form.has_key('date') and form.has_key('path'):
date = form('date').replace(' ', '-')
path = form('path').lstrip('/')
path = path.replace('_', '__')
path = path.replace('/', '_') + '.diff'
uri = '/changes/' + date + '-' + path
header(status=303, other={'Location': uri})
else: barf()
def head(method, path, match):
header()
def request():
method = os.environ['REQUEST_METHOD']
# Assume that the script is being mod_rewritten to
script = os.environ['SCRIPT_NAME']
script = '/'.join(script.split('/')[:-1])
requri = os.environ['REQUEST_URI']
assert requri.startswith(script)
path = requri[len(script):]
return method, path
def main():
# Get the method and path
method, path = request()
mappings = {
'GET /': homepage,
'GET /summary': summary,
'GET /(\d+-\d+)': month,
'GET /(\d+-\d+-\d+-.+\.diff)': diff,
'GET /diff(/.*)?': diffget,
'POST /diff': diffpost,
# 'HEAD /.*': head
}
for (pattern, dispatch) in mappings.iteritems():
patmethod, regexp = pattern.split(' ', 1)
r_path = re.compile(r'^%s$' % regexp)
if method == patmethod:
match = r_path.match(path)
if match:
dispatch(method, path, match)
break
else: barf()
if __name__=="__main__":
main()