comparison mercurial/hgweb.py @ 1076:01db658cc78a

tarball support v0.3 Hello, I'm slowly improving support for tarballs in Mercurial. Attached patch is made against current tip in Matt's repository - f859e9cba1b9, and contains everything done so far. Changes: - gzip and bzip2 tarballs are sent immediately without writing to temporary files (I was wrong Matt, it can be done very easy) - hgrc customization, you can choose which type (if any) you will support There's no easy way to support compression levels, since TarFile open() assume that it is 9. I tried to use gzopen(), and bz2open() methods instead, but it seems that headers of generated archives, are missing or wrong. We could eventually try to rewrite tarfile.py and include our own version into Mercurial, but I don't know if it's good idea... Wojtek
author Wojciech Milkowski <wmilkowski@interia.pl>
date Fri, 26 Aug 2005 20:51:34 -0700
parents 7b35a980b982
children b87aeccf73d9
comparison
equal deleted inserted replaced
1075:e254bcbfe636 1076:01db658cc78a
56 up = os.path.dirname(p) 56 up = os.path.dirname(p)
57 if up == "/": 57 if up == "/":
58 return "/" 58 return "/"
59 return up + "/" 59 return up + "/"
60 60
61 def httphdr(type): 61 def httphdr(type, file="", size=0):
62 sys.stdout.write('Content-type: %s\n\n' % type) 62 sys.stdout.write('Content-type: %s\n' % type)
63 if file:
64 sys.stdout.write('Content-disposition: attachment; filename=%s\n'
65 % file)
66 if size > 0:
67 sys.stdout.write('Content-length: %d\n' % size)
68 sys.stdout.write('\n')
63 69
64 def write(*things): 70 def write(*things):
65 for thing in things: 71 for thing in things:
66 if hasattr(thing, "__iter__"): 72 if hasattr(thing, "__iter__"):
67 for part in thing: 73 for part in thing:
159 self.mtime = s.st_mtime 165 self.mtime = s.st_mtime
160 self.repo = repository(self.repo.ui, self.repo.root) 166 self.repo = repository(self.repo.ui, self.repo.root)
161 self.maxchanges = self.repo.ui.config("web", "maxchanges", 10) 167 self.maxchanges = self.repo.ui.config("web", "maxchanges", 10)
162 self.maxfiles = self.repo.ui.config("web", "maxchanges", 10) 168 self.maxfiles = self.repo.ui.config("web", "maxchanges", 10)
163 self.allowpull = self.repo.ui.configbool("web", "allowpull", True) 169 self.allowpull = self.repo.ui.configbool("web", "allowpull", True)
170 self.allowzip = self.repo.ui.configbool("web", "zip", True)
171 self.allowgz = self.repo.ui.configbool("web", "gz", True)
172 self.allowbz2 = self.repo.ui.configbool("web", "bz2", True)
164 173
165 def date(self, cs): 174 def date(self, cs):
166 return time.asctime(time.gmtime(float(cs[2].split(' ')[0]))) 175 return time.asctime(time.gmtime(float(cs[2].split(' ')[0])))
167 176
168 def listfiles(self, files, mf): 177 def listfiles(self, files, mf):
185 yield self.t(t1, node=hex(node), rev=rev(node), **args) 194 yield self.t(t1, node=hex(node), rev=rev(node), **args)
186 195
187 def showtag(self, t1, node=nullid, **args): 196 def showtag(self, t1, node=nullid, **args):
188 for t in self.repo.nodetags(node): 197 for t in self.repo.nodetags(node):
189 yield self.t(t1, tag=t, **args) 198 yield self.t(t1, tag=t, **args)
199
200 def tarballbuttons(self, m):
201 s = ''
202 if self.allowzip:
203 s += '<a href="?cmd=tarball;manifest=%s;type=zip">zip</a>\n' % m
204 if self.allowgz:
205 s += '<a href="?cmd=tarball;manifest=%s;type=gz">gz</a>\n' % m
206 if self.allowbz2:
207 s += '<a href="?cmd=tarball;manifest=%s;type=bz2">bz2</a>\n' % m
208 return s
190 209
191 def diff(self, node1, node2, files): 210 def diff(self, node1, node2, files):
192 def filterfiles(list, files): 211 def filterfiles(list, files):
193 l = [x for x in list if x in files] 212 l = [x for x in list if x in files]
194 213
393 changesettag=self.showtag("changesettag",n), 412 changesettag=self.showtag("changesettag",n),
394 manifest=hex(changes[0]), 413 manifest=hex(changes[0]),
395 author=changes[1], 414 author=changes[1],
396 desc=changes[4], 415 desc=changes[4],
397 date=t, 416 date=t,
398 files=files) 417 files=files,
418 tarballbuttons=self.tarballbuttons(hex(changes[0])))
399 419
400 def filelog(self, f, filenode): 420 def filelog(self, f, filenode):
401 cl = self.repo.changelog 421 cl = self.repo.changelog
402 fl = self.repo.file(f) 422 fl = self.repo.file(f)
403 count = fl.count() 423 count = fl.count()
621 rev=self.repo.changelog.rev(n), 641 rev=self.repo.changelog.rev(n),
622 parent=self.parents("filediffparent", 642 parent=self.parents("filediffparent",
623 cl.parents(n), cl.rev), 643 cl.parents(n), cl.rev),
624 diff=diff) 644 diff=diff)
625 645
646 def ziparchive(self, mnode):
647 import zipfile
648
649 tmp = tempfile.mkstemp()[1]
650 zf = zipfile.ZipFile(tmp, "w", zipfile.ZIP_DEFLATED)
651 mf = self.repo.manifest.read(bin(mnode))
652 rev = self.repo.manifest.rev(bin(mnode))
653 cnode = short(self.repo.changelog.node(rev))
654 name = os.path.basename(self.repo.path[:-4]) # without '/.hg' suffix
655 name += '-' + str(rev) + '-' + cnode + '/'
656
657 for fname in mf.keys():
658 r = self.repo.file(fname)
659 zf.writestr(name + fname, r.read(mf[fname]))
660 zf.close()
661
662 f = open(tmp, 'r')
663 httphdr('application/zip', name[:-1] + '.zip', os.path.getsize(tmp))
664 sys.stdout.write(f.read())
665 f.close()
666 os.unlink(tmp)
667
668 def tararchive(self, mnode, type):
669 import StringIO
670 import time
671 import tarfile
672
673 #if type == "gz":
674 # tf = tarfile.TarFile.gzopen('', 'w', sys.stdout, compressionlevel)
675 #else:
676 # tf = tarfile.TarFile.bz2open('', 'w', sys.stdout, compressionlevel)
677 tf = tarfile.TarFile.open(mode='w|' + type, fileobj=sys.stdout)
678
679 mf = self.repo.manifest.read(bin(mnode))
680 rev = self.repo.manifest.rev(bin(mnode))
681 cnode = short(self.repo.changelog.node(rev))
682 mff = self.repo.manifest.readflags(bin(mnode))
683 mtime = int(time.time())
684 name = os.path.basename(self.repo.path[:-4]) # without '/.hg' suffix
685 name += '-' + str(rev) + '-' + cnode + '/'
686
687 httphdr('application/octet-stream', name[:-1] + '.tar.' + type)
688 for fname in mf.keys():
689 r = self.repo.file(fname)
690 rcont = r.read(mf[fname])
691 finfo = tarfile.TarInfo(name + fname)
692 finfo.mtime = mtime
693 finfo.size = len(rcont)
694 finfo.mode = mff[fname] and 0755 or 0644
695 tf.addfile(finfo, StringIO.StringIO(rcont))
696 tf.close()
697
626 # add tags to things 698 # add tags to things
627 # tags -> list of changesets corresponding to tags 699 # tags -> list of changesets corresponding to tags
628 # find tag, changeset, file 700 # find tag, changeset, file
629 701
630 def run(self): 702 def run(self):
737 if not chunk: 809 if not chunk:
738 break 810 break
739 sys.stdout.write(z.compress(chunk)) 811 sys.stdout.write(z.compress(chunk))
740 812
741 sys.stdout.write(z.flush()) 813 sys.stdout.write(z.flush())
814
815 elif args['cmd'][0] == 'tarball':
816 manifest = args['manifest'][0]
817 type = args['type'][0]
818 if type == 'zip' and self.allowzip:
819 self.ziparchive(manifest)
820 elif type == 'gz' and self.allowgz:
821 self.tararchive(manifest, 'gz')
822 elif type == 'bz2' and self.allowbz2:
823 self.tararchive(manifest, 'bz2')
824 else:
825 write(self.t("error"))
742 826
743 else: 827 else:
744 write(self.t("error")) 828 write(self.t("error"))
745 829
746 def create_server(repo): 830 def create_server(repo):