# # # add_file "templates/revisionbrowse.html" # content [45348e21f3fc76b5cfa945ec4be8fbba1af7a267] # # patch "viewmtn.py" # from [88e9dbedf9327ae01d3866eac3769733b9197efc] # to [5c41506fafddfc5f74233a652edda92f89be421e] # ============================================================ --- templates/revisionbrowse.html 45348e21f3fc76b5cfa945ec4be8fbba1af7a267 +++ templates/revisionbrowse.html 45348e21f3fc76b5cfa945ec4be8fbba1af7a267 @@ -0,0 +1,50 @@ +#extends revision + +#def body + +#filter Filter +

+Path [$path] in revision $link($revision).html() +#if len($branches) == 1 +of branch +#end if +#if len($branches) > 1 +of branches +#end if +#if $branches +$branch_links +#end if +

+#filter WebSafe + + + +#for $stanza_type, $this_path, $author, $ago, $content_mark, $shortlog in $entries + + + + + + + +#end for +
NameAgeAuthorLast log entry
+ + + #filter Filter + $link($this_path).html() + #filter WebSafe + + #if $content_mark + #filter Filter + $link($content_mark).html($ago, True) + #filter WebSafe + #end if + + #filter Filter + $author + #filter WebSafe + $shortlog +
+ +#end def ============================================================ --- viewmtn.py 88e9dbedf9327ae01d3866eac3769733b9197efc +++ viewmtn.py 5c41506fafddfc5f74233a652edda92f89be421e @@ -52,6 +52,9 @@ def quicklog(changelog): interesting_line = interesting_line[1:].strip() return interesting_line +def nbhq(s): + return ' '.join([hq(t) for t in s.split(' ')]) + def normalise_changelog(changelog): changelog = map(hq, changelog.split('\n')) if changelog and changelog[-1] == '': @@ -64,9 +67,12 @@ class Link: self.description = description def uri(self): return dynamic_join(self.relative_uri) - def html(self, override_description=None): + def html(self, override_description=None, force_nbsp=False): if override_description: - d = hq(override_description) + if force_nbsp: + d = nbhq(override_description) + else: + d = hq(override_description) else: d = self.description return '%s' % (dynamic_join(self.relative_uri), @@ -329,7 +335,7 @@ class BranchChanges: elif cert[5] == 'author': author = cert[7] elif cert[5] == 'changelog': - changelog = normalised_changelog(cert[7]) + changelog = normalise_changelog(cert[7]) shortlog = quicklog(changelog) if rev_branch != branch.name: # yikes, fallen down a well @@ -451,14 +457,7 @@ class RevisionBrowse(RevisionPage): revision = mtn.Revision(revision) branches = RevisionPage.branches_for_rev(self, revision) revisions = ops.get_revision(revision) - page_title = "Browsing revision %s [%s]" % (revision.abbrev(), path or '') - if len(branches) > 0: - if len(branches) == 1: - branch_plural = 'branch' - else: - branch_plural = 'branches' - page_title += " of %s %s" % (branch_plural, ', '.join(branches)) - + def components(path): # NB: mtn internally uses '/' for paths, so we shouldn't use os.path.join() # we should do things manually; otherwise we'll break on other platforms @@ -477,11 +476,20 @@ class RevisionBrowse(RevisionPage): rv.append(pc[0]) path = '' return rv - + + path = path or "" path_components = components(path) normalised_path = '/'.join(path_components) # TODO: detect whether or not this exists and skip the following if it doesn't. + page_title = "Browsing revision %s [%s]" % (revision.abbrev(), normalised_path or '') + if len(branches) > 0: + if len(branches) == 1: + branch_plural = 'branch' + else: + branch_plural = 'branches' + page_title += " of %s %s" % (branch_plural, ', '.join(branches)) + def cut_manifest_to_subdir(): manifest = map(None, ops.get_manifest_of(revision)) in_the_dir = False @@ -496,33 +504,42 @@ class RevisionBrowse(RevisionPage): in_the_dir = True continue - # debug(["inthedir", stanza_type, this_path]) this_path_components = components(this_path) + # debug(["inthedir", stanza_type, this_path, len(this_path_components), len(path_components)]) if stanza_type == "dir": - if len(this_path_components) == len(path_components) + 1 and \ + # are we still in our directory? + if len(this_path_components) > len(path_components) and \ this_path_components[:len(path_components)] == path_components: - yield (stanza_type, this_path) + # is this an immediate subdirectory of our directory? + if len(this_path_components) == len(path_components) + 1: + yield (stanza_type, this_path) else: in_the_dir = False # and we've come out of the dir ne'er to re-enter, so.. break - elif stanza_type == "file" and len(this_path_components) == len(path_components): + elif stanza_type == "file" and len(this_path_components) == len(path_components) + 1: yield (stanza_type, this_path) - def get_timecert(rev): - for cert in ops.certs(rev): - if cert[4] == 'name' and cert[5] == 'date': - revdate = common.parse_timecert(cert[7]) + def info_for_manifest(entry_iter): + def timecert(certs): + for cert in certs: + if cert[4] == 'name' and cert[5] == 'date': + revdate = common.parse_timecert(cert[7]) - def info_for_manifest(entry_iter): - 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.sort(lambda b, a: cmp(get_timecert(a), get_timecert(b))) - content_mark = content_marks[0] - # determine the author, and the shortlog + # should probably limit memory usage (worst case is this gets huge) + # but for now, this is really a needed optimisation, as most of the + # time a single cert will be seen *many* times + certs = {} + certinfo = {} + + def get_cert(cert): + if not certs.has_key(cert): + certs[cert] = ops.certs(cert) + return certs[cert] + + def _get_certinfo(cert): author, ago, shortlog = None, None, None - for cert in ops.certs(content_mark): + for cert in get_cert(cert): if cert[4] != 'name': continue name, value = cert[5], cert[7] @@ -533,15 +550,48 @@ class RevisionBrowse(RevisionPage): ago = common.ago(revdate) elif name == "changelog": shortlog = quicklog(normalise_changelog(value)) - to_yield = (stanza_type, this_path, author, ago, shortlog) - yield map(lambda x: x or "", to_yield) + to_return = (author, ago, shortlog) + return [t or "" for t in to_return] + def get_certinfo(cert): + if not certinfo.has_key(cert): + certinfo[cert] = _get_certinfo(cert) + return certinfo[cert] + + 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)] + for mark in content_marks: + certs[mark] = get_cert(mark) + if len(content_marks): + content_marks.sort(lambda b, a: cmp(timecert(certs[a]), timecert(certs[b]))) + content_mark = mtn.Revision(content_marks[0]) + author, ago, shortlog = get_certinfo(content_mark) + else: + author, ago, shortlog, content_mark = "", "", "", None + yield (stanza_type, mtn.File(this_path, revision), nbhq(author), ago, content_mark, shortlog) + + def path_links(components): + # we always want a link to '/' + links = ["/"] + running_path = "" + for component in components: + running_path += component + "/" + links.append(running_path) + + def row_class(): + while True: + yield "even" + yield "odd" + renderer.render('revisionbrowse.html', branches=branches, branch_links=', '.join(map(lambda b: link(mtn.Branch(b)).html(), branches)), path=path, page_title=page_title, revision=revision, + path_links=path_links(path_components), + row_class=row_class(), entries=info_for_manifest(cut_manifest_to_subdir())) class RevisionTar: