comparison mercurial/hgweb.py @ 1159:b6f5a947e62e

Change use of global sys.stdout, sys.stdin os.environ to a hgrequest object. Note: also change hgrequest.write(str(thing)) to hgrequest.write(thing), people should make sure they write strings.
author Vincent Wagelaar <vincent@ricardis.tudelft.nl>
date Tue, 30 Aug 2005 10:57:52 +0200
parents 4fffb3d84b7c
children 0da98529a476
comparison
equal deleted inserted replaced
1154:c3cb9f39a91f 1159:b6f5a947e62e
58 up = os.path.dirname(p) 58 up = os.path.dirname(p)
59 if up == "/": 59 if up == "/":
60 return "/" 60 return "/"
61 return up + "/" 61 return up + "/"
62 62
63 def httphdr(type, file="", size=0): 63 class hgrequest:
64 sys.stdout.write('Content-type: %s\n' % type) 64 def __init__(self, inp=None, out=None, env=None):
65 if file: 65 self.inp = inp or sys.stdin
66 sys.stdout.write('Content-disposition: attachment; filename=%s\n' 66 self.out = out or sys.stdout
67 % file) 67 self.env = env or os.environ
68 if size > 0: 68 self.form = cgi.parse(self.inp, self.env)
69 sys.stdout.write('Content-length: %d\n' % size) 69
70 sys.stdout.write('\n') 70 def write(self, *things):
71 71 for thing in things:
72 def write(*things): 72 if hasattr(thing, "__iter__"):
73 for thing in things: 73 for part in thing:
74 if hasattr(thing, "__iter__"): 74 self.write(part)
75 for part in thing: 75 else:
76 write(part) 76 try:
77 else: 77 self.out.write(thing)
78 try: 78 except socket.error, x:
79 sys.stdout.write(str(thing)) 79 if x[0] != errno.ECONNRESET:
80 except socket.error, x: 80 raise
81 if x[0] != errno.ECONNRESET: 81
82 raise 82 def header(self, headers=[('Content-type','text/html')]):
83 for header in headers:
84 self.out.write("%s: %s\r\n" % header)
85 self.out.write("\r\n")
86
87 def httphdr(self, type, file="", size=0):
88
89 headers = [('Content-type', type)]
90 if file:
91 headers.append(('Content-disposition', 'attachment; filename=%s' % file))
92 if size > 0:
93 headers.append(('Content-length', str(size)))
94 self.header(headers)
83 95
84 class templater: 96 class templater:
85 def __init__(self, mapfile, filters={}, defaults={}): 97 def __init__(self, mapfile, filters={}, defaults={}):
86 self.cache = {} 98 self.cache = {}
87 self.map = {} 99 self.map = {}
151 "short": (lambda x: x[:12]), 163 "short": (lambda x: x[:12]),
152 "firstline": (lambda x: x.splitlines(1)[0]), 164 "firstline": (lambda x: x.splitlines(1)[0]),
153 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"), 165 "permissions": (lambda x: x and "-rwxr-xr-x" or "-rw-r--r--"),
154 "rfc822date": rfc822date, 166 "rfc822date": rfc822date,
155 } 167 }
168
169
156 170
157 class hgweb: 171 class hgweb:
158 def __init__(self, repo, name=None): 172 def __init__(self, repo, name=None):
159 if type(repo) == type(""): 173 if type(repo) == type(""):
160 self.repo = repository(ui(), repo) 174 self.repo = repository(ui(), repo)
633 rev=self.repo.changelog.rev(n), 647 rev=self.repo.changelog.rev(n),
634 parent=self.parents("filediffparent", 648 parent=self.parents("filediffparent",
635 cl.parents(n), cl.rev), 649 cl.parents(n), cl.rev),
636 diff=diff) 650 diff=diff)
637 651
638 def archive(self, cnode, type): 652 def archive(self, req, cnode, type):
639 cs = self.repo.changelog.read(cnode) 653 cs = self.repo.changelog.read(cnode)
640 mnode = cs[0] 654 mnode = cs[0]
641 mf = self.repo.manifest.read(mnode) 655 mf = self.repo.manifest.read(mnode)
642 rev = self.repo.manifest.rev(mnode) 656 rev = self.repo.manifest.rev(mnode)
643 reponame = re.sub(r"\W+", "-", self.reponame) 657 reponame = re.sub(r"\W+", "-", self.reponame)
656 for f in files: 670 for f in files:
657 zf.writestr(name + f, self.repo.file(f).read(mf[f])) 671 zf.writestr(name + f, self.repo.file(f).read(mf[f]))
658 zf.close() 672 zf.close()
659 673
660 f = open(tmp, 'r') 674 f = open(tmp, 'r')
661 httphdr('application/zip', name[:-1] + '.zip', 675 req.httphdr('application/zip', name[:-1] + '.zip',
662 os.path.getsize(tmp)) 676 os.path.getsize(tmp))
663 sys.stdout.write(f.read()) 677 req.write(f.read())
664 f.close() 678 f.close()
665 finally: 679 finally:
666 os.unlink(tmp) 680 os.unlink(tmp)
667 681
668 else: 682 else:
669 import StringIO 683 import StringIO
670 import time 684 import time
671 import tarfile 685 import tarfile
672 686
673 tf = tarfile.TarFile.open(mode='w|' + type, fileobj=sys.stdout) 687 tf = tarfile.TarFile.open(mode='w|' + type, fileobj=req.out)
674 mff = self.repo.manifest.readflags(mnode) 688 mff = self.repo.manifest.readflags(mnode)
675 mtime = int(time.time()) 689 mtime = int(time.time())
676 690
677 httphdr('application/octet-stream', name[:-1] + '.tar.' + type) 691 req.httphdr('application/octet-stream', name[:-1] + '.tar.' + type)
678 for fname in files: 692 for fname in files:
679 rcont = self.repo.file(fname).read(mf[fname]) 693 rcont = self.repo.file(fname).read(mf[fname])
680 finfo = tarfile.TarInfo(name + fname) 694 finfo = tarfile.TarInfo(name + fname)
681 finfo.mtime = mtime 695 finfo.mtime = mtime
682 finfo.size = len(rcont) 696 finfo.size = len(rcont)
686 700
687 # add tags to things 701 # add tags to things
688 # tags -> list of changesets corresponding to tags 702 # tags -> list of changesets corresponding to tags
689 # find tag, changeset, file 703 # find tag, changeset, file
690 704
691 def run(self): 705 def run(self, req=hgrequest()):
692 def header(**map): 706 def header(**map):
693 yield self.t("header", **map) 707 yield self.t("header", **map)
694 708
695 def footer(**map): 709 def footer(**map):
696 yield self.t("footer", **map) 710 yield self.t("footer", **map)
697 711
698 self.refresh() 712 self.refresh()
699 args = cgi.parse()
700 713
701 t = self.repo.ui.config("web", "templates", templatepath()) 714 t = self.repo.ui.config("web", "templates", templatepath())
702 m = os.path.join(t, "map") 715 m = os.path.join(t, "map")
703 style = self.repo.ui.config("web", "style", "") 716 style = self.repo.ui.config("web", "style", "")
704 if args.has_key('style'): 717 if req.form.has_key('style'):
705 style = args['style'][0] 718 style = req.form['style'][0]
706 if style: 719 if style:
707 b = os.path.basename("map-" + style) 720 b = os.path.basename("map-" + style)
708 p = os.path.join(t, b) 721 p = os.path.join(t, b)
709 if os.path.isfile(p): 722 if os.path.isfile(p):
710 m = p 723 m = p
711 724
712 port = os.environ["SERVER_PORT"] 725 port = req.env["SERVER_PORT"]
713 port = port != "80" and (":" + port) or "" 726 port = port != "80" and (":" + port) or ""
714 uri = os.environ["REQUEST_URI"] 727 uri = req.env["REQUEST_URI"]
715 if "?" in uri: 728 if "?" in uri:
716 uri = uri.split("?")[0] 729 uri = uri.split("?")[0]
717 url = "http://%s%s%s" % (os.environ["SERVER_NAME"], port, uri) 730 url = "http://%s%s%s" % (req.env["SERVER_NAME"], port, uri)
718 731
719 self.t = templater(m, common_filters, 732 self.t = templater(m, common_filters,
720 {"url": url, 733 {"url": url,
721 "repo": self.reponame, 734 "repo": self.reponame,
722 "header": header, 735 "header": header,
723 "footer": footer, 736 "footer": footer,
724 }) 737 })
725 738
726 if not args.has_key('cmd'): 739 if not req.form.has_key('cmd'):
727 args['cmd'] = [self.t.cache['default'],] 740 req.form['cmd'] = [self.t.cache['default'],]
728 741
729 if args['cmd'][0] == 'changelog': 742 if req.form['cmd'][0] == 'changelog':
730 c = self.repo.changelog.count() - 1 743 c = self.repo.changelog.count() - 1
731 hi = c 744 hi = c
732 if args.has_key('rev'): 745 if req.form.has_key('rev'):
733 hi = args['rev'][0] 746 hi = req.form['rev'][0]
734 try: 747 try:
735 hi = self.repo.changelog.rev(self.repo.lookup(hi)) 748 hi = self.repo.changelog.rev(self.repo.lookup(hi))
736 except RepoError: 749 except RepoError:
737 write(self.search(hi)) 750 req.write(self.search(hi))
738 return 751 return
739 752
740 write(self.changelog(hi)) 753 req.write(self.changelog(hi))
741 754
742 elif args['cmd'][0] == 'changeset': 755 elif req.form['cmd'][0] == 'changeset':
743 write(self.changeset(args['node'][0])) 756 req.write(self.changeset(req.form['node'][0]))
744 757
745 elif args['cmd'][0] == 'manifest': 758 elif req.form['cmd'][0] == 'manifest':
746 write(self.manifest(args['manifest'][0], args['path'][0])) 759 req.write(self.manifest(req.form['manifest'][0], req.form['path'][0]))
747 760
748 elif args['cmd'][0] == 'tags': 761 elif req.form['cmd'][0] == 'tags':
749 write(self.tags()) 762 req.write(self.tags())
750 763
751 elif args['cmd'][0] == 'filediff': 764 elif req.form['cmd'][0] == 'filediff':
752 write(self.filediff(args['file'][0], args['node'][0])) 765 req.write(self.filediff(req.form['file'][0], req.form['node'][0]))
753 766
754 elif args['cmd'][0] == 'file': 767 elif req.form['cmd'][0] == 'file':
755 write(self.filerevision(args['file'][0], args['filenode'][0])) 768 req.write(self.filerevision(req.form['file'][0], req.form['filenode'][0]))
756 769
757 elif args['cmd'][0] == 'annotate': 770 elif req.form['cmd'][0] == 'annotate':
758 write(self.fileannotate(args['file'][0], args['filenode'][0])) 771 req.write(self.fileannotate(req.form['file'][0], req.form['filenode'][0]))
759 772
760 elif args['cmd'][0] == 'filelog': 773 elif req.form['cmd'][0] == 'filelog':
761 write(self.filelog(args['file'][0], args['filenode'][0])) 774 req.write(self.filelog(req.form['file'][0], req.form['filenode'][0]))
762 775
763 elif args['cmd'][0] == 'heads': 776 elif req.form['cmd'][0] == 'heads':
764 httphdr("application/mercurial-0.1") 777 req.httphdr("application/mercurial-0.1")
765 h = self.repo.heads() 778 h = self.repo.heads()
766 sys.stdout.write(" ".join(map(hex, h)) + "\n") 779 req.write(" ".join(map(hex, h)) + "\n")
767 780
768 elif args['cmd'][0] == 'branches': 781 elif req.form['cmd'][0] == 'branches':
769 httphdr("application/mercurial-0.1") 782 req.httphdr("application/mercurial-0.1")
770 nodes = [] 783 nodes = []
771 if args.has_key('nodes'): 784 if req.form.has_key('nodes'):
772 nodes = map(bin, args['nodes'][0].split(" ")) 785 nodes = map(bin, req.form['nodes'][0].split(" "))
773 for b in self.repo.branches(nodes): 786 for b in self.repo.branches(nodes):
774 sys.stdout.write(" ".join(map(hex, b)) + "\n") 787 req.write(" ".join(map(hex, b)) + "\n")
775 788
776 elif args['cmd'][0] == 'between': 789 elif req.form['cmd'][0] == 'between':
777 httphdr("application/mercurial-0.1") 790 req.httphdr("application/mercurial-0.1")
778 nodes = [] 791 nodes = []
779 if args.has_key('pairs'): 792 if req.form.has_key('pairs'):
780 pairs = [map(bin, p.split("-")) 793 pairs = [map(bin, p.split("-"))
781 for p in args['pairs'][0].split(" ")] 794 for p in req.form['pairs'][0].split(" ")]
782 for b in self.repo.between(pairs): 795 for b in self.repo.between(pairs):
783 sys.stdout.write(" ".join(map(hex, b)) + "\n") 796 req.write(" ".join(map(hex, b)) + "\n")
784 797
785 elif args['cmd'][0] == 'changegroup': 798 elif req.form['cmd'][0] == 'changegroup':
786 httphdr("application/mercurial-0.1") 799 req.httphdr("application/mercurial-0.1")
787 nodes = [] 800 nodes = []
788 if not self.allowpull: 801 if not self.allowpull:
789 return 802 return
790 803
791 if args.has_key('roots'): 804 if req.form.has_key('roots'):
792 nodes = map(bin, args['roots'][0].split(" ")) 805 nodes = map(bin, req.form['roots'][0].split(" "))
793 806
794 z = zlib.compressobj() 807 z = zlib.compressobj()
795 f = self.repo.changegroup(nodes) 808 f = self.repo.changegroup(nodes)
796 while 1: 809 while 1:
797 chunk = f.read(4096) 810 chunk = f.read(4096)
798 if not chunk: 811 if not chunk:
799 break 812 break
800 sys.stdout.write(z.compress(chunk)) 813 req.write(z.compress(chunk))
801 814
802 sys.stdout.write(z.flush()) 815 req.write(z.flush())
803 816
804 elif args['cmd'][0] == 'archive': 817 elif req.form['cmd'][0] == 'archive':
805 changeset = bin(args['node'][0]) 818 changeset = bin(req.form['node'][0])
806 type = args['type'][0] 819 type = req.form['type'][0]
807 if (type in self.archives and 820 if (type in self.archives and
808 self.repo.ui.configbool("web", "allow" + type, False)): 821 self.repo.ui.configbool("web", "allow" + type, False)):
809 self.archive(changeset, type) 822 self.archive(req, changeset, type)
810 return 823 return
811 824
812 write(self.t("error")) 825 req.write(self.t("error"))
813 826
814 else: 827 else:
815 write(self.t("error")) 828 req.write(self.t("error"))
816 829
817 def create_server(repo): 830 def create_server(repo):
818 831
819 def openlog(opt, default): 832 def openlog(opt, default):
820 if opt and opt != '-': 833 if opt and opt != '-':
931 cp = ConfigParser.SafeConfigParser() 944 cp = ConfigParser.SafeConfigParser()
932 cp.read(config) 945 cp.read(config)
933 self.repos = cp.items("paths") 946 self.repos = cp.items("paths")
934 self.repos.sort() 947 self.repos.sort()
935 948
936 def run(self): 949 def run(self, req=hgrequest()):
937 def header(**map): 950 def header(**map):
938 yield tmpl("header", **map) 951 yield tmpl("header", **map)
939 952
940 def footer(**map): 953 def footer(**map):
941 yield tmpl("footer", **map) 954 yield tmpl("footer", **map)
949 for name, path in self.repos: 962 for name, path in self.repos:
950 u = ui() 963 u = ui()
951 u.readconfig(file(os.path.join(path, '.hg', 'hgrc'))) 964 u.readconfig(file(os.path.join(path, '.hg', 'hgrc')))
952 get = u.config 965 get = u.config
953 966
954 url = ('/'.join([os.environ["REQUEST_URI"], name]) 967 url = ('/'.join([req.env["REQUEST_URI"], name])
955 .replace("//", "/")) 968 .replace("//", "/"))
956 969
957 yield dict(contact=get("web", "contact") or 970 yield dict(contact=get("web", "contact") or
958 get("web", "author", "unknown"), 971 get("web", "author", "unknown"),
959 name=get("web", "name", name), 972 name=get("web", "name", name),
963 lastupdate=os.stat(os.path.join(path, ".hg", 976 lastupdate=os.stat(os.path.join(path, ".hg",
964 "00changelog.d")).st_mtime) 977 "00changelog.d")).st_mtime)
965 978
966 parity = 1 - parity 979 parity = 1 - parity
967 980
968 virtual = os.environ.get("PATH_INFO", "").strip('/') 981 virtual = req.env.get("PATH_INFO", "").strip('/')
969 if virtual: 982 if virtual:
970 real = dict(self.repos).get(virtual) 983 real = dict(self.repos).get(virtual)
971 if real: 984 if real:
972 hgweb(real).run() 985 hgweb(real).run(req)
973 else: 986 else:
974 write(tmpl("notfound", repo=virtual)) 987 req.write(tmpl("notfound", repo=virtual))
975 else: 988 else:
976 write(tmpl("index", entries=entries)) 989 req.write(tmpl("index", entries=entries))