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