# # # patch "viewmtn.py" # from [7a151db43bc8aef575ac63d8510c0b93867c89c2] # to [b7505915964d790e9c43161a9997245a5a8c5610] # ============================================================ --- viewmtn.py 7a151db43bc8aef575ac63d8510c0b93867c89c2 +++ viewmtn.py b7505915964d790e9c43161a9997245a5a8c5610 @@ -1,17 +1,21 @@ #!/usr/bin/env python2.4 +import os import cgi import mtn import sys import web +import struct import rfc822 import config import common import urllib import urlparse import syntax +import tarfile import tempfile import datetime +import cStringIO hq = cgi.escape import web @@ -61,6 +65,13 @@ def quicklog(changelog, max_size=None): interesting_line += '..' return interesting_line +def timecert(certs): + revdate = None + for cert in certs: + if cert[4] == 'name' and cert[5] == 'date': + revdate = common.parse_timecert(cert[7]) + return revdate + def nbhq(s): return ' '.join([hq(t) for t in s.split(' ')]) @@ -152,7 +163,6 @@ class FileLink(Link): class FileLink(Link): def __init__(self, file, **kwargs): Link.__init__(*(self, ), **kwargs) - debug(kwargs) if kwargs.has_key('for_download'): access_method = 'downloadfile' else: @@ -505,6 +515,45 @@ class RevisionDownloadFile(RevisionPage) sys.stdout.write(data) sys.stdout.flush() +class RevisionTar: + def GET(self, 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) + manifest = [stanza for stanza in 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 + tarobj = tarfile.open(mode="w", fileobj=sys.stdout) + dir_mode, file_mode = "0700", "0600" + certs = {} + for stanza in manifest: + stanza_type = stanza[0] + if stanza_type != 'file': + continue + filename, fileid = stanza[1], stanza[3] + filecontents = cStringIO.StringIO() + filesize = 0 + for data in ops.get_file(fileid): + filesize += len(data) + filecontents.write(data) + ti = tarfile.TarInfo() + ti.name = os.path.join(revision, filename) + 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)] + 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) + ti.mtime = since_epoch.days * 24 * 60 * 60 + since_epoch.seconds + else: + ti.mtime = 0 + ti.size = filesize + filecontents.seek(0) + tarobj.addfile(ti, filecontents) + class RevisionBrowse(RevisionPage): def GET(self, revision, path): revision = mtn.Revision(revision) @@ -574,11 +623,6 @@ class RevisionBrowse(RevisionPage): yield (stanza_type, this_path) 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]) - # 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 @@ -617,7 +661,7 @@ class RevisionBrowse(RevisionPage): # 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) + 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]) @@ -653,11 +697,6 @@ class RevisionBrowse(RevisionPage): row_class=row_class(), entries=info_for_manifest(cut_manifest_to_subdir())) -class RevisionTar: - def GET(self, revision): - revision = mtn.Revision(revision) - print "not implemented" - class RevisionGraph: def GET(self, revision, revision_count=10):