Mercurial > public > mercurial-scm > hg-stable
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): |