# # # patch "config.py" # from [873667db24c6715f19d6a23c9c39b46d42b3b2af] # to [ec1da48608a688595fedb41cf4600a3d9d0699e7] # # patch "monotone.py" # from [db94b133c60582cc38327251327147bcf5f2f461] # to [bbcdd36f0094c2e02895fa0aaa28ddf97fe51b3d] # # patch "revision.psp" # from [65c3b846ff13c46662f9ed4f1aafb3017181e354] # to [3dc4b749e678a9c194796deccb322c3ed0338c2b] # ============================================================ --- config.py 873667db24c6715f19d6a23c9c39b46d42b3b2af +++ config.py ec1da48608a688595fedb41cf4600a3d9d0699e7 @@ -1,7 +1,9 @@ import sys sys.path.append('/home/grahame/monotone/goatpy') monotone = '/opt/monotone/bin/monotone' dbfile = '/home/grahame/public_html/viewmtn/viewmtn.db' +graphdir = '/home/grahame/public_html/viewmtn/graph/' +graphuri = 'graph/' ============================================================ --- monotone.py db94b133c60582cc38327251327147bcf5f2f461 +++ monotone.py bbcdd36f0094c2e02895fa0aaa28ddf97fe51b3d @@ -1,7 +1,10 @@ from goatpy import utility +import urllib import pipes +import sets import re +import os # # a python wrapper for the "monotone" command @@ -113,6 +116,39 @@ entry[attr].append(value) if entry: rv.append(entry) return rv + def ancestry_graph(self, graphdir, graphuri, id, limit=0): + rv = { + 'dot_file' : os.path.join(graphdir, id + ".dot"), + 'image_file' : os.path.join(graphdir, id + ".png"), + 'imagemap_file' : os.path.join(graphdir, id + ".html"), + 'dot_uri' : "%s/%s.dot" % (graphuri, urllib.quote(id)), + 'image_uri' : "%s/%s.png" % (graphuri, urllib.quote(id)), + 'imagemap_uri' : "%s/%s.html" % (graphuri, urllib.quote(id)), + } + missing = filter(lambda x: x != True, map(lambda x: os.access(x, os.R_OK), rv.values())) + if len(missing) == 0: + rv['cached'] = True + return rv + contents = """ + graph ancestry { + """ + revisions = sets.Set() + for attrs in self.ancestry(id, limit): + if not attrs.has_key("Revision") or not attrs.has_key("Ancestor"): + continue + revision = attrs['Revision'][0] + revisions.add(revision) + for ancestor in attrs['Ancestor']: + if len(ancestor) == 0: continue + revisions.add(ancestor) + contents += '"%s"--"%s"\n' % (revision, ancestor) + for revision in revisions: + contents += '"%s" [fontsize=8,shape=square,href="revision.psp?id=%s"]\n' % (revision, urllib.quote(revision)) + contents += "}\n" + open(rv['dot_file'], 'w').write(contents) + os.system("/usr/bin/dot -Tcmapx -o %s -Tpng -o %s %s" % (pipes.quote(rv['imagemap_file']), rv['image_file'], rv['dot_file'])) + rv['cached'] = False + return rv def is_valid_id(s): return len(s) == 40 and id_re.match(s) != None ============================================================ --- revision.psp 65c3b846ff13c46662f9ed4f1aafb3017181e354 +++ revision.psp 3dc4b749e678a9c194796deccb322c3ed0338c2b @@ -8,6 +8,7 @@ from template import header,footer from monotone import Monotone +reload(config) reload(common) reload(template) reload(monotone) @@ -31,20 +32,25 @@ info = {'title' : "Revision %s" % (hq(id))} req.write(header(info)) +ancestry_graph = mt.ancestry_graph(config.graphdir, config.graphuri, id, 20) +req.write(open(ancestry_graph['imagemap_file']).read()) + %> +Ancestry of <%= hq(id) %> +

Certificates

- <% certs = mt.certs(id) for cert in certs: %> - - - + + <% @@ -53,6 +59,10 @@

Revision details

+

+Not yet implemented. Feel like writing a parser for monotone cat revision? :-) +

+ <% revision = mt.revision(id) %>
Signed byNameValue
<%="%s (%s)" % (hq(cert.get('Key', '')), hq(cert.get('Sig', '')))%><%=hq(cert.get("Name", ''))%><%=hq(cert.get("Value", ''))%><%=hq(cert.get("Name", ''))%> + <%=hq(cert.get("Value", ''))%>