Mercurial > public > mercurial-scm > hg
comparison mercurial/hgweb/hgwebdir_mod.py @ 8371:1bd0fdf4c1ec
hgwebdir: refresh configuration periodically
The old default behaviour of hgwebdir was to maintain a list of
repositories permanently. This interacted badly with persistent
application hosting software such as WSGI containers. If a new repository
was published, it would potentially never appear in the top-level list
of repositories.
This change causes the hgwebdir configuration and list of repositories
served to be refreshed periodically (at most every 20 seconds).
author | Bryan O'Sullivan <bos@serpentine.com> |
---|---|
date | Wed, 13 May 2009 13:30:28 -0700 |
parents | acc202b71619 |
children | 4b798b100c32 |
comparison
equal
deleted
inserted
replaced
8370:45ed015b524e | 8371:1bd0fdf4c1ec |
---|---|
4 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com> | 4 # Copyright 2005, 2006 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, incorporated herein by reference. | 7 # GNU General Public License version 2, incorporated herein by reference. |
8 | 8 |
9 import os | 9 import os, time |
10 from mercurial.i18n import _ | 10 from mercurial.i18n import _ |
11 from mercurial import ui, hg, util, templater | 11 from mercurial import ui, hg, util, templater |
12 from mercurial import error, encoding | 12 from mercurial import error, encoding |
13 from common import ErrorResponse, get_mtime, staticfile, paritygen,\ | 13 from common import ErrorResponse, get_mtime, staticfile, paritygen,\ |
14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR | 14 get_contact, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR |
18 | 18 |
19 def cleannames(items): | 19 def cleannames(items): |
20 return [(util.pconvert(name).strip('/'), path) for name, path in items] | 20 return [(util.pconvert(name).strip('/'), path) for name, path in items] |
21 | 21 |
22 class hgwebdir(object): | 22 class hgwebdir(object): |
23 refreshinterval = 20 | |
23 | 24 |
24 def __init__(self, conf, baseui=None): | 25 def __init__(self, conf, baseui=None): |
25 | 26 self.conf = conf |
26 if baseui: | 27 self.baseui = baseui |
27 self.ui = baseui.copy() | 28 self.lastrefresh = 0 |
29 self.refresh() | |
30 | |
31 def refresh(self): | |
32 if self.lastrefresh + self.refreshinterval > time.time(): | |
33 return | |
34 | |
35 if self.baseui: | |
36 self.ui = self.baseui.copy() | |
28 else: | 37 else: |
29 self.ui = ui.ui() | 38 self.ui = ui.ui() |
30 self.ui.setconfig('ui', 'report_untrusted', 'off') | 39 self.ui.setconfig('ui', 'report_untrusted', 'off') |
31 self.ui.setconfig('ui', 'interactive', 'off') | 40 self.ui.setconfig('ui', 'interactive', 'off') |
32 | 41 |
33 if isinstance(conf, (list, tuple)): | 42 if isinstance(self.conf, (list, tuple)): |
34 self.repos = cleannames(conf) | 43 self.repos = cleannames(conf) |
35 elif isinstance(conf, dict): | 44 elif isinstance(self.conf, dict): |
36 self.repos = sorted(cleannames(conf.items())) | 45 self.repos = sorted(cleannames(self.conf.items())) |
37 else: | 46 else: |
38 self.ui.readconfig(conf, remap={'paths': 'hgweb-paths'}, trust=True) | 47 self.ui.readconfig(self.conf, remap={'paths': 'hgweb-paths'}, trust=True) |
39 self.repos = [] | 48 self.repos = [] |
40 | 49 |
41 self.motd = self.ui.config('web', 'motd') | 50 self.motd = self.ui.config('web', 'motd') |
42 self.style = self.ui.config('web', 'style', 'paper') | 51 self.style = self.ui.config('web', 'style', 'paper') |
43 self.stripecount = self.ui.config('web', 'stripes', 1) | 52 self.stripecount = self.ui.config('web', 'stripes', 1) |
75 if name.startswith(prefix): | 84 if name.startswith(prefix): |
76 name = name[len(prefix):] | 85 name = name[len(prefix):] |
77 self.repos.append((name.lstrip(os.sep), repo)) | 86 self.repos.append((name.lstrip(os.sep), repo)) |
78 | 87 |
79 self.repos.sort() | 88 self.repos.sort() |
89 self.lastrefresh = time.time() | |
80 | 90 |
81 def run(self): | 91 def run(self): |
82 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."): | 92 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."): |
83 raise RuntimeError("This function is only intended to be called while running as a CGI script.") | 93 raise RuntimeError("This function is only intended to be called while running as a CGI script.") |
84 import mercurial.hgweb.wsgicgi as wsgicgi | 94 import mercurial.hgweb.wsgicgi as wsgicgi |
109 return True | 119 return True |
110 | 120 |
111 return False | 121 return False |
112 | 122 |
113 def run_wsgi(self, req): | 123 def run_wsgi(self, req): |
114 | |
115 try: | 124 try: |
116 try: | 125 try: |
126 self.refresh() | |
117 | 127 |
118 virtual = req.env.get("PATH_INFO", "").strip('/') | 128 virtual = req.env.get("PATH_INFO", "").strip('/') |
119 tmpl = self.templater(req) | 129 tmpl = self.templater(req) |
120 ctype = tmpl('mimetype', encoding=encoding.encoding) | 130 ctype = tmpl('mimetype', encoding=encoding.encoding) |
121 ctype = templater.stringify(ctype) | 131 ctype = templater.stringify(ctype) |
243 rows.reverse() | 253 rows.reverse() |
244 for key, row in rows: | 254 for key, row in rows: |
245 row['parity'] = parity.next() | 255 row['parity'] = parity.next() |
246 yield row | 256 yield row |
247 | 257 |
258 self.refresh() | |
248 sortable = ["name", "description", "contact", "lastchange"] | 259 sortable = ["name", "description", "contact", "lastchange"] |
249 sortcolumn, descending = sortdefault | 260 sortcolumn, descending = sortdefault |
250 if 'sort' in req.form: | 261 if 'sort' in req.form: |
251 sortcolumn = req.form['sort'][0] | 262 sortcolumn = req.form['sort'][0] |
252 descending = sortcolumn.startswith('-') | 263 descending = sortcolumn.startswith('-') |
258 sort = [("sort_%s" % column, | 269 sort = [("sort_%s" % column, |
259 "%s%s" % ((not descending and column == sortcolumn) | 270 "%s%s" % ((not descending and column == sortcolumn) |
260 and "-" or "", column)) | 271 and "-" or "", column)) |
261 for column in sortable] | 272 for column in sortable] |
262 | 273 |
274 self.refresh() | |
263 if self._baseurl is not None: | 275 if self._baseurl is not None: |
264 req.env['SCRIPT_NAME'] = self._baseurl | 276 req.env['SCRIPT_NAME'] = self._baseurl |
265 | 277 |
266 return tmpl("index", entries=entries, subdir=subdir, | 278 return tmpl("index", entries=entries, subdir=subdir, |
267 sortcolumn=sortcolumn, descending=descending, | 279 sortcolumn=sortcolumn, descending=descending, |