The unified diff between revisions [92eb8752..] and [14e5fc76..] is displayed below. It can also be downloaded as a raw diff.
#
#
# add_file "urls.py"
# content [16a510f175f983e3853bc0d61029a95e59ae0bbe]
#
# patch "branchdiv.py"
# from [5fbaaeb9d3050ab0f510c34b4ccfe18e7fda89a1]
# to [49a419788c7b54eed260b770c7a89066da499c1f]
#
# patch "handlers.py"
# from [59c9ba315b35d9ffe2667872266876b511188802]
# to [fa13ff0c027a94aeec104c8b07f63d605ad78db4]
#
# patch "render.py"
# from [032026fe3b80f63a098218b7c77c90c4d7a2e518]
# to [c1223ddbb5396f63101b981838cd8296d0cc82ba]
#
# patch "viewmtn.py"
# from [a3a3446ad7ea43e0ff0ceb6daa04dac0b7719bae]
# to [6629b45724cc639d2555c41248ccadf35838b83e]
#
============================================================
--- urls.py 16a510f175f983e3853bc0d61029a95e59ae0bbe
+++ urls.py 16a510f175f983e3853bc0d61029a95e59ae0bbe
@@ -0,0 +1,60 @@
+# Copyright (C) 2005 Grahame Bowland <grahame@angrygoats.net>
+#
+# This program is made available under the GNU GPL version 2.0 or
+# greater. See the accompanying file COPYING for details.
+#
+# This program is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+# PURPOSE.
+
+from mtn import revision_re
+
+#
+# these are the same, regardless of which database the user wishes
+# to view. These handles do not receive a RequestContext instance
+# as their first argument.
+#
+common_urls = (
+ r'about', 'About',
+ r'help', 'Help',
+ r'robots.txt', 'RobotsTxt', ## FIXME needs o exclude per-db paths
+ r'mimeicon/([A-Za-z0-9][a-z0-9\-\+\.]*)/([A-Za-z0-9][a-z0-9\-\+\.]*)', 'MimeIcon',
+)
+
+#
+# all of these should have GET handler that takes a per-DB context as an argument.
+# They get a RequestContext instance as their first argument to methods, eg. GET
+#
+perdb_urls = (
+ r'', 'Index',
+ r'tags', 'Tags',
+ r'json/([A-Za-z]+)/(.*)', 'Json',
+
+ r'([a-zA-Z]/)?revision/browse/('+revision_re+')/(.*)', 'RevisionBrowse',
+ r'revision/browse/('+revision_re+')()', 'RevisionBrowse',
+ r'revision/diff/('+revision_re+')/with/('+revision_re+')', 'RevisionDiff',
+ r'revision/diff/('+revision_re+')/with/('+revision_re+')'+'/(.*)', 'RevisionDiff',
+ r'revision/rawdiff/('+revision_re+')/with/('+revision_re+')', 'RevisionRawDiff',
+ r'revision/rawdiff/('+revision_re+')/with/('+revision_re+')'+'/(.*)', 'RevisionRawDiff',
+ r'revision/file/('+revision_re+')/(.*)', 'RevisionFile',
+ r'revision/filechanges/()()('+revision_re+')/(.*)', 'RevisionFileChanges',
+ r'revision/filechanges/from/(\d+)/to/(\d+)/('+revision_re+')/(.*)', 'RevisionFileChanges',
+ r'revision/filechanges/rss/()()('+revision_re+')/(.*)', 'RevisionFileChangesRSS',
+ r'revision/filechanges/rss/from/(\d+)/to/(\d+)/('+revision_re+')/(.*)', 'RevisionFileChangesRSS',
+ r'revision/downloadfile/('+revision_re+')/(.*)', 'RevisionDownloadFile',
+ r'revision/info/('+revision_re+')', 'RevisionInfo',
+ r'revision/tar/('+revision_re+')', 'RevisionTar',
+ r'revision/graph/('+revision_re+')', 'RevisionGraph',
+
+ r'branch/changes/(.*)/from/(\d+)/to/(\d+)', 'HTMLBranchChanges',
+ r'branch/changes/([^/]+)()()', 'HTMLBranchChanges',
+ r'branch/changes/(.*)/from/(\d+)/to/(\d+)/rss', 'RSSBranchChanges',
+ r'branch/changes/([^/]+)()()/rss', 'RSSBranchChanges',
+ r'branch/tags/([^/]+)', 'Tags',
+
+ # let's make it possible to access any function on the head revision
+ # through this proxy method; it'll return a redirect to the head revision
+ # with the specified function
+ r'branch/(head)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead',
+ r'branch/(anyhead)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead',
+)
============================================================
--- branchdiv.py 5fbaaeb9d3050ab0f510c34b4ccfe18e7fda89a1
+++ branchdiv.py 49a419788c7b54eed260b770c7a89066da499c1f
@@ -8,14 +8,21 @@ from mk2 import MarkovChain
# PURPOSE.
from mk2 import MarkovChain
+import sys
+# it's hardly worth doing anything in this case..
+min_to_divide = 20
+
class BranchDivisions(object):
def __init__ (self):
self.divisions = None
def calculate_divisions (self, branches):
- if self.divisions != None:
+ if not self.divisions is None:
return
+ if len(branches) < 20:
+ self.divisions = []
+ return
chain = MarkovChain (2, join_token='.', cutoff_func=MarkovChain.log_chunkable)
for branch in branches:
chain.update (branch.name.split ('.'))
============================================================
--- handlers.py 59c9ba315b35d9ffe2667872266876b511188802
+++ handlers.py fa13ff0c027a94aeec104c8b07f63d605ad78db4
@@ -17,9 +17,8 @@ from fdo import sharedmimeinfo, iconthem
# FreeDesktop.org share mime info and icon theme specification
from fdo import sharedmimeinfo, icontheme
# Other bits of ViewMTN
-import mtn, common, syntax, release
+import mtn, common, syntax, release, branchdiv
from links import link, dynamic_join, static_join
-from branchdiv import BranchDivisions
from ancestry import ancestry_graph
from render import *
hq = cgi.escape
@@ -38,30 +37,15 @@ else:
raise e
else:
mimeicon = None
+
# Renderer, sort out template inheritance, etc, etc.
renderer = Renderer()
# Figure out branch divisions
-divisions = BranchDivisions ()
+divisions = branchdiv.BranchDivisions ()
-class ComparisonRev:
- def __init__(self, ops, revision):
- self.revision = revision
- self.certs = list(ops.certs(self.revision))
- self.date = None
- for cert in self.certs:
- if cert[4] == 'name' and cert[5] == 'date':
- self.date = common.parse_timecert(cert[7])
- def __repr__(self):
- return "ComparisonRev <%s>" % (repr(self.revision))
- def __cmp__(self, other):
- # irritating edge-case, heapq compares us to empty string if
- # there's only one thing in the list
- if not other: return 1
- return cmp(other.date, self.date)
-
class Index(object):
- def GET(self, ops):
- branches = list(ops.branches ())
+ def GET(self, ctxt):
+ branches = list(ctxt.ops.branches ())
divisions.calculate_divisions (branches)
def division_iter():
bitter = iter(branches)
@@ -99,9 +83,9 @@ class Tags(object):
renderer.render('about.html', page_title="About")
class Tags(object):
- def GET(self, ops, restrict_branch=None):
+ def GET(self, ctxt, restrict_branch=None):
# otherwise we couldn't use automate again..
- tags = list(ops.tags())
+ tags = list(ctxt.ops.tags())
if restrict_branch != None:
restrict_branch = mtn.Branch(restrict_branch)
def tag_in(tag):
@@ -116,7 +100,7 @@ class Tags(object):
tags.sort(lambda t1, t2: cmp(t1.name, t2.name))
def revision_ago(rev):
rv = ""
- for cert in ops.certs(rev):
+ for cert in ctxt.ops.certs(rev):
if cert[4] == 'name' and cert[5] == 'date':
revdate = common.parse_timecert(cert[7])
rv = common.ago(revdate)
@@ -128,6 +112,24 @@ class Changes(object):
renderer.render('help.html', page_title="Help")
class Changes(object):
+ class ComparisonRev:
+ def __init__(self, ops, revision):
+ self.revision = revision
+ self.certs = list(ops.certs(self.revision))
+ self.date = None
+ for cert in self.certs:
+ if cert[4] == 'name' and cert[5] == 'date':
+ self.date = common.parse_timecert(cert[7])
+ def __repr__(self):
+ return "ComparisonRev <%s>" % (repr(self.revision))
+ def __cmp__(self, other):
+ # irritating edge-case, heapq compares us to empty string if
+ # there's only one thing in the list
+ if not other:
+ return 1
+ return cmp(other.date, self.date)
+
+
def __get_last_changes(self, ops, start_from, parent_func, selection_func, n):
"""returns at least n revisions that are parents of the revisions in start_from,
ordered by time (descending). selection_func is called for each revision, and
@@ -146,7 +148,7 @@ class Changes(object):
result = []
revq = []
for rev in start_from:
- heapq.heappush(revq, ComparisonRev(ops, rev))
+ heapq.heappush(revq, Changes.ComparisonRev(ops, rev))
while len(result) < n:
# print >>sys.stderr, "start_revq state:", map(lambda x: (x.revision, x.date), revq)
# update based on the last result we output
@@ -155,7 +157,7 @@ class Changes(object):
for parent_rev in parents:
if parent_rev == None:
continue
- heapq.heappush(revq, ComparisonRev(ops, parent_rev))
+ heapq.heappush(revq, Changes.ComparisonRev(ops, parent_rev))
# try and find something we haven't already output in the heap
last_result = None
@@ -245,10 +247,10 @@ class Changes(object):
to_change)
return changed, new_starting_point
- def Branch_GET(self, ops, branch, from_change, to_change, template_name):
+ def Branch_GET(self, ctxt, branch, from_change, to_change, template_name):
branch = mtn.Branch(branch)
from_change, to_change, next_from, next_to, previous_from, previous_to = self.determine_bounds(from_change, to_change)
- changed, new_starting_point = self.branch_get_last_changes(ops, branch, from_change, to_change)
+ changed, new_starting_point = self.branch_get_last_changes(ctxt.ops, branch, from_change, to_change)
changed = changed[from_change:to_change]
if len(changed) != to_change - from_change:
next_from, next_to = None, None
@@ -263,7 +265,7 @@ class Changes(object):
previous_to=previous_to,
next_from=next_from,
next_to=next_to,
- display_revs=self.for_template(ops, changed))
+ display_revs=self.for_template(ctxt.ops, changed))
def file_get_last_changes(self, ops, from_change, to_change, revision, path):
def content_changed_fn(start_revision, start_path, in_revision, pathinfo):
@@ -291,9 +293,9 @@ class Changes(object):
to_change)
return changed, new_starting_point, pathinfo
- def File_GET(self, ops, from_change, to_change, revision, path, template_name):
+ def File_GET(self, ctxt, from_change, to_change, revision, path, template_name):
from_change, to_change, next_from, next_to, previous_from, previous_to = self.determine_bounds(from_change, to_change)
- changed, new_starting_point, pathinfo = self.file_get_last_changes(ops, from_change, to_change, revision, path)
+ changed, new_starting_point, pathinfo = self.file_get_last_changes(ctxt.ops, from_change, to_change, revision, path)
changed = changed[from_change:to_change]
if len(changed) != to_change - from_change:
next_from, next_to = None, None
@@ -309,15 +311,15 @@ class Changes(object):
previous_to=previous_to,
next_from=next_from,
next_to=next_to,
- display_revs=self.for_template(ops, changed, pathinfo=pathinfo, constrain_diff_to=revision))
+ display_revs=self.for_template(ctxt.ops, changed, pathinfo=pathinfo, constrain_diff_to=revision))
class HTMLBranchChanges(Changes):
- def GET(self, ops, branch, from_change, to_change):
- Changes.Branch_GET(self, ops, branch, from_change, to_change, "branchchanges.html")
+ def GET(self, ctxt, branch, from_change, to_change):
+ Changes.Branch_GET(self, ctxt, branch, from_change, to_change, "branchchanges.html")
class RSSBranchChanges(Changes):
- def GET(self, ops, branch, from_change, to_change):
- Changes.Branch_GET(self, ops, branch, from_change, to_change, "branchchangesrss.html")
+ def GET(self, ctxt, branch, from_change, to_change):
+ Changes.Branch_GET(self, ctxt, branch, from_change, to_change, "branchchangesrss.html")
class RevisionPage(object):
def get_fileid(self, ops, revision, filename):
@@ -344,27 +346,27 @@ class RevisionFileChanges(Changes, Revis
return rv
class RevisionFileChanges(Changes, RevisionPage):
- def GET(self, ops, from_change, to_change, revision, path):
+ def GET(self, ctxt, from_change, to_change, revision, path):
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
- Changes.File_GET(self, ops, from_change, to_change, revision, path, "revisionfilechanges.html")
+ Changes.File_GET(self, ctxt, from_change, to_change, revision, path, "revisionfilechanges.html")
class RevisionFileChangesRSS(Changes, RevisionPage):
- def GET(self, ops, from_change, to_change, revision, path):
+ def GET(self, ctxt, from_change, to_change, revision, path):
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
- Changes.File_GET(self, ops, from_change, to_change, revision, path, "revisionfilechangesrss.html")
+ Changes.File_GET(self, ctxt, from_change, to_change, revision, path, "revisionfilechangesrss.html")
class RevisionInfo(RevisionPage):
- def GET(self, ops, revision):
+ def GET(self, ctxt, revision):
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
- certs = ops.certs(revision)
- revisions = ops.get_revision(revision)
- output_png, output_imagemap = ancestry_graph(ops, revision)
+ certs = ctxt.ops.certs(revision)
+ revisions = ctxt.ops.get_revision(revision)
+ output_png, output_imagemap = ancestry_graph(ctxt.ops, revision)
if os.access(output_imagemap, os.R_OK):
imagemap = open(output_imagemap).read().replace('\\n', ' by ')
imageuri = dynamic_join('revision/graph/' + revision)
@@ -379,18 +381,18 @@ class RevisionDiff(RevisionPage):
revisions=revisions_for_template(revision, revisions))
class RevisionDiff(RevisionPage):
- def GET(self, ops, revision_from, revision_to, filename=None):
+ def GET(self, ctxt, revision_from, revision_to, filename=None):
revision_from = mtn.Revision(revision_from)
revision_to = mtn.Revision(revision_to)
- if not self.exists(ops, revision_from):
+ if not self.exists(ctxt.ops, revision_from):
return web.notfound()
- if not self.exists(ops, revision_to):
+ if not self.exists(ctxt.ops, revision_to):
return web.notfound()
if filename != None:
files = [filename]
else:
files = []
- diff = ops.diff(revision_from, revision_to, files)
+ diff = ctxt.ops.diff(revision_from, revision_to, files)
diff_obj = Diff(revision_from, revision_to, files)
renderer.render('revisiondiff.html',
page_title="Diff from %s to %s" % (revision_from.abbrev(), revision_to.abbrev()),
@@ -402,33 +404,33 @@ class RevisionRawDiff(RevisionPage):
files=files)
class RevisionRawDiff(RevisionPage):
- def GET(self, ops, revision_from, revision_to, filename=None):
+ def GET(self, ctxt, revision_from, revision_to, filename=None):
revision_from = mtn.Revision(revision_from)
revision_to = mtn.Revision(revision_to)
- if not self.exists(ops, revision_from):
+ if not self.exists(ctxt.ops, revision_from):
return web.notfound()
- if not self.exists(ops, revision_to):
+ if not self.exists(ctxt.ops, revision_to):
return web.notfound()
if filename != None:
files = [filename]
else:
files = []
- diff = ops.diff(revision_from, revision_to, files)
+ diff = ctxt.ops.diff(revision_from, revision_to, files)
web.header('Content-Type', 'text/x-diff')
for line in diff:
sys.stdout.write (line)
sys.stdout.flush()
class RevisionFile(RevisionPage):
- def GET(self, ops, revision, filename):
+ def GET(self, ctxt, revision, filename):
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
language = filename.rsplit('.', 1)[-1]
- fileid = RevisionPage.get_fileid(self, ops, revision, filename)
+ fileid = RevisionPage.get_fileid(self, ctxt.ops, revision, filename)
if not fileid:
return web.notfound()
- contents = ops.get_file(fileid)
+ contents = ctxt.ops.get_file(fileid)
mimetype = mimehelp.lookup(filename, '')
mime_to_template = {
'image/jpeg' : 'revisionfileimg.html',
@@ -453,15 +455,15 @@ class RevisionDownloadFile(RevisionPage)
contents=syntax.highlight(contents, language))
class RevisionDownloadFile(RevisionPage):
- def GET(self, ops, revision, filename):
+ def GET(self, ctxt, revision, filename):
web.header('Content-Disposition', 'attachment; filename=%s' % filename)
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
- fileid = RevisionPage.get_fileid(self, ops, revision, filename)
+ fileid = RevisionPage.get_fileid(self, ctxt.ops, revision, filename)
if not fileid:
return web.notfound()
- for idx, data in enumerate(ops.get_file(fileid)):
+ for idx, data in enumerate(ctxt.ops.get_file(fileid)):
if idx == 0:
mimetype = mimehelp.lookup(filename, data)
web.header('Content-Type', mimetype)
@@ -469,16 +471,16 @@ class RevisionTar(RevisionPage):
sys.stdout.flush()
class RevisionTar(RevisionPage):
- def GET(self, ops, revision):
+ def GET(self, ctxt, revision):
# we'll output in the USTAR tar format; documentation taken from:
# http://en.wikipedia.org/wiki/Tar_%28file_format%29
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
filename = "%s.tar" % revision
web.header('Content-Disposition', 'attachment; filename=%s' % filename)
web.header('Content-Type', 'application/x-tar')
- manifest = [stanza for stanza in ops.get_manifest_of(revision)]
+ manifest = [stanza for stanza in ctxt.ops.get_manifest_of(revision)]
# for now; we might want to come up with something more interesting;
# maybe the branch name (but there might be multiple branches?)
basedirname = revision
@@ -492,7 +494,7 @@ class RevisionTar(RevisionPage):
filename, fileid = stanza[1], stanza[3]
filecontents = cStringIO.StringIO()
filesize = 0
- for data in ops.get_file(fileid):
+ for data in ctxt.ops.get_file(fileid):
filesize += len(data)
filecontents.write(data)
ti = tarfile.TarInfo()
@@ -500,11 +502,11 @@ class RevisionTar(RevisionPage):
ti.mode, ti.type = 00600, tarfile.REGTYPE
ti.uid = ti.gid = 0
# determine the most recent of the content marks
- content_marks = [t[1] for t in ops.get_content_changed(revision, filename)]
+ content_marks = [t[1] for t in ctxt.ops.get_content_changed(revision, filename)]
if len(content_marks) > 0:
# just pick one to make this faster
content_mark = content_marks[0]
- since_epoch = timecert(ops.certs(content_mark)) - datetime.datetime.fromtimestamp(0)
+ since_epoch = timecert(ctxt.ops.certs(content_mark)) - datetime.datetime.fromtimestamp(0)
ti.mtime = since_epoch.days * 24 * 60 * 60 + since_epoch.seconds
else:
ti.mtime = 0
@@ -513,12 +515,12 @@ class RevisionBrowse(RevisionPage):
tarobj.addfile(ti, filecontents)
class RevisionBrowse(RevisionPage):
- def GET(self, ops, revision, path):
+ def GET(self, ctxt, revision, path):
revision = mtn.Revision(revision)
- if not self.exists(ops, revision):
+ if not self.exists(ctxt.ops, revision):
return web.notfound()
- branches = RevisionPage.branches_for_rev(self, ops, revision)
- revisions = ops.get_revision(revision)
+ branches = RevisionPage.branches_for_rev(self, ctxt.ops, revision)
+ revisions = ctxt.ops.get_revision(revision)
def components(path):
# NB: mtn internally uses '/' for paths, so we shouldn't use os.path.join()
@@ -553,7 +555,7 @@ class RevisionBrowse(RevisionPage):
page_title += " of %s %s" % (branch_plural, ', '.join(branches))
def cut_manifest_to_subdir():
- manifest = list(ops.get_manifest_of(revision))
+ manifest = list(ctxt.ops.get_manifest_of(revision))
in_the_dir = False
for stanza in manifest:
stanza_type = stanza[0]
@@ -593,7 +595,7 @@ class RevisionBrowse(RevisionPage):
if not certs.has_key(revision):
# subtle bug slipped in here; ops.cert() is a generator
# so we can't just store it in a cache!
- certs[revision] = list(ops.certs(revision))
+ certs[revision] = list(ctxt.ops.certs(revision))
return certs[revision]
def _get_certinfo(revision):
@@ -619,7 +621,7 @@ class RevisionBrowse(RevisionPage):
for stanza_type, this_path in entry_iter:
# determine the most recent of the content marks
- content_marks = [t[1] for t in ops.get_content_changed(revision, this_path)]
+ content_marks = [t[1] for t in ctxt.ops.get_content_changed(revision, this_path)]
for mark in content_marks:
get_cert(mark)
if len(content_marks):
@@ -664,8 +666,8 @@ class RevisionGraph(object):
entries=info_for_manifest(cut_manifest_to_subdir()))
class RevisionGraph(object):
- def GET(self, ops, revision):
- output_png, output_imagemap = ancestry_graph(ops, revision)
+ def GET(self, ctxt, revision):
+ output_png, output_imagemap = ancestry_graph(ctxt.ops, revision)
if os.access(output_png, os.R_OK):
web.header('Content-Type', 'image/png')
sys.stdout.write(open(output_png).read())
@@ -683,13 +685,13 @@ class Json(object):
revdate = common.parse_timecert(cert[7])
rv['ago'] = common.ago(revdate)
- def BranchLink(self, ops, for_branch):
+ def BranchLink(self, ctxt, for_branch):
rv = {
'type' : 'branch',
'branch' : for_branch,
}
branch = mtn.Branch(for_branch)
- changes, new_starting_point = Changes().branch_get_last_changes(ops, branch, 0, 1)
+ changes, new_starting_point = Changes().branch_get_last_changes(ctxt.ops, branch, 0, 1)
if len(changes) < 1:
return web.notfound()
if not changes:
@@ -699,34 +701,34 @@ class Json(object):
self.fill_from_certs(rv, certs)
return rv
- def RevisionLink(self, ops, revision_id):
+ def RevisionLink(self, ctxt, revision_id):
rv = {
'type' : 'revision',
'revision_id' : revision_id,
}
rev = mtn.Revision(revision_id)
- certs = ops.certs(rev)
+ certs = ctxt.ops.certs(rev)
self.fill_from_certs(rv, certs)
return rv
- def GET(self, ops, method, encoded_args):
+ def GET(self, ctxt, method, encoded_args):
writer = json.JsonWriter()
if not encoded_args.startswith('js_'):
return web.notfound()
args = json.read(binascii.unhexlify((encoded_args[3:])))
if hasattr(self, method):
- rv = getattr(self, method)(ops, *args)
+ rv = getattr(self, method)(ctxt, *args)
else:
return web.notfound()
print writer.write(rv)
class BranchHead(object):
- def GET(self, ops, head_method, proxy_to, branch, extra_path):
+ def GET(self, ctxt, head_method, proxy_to, branch, extra_path):
branch = mtn.Branch(branch)
valid = ('browse', 'file', 'downloadfile', 'info', 'tar', 'graph')
if not proxy_to in valid:
return web.notfound()
- heads = [head for head in ops.heads(branch.name)]
+ heads = [head for head in ctxt.ops.heads(branch.name)]
if len(heads) == 0:
return web.notfound()
def proxyurl(revision):
@@ -740,7 +742,7 @@ class BranchHead(object):
head_links = []
for revision in heads:
author, date = '', ''
- for cert in ops.certs(revision):
+ for cert in ctxt.ops.certs(revision):
if cert[4] == 'name' and cert[5] == 'date':
date = cert[7]
elif cert[4] == 'name' and cert[5] == 'author':
============================================================
--- render.py 032026fe3b80f63a098218b7c77c90c4d7a2e518
+++ render.py c1223ddbb5396f63101b981838cd8296d0cc82ba
@@ -8,7 +8,7 @@ import cgi, urllib, web
# PURPOSE.
import cgi, urllib, web
-import mtn, release, config
+import mtn, release, config, common
from links import link, dynamic_join, static_join
hq = cgi.escape
============================================================
--- viewmtn.py a3a3446ad7ea43e0ff0ceb6daa04dac0b7719bae
+++ viewmtn.py 6629b45724cc639d2555c41248ccadf35838b83e
@@ -11,21 +11,24 @@ from itertools import izip, chain, repea
import os, sys
from itertools import izip, chain, repeat
-# web.py
import web
-# Other bits of ViewMTN
import mtn, handlers
-# The user configuration file
+from urls import common_urls, perdb_urls
import config
-debug = web.debug
-
# purloined from: http://docs.python.org/lib/itertools-recipes.html
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
-class OperationsFactory(object):
+class RequestContext(object):
+ def __init__ (self, dbname, ops):
+ self.dbname, self.ops = dbname, ops
+ # make sure that any unread automate output is flushed away
+ if not ops is None:
+ ops.per_request()
+
+class RequestContextFactory(object):
def __init__ (self):
# has the user specified a dbfiles hash? if so, use it
self.ops_instances = {}
@@ -39,64 +42,14 @@ class OperationsFactory(object):
self.ops_instances["legacy"] = mtn.Operations([config.monotone, config.dbfile])
self.default = "legacy"
- def get_ops(self, name):
- ops = None
+ def __getitem__(self, name):
if name is None:
ops = self.ops_instances.get (self.default, None)
else:
name = name.rstrip('/')
ops = self.ops_instances.get (name, None)
- # technically it'd be better to do this before serving the
- # request, however this is about the only per-request
- # spot that runs for every handler..
- if not ops is None:
- ops.per_request()
- return ops
+ return RequestContext(name, ops)
-op_fact = OperationsFactory()
-
-common_urls = (
-# these don't care about multiple databases specified via the URL
- r'about', 'About',
- r'help', 'Help',
- r'robots.txt', 'RobotsTxt', ## FIXME needs o exclude per-db paths
- r'mimeicon/([A-Za-z0-9][a-z0-9\-\+\.]*)/([A-Za-z0-9][a-z0-9\-\+\.]*)', 'MimeIcon',
-)
-
-perdb_urls = (
- r'', 'Index',
- r'tags', 'Tags',
- r'json/([A-Za-z]+)/(.*)', 'Json',
-
- r'([a-zA-Z]/)?revision/browse/('+mtn.revision_re+')/(.*)', 'RevisionBrowse',
- r'revision/browse/('+mtn.revision_re+')()', 'RevisionBrowse',
- r'revision/diff/('+mtn.revision_re+')/with/('+mtn.revision_re+')', 'RevisionDiff',
- r'revision/diff/('+mtn.revision_re+')/with/('+mtn.revision_re+')'+'/(.*)', 'RevisionDiff',
- r'revision/rawdiff/('+mtn.revision_re+')/with/('+mtn.revision_re+')', 'RevisionRawDiff',
- r'revision/rawdiff/('+mtn.revision_re+')/with/('+mtn.revision_re+')'+'/(.*)', 'RevisionRawDiff',
- r'revision/file/('+mtn.revision_re+')/(.*)', 'RevisionFile',
- r'revision/filechanges/()()('+mtn.revision_re+')/(.*)', 'RevisionFileChanges',
- r'revision/filechanges/from/(\d+)/to/(\d+)/('+mtn.revision_re+')/(.*)', 'RevisionFileChanges',
- r'revision/filechanges/rss/()()('+mtn.revision_re+')/(.*)', 'RevisionFileChangesRSS',
- r'revision/filechanges/rss/from/(\d+)/to/(\d+)/('+mtn.revision_re+')/(.*)', 'RevisionFileChangesRSS',
- r'revision/downloadfile/('+mtn.revision_re+')/(.*)', 'RevisionDownloadFile',
- r'revision/info/('+mtn.revision_re+')', 'RevisionInfo',
- r'revision/tar/('+mtn.revision_re+')', 'RevisionTar',
- r'revision/graph/('+mtn.revision_re+')', 'RevisionGraph',
-
- r'branch/changes/(.*)/from/(\d+)/to/(\d+)', 'HTMLBranchChanges',
- r'branch/changes/([^/]+)()()', 'HTMLBranchChanges',
- r'branch/changes/(.*)/from/(\d+)/to/(\d+)/rss', 'RSSBranchChanges',
- r'branch/changes/([^/]+)()()/rss', 'RSSBranchChanges',
- r'branch/tags/([^/]+)', 'Tags',
-
- # let's make it possible to access any function on the head revision
- # through this proxy method; it'll return a redirect to the head revision
- # with the specified function
- r'branch/(head)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead',
- r'branch/(anyhead)/([A-Za-z]+)/([^/]+)(.*)', 'BranchHead',
-)
-
def runfcgi_apache(func):
web.wsgi.runfcgi(func, None)
@@ -112,7 +65,9 @@ if __name__ == '__main__':
def assemble_urls():
fvars = {}
urls = ()
-
+
+ factory = RequestContextFactory()
+
for url, fn in grouper (2, common_urls):
url = r'^/' + url
if hasattr(handlers, fn):
@@ -125,7 +80,7 @@ if __name__ == '__main__':
class PerDBClosure(object):
def GET (self, *args, **kwargs):
db, other_args = args[0], args[1:]
- ops = op_fact.get_ops (db)
+ ops = factory[db]
if ops is None:
return web.notfound()
return handler.GET (ops, *other_args, **kwargs)