# # # patch "common.py" # from [1bbdf3b52720be34cf84c878bc04cd35ac0a6b28] # to [dee058e73c68b381c4c9c4343fc7d74e3b26479e] # # patch "mtn.py" # from [bfdcd3f284ef8508f44fc96f3ae2c54aa5809b61] # to [93ca32757dbb55233d8215aedfc6c155432f3d02] # # patch "templates/branchchanges.html" # from [40fd79c1afb1a371288d26707f8592115dc09e36] # to [bab70162c2dd25a6eb276b7dc09933527b4131fd] # # patch "viewmtn.py" # from [1001ee02e7b1f4554682a8cc0544e161deff6fde] # to [a2ea5c28701ff9a4d9f2ff0e9023640dc667fc8a] # ============================================================ --- common.py 1bbdf3b52720be34cf84c878bc04cd35ac0a6b28 +++ common.py dee058e73c68b381c4c9c4343fc7d74e3b26479e @@ -25,13 +25,6 @@ def terminate_popen3(process): except: debug("%s failed_to_stop %s" % (os.getpid(), process.pid)) -def quicklog(value): - hq = html_escape() - rv = hq(value.strip().split('\n')[0]) - if rv.startswith('*'): - rv = rv[1:].strip() - return rv - def ago(event): def plural(v, singular, plural): if v == 1: ============================================================ --- mtn.py bfdcd3f284ef8508f44fc96f3ae2c54aa5809b61 +++ mtn.py 93ca32757dbb55233d8215aedfc6c155432f3d02 @@ -312,6 +312,25 @@ class Operations: for line in self.automate.run('graph', []): yield line + def parents(self, revision): + if revision != "": + for line in (t.strip() for t in self.automate.run('parents', [revision])): + if not line: + continue + yield apply(Revision, (line,)) + + def toposort(self, revisions): + for line in (t.strip() for t in self.automate.run('toposort', revisions)): + if not line: + continue + yield apply(Revision, (line,)) + + def heads(self, branch): + for line in (t.strip() for t in self.automate.run('heads', [branch])): + if not line: + continue + yield apply(Revision, (line,)) + def get_revision(self, revision): for stanza in basic_io_from_stream(self.automate.run('get_revision', [revision])): yield stanza ============================================================ --- templates/branchchanges.html 40fd79c1afb1a371288d26707f8592115dc09e36 +++ templates/branchchanges.html bab70162c2dd25a6eb276b7dc09933527b4131fd @@ -1,7 +1,41 @@ #extends branch #def body -Woo, changes. +

+Displaying topologically sorted log of changes (estimated as being changes 1 - 10)
+

