22 'stream_out': 'pull', |
22 'stream_out': 'pull', |
23 'listkeys': 'pull', |
23 'listkeys': 'pull', |
24 'unbundle': 'push', |
24 'unbundle': 'push', |
25 'pushkey': 'push', |
25 'pushkey': 'push', |
26 } |
26 } |
27 |
|
28 ## Files of interest |
|
29 # Used to check if the repository has changed looking at mtime and size of |
|
30 # theses files. This should probably be relocated a bit higher in core. |
|
31 foi = [('spath', '00changelog.i'), |
|
32 ('spath', 'phaseroots'), # ! phase can change content at the same size |
|
33 ('spath', 'obsstore'), |
|
34 ('path', 'bookmarks'), # ! bookmark can change content at the same size |
|
35 ] |
|
36 |
27 |
37 def makebreadcrumb(url, prefix=''): |
28 def makebreadcrumb(url, prefix=''): |
38 '''Return a 'URL breadcrumb' list |
29 '''Return a 'URL breadcrumb' list |
39 |
30 |
40 A 'URL breadcrumb' is a list of URL-name pairs, |
31 A 'URL breadcrumb' is a list of URL-name pairs, |
64 |
55 |
65 Servers can be multi-threaded. Holding state on the WSGI application |
56 Servers can be multi-threaded. Holding state on the WSGI application |
66 is prone to race conditions. Instances of this class exist to hold |
57 is prone to race conditions. Instances of this class exist to hold |
67 mutable and race-free state for requests. |
58 mutable and race-free state for requests. |
68 """ |
59 """ |
69 def __init__(self, app): |
60 def __init__(self, app, repo): |
70 self.repo = app.repo |
61 self.repo = repo |
71 self.reponame = app.reponame |
62 self.reponame = app.reponame |
72 |
63 |
73 self.archives = ('zip', 'gz', 'bz2') |
64 self.archives = ('zip', 'gz', 'bz2') |
74 |
65 |
75 self.maxchanges = self.configint('web', 'maxchanges', 10) |
66 self.maxchanges = self.configint('web', 'maxchanges', 10) |
215 r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb') |
206 r.baseui.setconfig('ui', 'nontty', 'true', 'hgweb') |
216 # displaying bundling progress bar while serving feel wrong and may |
207 # displaying bundling progress bar while serving feel wrong and may |
217 # break some wsgi implementation. |
208 # break some wsgi implementation. |
218 r.ui.setconfig('progress', 'disable', 'true', 'hgweb') |
209 r.ui.setconfig('progress', 'disable', 'true', 'hgweb') |
219 r.baseui.setconfig('progress', 'disable', 'true', 'hgweb') |
210 r.baseui.setconfig('progress', 'disable', 'true', 'hgweb') |
220 self.repo = self._webifyrepo(r) |
211 self._repo = hg.cachedlocalrepo(self._webifyrepo(r)) |
221 hook.redirect(True) |
212 hook.redirect(True) |
222 self.repostate = None |
|
223 self.mtime = -1 |
|
224 self.reponame = name |
213 self.reponame = name |
225 |
214 |
226 def _webifyrepo(self, repo): |
215 def _webifyrepo(self, repo): |
227 repo = getwebview(repo) |
216 repo = getwebview(repo) |
228 self.websubtable = webutil.getwebsubs(repo) |
217 self.websubtable = webutil.getwebsubs(repo) |
229 return repo |
218 return repo |
230 |
219 |
231 def refresh(self): |
220 def _getrepo(self): |
232 repostate = [] |
221 r, created = self._repo.fetch() |
233 mtime = 0 |
222 if created: |
234 # file of interrests mtime and size |
223 r = self._webifyrepo(r) |
235 for meth, fname in foi: |
224 |
236 prefix = getattr(self.repo, meth) |
225 self.mtime = self._repo.mtime |
237 st = get_stat(prefix, fname) |
226 return r |
238 repostate.append((st.st_mtime, st.st_size)) |
|
239 mtime = max(mtime, st.st_mtime) |
|
240 repostate = tuple(repostate) |
|
241 # we need to compare file size in addition to mtime to catch |
|
242 # changes made less than a second ago |
|
243 if repostate != self.repostate: |
|
244 r = hg.repository(self.repo.baseui, self.repo.url()) |
|
245 self.repo = self._webifyrepo(r) |
|
246 # update these last to avoid threads seeing empty settings |
|
247 self.repostate = repostate |
|
248 # mtime is needed for ETag |
|
249 self.mtime = mtime |
|
250 |
227 |
251 def run(self): |
228 def run(self): |
252 """Start a server from CGI environment. |
229 """Start a server from CGI environment. |
253 |
230 |
254 Modern servers should be using WSGI and should avoid this |
231 Modern servers should be using WSGI and should avoid this |
272 """Internal method to run the WSGI application. |
249 """Internal method to run the WSGI application. |
273 |
250 |
274 This is typically only called by Mercurial. External consumers |
251 This is typically only called by Mercurial. External consumers |
275 should be using instances of this class as the WSGI application. |
252 should be using instances of this class as the WSGI application. |
276 """ |
253 """ |
277 self.refresh() |
254 repo = self._getrepo() |
278 rctx = requestcontext(self) |
255 rctx = requestcontext(self, repo) |
279 |
256 |
280 # This state is global across all threads. |
257 # This state is global across all threads. |
281 encoding.encoding = rctx.config('web', 'encoding', encoding.encoding) |
258 encoding.encoding = rctx.config('web', 'encoding', encoding.encoding) |
282 rctx.repo.ui.environ = req.env |
259 rctx.repo.ui.environ = req.env |
283 |
260 |