mercurial/hgweb/hgweb_mod.py
changeset 26220 a43328baa2ac
parent 26219 ae33fff17c1e
child 26226 efebefe162e9
equal deleted inserted replaced
26219:ae33fff17c1e 26220:a43328baa2ac
     4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
     4 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
     5 #
     5 #
     6 # This software may be used and distributed according to the terms of the
     6 # This software may be used and distributed according to the terms of the
     7 # GNU General Public License version 2 or any later version.
     7 # GNU General Public License version 2 or any later version.
     8 
     8 
       
     9 import contextlib
     9 import os
    10 import os
    10 from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
    11 from mercurial import ui, hg, hook, error, encoding, templater, util, repoview
    11 from mercurial.templatefilters import websub
    12 from mercurial.templatefilters import websub
    12 from common import get_stat, ErrorResponse, permhooks, caching
    13 from common import get_stat, ErrorResponse, permhooks, caching
    13 from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
    14 from common import HTTP_OK, HTTP_NOT_MODIFIED, HTTP_BAD_REQUEST
   206         r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
   207         r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb')
   207         # displaying bundling progress bar while serving feel wrong and may
   208         # displaying bundling progress bar while serving feel wrong and may
   208         # break some wsgi implementation.
   209         # break some wsgi implementation.
   209         r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
   210         r.ui.setconfig('progress', 'disable', 'true', 'hgweb')
   210         r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
   211         r.baseui.setconfig('progress', 'disable', 'true', 'hgweb')
   211         self._repo = hg.cachedlocalrepo(self._webifyrepo(r))
   212         self._repos = [hg.cachedlocalrepo(self._webifyrepo(r))]
       
   213         self._lastrepo = self._repos[0]
   212         hook.redirect(True)
   214         hook.redirect(True)
   213         self.reponame = name
   215         self.reponame = name
   214 
   216 
   215     def _webifyrepo(self, repo):
   217     def _webifyrepo(self, repo):
   216         repo = getwebview(repo)
   218         repo = getwebview(repo)
   217         self.websubtable = webutil.getwebsubs(repo)
   219         self.websubtable = webutil.getwebsubs(repo)
   218         return repo
   220         return repo
   219 
   221 
   220     def _getrepo(self):
   222     @contextlib.contextmanager
   221         r, created = self._repo.fetch()
   223     def _obtainrepo(self):
   222         if created:
   224         """Obtain a repo unique to the caller.
   223             r = self._webifyrepo(r)
   225 
   224 
   226         Internally we maintain a stack of cachedlocalrepo instances
   225         self.mtime = self._repo.mtime
   227         to be handed out. If one is available, we pop it and return it,
   226         return r
   228         ensuring it is up to date in the process. If one is not available,
       
   229         we clone the most recently used repo instance and return it.
       
   230 
       
   231         It is currently possible for the stack to grow without bounds
       
   232         if the server allows infinite threads. However, servers should
       
   233         have a thread limit, thus establishing our limit.
       
   234         """
       
   235         if self._repos:
       
   236             cached = self._repos.pop()
       
   237             r, created = cached.fetch()
       
   238             if created:
       
   239                 r = self._webifyrepo(r)
       
   240         else:
       
   241             cached = self._lastrepo.copy()
       
   242             r, created = cached.fetch()
       
   243 
       
   244         self._lastrepo = cached
       
   245         self.mtime = cached.mtime
       
   246         try:
       
   247             yield r
       
   248         finally:
       
   249             self._repos.append(cached)
   227 
   250 
   228     def run(self):
   251     def run(self):
   229         """Start a server from CGI environment.
   252         """Start a server from CGI environment.
   230 
   253 
   231         Modern servers should be using WSGI and should avoid this
   254         Modern servers should be using WSGI and should avoid this
   249         """Internal method to run the WSGI application.
   272         """Internal method to run the WSGI application.
   250 
   273 
   251         This is typically only called by Mercurial. External consumers
   274         This is typically only called by Mercurial. External consumers
   252         should be using instances of this class as the WSGI application.
   275         should be using instances of this class as the WSGI application.
   253         """
   276         """
   254         repo = self._getrepo()
   277         with self._obtainrepo() as repo:
       
   278             return self._runwsgi(req, repo)
       
   279 
       
   280     def _runwsgi(self, req, repo):
   255         rctx = requestcontext(self, repo)
   281         rctx = requestcontext(self, repo)
   256 
   282 
   257         # This state is global across all threads.
   283         # This state is global across all threads.
   258         encoding.encoding = rctx.config('web', 'encoding', encoding.encoding)
   284         encoding.encoding = rctx.config('web', 'encoding', encoding.encoding)
   259         rctx.repo.ui.environ = req.env
   285         rctx.repo.ui.environ = req.env