mercurial/hgweb/hgweb_mod.py
changeset 3541 881064004fd0
parent 3493 e0db0b7934f2
child 3543 f7dee427cd14
equal deleted inserted replaced
3540:da3ee7ca620f 3541:881064004fd0
    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'])
  1034             req.write('0\n')
  1053             req.write('0\n')
  1035             req.write(response)
  1054             req.write(response)
  1036 
  1055 
  1037         # require ssl by default, auth info cannot be sniffed and
  1056         # require ssl by default, auth info cannot be sniffed and
  1038         # replayed
  1057         # replayed
  1039         ssl_req = self.repo.ui.configbool('web', 'push_ssl', True)
  1058         ssl_req = self.configbool('web', 'push_ssl', True)
  1040         if ssl_req:
  1059         if ssl_req:
  1041             if not req.env.get('HTTPS'):
  1060             if not req.env.get('HTTPS'):
  1042                 bail(_('ssl required\n'))
  1061                 bail(_('ssl required\n'))
  1043                 return
  1062                 return
  1044             proto = 'https'
  1063             proto = 'https'