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, |