##// END OF EJS Templates
hgweb: make paths wildcards expanding in a repo root match repo correctly...
Mads Kiilerich -
r13403:8ed91088 default
parent child Browse files
Show More
@@ -1,370 +1,368 b''
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
1 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
2 #
2 #
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
3 # Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
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 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 import os, re, time, urlparse
9 import os, re, time, urlparse
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
15 from hgweb_mod import hgweb
15 from hgweb_mod import hgweb
16 from request import wsgirequest
16 from request import wsgirequest
17 import webutil
17 import webutil
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 def findrepos(paths):
22 def findrepos(paths):
23 repos = []
23 repos = []
24 for prefix, root in cleannames(paths):
24 for prefix, root in cleannames(paths):
25 roothead, roottail = os.path.split(root)
25 roothead, roottail = os.path.split(root)
26 # "foo = /bar/*" makes every subrepo of /bar/ to be
26 # "foo = /bar/*" makes every subrepo of /bar/ to be
27 # mounted as foo/subrepo
27 # mounted as foo/subrepo
28 # and "foo = /bar/**" also recurses into the subdirectories,
28 # and "foo = /bar/**" also recurses into the subdirectories,
29 # remember to use it without working dir.
29 # remember to use it without working dir.
30 try:
30 try:
31 recurse = {'*': False, '**': True}[roottail]
31 recurse = {'*': False, '**': True}[roottail]
32 except KeyError:
32 except KeyError:
33 repos.append((prefix, root))
33 repos.append((prefix, root))
34 continue
34 continue
35 roothead = os.path.normpath(os.path.abspath(roothead))
35 roothead = os.path.normpath(os.path.abspath(roothead))
36 paths = util.walkrepos(roothead, followsym=True, recurse=recurse)
36 paths = util.walkrepos(roothead, followsym=True, recurse=recurse)
37 repos.extend(urlrepos(prefix, roothead, paths))
37 repos.extend(urlrepos(prefix, roothead, paths))
38 return repos
38 return repos
39
39
40 def urlrepos(prefix, roothead, paths):
40 def urlrepos(prefix, roothead, paths):
41 """yield url paths and filesystem paths from a list of repo paths
41 """yield url paths and filesystem paths from a list of repo paths
42
42
43 >>> list(urlrepos('hg', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
43 >>> list(urlrepos('hg', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
44 [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg/', '/opt')]
44 [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg', '/opt')]
45 >>> list(urlrepos('', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
45 >>> list(urlrepos('', '/opt', ['/opt/r', '/opt/r/r', '/opt']))
46 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
46 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
47 """
47 """
48 for path in paths:
48 for path in paths:
49 path = os.path.normpath(path)
49 path = os.path.normpath(path)
50 name = util.pconvert(path[len(roothead):]).strip('/')
50 yield (prefix + '/' +
51 if prefix:
51 util.pconvert(path[len(roothead):]).lstrip('/')).strip('/'), path
52 name = prefix + '/' + name
53 yield name, path
54
52
55 class hgwebdir(object):
53 class hgwebdir(object):
56 refreshinterval = 20
54 refreshinterval = 20
57
55
58 def __init__(self, conf, baseui=None):
56 def __init__(self, conf, baseui=None):
59 self.conf = conf
57 self.conf = conf
60 self.baseui = baseui
58 self.baseui = baseui
61 self.lastrefresh = 0
59 self.lastrefresh = 0
62 self.motd = None
60 self.motd = None
63 self.refresh()
61 self.refresh()
64
62
65 def refresh(self):
63 def refresh(self):
66 if self.lastrefresh + self.refreshinterval > time.time():
64 if self.lastrefresh + self.refreshinterval > time.time():
67 return
65 return
68
66
69 if self.baseui:
67 if self.baseui:
70 u = self.baseui.copy()
68 u = self.baseui.copy()
71 else:
69 else:
72 u = ui.ui()
70 u = ui.ui()
73 u.setconfig('ui', 'report_untrusted', 'off')
71 u.setconfig('ui', 'report_untrusted', 'off')
74 u.setconfig('ui', 'interactive', 'off')
72 u.setconfig('ui', 'interactive', 'off')
75
73
76 if not isinstance(self.conf, (dict, list, tuple)):
74 if not isinstance(self.conf, (dict, list, tuple)):
77 map = {'paths': 'hgweb-paths'}
75 map = {'paths': 'hgweb-paths'}
78 if not os.path.exists(self.conf):
76 if not os.path.exists(self.conf):
79 raise util.Abort(_('config file %s not found!') % self.conf)
77 raise util.Abort(_('config file %s not found!') % self.conf)
80 u.readconfig(self.conf, remap=map, trust=True)
78 u.readconfig(self.conf, remap=map, trust=True)
81 paths = u.configitems('hgweb-paths')
79 paths = u.configitems('hgweb-paths')
82 elif isinstance(self.conf, (list, tuple)):
80 elif isinstance(self.conf, (list, tuple)):
83 paths = self.conf
81 paths = self.conf
84 elif isinstance(self.conf, dict):
82 elif isinstance(self.conf, dict):
85 paths = self.conf.items()
83 paths = self.conf.items()
86
84
87 repos = findrepos(paths)
85 repos = findrepos(paths)
88 for prefix, root in u.configitems('collections'):
86 for prefix, root in u.configitems('collections'):
89 prefix = util.pconvert(prefix)
87 prefix = util.pconvert(prefix)
90 for path in util.walkrepos(root, followsym=True):
88 for path in util.walkrepos(root, followsym=True):
91 repo = os.path.normpath(path)
89 repo = os.path.normpath(path)
92 name = util.pconvert(repo)
90 name = util.pconvert(repo)
93 if name.startswith(prefix):
91 if name.startswith(prefix):
94 name = name[len(prefix):]
92 name = name[len(prefix):]
95 repos.append((name.lstrip('/'), repo))
93 repos.append((name.lstrip('/'), repo))
96
94
97 self.repos = repos
95 self.repos = repos
98 self.ui = u
96 self.ui = u
99 encoding.encoding = self.ui.config('web', 'encoding',
97 encoding.encoding = self.ui.config('web', 'encoding',
100 encoding.encoding)
98 encoding.encoding)
101 self.style = self.ui.config('web', 'style', 'paper')
99 self.style = self.ui.config('web', 'style', 'paper')
102 self.templatepath = self.ui.config('web', 'templates', None)
100 self.templatepath = self.ui.config('web', 'templates', None)
103 self.stripecount = self.ui.config('web', 'stripes', 1)
101 self.stripecount = self.ui.config('web', 'stripes', 1)
104 if self.stripecount:
102 if self.stripecount:
105 self.stripecount = int(self.stripecount)
103 self.stripecount = int(self.stripecount)
106 self._baseurl = self.ui.config('web', 'baseurl')
104 self._baseurl = self.ui.config('web', 'baseurl')
107 self.lastrefresh = time.time()
105 self.lastrefresh = time.time()
108
106
109 def run(self):
107 def run(self):
110 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
108 if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
111 raise RuntimeError("This function is only intended to be "
109 raise RuntimeError("This function is only intended to be "
112 "called while running as a CGI script.")
110 "called while running as a CGI script.")
113 import mercurial.hgweb.wsgicgi as wsgicgi
111 import mercurial.hgweb.wsgicgi as wsgicgi
114 wsgicgi.launch(self)
112 wsgicgi.launch(self)
115
113
116 def __call__(self, env, respond):
114 def __call__(self, env, respond):
117 req = wsgirequest(env, respond)
115 req = wsgirequest(env, respond)
118 return self.run_wsgi(req)
116 return self.run_wsgi(req)
119
117
120 def read_allowed(self, ui, req):
118 def read_allowed(self, ui, req):
121 """Check allow_read and deny_read config options of a repo's ui object
119 """Check allow_read and deny_read config options of a repo's ui object
122 to determine user permissions. By default, with neither option set (or
120 to determine user permissions. By default, with neither option set (or
123 both empty), allow all users to read the repo. There are two ways a
121 both empty), allow all users to read the repo. There are two ways a
124 user can be denied read access: (1) deny_read is not empty, and the
122 user can be denied read access: (1) deny_read is not empty, and the
125 user is unauthenticated or deny_read contains user (or *), and (2)
123 user is unauthenticated or deny_read contains user (or *), and (2)
126 allow_read is not empty and the user is not in allow_read. Return True
124 allow_read is not empty and the user is not in allow_read. Return True
127 if user is allowed to read the repo, else return False."""
125 if user is allowed to read the repo, else return False."""
128
126
129 user = req.env.get('REMOTE_USER')
127 user = req.env.get('REMOTE_USER')
130
128
131 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
129 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
132 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
130 if deny_read and (not user or deny_read == ['*'] or user in deny_read):
133 return False
131 return False
134
132
135 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
133 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
136 # by default, allow reading if no allow_read option has been set
134 # by default, allow reading if no allow_read option has been set
137 if (not allow_read) or (allow_read == ['*']) or (user in allow_read):
135 if (not allow_read) or (allow_read == ['*']) or (user in allow_read):
138 return True
136 return True
139
137
140 return False
138 return False
141
139
142 def run_wsgi(self, req):
140 def run_wsgi(self, req):
143 try:
141 try:
144 try:
142 try:
145 self.refresh()
143 self.refresh()
146
144
147 virtual = req.env.get("PATH_INFO", "").strip('/')
145 virtual = req.env.get("PATH_INFO", "").strip('/')
148 tmpl = self.templater(req)
146 tmpl = self.templater(req)
149 ctype = tmpl('mimetype', encoding=encoding.encoding)
147 ctype = tmpl('mimetype', encoding=encoding.encoding)
150 ctype = templater.stringify(ctype)
148 ctype = templater.stringify(ctype)
151
149
152 # a static file
150 # a static file
153 if virtual.startswith('static/') or 'static' in req.form:
151 if virtual.startswith('static/') or 'static' in req.form:
154 if virtual.startswith('static/'):
152 if virtual.startswith('static/'):
155 fname = virtual[7:]
153 fname = virtual[7:]
156 else:
154 else:
157 fname = req.form['static'][0]
155 fname = req.form['static'][0]
158 static = templater.templatepath('static')
156 static = templater.templatepath('static')
159 return (staticfile(static, fname, req),)
157 return (staticfile(static, fname, req),)
160
158
161 # top-level index
159 # top-level index
162 elif not virtual:
160 elif not virtual:
163 req.respond(HTTP_OK, ctype)
161 req.respond(HTTP_OK, ctype)
164 return self.makeindex(req, tmpl)
162 return self.makeindex(req, tmpl)
165
163
166 # nested indexes and hgwebs
164 # nested indexes and hgwebs
167
165
168 repos = dict(self.repos)
166 repos = dict(self.repos)
169 virtualrepo = virtual
167 virtualrepo = virtual
170 while virtualrepo:
168 while virtualrepo:
171 real = repos.get(virtualrepo)
169 real = repos.get(virtualrepo)
172 if real:
170 if real:
173 req.env['REPO_NAME'] = virtualrepo
171 req.env['REPO_NAME'] = virtualrepo
174 try:
172 try:
175 repo = hg.repository(self.ui, real)
173 repo = hg.repository(self.ui, real)
176 return hgweb(repo).run_wsgi(req)
174 return hgweb(repo).run_wsgi(req)
177 except IOError, inst:
175 except IOError, inst:
178 msg = inst.strerror
176 msg = inst.strerror
179 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
177 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
180 except error.RepoError, inst:
178 except error.RepoError, inst:
181 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
179 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
182
180
183 up = virtualrepo.rfind('/')
181 up = virtualrepo.rfind('/')
184 if up < 0:
182 if up < 0:
185 break
183 break
186 virtualrepo = virtualrepo[:up]
184 virtualrepo = virtualrepo[:up]
187
185
188 # browse subdirectories
186 # browse subdirectories
189 subdir = virtual + '/'
187 subdir = virtual + '/'
190 if [r for r in repos if r.startswith(subdir)]:
188 if [r for r in repos if r.startswith(subdir)]:
191 req.respond(HTTP_OK, ctype)
189 req.respond(HTTP_OK, ctype)
192 return self.makeindex(req, tmpl, subdir)
190 return self.makeindex(req, tmpl, subdir)
193
191
194 # prefixes not found
192 # prefixes not found
195 req.respond(HTTP_NOT_FOUND, ctype)
193 req.respond(HTTP_NOT_FOUND, ctype)
196 return tmpl("notfound", repo=virtual)
194 return tmpl("notfound", repo=virtual)
197
195
198 except ErrorResponse, err:
196 except ErrorResponse, err:
199 req.respond(err, ctype)
197 req.respond(err, ctype)
200 return tmpl('error', error=err.message or '')
198 return tmpl('error', error=err.message or '')
201 finally:
199 finally:
202 tmpl = None
200 tmpl = None
203
201
204 def makeindex(self, req, tmpl, subdir=""):
202 def makeindex(self, req, tmpl, subdir=""):
205
203
206 def archivelist(ui, nodeid, url):
204 def archivelist(ui, nodeid, url):
207 allowed = ui.configlist("web", "allow_archive", untrusted=True)
205 allowed = ui.configlist("web", "allow_archive", untrusted=True)
208 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
206 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
209 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
207 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
210 untrusted=True):
208 untrusted=True):
211 yield {"type" : i[0], "extension": i[1],
209 yield {"type" : i[0], "extension": i[1],
212 "node": nodeid, "url": url}
210 "node": nodeid, "url": url}
213
211
214 def rawentries(subdir="", **map):
212 def rawentries(subdir="", **map):
215
213
216 descend = self.ui.configbool('web', 'descend', True)
214 descend = self.ui.configbool('web', 'descend', True)
217 for name, path in self.repos:
215 for name, path in self.repos:
218
216
219 if not name.startswith(subdir):
217 if not name.startswith(subdir):
220 continue
218 continue
221 name = name[len(subdir):]
219 name = name[len(subdir):]
222 if not descend and '/' in name:
220 if not descend and '/' in name:
223 continue
221 continue
224
222
225 u = self.ui.copy()
223 u = self.ui.copy()
226 try:
224 try:
227 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
225 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
228 except Exception, e:
226 except Exception, e:
229 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
227 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
230 continue
228 continue
231 def get(section, name, default=None):
229 def get(section, name, default=None):
232 return u.config(section, name, default, untrusted=True)
230 return u.config(section, name, default, untrusted=True)
233
231
234 if u.configbool("web", "hidden", untrusted=True):
232 if u.configbool("web", "hidden", untrusted=True):
235 continue
233 continue
236
234
237 if not self.read_allowed(u, req):
235 if not self.read_allowed(u, req):
238 continue
236 continue
239
237
240 parts = [name]
238 parts = [name]
241 if 'PATH_INFO' in req.env:
239 if 'PATH_INFO' in req.env:
242 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
240 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
243 if req.env['SCRIPT_NAME']:
241 if req.env['SCRIPT_NAME']:
244 parts.insert(0, req.env['SCRIPT_NAME'])
242 parts.insert(0, req.env['SCRIPT_NAME'])
245 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
243 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
246
244
247 # update time with local timezone
245 # update time with local timezone
248 try:
246 try:
249 r = hg.repository(self.ui, path)
247 r = hg.repository(self.ui, path)
250 except error.RepoError:
248 except error.RepoError:
251 u.warn(_('error accessing repository at %s\n') % path)
249 u.warn(_('error accessing repository at %s\n') % path)
252 continue
250 continue
253 try:
251 try:
254 d = (get_mtime(r.spath), util.makedate()[1])
252 d = (get_mtime(r.spath), util.makedate()[1])
255 except OSError:
253 except OSError:
256 continue
254 continue
257
255
258 contact = get_contact(get)
256 contact = get_contact(get)
259 description = get("web", "description", "")
257 description = get("web", "description", "")
260 name = get("web", "name", name)
258 name = get("web", "name", name)
261 row = dict(contact=contact or "unknown",
259 row = dict(contact=contact or "unknown",
262 contact_sort=contact.upper() or "unknown",
260 contact_sort=contact.upper() or "unknown",
263 name=name,
261 name=name,
264 name_sort=name,
262 name_sort=name,
265 url=url,
263 url=url,
266 description=description or "unknown",
264 description=description or "unknown",
267 description_sort=description.upper() or "unknown",
265 description_sort=description.upper() or "unknown",
268 lastchange=d,
266 lastchange=d,
269 lastchange_sort=d[1]-d[0],
267 lastchange_sort=d[1]-d[0],
270 archives=archivelist(u, "tip", url))
268 archives=archivelist(u, "tip", url))
271 yield row
269 yield row
272
270
273 sortdefault = None, False
271 sortdefault = None, False
274 def entries(sortcolumn="", descending=False, subdir="", **map):
272 def entries(sortcolumn="", descending=False, subdir="", **map):
275 rows = rawentries(subdir=subdir, **map)
273 rows = rawentries(subdir=subdir, **map)
276
274
277 if sortcolumn and sortdefault != (sortcolumn, descending):
275 if sortcolumn and sortdefault != (sortcolumn, descending):
278 sortkey = '%s_sort' % sortcolumn
276 sortkey = '%s_sort' % sortcolumn
279 rows = sorted(rows, key=lambda x: x[sortkey],
277 rows = sorted(rows, key=lambda x: x[sortkey],
280 reverse=descending)
278 reverse=descending)
281 for row, parity in zip(rows, paritygen(self.stripecount)):
279 for row, parity in zip(rows, paritygen(self.stripecount)):
282 row['parity'] = parity
280 row['parity'] = parity
283 yield row
281 yield row
284
282
285 self.refresh()
283 self.refresh()
286 sortable = ["name", "description", "contact", "lastchange"]
284 sortable = ["name", "description", "contact", "lastchange"]
287 sortcolumn, descending = sortdefault
285 sortcolumn, descending = sortdefault
288 if 'sort' in req.form:
286 if 'sort' in req.form:
289 sortcolumn = req.form['sort'][0]
287 sortcolumn = req.form['sort'][0]
290 descending = sortcolumn.startswith('-')
288 descending = sortcolumn.startswith('-')
291 if descending:
289 if descending:
292 sortcolumn = sortcolumn[1:]
290 sortcolumn = sortcolumn[1:]
293 if sortcolumn not in sortable:
291 if sortcolumn not in sortable:
294 sortcolumn = ""
292 sortcolumn = ""
295
293
296 sort = [("sort_%s" % column,
294 sort = [("sort_%s" % column,
297 "%s%s" % ((not descending and column == sortcolumn)
295 "%s%s" % ((not descending and column == sortcolumn)
298 and "-" or "", column))
296 and "-" or "", column))
299 for column in sortable]
297 for column in sortable]
300
298
301 self.refresh()
299 self.refresh()
302 self.updatereqenv(req.env)
300 self.updatereqenv(req.env)
303
301
304 return tmpl("index", entries=entries, subdir=subdir,
302 return tmpl("index", entries=entries, subdir=subdir,
305 sortcolumn=sortcolumn, descending=descending,
303 sortcolumn=sortcolumn, descending=descending,
306 **dict(sort))
304 **dict(sort))
307
305
308 def templater(self, req):
306 def templater(self, req):
309
307
310 def header(**map):
308 def header(**map):
311 yield tmpl('header', encoding=encoding.encoding, **map)
309 yield tmpl('header', encoding=encoding.encoding, **map)
312
310
313 def footer(**map):
311 def footer(**map):
314 yield tmpl("footer", **map)
312 yield tmpl("footer", **map)
315
313
316 def motd(**map):
314 def motd(**map):
317 if self.motd is not None:
315 if self.motd is not None:
318 yield self.motd
316 yield self.motd
319 else:
317 else:
320 yield config('web', 'motd', '')
318 yield config('web', 'motd', '')
321
319
322 def config(section, name, default=None, untrusted=True):
320 def config(section, name, default=None, untrusted=True):
323 return self.ui.config(section, name, default, untrusted)
321 return self.ui.config(section, name, default, untrusted)
324
322
325 self.updatereqenv(req.env)
323 self.updatereqenv(req.env)
326
324
327 url = req.env.get('SCRIPT_NAME', '')
325 url = req.env.get('SCRIPT_NAME', '')
328 if not url.endswith('/'):
326 if not url.endswith('/'):
329 url += '/'
327 url += '/'
330
328
331 vars = {}
329 vars = {}
332 styles = (
330 styles = (
333 req.form.get('style', [None])[0],
331 req.form.get('style', [None])[0],
334 config('web', 'style'),
332 config('web', 'style'),
335 'paper'
333 'paper'
336 )
334 )
337 style, mapfile = templater.stylemap(styles, self.templatepath)
335 style, mapfile = templater.stylemap(styles, self.templatepath)
338 if style == styles[0]:
336 if style == styles[0]:
339 vars['style'] = style
337 vars['style'] = style
340
338
341 start = url[-1] == '?' and '&' or '?'
339 start = url[-1] == '?' and '&' or '?'
342 sessionvars = webutil.sessionvars(vars, start)
340 sessionvars = webutil.sessionvars(vars, start)
343 staticurl = config('web', 'staticurl') or url + 'static/'
341 staticurl = config('web', 'staticurl') or url + 'static/'
344 if not staticurl.endswith('/'):
342 if not staticurl.endswith('/'):
345 staticurl += '/'
343 staticurl += '/'
346
344
347 tmpl = templater.templater(mapfile,
345 tmpl = templater.templater(mapfile,
348 defaults={"header": header,
346 defaults={"header": header,
349 "footer": footer,
347 "footer": footer,
350 "motd": motd,
348 "motd": motd,
351 "url": url,
349 "url": url,
352 "staticurl": staticurl,
350 "staticurl": staticurl,
353 "sessionvars": sessionvars})
351 "sessionvars": sessionvars})
354 return tmpl
352 return tmpl
355
353
356 def updatereqenv(self, env):
354 def updatereqenv(self, env):
357 def splitnetloc(netloc):
355 def splitnetloc(netloc):
358 if ':' in netloc:
356 if ':' in netloc:
359 return netloc.split(':', 1)
357 return netloc.split(':', 1)
360 else:
358 else:
361 return (netloc, None)
359 return (netloc, None)
362
360
363 if self._baseurl is not None:
361 if self._baseurl is not None:
364 urlcomp = urlparse.urlparse(self._baseurl)
362 urlcomp = urlparse.urlparse(self._baseurl)
365 host, port = splitnetloc(urlcomp[1])
363 host, port = splitnetloc(urlcomp[1])
366 path = urlcomp[2]
364 path = urlcomp[2]
367 env['SERVER_NAME'] = host
365 env['SERVER_NAME'] = host
368 if port:
366 if port:
369 env['SERVER_PORT'] = port
367 env['SERVER_PORT'] = port
370 env['SCRIPT_NAME'] = path
368 env['SCRIPT_NAME'] = path
@@ -1,648 +1,673 b''
1 Tests some basic hgwebdir functionality. Tests setting up paths and
1 Tests some basic hgwebdir functionality. Tests setting up paths and
2 collection, different forms of 404s and the subdirectory support.
2 collection, different forms of 404s and the subdirectory support.
3
3
4 $ mkdir webdir
4 $ mkdir webdir
5 $ cd webdir
5 $ cd webdir
6 $ hg init a
6 $ hg init a
7 $ echo a > a/a
7 $ echo a > a/a
8 $ hg --cwd a ci -Ama -d'1 0'
8 $ hg --cwd a ci -Ama -d'1 0'
9 adding a
9 adding a
10
10
11 create a mercurial queue repository
11 create a mercurial queue repository
12
12
13 $ hg --cwd a qinit --config extensions.hgext.mq= -c
13 $ hg --cwd a qinit --config extensions.hgext.mq= -c
14 $ hg init b
14 $ hg init b
15 $ echo b > b/b
15 $ echo b > b/b
16 $ hg --cwd b ci -Amb -d'2 0'
16 $ hg --cwd b ci -Amb -d'2 0'
17 adding b
17 adding b
18
18
19 create a nested repository
19 create a nested repository
20
20
21 $ cd b
21 $ cd b
22 $ hg init d
22 $ hg init d
23 $ echo d > d/d
23 $ echo d > d/d
24 $ hg --cwd d ci -Amd -d'3 0'
24 $ hg --cwd d ci -Amd -d'3 0'
25 adding d
25 adding d
26 $ cd ..
26 $ cd ..
27 $ hg init c
27 $ hg init c
28 $ echo c > c/c
28 $ echo c > c/c
29 $ hg --cwd c ci -Amc -d'3 0'
29 $ hg --cwd c ci -Amc -d'3 0'
30 adding c
30 adding c
31
31
32 create repository without .hg/store
32 create repository without .hg/store
33
33
34 $ hg init nostore
34 $ hg init nostore
35 $ rm -R nostore/.hg/store
35 $ rm -R nostore/.hg/store
36 $ root=`pwd`
36 $ root=`pwd`
37 $ cd ..
37 $ cd ..
38 $ cat > paths.conf <<EOF
38 $ cat > paths.conf <<EOF
39 > [paths]
39 > [paths]
40 > a=$root/a
40 > a=$root/a
41 > b=$root/b
41 > b=$root/b
42 > EOF
42 > EOF
43 $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
43 $ hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
44 > -A access-paths.log -E error-paths-1.log
44 > -A access-paths.log -E error-paths-1.log
45 $ cat hg.pid >> $DAEMON_PIDS
45 $ cat hg.pid >> $DAEMON_PIDS
46
46
47 should give a 404 - file does not exist
47 should give a 404 - file does not exist
48
48
49 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
49 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
50 404 Not Found
50 404 Not Found
51
51
52
52
53 error: bork@8580ff50825a: not found in manifest
53 error: bork@8580ff50825a: not found in manifest
54 [1]
54 [1]
55
55
56 should succeed
56 should succeed
57
57
58 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
58 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
59 200 Script output follows
59 200 Script output follows
60
60
61
61
62 /a/
62 /a/
63 /b/
63 /b/
64
64
65 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
65 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
66 200 Script output follows
66 200 Script output follows
67
67
68 a
68 a
69 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
69 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
70 200 Script output follows
70 200 Script output follows
71
71
72 b
72 b
73
73
74 should give a 404 - repo is not published
74 should give a 404 - repo is not published
75
75
76 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
76 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
77 404 Not Found
77 404 Not Found
78
78
79
79
80 error: repository c/file/tip/c not found
80 error: repository c/file/tip/c not found
81 [1]
81 [1]
82
82
83 atom-log without basedir
83 atom-log without basedir
84
84
85 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' | grep '<link'
85 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' | grep '<link'
86 <link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
86 <link rel="self" href="http://*:$HGPORT/a/atom-log"/> (glob)
87 <link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
87 <link rel="alternate" href="http://*:$HGPORT/a/"/> (glob)
88 <link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
88 <link href="http://*:$HGPORT/a/rev/8580ff50825a"/> (glob)
89
89
90 rss-log without basedir
90 rss-log without basedir
91
91
92 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' | grep '<guid'
92 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' | grep '<guid'
93 <guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
93 <guid isPermaLink="true">http://*:$HGPORT/a/rev/8580ff50825a</guid> (glob)
94 $ cat > paths.conf <<EOF
94 $ cat > paths.conf <<EOF
95 > [paths]
95 > [paths]
96 > t/a/=$root/a
96 > t/a/=$root/a
97 > b=$root/b
97 > b=$root/b
98 > coll=$root/*
98 > coll=$root/*
99 > rcoll=$root/**
99 > rcoll=$root/**
100 > star=*
100 > star=*
101 > starstar=**
101 > starstar=**
102 > astar=webdir/a/*
102 > EOF
103 > EOF
103 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
104 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
104 > -A access-paths.log -E error-paths-2.log
105 > -A access-paths.log -E error-paths-2.log
105 $ cat hg.pid >> $DAEMON_PIDS
106 $ cat hg.pid >> $DAEMON_PIDS
106
107
107 should succeed, slashy names
108 should succeed, slashy names
108
109
109 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
110 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
110 200 Script output follows
111 200 Script output follows
111
112
112
113
113 /t/a/
114 /t/a/
114 /b/
115 /b/
115 /coll/a/
116 /coll/a/
116 /coll/a/.hg/patches/
117 /coll/a/.hg/patches/
117 /coll/b/
118 /coll/b/
118 /coll/c/
119 /coll/c/
119 /rcoll/a/
120 /rcoll/a/
120 /rcoll/a/.hg/patches/
121 /rcoll/a/.hg/patches/
121 /rcoll/b/
122 /rcoll/b/
122 /rcoll/b/d/
123 /rcoll/b/d/
123 /rcoll/c/
124 /rcoll/c/
124 /star/webdir/a/
125 /star/webdir/a/
125 /star/webdir/a/.hg/patches/
126 /star/webdir/a/.hg/patches/
126 /star/webdir/b/
127 /star/webdir/b/
127 /star/webdir/c/
128 /star/webdir/c/
128 /starstar/webdir/a/
129 /starstar/webdir/a/
129 /starstar/webdir/a/.hg/patches/
130 /starstar/webdir/a/.hg/patches/
130 /starstar/webdir/b/
131 /starstar/webdir/b/
131 /starstar/webdir/b/d/
132 /starstar/webdir/b/d/
132 /starstar/webdir/c/
133 /starstar/webdir/c/
134 /astar/
135 /astar/.hg/patches/
133
136
134 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper'
137 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper'
135 200 Script output follows
138 200 Script output follows
136
139
137 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
140 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
138 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
141 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
139 <head>
142 <head>
140 <link rel="icon" href="/static/hgicon.png" type="image/png" />
143 <link rel="icon" href="/static/hgicon.png" type="image/png" />
141 <meta name="robots" content="index, nofollow" />
144 <meta name="robots" content="index, nofollow" />
142 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
145 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
143
146
144 <title>Mercurial repositories index</title>
147 <title>Mercurial repositories index</title>
145 </head>
148 </head>
146 <body>
149 <body>
147
150
148 <div class="container">
151 <div class="container">
149 <div class="menu">
152 <div class="menu">
150 <a href="http://mercurial.selenic.com/">
153 <a href="http://mercurial.selenic.com/">
151 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
154 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
152 </div>
155 </div>
153 <div class="main">
156 <div class="main">
154 <h2>Mercurial Repositories</h2>
157 <h2>Mercurial Repositories</h2>
155
158
156 <table class="bigtable">
159 <table class="bigtable">
157 <tr>
160 <tr>
158 <th><a href="?sort=name">Name</a></th>
161 <th><a href="?sort=name">Name</a></th>
159 <th><a href="?sort=description">Description</a></th>
162 <th><a href="?sort=description">Description</a></th>
160 <th><a href="?sort=contact">Contact</a></th>
163 <th><a href="?sort=contact">Contact</a></th>
161 <th><a href="?sort=lastchange">Last modified</a></th>
164 <th><a href="?sort=lastchange">Last modified</a></th>
162 <th>&nbsp;</th>
165 <th>&nbsp;</th>
163 </tr>
166 </tr>
164
167
165 <tr class="parity0">
168 <tr class="parity0">
166 <td><a href="/t/a/?style=paper">t/a</a></td>
169 <td><a href="/t/a/?style=paper">t/a</a></td>
167 <td>unknown</td>
170 <td>unknown</td>
168 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
171 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
169 <td class="age">* ago</td> (glob)
172 <td class="age">* ago</td> (glob)
170 <td class="indexlinks"></td>
173 <td class="indexlinks"></td>
171 </tr>
174 </tr>
172
175
173 <tr class="parity1">
176 <tr class="parity1">
174 <td><a href="/b/?style=paper">b</a></td>
177 <td><a href="/b/?style=paper">b</a></td>
175 <td>unknown</td>
178 <td>unknown</td>
176 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
179 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
177 <td class="age">* ago</td> (glob)
180 <td class="age">* ago</td> (glob)
178 <td class="indexlinks"></td>
181 <td class="indexlinks"></td>
179 </tr>
182 </tr>
180
183
181 <tr class="parity0">
184 <tr class="parity0">
182 <td><a href="/coll/a/?style=paper">coll/a</a></td>
185 <td><a href="/coll/a/?style=paper">coll/a</a></td>
183 <td>unknown</td>
186 <td>unknown</td>
184 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
187 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
185 <td class="age">* ago</td> (glob)
188 <td class="age">* ago</td> (glob)
186 <td class="indexlinks"></td>
189 <td class="indexlinks"></td>
187 </tr>
190 </tr>
188
191
189 <tr class="parity1">
192 <tr class="parity1">
190 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
193 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
191 <td>unknown</td>
194 <td>unknown</td>
192 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
195 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
193 <td class="age">* ago</td> (glob)
196 <td class="age">* ago</td> (glob)
194 <td class="indexlinks"></td>
197 <td class="indexlinks"></td>
195 </tr>
198 </tr>
196
199
197 <tr class="parity0">
200 <tr class="parity0">
198 <td><a href="/coll/b/?style=paper">coll/b</a></td>
201 <td><a href="/coll/b/?style=paper">coll/b</a></td>
199 <td>unknown</td>
202 <td>unknown</td>
200 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
203 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
201 <td class="age">* ago</td> (glob)
204 <td class="age">* ago</td> (glob)
202 <td class="indexlinks"></td>
205 <td class="indexlinks"></td>
203 </tr>
206 </tr>
204
207
205 <tr class="parity1">
208 <tr class="parity1">
206 <td><a href="/coll/c/?style=paper">coll/c</a></td>
209 <td><a href="/coll/c/?style=paper">coll/c</a></td>
207 <td>unknown</td>
210 <td>unknown</td>
208 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
211 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
209 <td class="age">* ago</td> (glob)
212 <td class="age">* ago</td> (glob)
210 <td class="indexlinks"></td>
213 <td class="indexlinks"></td>
211 </tr>
214 </tr>
212
215
213 <tr class="parity0">
216 <tr class="parity0">
214 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
217 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
215 <td>unknown</td>
218 <td>unknown</td>
216 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
219 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
217 <td class="age">* ago</td> (glob)
220 <td class="age">* ago</td> (glob)
218 <td class="indexlinks"></td>
221 <td class="indexlinks"></td>
219 </tr>
222 </tr>
220
223
221 <tr class="parity1">
224 <tr class="parity1">
222 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
225 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
223 <td>unknown</td>
226 <td>unknown</td>
224 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
227 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
225 <td class="age">* ago</td> (glob)
228 <td class="age">* ago</td> (glob)
226 <td class="indexlinks"></td>
229 <td class="indexlinks"></td>
227 </tr>
230 </tr>
228
231
229 <tr class="parity0">
232 <tr class="parity0">
230 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
233 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
231 <td>unknown</td>
234 <td>unknown</td>
232 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
235 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
233 <td class="age">* ago</td> (glob)
236 <td class="age">* ago</td> (glob)
234 <td class="indexlinks"></td>
237 <td class="indexlinks"></td>
235 </tr>
238 </tr>
236
239
237 <tr class="parity1">
240 <tr class="parity1">
238 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
241 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
239 <td>unknown</td>
242 <td>unknown</td>
240 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
243 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
241 <td class="age">* ago</td> (glob)
244 <td class="age">* ago</td> (glob)
242 <td class="indexlinks"></td>
245 <td class="indexlinks"></td>
243 </tr>
246 </tr>
244
247
245 <tr class="parity0">
248 <tr class="parity0">
246 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
249 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
247 <td>unknown</td>
250 <td>unknown</td>
248 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
251 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
249 <td class="age">* ago</td> (glob)
252 <td class="age">* ago</td> (glob)
250 <td class="indexlinks"></td>
253 <td class="indexlinks"></td>
251 </tr>
254 </tr>
252
255
253 <tr class="parity1">
256 <tr class="parity1">
254 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
257 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
255 <td>unknown</td>
258 <td>unknown</td>
256 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
259 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
257 <td class="age">* ago</td> (glob)
260 <td class="age">* ago</td> (glob)
258 <td class="indexlinks"></td>
261 <td class="indexlinks"></td>
259 </tr>
262 </tr>
260
263
261 <tr class="parity0">
264 <tr class="parity0">
262 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
265 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
263 <td>unknown</td>
266 <td>unknown</td>
264 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
267 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
265 <td class="age">* ago</td> (glob)
268 <td class="age">* ago</td> (glob)
266 <td class="indexlinks"></td>
269 <td class="indexlinks"></td>
267 </tr>
270 </tr>
268
271
269 <tr class="parity1">
272 <tr class="parity1">
270 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
273 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
271 <td>unknown</td>
274 <td>unknown</td>
272 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
275 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
273 <td class="age">* ago</td> (glob)
276 <td class="age">* ago</td> (glob)
274 <td class="indexlinks"></td>
277 <td class="indexlinks"></td>
275 </tr>
278 </tr>
276
279
277 <tr class="parity0">
280 <tr class="parity0">
278 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
281 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
279 <td>unknown</td>
282 <td>unknown</td>
280 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
283 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
281 <td class="age">* ago</td> (glob)
284 <td class="age">* ago</td> (glob)
282 <td class="indexlinks"></td>
285 <td class="indexlinks"></td>
283 </tr>
286 </tr>
284
287
285 <tr class="parity1">
288 <tr class="parity1">
286 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
289 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
287 <td>unknown</td>
290 <td>unknown</td>
288 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
291 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
289 <td class="age">* ago</td> (glob)
292 <td class="age">* ago</td> (glob)
290 <td class="indexlinks"></td>
293 <td class="indexlinks"></td>
291 </tr>
294 </tr>
292
295
293 <tr class="parity0">
296 <tr class="parity0">
294 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
297 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
295 <td>unknown</td>
298 <td>unknown</td>
296 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
299 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
297 <td class="age">* ago</td> (glob)
300 <td class="age">* ago</td> (glob)
298 <td class="indexlinks"></td>
301 <td class="indexlinks"></td>
299 </tr>
302 </tr>
300
303
301 <tr class="parity1">
304 <tr class="parity1">
302 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
305 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
303 <td>unknown</td>
306 <td>unknown</td>
304 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
307 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
305 <td class="age">* ago</td> (glob)
308 <td class="age">* ago</td> (glob)
306 <td class="indexlinks"></td>
309 <td class="indexlinks"></td>
307 </tr>
310 </tr>
308
311
309 <tr class="parity0">
312 <tr class="parity0">
310 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
313 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
311 <td>unknown</td>
314 <td>unknown</td>
312 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
315 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
313 <td class="age">* ago</td> (glob)
316 <td class="age">* ago</td> (glob)
314 <td class="indexlinks"></td>
317 <td class="indexlinks"></td>
315 </tr>
318 </tr>
316
319
317 <tr class="parity1">
320 <tr class="parity1">
318 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
321 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
319 <td>unknown</td>
322 <td>unknown</td>
320 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
323 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
321 <td class="age">* ago</td> (glob)
324 <td class="age">* ago</td> (glob)
322 <td class="indexlinks"></td>
325 <td class="indexlinks"></td>
323 </tr>
326 </tr>
324
327
328 <tr class="parity0">
329 <td><a href="/astar/?style=paper">astar</a></td>
330 <td>unknown</td>
331 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
332 <td class="age">* ago</td> (glob)
333 <td class="indexlinks"></td>
334 </tr>
335
336 <tr class="parity1">
337 <td><a href="/astar/.hg/patches/?style=paper">astar/.hg/patches</a></td>
338 <td>unknown</td>
339 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
340 <td class="age">* ago</td> (glob)
341 <td class="indexlinks"></td>
342 </tr>
343
325 </table>
344 </table>
326 </div>
345 </div>
327 </div>
346 </div>
328
347
329
348
330 </body>
349 </body>
331 </html>
350 </html>
332
351
333 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
352 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
334 200 Script output follows
353 200 Script output follows
335
354
336
355
337 /t/a/
356 /t/a/
338
357
339 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
358 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
340 200 Script output follows
359 200 Script output follows
341
360
342
361
343 /t/a/
362 /t/a/
344
363
345 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper'
364 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper'
346 200 Script output follows
365 200 Script output follows
347
366
348 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
367 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
349 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
368 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
350 <head>
369 <head>
351 <link rel="icon" href="/static/hgicon.png" type="image/png" />
370 <link rel="icon" href="/static/hgicon.png" type="image/png" />
352 <meta name="robots" content="index, nofollow" />
371 <meta name="robots" content="index, nofollow" />
353 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
372 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
354
373
355 <title>Mercurial repositories index</title>
374 <title>Mercurial repositories index</title>
356 </head>
375 </head>
357 <body>
376 <body>
358
377
359 <div class="container">
378 <div class="container">
360 <div class="menu">
379 <div class="menu">
361 <a href="http://mercurial.selenic.com/">
380 <a href="http://mercurial.selenic.com/">
362 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
381 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
363 </div>
382 </div>
364 <div class="main">
383 <div class="main">
365 <h2>Mercurial Repositories</h2>
384 <h2>Mercurial Repositories</h2>
366
385
367 <table class="bigtable">
386 <table class="bigtable">
368 <tr>
387 <tr>
369 <th><a href="?sort=name">Name</a></th>
388 <th><a href="?sort=name">Name</a></th>
370 <th><a href="?sort=description">Description</a></th>
389 <th><a href="?sort=description">Description</a></th>
371 <th><a href="?sort=contact">Contact</a></th>
390 <th><a href="?sort=contact">Contact</a></th>
372 <th><a href="?sort=lastchange">Last modified</a></th>
391 <th><a href="?sort=lastchange">Last modified</a></th>
373 <th>&nbsp;</th>
392 <th>&nbsp;</th>
374 </tr>
393 </tr>
375
394
376 <tr class="parity0">
395 <tr class="parity0">
377 <td><a href="/t/a/?style=paper">a</a></td>
396 <td><a href="/t/a/?style=paper">a</a></td>
378 <td>unknown</td>
397 <td>unknown</td>
379 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
398 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
380 <td class="age">* ago</td> (glob)
399 <td class="age">* ago</td> (glob)
381 <td class="indexlinks"></td>
400 <td class="indexlinks"></td>
382 </tr>
401 </tr>
383
402
384 </table>
403 </table>
385 </div>
404 </div>
386 </div>
405 </div>
387
406
388
407
389 </body>
408 </body>
390 </html>
409 </html>
391
410
392 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom'
411 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom'
393 200 Script output follows
412 200 Script output follows
394
413
395 <?xml version="1.0" encoding="ascii"?>
414 <?xml version="1.0" encoding="ascii"?>
396 <feed xmlns="http://www.w3.org/2005/Atom">
415 <feed xmlns="http://www.w3.org/2005/Atom">
397 <!-- Changelog -->
416 <!-- Changelog -->
398 <id>http://*:$HGPORT1/t/a/</id> (glob)
417 <id>http://*:$HGPORT1/t/a/</id> (glob)
399 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
418 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
400 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
419 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
401 <title>t/a Changelog</title>
420 <title>t/a Changelog</title>
402 <updated>1970-01-01T00:00:01+00:00</updated>
421 <updated>1970-01-01T00:00:01+00:00</updated>
403
422
404 <entry>
423 <entry>
405 <title>a</title>
424 <title>a</title>
406 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
425 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
407 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
426 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
408 <author>
427 <author>
409 <name>test</name>
428 <name>test</name>
410 <email>&#116;&#101;&#115;&#116;</email>
429 <email>&#116;&#101;&#115;&#116;</email>
411 </author>
430 </author>
412 <updated>1970-01-01T00:00:01+00:00</updated>
431 <updated>1970-01-01T00:00:01+00:00</updated>
413 <published>1970-01-01T00:00:01+00:00</published>
432 <published>1970-01-01T00:00:01+00:00</published>
414 <content type="xhtml">
433 <content type="xhtml">
415 <div xmlns="http://www.w3.org/1999/xhtml">
434 <div xmlns="http://www.w3.org/1999/xhtml">
416 <pre xml:space="preserve">a</pre>
435 <pre xml:space="preserve">a</pre>
417 </div>
436 </div>
418 </content>
437 </content>
419 </entry>
438 </entry>
420
439
421 </feed>
440 </feed>
422 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom'
441 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom'
423 200 Script output follows
442 200 Script output follows
424
443
425 <?xml version="1.0" encoding="ascii"?>
444 <?xml version="1.0" encoding="ascii"?>
426 <feed xmlns="http://www.w3.org/2005/Atom">
445 <feed xmlns="http://www.w3.org/2005/Atom">
427 <!-- Changelog -->
446 <!-- Changelog -->
428 <id>http://*:$HGPORT1/t/a/</id> (glob)
447 <id>http://*:$HGPORT1/t/a/</id> (glob)
429 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
448 <link rel="self" href="http://*:$HGPORT1/t/a/atom-log"/> (glob)
430 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
449 <link rel="alternate" href="http://*:$HGPORT1/t/a/"/> (glob)
431 <title>t/a Changelog</title>
450 <title>t/a Changelog</title>
432 <updated>1970-01-01T00:00:01+00:00</updated>
451 <updated>1970-01-01T00:00:01+00:00</updated>
433
452
434 <entry>
453 <entry>
435 <title>a</title>
454 <title>a</title>
436 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
455 <id>http://*:$HGPORT1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id> (glob)
437 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
456 <link href="http://*:$HGPORT1/t/a/rev/8580ff50825a"/> (glob)
438 <author>
457 <author>
439 <name>test</name>
458 <name>test</name>
440 <email>&#116;&#101;&#115;&#116;</email>
459 <email>&#116;&#101;&#115;&#116;</email>
441 </author>
460 </author>
442 <updated>1970-01-01T00:00:01+00:00</updated>
461 <updated>1970-01-01T00:00:01+00:00</updated>
443 <published>1970-01-01T00:00:01+00:00</published>
462 <published>1970-01-01T00:00:01+00:00</published>
444 <content type="xhtml">
463 <content type="xhtml">
445 <div xmlns="http://www.w3.org/1999/xhtml">
464 <div xmlns="http://www.w3.org/1999/xhtml">
446 <pre xml:space="preserve">a</pre>
465 <pre xml:space="preserve">a</pre>
447 </div>
466 </div>
448 </content>
467 </content>
449 </entry>
468 </entry>
450
469
451 </feed>
470 </feed>
452 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
471 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
453 200 Script output follows
472 200 Script output follows
454
473
455 a
474 a
456
475
457 Test [paths] '*' extension
476 Test [paths] '*' extension
458
477
459 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
478 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
460 200 Script output follows
479 200 Script output follows
461
480
462
481
463 /coll/a/
482 /coll/a/
464 /coll/a/.hg/patches/
483 /coll/a/.hg/patches/
465 /coll/b/
484 /coll/b/
466 /coll/c/
485 /coll/c/
467
486
468 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
487 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
469 200 Script output follows
488 200 Script output follows
470
489
471 a
490 a
472
491
473 est [paths] '**' extension
492 Test [paths] '**' extension
474
493
475 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
494 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
476 200 Script output follows
495 200 Script output follows
477
496
478
497
479 /rcoll/a/
498 /rcoll/a/
480 /rcoll/a/.hg/patches/
499 /rcoll/a/.hg/patches/
481 /rcoll/b/
500 /rcoll/b/
482 /rcoll/b/d/
501 /rcoll/b/d/
483 /rcoll/c/
502 /rcoll/c/
484
503
485 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
504 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
486 200 Script output follows
505 200 Script output follows
487
506
488 d
507 d
508
509 Test [paths] '*' in a repo root
510
511 $ hg id http://localhost:$HGPORT1/astar
512 8580ff50825a
513
489 $ "$TESTDIR/killdaemons.py"
514 $ "$TESTDIR/killdaemons.py"
490 $ cat > paths.conf <<EOF
515 $ cat > paths.conf <<EOF
491 > [paths]
516 > [paths]
492 > t/a = $root/a
517 > t/a = $root/a
493 > t/b = $root/b
518 > t/b = $root/b
494 > c = $root/c
519 > c = $root/c
495 > [web]
520 > [web]
496 > descend=false
521 > descend=false
497 > EOF
522 > EOF
498 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
523 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
499 > -A access-paths.log -E error-paths-3.log
524 > -A access-paths.log -E error-paths-3.log
500 $ cat hg.pid >> $DAEMON_PIDS
525 $ cat hg.pid >> $DAEMON_PIDS
501
526
502 test descend = False
527 test descend = False
503
528
504 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
529 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
505 200 Script output follows
530 200 Script output follows
506
531
507
532
508 /c/
533 /c/
509
534
510 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
535 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
511 200 Script output follows
536 200 Script output follows
512
537
513
538
514 /t/a/
539 /t/a/
515 /t/b/
540 /t/b/
516
541
517 $ "$TESTDIR/killdaemons.py"
542 $ "$TESTDIR/killdaemons.py"
518 $ cat > paths.conf <<EOF
543 $ cat > paths.conf <<EOF
519 > [paths]
544 > [paths]
520 > nostore = $root/nostore
545 > nostore = $root/nostore
521 > inexistent = $root/inexistent
546 > inexistent = $root/inexistent
522 > EOF
547 > EOF
523 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
548 $ hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
524 > -A access-paths.log -E error-paths-4.log
549 > -A access-paths.log -E error-paths-4.log
525 $ cat hg.pid >> $DAEMON_PIDS
550 $ cat hg.pid >> $DAEMON_PIDS
526
551
527 test inexistent and inaccessible repo should be ignored silently
552 test inexistent and inaccessible repo should be ignored silently
528
553
529 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/'
554 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/'
530 200 Script output follows
555 200 Script output follows
531
556
532 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
557 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
533 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
558 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
534 <head>
559 <head>
535 <link rel="icon" href="/static/hgicon.png" type="image/png" />
560 <link rel="icon" href="/static/hgicon.png" type="image/png" />
536 <meta name="robots" content="index, nofollow" />
561 <meta name="robots" content="index, nofollow" />
537 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
562 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
538
563
539 <title>Mercurial repositories index</title>
564 <title>Mercurial repositories index</title>
540 </head>
565 </head>
541 <body>
566 <body>
542
567
543 <div class="container">
568 <div class="container">
544 <div class="menu">
569 <div class="menu">
545 <a href="http://mercurial.selenic.com/">
570 <a href="http://mercurial.selenic.com/">
546 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
571 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
547 </div>
572 </div>
548 <div class="main">
573 <div class="main">
549 <h2>Mercurial Repositories</h2>
574 <h2>Mercurial Repositories</h2>
550
575
551 <table class="bigtable">
576 <table class="bigtable">
552 <tr>
577 <tr>
553 <th><a href="?sort=name">Name</a></th>
578 <th><a href="?sort=name">Name</a></th>
554 <th><a href="?sort=description">Description</a></th>
579 <th><a href="?sort=description">Description</a></th>
555 <th><a href="?sort=contact">Contact</a></th>
580 <th><a href="?sort=contact">Contact</a></th>
556 <th><a href="?sort=lastchange">Last modified</a></th>
581 <th><a href="?sort=lastchange">Last modified</a></th>
557 <th>&nbsp;</th>
582 <th>&nbsp;</th>
558 </tr>
583 </tr>
559
584
560 </table>
585 </table>
561 </div>
586 </div>
562 </div>
587 </div>
563
588
564
589
565 </body>
590 </body>
566 </html>
591 </html>
567
592
568 $ cat > collections.conf <<EOF
593 $ cat > collections.conf <<EOF
569 > [collections]
594 > [collections]
570 > $root=$root
595 > $root=$root
571 > EOF
596 > EOF
572 $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
597 $ hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
573 > --pid-file=hg.pid --webdir-conf collections.conf \
598 > --pid-file=hg.pid --webdir-conf collections.conf \
574 > -A access-collections.log -E error-collections.log
599 > -A access-collections.log -E error-collections.log
575 $ cat hg.pid >> $DAEMON_PIDS
600 $ cat hg.pid >> $DAEMON_PIDS
576
601
577 collections: should succeed
602 collections: should succeed
578
603
579 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
604 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
580 200 Script output follows
605 200 Script output follows
581
606
582
607
583 /a/
608 /a/
584 /a/.hg/patches/
609 /a/.hg/patches/
585 /b/
610 /b/
586 /c/
611 /c/
587
612
588 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
613 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
589 200 Script output follows
614 200 Script output follows
590
615
591 a
616 a
592 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
617 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
593 200 Script output follows
618 200 Script output follows
594
619
595 b
620 b
596 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
621 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
597 200 Script output follows
622 200 Script output follows
598
623
599 c
624 c
600
625
601 atom-log with basedir /
626 atom-log with basedir /
602
627
603 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' | grep '<link'
628 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' | grep '<link'
604 <link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
629 <link rel="self" href="http://hg.example.com:8080/a/atom-log"/>
605 <link rel="alternate" href="http://hg.example.com:8080/a/"/>
630 <link rel="alternate" href="http://hg.example.com:8080/a/"/>
606 <link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
631 <link href="http://hg.example.com:8080/a/rev/8580ff50825a"/>
607
632
608 rss-log with basedir /
633 rss-log with basedir /
609
634
610 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' | grep '<guid'
635 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' | grep '<guid'
611 <guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
636 <guid isPermaLink="true">http://hg.example.com:8080/a/rev/8580ff50825a</guid>
612 $ "$TESTDIR/killdaemons.py"
637 $ "$TESTDIR/killdaemons.py"
613 $ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
638 $ hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
614 > --pid-file=hg.pid --webdir-conf collections.conf \
639 > --pid-file=hg.pid --webdir-conf collections.conf \
615 > -A access-collections-2.log -E error-collections-2.log
640 > -A access-collections-2.log -E error-collections-2.log
616 $ cat hg.pid >> $DAEMON_PIDS
641 $ cat hg.pid >> $DAEMON_PIDS
617
642
618 atom-log with basedir /foo/
643 atom-log with basedir /foo/
619
644
620 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' | grep '<link'
645 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' | grep '<link'
621 <link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
646 <link rel="self" href="http://hg.example.com:8080/foo/a/atom-log"/>
622 <link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
647 <link rel="alternate" href="http://hg.example.com:8080/foo/a/"/>
623 <link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
648 <link href="http://hg.example.com:8080/foo/a/rev/8580ff50825a"/>
624
649
625 rss-log with basedir /foo/
650 rss-log with basedir /foo/
626
651
627 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' | grep '<guid'
652 $ "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' | grep '<guid'
628 <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
653 <guid isPermaLink="true">http://hg.example.com:8080/foo/a/rev/8580ff50825a</guid>
629
654
630 paths errors 1
655 paths errors 1
631
656
632 $ cat error-paths-1.log
657 $ cat error-paths-1.log
633
658
634 paths errors 2
659 paths errors 2
635
660
636 $ cat error-paths-2.log
661 $ cat error-paths-2.log
637
662
638 paths errors 3
663 paths errors 3
639
664
640 $ cat error-paths-3.log
665 $ cat error-paths-3.log
641
666
642 collections errors
667 collections errors
643
668
644 $ cat error-collections.log
669 $ cat error-collections.log
645
670
646 collections errors 2
671 collections errors 2
647
672
648 $ cat error-collections-2.log
673 $ cat error-collections-2.log
General Comments 0
You need to be logged in to leave comments. Login now