+ + +#for $revision, $diffs, $ago, $author, $changelog, $shortlog, $when in $display_revs + + + + + + + + + + + + +#end for + +
+ $ago ago: $shortlog
+#filter Filter + + $link($revision).html("revision info") | + $link($revision, "browse").html("browse files") + $diffs + +#filter WebSafe +
Author:$author
Changelog: +#filter Filter +
$changelog
+#filter WebSafe +
Date:$when
+ #end def ============================================================ --- viewmtn.py 1001ee02e7b1f4554682a8cc0544e161deff6fde +++ viewmtn.py a2ea5c28701ff9a4d9f2ff0e9023640dc667fc8a @@ -40,17 +40,26 @@ class Link: static_join = lambda path: urlparse.urljoin(config.static_uri_path, path) class Link: - def __init__(self, description=None): + def __init__(self, description=None, link_type=None): self.relative_uri = None self.description = description - def html(self): + def html(self, override_description=None): + if override_description: + d = hq(override_description) + else: + d = self.description return '%s' % (dynamic_join(self.relative_uri), - self.description) + d) class RevisionLink(Link): def __init__(self, revision, **kwargs): + link_type = kwargs.get("link_type") + if link_type == "browse": + subpage = "browse" + else: + subpage = "info" Link.__init__(*(self, ), **kwargs) - self.relative_uri = 'revision/info/%s' % (revision) + self.relative_uri = 'revision/%s/%s' % (subpage, revision) self.description = revision.abbrev() class TagLink(Link): @@ -170,11 +179,11 @@ type_to_link_class = { 'tag' : TagLink, } -def link(obj): +def link(obj, link_type=None): link_class = type_to_link_class.get(obj.obj_type) if not link_class: raise LinkException("Unable to link to objects of type: '%s'" % (obj.obj_type)) - return link_class(obj) + return link_class(obj, link_type=link_type) class Renderer: def __init__(self): @@ -234,16 +243,83 @@ class BranchChanges: renderer.render('help.html', page_title="Help") class BranchChanges: - def GET(self, branch): + def get_last_changes(self, branch, start_at, count): + if len(start_at) == 0: + revs = map(None, ops.heads(branch.name)) + else: + revs = start_at + if len(revs) == 0: + raise Exception("get_last_changes() unable to find somewhere to start!") + to_parent = revs+[] # copy + while len(revs) < count: + new_to_parent = [] + for rev in to_parent: + new_to_parent += ops.parents(rev) + if len(new_to_parent) == 0: + # out of revisions... + break + to_parent = new_to_parent + revs += new_to_parent +# toposort seems pretty darn slow; let's avoid this one.. +# revs = map(None, ops.toposort(revs))[:count] + certs_for_revs = [] + for rev in revs: + certs_for_revs.append((rev, map(None, ops.certs(rev)))) + def cd(certs): + for cert in certs: + if cert[4] == 'name' and cert[5] == 'date': + return common.parse_timecert(cert[7]) + return None + certs_for_revs.sort(lambda b, a: cmp(cd(a[1]), cd(b[1]))) + return certs_for_revs[:count], new_to_parent + + def GET(self, branch, start_at=[], old_start_at=[]): + def quicklog(changelog): + rv = changelog[0].strip() + if rv.startswith('*'): + rv = rv[1:].strip() + return rv + def for_template(revs): + rv = [] + for rev, certs in revs: + rev_branch = "" + revision, diffs, ago, author, changelog, shortlog, when = mtn.Revision(rev), [], "", "", "", "", "" + for cert in certs: + if cert[4] != 'name': + continue + if cert[5] == "branch": + rev_branch = cert[7] + elif cert[5] == 'date': + when = cert[7] + revdate = common.parse_timecert(when) + ago = common.ago(revdate) + elif cert[5] == 'author': + author = cert[7] + elif cert[5] == 'changelog': + changelog = map(hq, cert[7].split('\n')) + if changelog and changelog[-1] == '': + changelog = changelog[:-1] + shortlog = quicklog(changelog) + if rev_branch != branch.name: + # yikes, fallen down a well + continue + for stanza in ops.get_revision(rev): + if stanza and stanza[0] == "old_revision": + old_revision = stanza[1] + diffs.append(Diff(mtn.Revision(old_revision), revision)) + if diffs: + diffs = '| ' + ', '.join(map(lambda d: link(d).html('diff'), diffs)) + else: + diffs = '' + rv.append((revision, diffs, ago, author, '\n'.join(changelog), shortlog, when)) + return rv branch = mtn.Branch(branch) + changed, new_starting_point = self.get_last_changes(branch, start_at, 10) renderer.render('branchchanges.html', - page_title="Branch %s" % branch, - branch=branch) + page_title="Branch %s" % branch.name, + branch=branch, + display_revs=for_template(changed)) -class RevisionBrowse: - def GET(self, revision): - print "not implemented..." - class RevisionInfo: def GET(self, revision): revision = mtn.Revision(revision) @@ -326,7 +402,7 @@ urls = ( '/revision/info/('+mtn.revision_re+')', 'RevisionInfo', '/revision/tar/('+mtn.revision_re+')', 'RevisionTar', - '/branch/changes/(.*)', 'BranchChanges', + '/branch/changes/(.*)()()', 'BranchChanges', '/branch/head/(.*)', 'BranchHead', '/branch/tar/(.*)', 'BranchTar', '/static/(.*)', 'Static'