75 |
75 |
76 self.mtime = -1 |
76 self.mtime = -1 |
77 self.reponame = name |
77 self.reponame = name |
78 self.archives = 'zip', 'gz', 'bz2' |
78 self.archives = 'zip', 'gz', 'bz2' |
79 self.stripecount = 1 |
79 self.stripecount = 1 |
80 self.templatepath = self.repo.ui.config("web", "templates", |
80 # a repo owner may set web.templates in .hg/hgrc to get any file |
81 templater.templatepath()) |
81 # readable by the user running the CGI script |
|
82 self.templatepath = self.config("web", "templates", |
|
83 templater.templatepath(), |
|
84 untrusted=False) |
|
85 |
|
86 # The CGI scripts are often run by a user different from the repo owner. |
|
87 # Trust the settings from the .hg/hgrc files by default. |
|
88 def config(self, section, name, default=None, untrusted=True): |
|
89 return self.repo.ui.config(section, name, default, |
|
90 untrusted=untrusted) |
|
91 |
|
92 def configbool(self, section, name, default=False, untrusted=True): |
|
93 return self.repo.ui.configbool(section, name, default, |
|
94 untrusted=untrusted) |
|
95 |
|
96 def configlist(self, section, name, default=None, untrusted=True): |
|
97 return self.repo.ui.configlist(section, name, default, |
|
98 untrusted=untrusted) |
82 |
99 |
83 def refresh(self): |
100 def refresh(self): |
84 mtime = get_mtime(self.repo.root) |
101 mtime = get_mtime(self.repo.root) |
85 if mtime != self.mtime: |
102 if mtime != self.mtime: |
86 self.mtime = mtime |
103 self.mtime = mtime |
87 self.repo = hg.repository(self.repo.ui, self.repo.root) |
104 self.repo = hg.repository(self.repo.ui, self.repo.root) |
88 self.maxchanges = int(self.repo.ui.config("web", "maxchanges", 10)) |
105 self.maxchanges = int(self.config("web", "maxchanges", 10)) |
89 self.stripecount = int(self.repo.ui.config("web", "stripes", 1)) |
106 self.stripecount = int(self.config("web", "stripes", 1)) |
90 self.maxshortchanges = int(self.repo.ui.config("web", "maxshortchanges", 60)) |
107 self.maxshortchanges = int(self.config("web", "maxshortchanges", 60)) |
91 self.maxfiles = int(self.repo.ui.config("web", "maxfiles", 10)) |
108 self.maxfiles = int(self.config("web", "maxfiles", 10)) |
92 self.allowpull = self.repo.ui.configbool("web", "allowpull", True) |
109 self.allowpull = self.configbool("web", "allowpull", True) |
93 |
110 |
94 def archivelist(self, nodeid): |
111 def archivelist(self, nodeid): |
95 allowed = self.repo.ui.configlist("web", "allow_archive") |
112 allowed = self.configlist("web", "allow_archive") |
96 for i, spec in self.archive_specs.iteritems(): |
113 for i, spec in self.archive_specs.iteritems(): |
97 if i in allowed or self.repo.ui.configbool("web", "allow" + i): |
114 if i in allowed or self.configbool("web", "allow" + i): |
98 yield {"type" : i, "extension" : spec[2], "node" : nodeid} |
115 yield {"type" : i, "extension" : spec[2], "node" : nodeid} |
99 |
116 |
100 def listfilediffs(self, files, changeset): |
117 def listfilediffs(self, files, changeset): |
101 for f in files[:self.maxfiles]: |
118 for f in files[:self.maxfiles]: |
102 yield self.t("filedifflink", node=hex(changeset), file=f) |
119 yield self.t("filedifflink", node=hex(changeset), file=f) |
167 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5] |
184 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5] |
168 if files: |
185 if files: |
169 modified, added, removed = map(lambda x: filterfiles(files, x), |
186 modified, added, removed = map(lambda x: filterfiles(files, x), |
170 (modified, added, removed)) |
187 (modified, added, removed)) |
171 |
188 |
172 diffopts = patch.diffopts(self.repo.ui) |
189 diffopts = patch.diffopts(self.repo.ui, untrusted=True) |
173 for f in modified: |
190 for f in modified: |
174 to = r.file(f).read(mmap1[f]) |
191 to = r.file(f).read(mmap1[f]) |
175 tn = r.file(f).read(mmap2[f]) |
192 tn = r.file(f).read(mmap2[f]) |
176 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
193 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, |
177 opts=diffopts), f, tn) |
194 opts=diffopts), f, tn) |
569 count = cl.count() |
586 count = cl.count() |
570 start = max(0, count - self.maxchanges) |
587 start = max(0, count - self.maxchanges) |
571 end = min(count, start + self.maxchanges) |
588 end = min(count, start + self.maxchanges) |
572 |
589 |
573 yield self.t("summary", |
590 yield self.t("summary", |
574 desc = self.repo.ui.config("web", "description", "unknown"), |
591 desc = self.config("web", "description", "unknown"), |
575 owner = (self.repo.ui.config("ui", "username") or # preferred |
592 owner = (self.config("ui", "username") or # preferred |
576 self.repo.ui.config("web", "contact") or # deprecated |
593 self.config("web", "contact") or # deprecated |
577 self.repo.ui.config("web", "author", "unknown")), # also |
594 self.config("web", "author", "unknown")), # also |
578 lastchange = cl.read(cl.tip())[2], |
595 lastchange = cl.read(cl.tip())[2], |
579 tags = tagentries, |
596 tags = tagentries, |
580 heads = heads, |
597 heads = heads, |
581 shortlog = changelist, |
598 shortlog = changelist, |
582 node = hex(cl.tip()), |
599 node = hex(cl.tip()), |
648 |
665 |
649 def footer(**map): |
666 def footer(**map): |
650 yield self.t("footer", **map) |
667 yield self.t("footer", **map) |
651 |
668 |
652 def motd(**map): |
669 def motd(**map): |
653 yield self.repo.ui.config("web", "motd", "") |
670 yield self.config("web", "motd", "") |
654 |
671 |
655 def expand_form(form): |
672 def expand_form(form): |
656 shortcuts = { |
673 shortcuts = { |
657 'cl': [('cmd', ['changelog']), ('rev', None)], |
674 'cl': [('cmd', ['changelog']), ('rev', None)], |
658 'sl': [('cmd', ['shortlog']), ('rev', None)], |
675 'sl': [('cmd', ['shortlog']), ('rev', None)], |
746 |
763 |
747 def sessionvars(**map): |
764 def sessionvars(**map): |
748 fields = [] |
765 fields = [] |
749 if req.form.has_key('style'): |
766 if req.form.has_key('style'): |
750 style = req.form['style'][0] |
767 style = req.form['style'][0] |
751 if style != self.repo.ui.config('web', 'style', ''): |
768 if style != self.config('web', 'style', ''): |
752 fields.append(('style', style)) |
769 fields.append(('style', style)) |
753 |
770 |
754 separator = req.url[-1] == '?' and ';' or '?' |
771 separator = req.url[-1] == '?' and ';' or '?' |
755 for name, value in fields: |
772 for name, value in fields: |
756 yield dict(name=name, value=value, separator=separator) |
773 yield dict(name=name, value=value, separator=separator) |
759 self.refresh() |
776 self.refresh() |
760 |
777 |
761 expand_form(req.form) |
778 expand_form(req.form) |
762 rewrite_request(req) |
779 rewrite_request(req) |
763 |
780 |
764 style = self.repo.ui.config("web", "style", "") |
781 style = self.config("web", "style", "") |
765 if req.form.has_key('style'): |
782 if req.form.has_key('style'): |
766 style = req.form['style'][0] |
783 style = req.form['style'][0] |
767 mapfile = style_map(self.templatepath, style) |
784 mapfile = style_map(self.templatepath, style) |
768 |
785 |
769 port = req.env["SERVER_PORT"] |
786 port = req.env["SERVER_PORT"] |
770 port = port != "80" and (":" + port) or "" |
787 port = port != "80" and (":" + port) or "" |
771 urlbase = 'http://%s%s' % (req.env['SERVER_NAME'], port) |
788 urlbase = 'http://%s%s' % (req.env['SERVER_NAME'], port) |
772 |
789 |
773 if not self.reponame: |
790 if not self.reponame: |
774 self.reponame = (self.repo.ui.config("web", "name") |
791 self.reponame = (self.config("web", "name") |
775 or req.env.get('REPO_NAME') |
792 or req.env.get('REPO_NAME') |
776 or req.url.strip('/') or self.repo.root) |
793 or req.url.strip('/') or self.repo.root) |
777 |
794 |
778 self.t = templater.templater(mapfile, templater.common_filters, |
795 self.t = templater.templater(mapfile, templater.common_filters, |
779 defaults={"url": req.url, |
796 defaults={"url": req.url, |
983 req.write(z.flush()) |
1000 req.write(z.flush()) |
984 |
1001 |
985 def do_archive(self, req): |
1002 def do_archive(self, req): |
986 changeset = self.repo.lookup(req.form['node'][0]) |
1003 changeset = self.repo.lookup(req.form['node'][0]) |
987 type_ = req.form['type'][0] |
1004 type_ = req.form['type'][0] |
988 allowed = self.repo.ui.configlist("web", "allow_archive") |
1005 allowed = self.configlist("web", "allow_archive") |
989 if (type_ in self.archives and (type_ in allowed or |
1006 if (type_ in self.archives and (type_ in allowed or |
990 self.repo.ui.configbool("web", "allow" + type_, False))): |
1007 self.configbool("web", "allow" + type_, False))): |
991 self.archive(req, changeset, type_) |
1008 self.archive(req, changeset, type_) |
992 return |
1009 return |
993 |
1010 |
994 req.write(self.t("error")) |
1011 req.write(self.t("error")) |
995 |
1012 |
996 def do_static(self, req): |
1013 def do_static(self, req): |
997 fname = req.form['file'][0] |
1014 fname = req.form['file'][0] |
998 static = self.repo.ui.config("web", "static", |
1015 # a repo owner may set web.static in .hg/hgrc to get any file |
999 os.path.join(self.templatepath, |
1016 # readable by the user running the CGI script |
1000 "static")) |
1017 static = self.config("web", "static", |
|
1018 os.path.join(self.templatepath, "static"), |
|
1019 untrusted=False) |
1001 req.write(staticfile(static, fname, req) |
1020 req.write(staticfile(static, fname, req) |
1002 or self.t("error", error="%r not found" % fname)) |
1021 or self.t("error", error="%r not found" % fname)) |
1003 |
1022 |
1004 def do_capabilities(self, req): |
1023 def do_capabilities(self, req): |
1005 caps = ['unbundle', 'lookup', 'changegroupsubset'] |
1024 caps = ['unbundle', 'lookup', 'changegroupsubset'] |
1006 if self.repo.ui.configbool('server', 'uncompressed'): |
1025 if self.configbool('server', 'uncompressed'): |
1007 caps.append('stream=%d' % self.repo.revlogversion) |
1026 caps.append('stream=%d' % self.repo.revlogversion) |
1008 resp = ' '.join(caps) |
1027 resp = ' '.join(caps) |
1009 req.httphdr("application/mercurial-0.1", length=len(resp)) |
1028 req.httphdr("application/mercurial-0.1", length=len(resp)) |
1010 req.write(resp) |
1029 req.write(resp) |
1011 |
1030 |
1014 return true if op allowed, else false. |
1033 return true if op allowed, else false. |
1015 default is policy to use if no config given.''' |
1034 default is policy to use if no config given.''' |
1016 |
1035 |
1017 user = req.env.get('REMOTE_USER') |
1036 user = req.env.get('REMOTE_USER') |
1018 |
1037 |
1019 deny = self.repo.ui.configlist('web', 'deny_' + op) |
1038 deny = self.configlist('web', 'deny_' + op) |
1020 if deny and (not user or deny == ['*'] or user in deny): |
1039 if deny and (not user or deny == ['*'] or user in deny): |
1021 return False |
1040 return False |
1022 |
1041 |
1023 allow = self.repo.ui.configlist('web', 'allow_' + op) |
1042 allow = self.configlist('web', 'allow_' + op) |
1024 return (allow and (allow == ['*'] or user in allow)) or default |
1043 return (allow and (allow == ['*'] or user in allow)) or default |
1025 |
1044 |
1026 def do_unbundle(self, req): |
1045 def do_unbundle(self, req): |
1027 def bail(response, headers={}): |
1046 def bail(response, headers={}): |
1028 length = int(req.env['CONTENT_LENGTH']) |
1047 length = int(req.env['CONTENT_LENGTH']) |