##// END OF EJS Templates
hgweb: handle exception of misconfigured path on index page...
Yuya Nishihara -
r12038:9617803b stable
parent child Browse files
Show More
@@ -1,352 +1,356 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 while virtual:
157 real = repos.get(virtual)
157 real = repos.get(virtual)
158 if real:
158 if real:
159 req.env['REPO_NAME'] = virtual
159 req.env['REPO_NAME'] = virtual
160 try:
160 try:
161 repo = hg.repository(self.ui, real)
161 repo = hg.repository(self.ui, real)
162 return hgweb(repo).run_wsgi(req)
162 return hgweb(repo).run_wsgi(req)
163 except IOError, inst:
163 except IOError, inst:
164 msg = inst.strerror
164 msg = inst.strerror
165 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
165 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
166 except error.RepoError, inst:
166 except error.RepoError, inst:
167 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
167 raise ErrorResponse(HTTP_SERVER_ERROR, str(inst))
168
168
169 # browse subdirectories
169 # browse subdirectories
170 subdir = virtual + '/'
170 subdir = virtual + '/'
171 if [r for r in repos if r.startswith(subdir)]:
171 if [r for r in repos if r.startswith(subdir)]:
172 req.respond(HTTP_OK, ctype)
172 req.respond(HTTP_OK, ctype)
173 return self.makeindex(req, tmpl, subdir)
173 return self.makeindex(req, tmpl, subdir)
174
174
175 up = virtual.rfind('/')
175 up = virtual.rfind('/')
176 if up < 0:
176 if up < 0:
177 break
177 break
178 virtual = virtual[:up]
178 virtual = virtual[:up]
179
179
180 # prefixes not found
180 # prefixes not found
181 req.respond(HTTP_NOT_FOUND, ctype)
181 req.respond(HTTP_NOT_FOUND, ctype)
182 return tmpl("notfound", repo=virtual)
182 return tmpl("notfound", repo=virtual)
183
183
184 except ErrorResponse, err:
184 except ErrorResponse, err:
185 req.respond(err, ctype)
185 req.respond(err, ctype)
186 return tmpl('error', error=err.message or '')
186 return tmpl('error', error=err.message or '')
187 finally:
187 finally:
188 tmpl = None
188 tmpl = None
189
189
190 def makeindex(self, req, tmpl, subdir=""):
190 def makeindex(self, req, tmpl, subdir=""):
191
191
192 def archivelist(ui, nodeid, url):
192 def archivelist(ui, nodeid, url):
193 allowed = ui.configlist("web", "allow_archive", untrusted=True)
193 allowed = ui.configlist("web", "allow_archive", untrusted=True)
194 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
194 for i in [('zip', '.zip'), ('gz', '.tar.gz'), ('bz2', '.tar.bz2')]:
195 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
195 if i[0] in allowed or ui.configbool("web", "allow" + i[0],
196 untrusted=True):
196 untrusted=True):
197 yield {"type" : i[0], "extension": i[1],
197 yield {"type" : i[0], "extension": i[1],
198 "node": nodeid, "url": url}
198 "node": nodeid, "url": url}
199
199
200 def rawentries(subdir="", **map):
200 def rawentries(subdir="", **map):
201
201
202 descend = self.ui.configbool('web', 'descend', True)
202 descend = self.ui.configbool('web', 'descend', True)
203 for name, path in self.repos:
203 for name, path in self.repos:
204
204
205 if not name.startswith(subdir):
205 if not name.startswith(subdir):
206 continue
206 continue
207 name = name[len(subdir):]
207 name = name[len(subdir):]
208 if not descend and '/' in name:
208 if not descend and '/' in name:
209 continue
209 continue
210
210
211 u = self.ui.copy()
211 u = self.ui.copy()
212 try:
212 try:
213 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
213 u.readconfig(os.path.join(path, '.hg', 'hgrc'))
214 except Exception, e:
214 except Exception, e:
215 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
215 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
216 continue
216 continue
217 def get(section, name, default=None):
217 def get(section, name, default=None):
218 return u.config(section, name, default, untrusted=True)
218 return u.config(section, name, default, untrusted=True)
219
219
220 if u.configbool("web", "hidden", untrusted=True):
220 if u.configbool("web", "hidden", untrusted=True):
221 continue
221 continue
222
222
223 if not self.read_allowed(u, req):
223 if not self.read_allowed(u, req):
224 continue
224 continue
225
225
226 parts = [name]
226 parts = [name]
227 if 'PATH_INFO' in req.env:
227 if 'PATH_INFO' in req.env:
228 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
228 parts.insert(0, req.env['PATH_INFO'].rstrip('/'))
229 if req.env['SCRIPT_NAME']:
229 if req.env['SCRIPT_NAME']:
230 parts.insert(0, req.env['SCRIPT_NAME'])
230 parts.insert(0, req.env['SCRIPT_NAME'])
231 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
231 url = re.sub(r'/+', '/', '/'.join(parts) + '/')
232
232
233 # update time with local timezone
233 # update time with local timezone
234 try:
234 try:
235 r = hg.repository(self.ui, path)
235 r = hg.repository(self.ui, path)
236 except error.RepoError:
237 u.warn(_('error accessing repository at %s\n') % path)
238 continue
239 try:
236 d = (get_mtime(r.spath), util.makedate()[1])
240 d = (get_mtime(r.spath), util.makedate()[1])
237 except OSError:
241 except OSError:
238 continue
242 continue
239
243
240 contact = get_contact(get)
244 contact = get_contact(get)
241 description = get("web", "description", "")
245 description = get("web", "description", "")
242 name = get("web", "name", name)
246 name = get("web", "name", name)
243 row = dict(contact=contact or "unknown",
247 row = dict(contact=contact or "unknown",
244 contact_sort=contact.upper() or "unknown",
248 contact_sort=contact.upper() or "unknown",
245 name=name,
249 name=name,
246 name_sort=name,
250 name_sort=name,
247 url=url,
251 url=url,
248 description=description or "unknown",
252 description=description or "unknown",
249 description_sort=description.upper() or "unknown",
253 description_sort=description.upper() or "unknown",
250 lastchange=d,
254 lastchange=d,
251 lastchange_sort=d[1]-d[0],
255 lastchange_sort=d[1]-d[0],
252 archives=archivelist(u, "tip", url))
256 archives=archivelist(u, "tip", url))
253 yield row
257 yield row
254
258
255 sortdefault = None, False
259 sortdefault = None, False
256 def entries(sortcolumn="", descending=False, subdir="", **map):
260 def entries(sortcolumn="", descending=False, subdir="", **map):
257 rows = rawentries(subdir=subdir, **map)
261 rows = rawentries(subdir=subdir, **map)
258
262
259 if sortcolumn and sortdefault != (sortcolumn, descending):
263 if sortcolumn and sortdefault != (sortcolumn, descending):
260 sortkey = '%s_sort' % sortcolumn
264 sortkey = '%s_sort' % sortcolumn
261 rows = sorted(rows, key=lambda x: x[sortkey],
265 rows = sorted(rows, key=lambda x: x[sortkey],
262 reverse=descending)
266 reverse=descending)
263 for row, parity in zip(rows, paritygen(self.stripecount)):
267 for row, parity in zip(rows, paritygen(self.stripecount)):
264 row['parity'] = parity
268 row['parity'] = parity
265 yield row
269 yield row
266
270
267 self.refresh()
271 self.refresh()
268 sortable = ["name", "description", "contact", "lastchange"]
272 sortable = ["name", "description", "contact", "lastchange"]
269 sortcolumn, descending = sortdefault
273 sortcolumn, descending = sortdefault
270 if 'sort' in req.form:
274 if 'sort' in req.form:
271 sortcolumn = req.form['sort'][0]
275 sortcolumn = req.form['sort'][0]
272 descending = sortcolumn.startswith('-')
276 descending = sortcolumn.startswith('-')
273 if descending:
277 if descending:
274 sortcolumn = sortcolumn[1:]
278 sortcolumn = sortcolumn[1:]
275 if sortcolumn not in sortable:
279 if sortcolumn not in sortable:
276 sortcolumn = ""
280 sortcolumn = ""
277
281
278 sort = [("sort_%s" % column,
282 sort = [("sort_%s" % column,
279 "%s%s" % ((not descending and column == sortcolumn)
283 "%s%s" % ((not descending and column == sortcolumn)
280 and "-" or "", column))
284 and "-" or "", column))
281 for column in sortable]
285 for column in sortable]
282
286
283 self.refresh()
287 self.refresh()
284 self.updatereqenv(req.env)
288 self.updatereqenv(req.env)
285
289
286 return tmpl("index", entries=entries, subdir=subdir,
290 return tmpl("index", entries=entries, subdir=subdir,
287 sortcolumn=sortcolumn, descending=descending,
291 sortcolumn=sortcolumn, descending=descending,
288 **dict(sort))
292 **dict(sort))
289
293
290 def templater(self, req):
294 def templater(self, req):
291
295
292 def header(**map):
296 def header(**map):
293 yield tmpl('header', encoding=encoding.encoding, **map)
297 yield tmpl('header', encoding=encoding.encoding, **map)
294
298
295 def footer(**map):
299 def footer(**map):
296 yield tmpl("footer", **map)
300 yield tmpl("footer", **map)
297
301
298 def motd(**map):
302 def motd(**map):
299 if self.motd is not None:
303 if self.motd is not None:
300 yield self.motd
304 yield self.motd
301 else:
305 else:
302 yield config('web', 'motd', '')
306 yield config('web', 'motd', '')
303
307
304 def config(section, name, default=None, untrusted=True):
308 def config(section, name, default=None, untrusted=True):
305 return self.ui.config(section, name, default, untrusted)
309 return self.ui.config(section, name, default, untrusted)
306
310
307 self.updatereqenv(req.env)
311 self.updatereqenv(req.env)
308
312
309 url = req.env.get('SCRIPT_NAME', '')
313 url = req.env.get('SCRIPT_NAME', '')
310 if not url.endswith('/'):
314 if not url.endswith('/'):
311 url += '/'
315 url += '/'
312
316
313 vars = {}
317 vars = {}
314 styles = (
318 styles = (
315 req.form.get('style', [None])[0],
319 req.form.get('style', [None])[0],
316 config('web', 'style'),
320 config('web', 'style'),
317 'paper'
321 'paper'
318 )
322 )
319 style, mapfile = templater.stylemap(styles, self.templatepath)
323 style, mapfile = templater.stylemap(styles, self.templatepath)
320 if style == styles[0]:
324 if style == styles[0]:
321 vars['style'] = style
325 vars['style'] = style
322
326
323 start = url[-1] == '?' and '&' or '?'
327 start = url[-1] == '?' and '&' or '?'
324 sessionvars = webutil.sessionvars(vars, start)
328 sessionvars = webutil.sessionvars(vars, start)
325 staticurl = config('web', 'staticurl') or url + 'static/'
329 staticurl = config('web', 'staticurl') or url + 'static/'
326 if not staticurl.endswith('/'):
330 if not staticurl.endswith('/'):
327 staticurl += '/'
331 staticurl += '/'
328
332
329 tmpl = templater.templater(mapfile,
333 tmpl = templater.templater(mapfile,
330 defaults={"header": header,
334 defaults={"header": header,
331 "footer": footer,
335 "footer": footer,
332 "motd": motd,
336 "motd": motd,
333 "url": url,
337 "url": url,
334 "staticurl": staticurl,
338 "staticurl": staticurl,
335 "sessionvars": sessionvars})
339 "sessionvars": sessionvars})
336 return tmpl
340 return tmpl
337
341
338 def updatereqenv(self, env):
342 def updatereqenv(self, env):
339 def splitnetloc(netloc):
343 def splitnetloc(netloc):
340 if ':' in netloc:
344 if ':' in netloc:
341 return netloc.split(':', 1)
345 return netloc.split(':', 1)
342 else:
346 else:
343 return (netloc, None)
347 return (netloc, None)
344
348
345 if self._baseurl is not None:
349 if self._baseurl is not None:
346 urlcomp = urlparse.urlparse(self._baseurl)
350 urlcomp = urlparse.urlparse(self._baseurl)
347 host, port = splitnetloc(urlcomp[1])
351 host, port = splitnetloc(urlcomp[1])
348 path = urlcomp[2]
352 path = urlcomp[2]
349 env['SERVER_NAME'] = host
353 env['SERVER_NAME'] = host
350 if port:
354 if port:
351 env['SERVER_PORT'] = port
355 env['SERVER_PORT'] = port
352 env['SCRIPT_NAME'] = path
356 env['SCRIPT_NAME'] = path
@@ -1,163 +1,181 b''
1 #!/bin/sh
1 #!/bin/sh
2 # Tests some basic hgwebdir functionality. Tests setting up paths and
2 # Tests some basic hgwebdir functionality. Tests setting up paths and
3 # collection, different forms of 404s and the subdirectory support.
3 # collection, different forms of 404s and the subdirectory support.
4
4
5 mkdir webdir
5 mkdir webdir
6 cd webdir
6 cd webdir
7
7
8 hg init a
8 hg init a
9 echo a > a/a
9 echo a > a/a
10 hg --cwd a ci -Ama -d'1 0'
10 hg --cwd a ci -Ama -d'1 0'
11 # create a mercurial queue repository
11 # create a mercurial queue repository
12 hg --cwd a qinit --config extensions.hgext.mq= -c
12 hg --cwd a qinit --config extensions.hgext.mq= -c
13
13
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
17
18 # create a nested repository
18 # create a nested repository
19 cd b
19 cd b
20 hg init d
20 hg init d
21 echo d > d/d
21 echo d > d/d
22 hg --cwd d ci -Amd -d'3 0'
22 hg --cwd d ci -Amd -d'3 0'
23 cd ..
23 cd ..
24
24
25 hg init c
25 hg init c
26 echo c > c/c
26 echo c > c/c
27 hg --cwd c ci -Amc -d'3 0'
27 hg --cwd c ci -Amc -d'3 0'
28
28
29 # create repository without .hg/store
30 hg init nostore
31 rm -R nostore/.hg/store
32
29 root=`pwd`
33 root=`pwd`
30 cd ..
34 cd ..
31
35
32
36
33 cat > paths.conf <<EOF
37 cat > paths.conf <<EOF
34 [paths]
38 [paths]
35 a=$root/a
39 a=$root/a
36 b=$root/b
40 b=$root/b
37 EOF
41 EOF
38
42
39 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 \
40 -A access-paths.log -E error-paths-1.log
44 -A access-paths.log -E error-paths-1.log
41 cat hg.pid >> $DAEMON_PIDS
45 cat hg.pid >> $DAEMON_PIDS
42
46
43 echo % should give a 404 - file does not exist
47 echo % should give a 404 - file does not exist
44 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
48 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
45
49
46 echo % should succeed
50 echo % should succeed
47 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
51 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
48 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
49 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
53 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
50
54
51 echo % should give a 404 - repo is not published
55 echo % should give a 404 - repo is not published
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
56 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
53
57
54 echo % atom-log without basedir
58 echo % atom-log without basedir
55 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' \
59 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' \
56 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
60 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
57
61
58 echo % rss-log without basedir
62 echo % rss-log without basedir
59 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' \
63 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' \
60 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
64 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
61
65
62 cat > paths.conf <<EOF
66 cat > paths.conf <<EOF
63 [paths]
67 [paths]
64 t/a/=$root/a
68 t/a/=$root/a
65 b=$root/b
69 b=$root/b
66 coll=$root/*
70 coll=$root/*
67 rcoll=$root/**
71 rcoll=$root/**
68 star=*
72 star=*
69 starstar=**
73 starstar=**
70 EOF
74 EOF
71
75
72 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
76 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
73 -A access-paths.log -E error-paths-2.log
77 -A access-paths.log -E error-paths-2.log
74 cat hg.pid >> $DAEMON_PIDS
78 cat hg.pid >> $DAEMON_PIDS
75
79
76 echo % should succeed, slashy names
80 echo % should succeed, slashy names
77 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
81 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
78 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
79 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
83 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
80 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
81 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
85 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
83 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
87 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
85 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
89 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
90 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
87 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
91 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
92 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
89 # Test [paths] '*' extension
93 # Test [paths] '*' extension
90 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
94 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
91 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
95 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
92 #test [paths] '**' extension
96 #test [paths] '**' extension
93 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
97 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
94 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
98 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
95
99
96
100
97 "$TESTDIR/killdaemons.py"
101 "$TESTDIR/killdaemons.py"
98 cat > paths.conf <<EOF
102 cat > paths.conf <<EOF
99 [paths]
103 [paths]
100 t/a = $root/a
104 t/a = $root/a
101 t/b = $root/b
105 t/b = $root/b
102 c = $root/c
106 c = $root/c
103 [web]
107 [web]
104 descend=false
108 descend=false
105 EOF
109 EOF
106
110
107 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
111 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
108 -A access-paths.log -E error-paths-3.log
112 -A access-paths.log -E error-paths-3.log
109 cat hg.pid >> $DAEMON_PIDS
113 cat hg.pid >> $DAEMON_PIDS
110 echo % test descend = False
114 echo % test descend = False
111 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
115 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
112 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
116 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
113
117
114
118
119 "$TESTDIR/killdaemons.py"
120 cat > paths.conf <<EOF
121 [paths]
122 nostore = $root/nostore
123 inexistent = $root/inexistent
124 EOF
125
126 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
127 -A access-paths.log -E error-paths-4.log
128 cat hg.pid >> $DAEMON_PIDS
129 echo % test inexistent and inaccessible repo should be ignored silently
130 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/'
131
132
115 cat > collections.conf <<EOF
133 cat > collections.conf <<EOF
116 [collections]
134 [collections]
117 $root=$root
135 $root=$root
118 EOF
136 EOF
119
137
120 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
138 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
121 --pid-file=hg.pid --webdir-conf collections.conf \
139 --pid-file=hg.pid --webdir-conf collections.conf \
122 -A access-collections.log -E error-collections.log
140 -A access-collections.log -E error-collections.log
123 cat hg.pid >> $DAEMON_PIDS
141 cat hg.pid >> $DAEMON_PIDS
124
142
125 echo % collections: should succeed
143 echo % collections: should succeed
126 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
144 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
127 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
145 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
128 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
146 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
129 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
147 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
130
148
131 echo % atom-log with basedir /
149 echo % atom-log with basedir /
132 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
150 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
133 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
151 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
134
152
135 echo % rss-log with basedir /
153 echo % rss-log with basedir /
136 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
154 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
137 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
155 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
138
156
139 "$TESTDIR/killdaemons.py"
157 "$TESTDIR/killdaemons.py"
140
158
141 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
159 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
142 --pid-file=hg.pid --webdir-conf collections.conf \
160 --pid-file=hg.pid --webdir-conf collections.conf \
143 -A access-collections-2.log -E error-collections-2.log
161 -A access-collections-2.log -E error-collections-2.log
144 cat hg.pid >> $DAEMON_PIDS
162 cat hg.pid >> $DAEMON_PIDS
145
163
146 echo % atom-log with basedir /foo/
164 echo % atom-log with basedir /foo/
147 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
165 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
148 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
166 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
149
167
150 echo % rss-log with basedir /foo/
168 echo % rss-log with basedir /foo/
151 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
169 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
152 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
170 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
153
171
154 echo % paths errors 1
172 echo % paths errors 1
155 cat error-paths-1.log
173 cat error-paths-1.log
156 echo % paths errors 2
174 echo % paths errors 2
157 cat error-paths-2.log
175 cat error-paths-2.log
158 echo % paths errors 3
176 echo % paths errors 3
159 cat error-paths-3.log
177 cat error-paths-3.log
160 echo % collections errors
178 echo % collections errors
161 cat error-collections.log
179 cat error-collections.log
162 echo % collections errors 2
180 echo % collections errors 2
163 cat error-collections-2.log
181 cat error-collections-2.log
@@ -1,443 +1,482 b''
1 adding a
1 adding a
2 adding b
2 adding b
3 adding d
3 adding d
4 adding c
4 adding c
5 % should give a 404 - file does not exist
5 % should give a 404 - file does not exist
6 404 Not Found
6 404 Not Found
7
7
8
8
9 error: bork@8580ff50825a: not found in manifest
9 error: bork@8580ff50825a: not found in manifest
10 % should succeed
10 % should succeed
11 200 Script output follows
11 200 Script output follows
12
12
13
13
14 /a/
14 /a/
15 /b/
15 /b/
16
16
17 200 Script output follows
17 200 Script output follows
18
18
19 a
19 a
20 200 Script output follows
20 200 Script output follows
21
21
22 b
22 b
23 % should give a 404 - repo is not published
23 % should give a 404 - repo is not published
24 404 Not Found
24 404 Not Found
25
25
26
26
27 error: repository c not found
27 error: repository c not found
28 % atom-log without basedir
28 % atom-log without basedir
29 <link rel="self" href="http://example.com:8080/a/atom-log"/>
29 <link rel="self" href="http://example.com:8080/a/atom-log"/>
30 <link rel="alternate" href="http://example.com:8080/a/"/>
30 <link rel="alternate" href="http://example.com:8080/a/"/>
31 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
31 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
32 % rss-log without basedir
32 % rss-log without basedir
33 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
33 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
34 % should succeed, slashy names
34 % should succeed, slashy names
35 200 Script output follows
35 200 Script output follows
36
36
37
37
38 /t/a/
38 /t/a/
39 /b/
39 /b/
40 /coll/a/
40 /coll/a/
41 /coll/a/.hg/patches/
41 /coll/a/.hg/patches/
42 /coll/b/
42 /coll/b/
43 /coll/c/
43 /coll/c/
44 /rcoll/a/
44 /rcoll/a/
45 /rcoll/a/.hg/patches/
45 /rcoll/a/.hg/patches/
46 /rcoll/b/
46 /rcoll/b/
47 /rcoll/b/d/
47 /rcoll/b/d/
48 /rcoll/c/
48 /rcoll/c/
49 /star/webdir/a/
49 /star/webdir/a/
50 /star/webdir/a/.hg/patches/
50 /star/webdir/a/.hg/patches/
51 /star/webdir/b/
51 /star/webdir/b/
52 /star/webdir/c/
52 /star/webdir/c/
53 /starstar/webdir/a/
53 /starstar/webdir/a/
54 /starstar/webdir/a/.hg/patches/
54 /starstar/webdir/a/.hg/patches/
55 /starstar/webdir/b/
55 /starstar/webdir/b/
56 /starstar/webdir/b/d/
56 /starstar/webdir/b/d/
57 /starstar/webdir/c/
57 /starstar/webdir/c/
58
58
59 200 Script output follows
59 200 Script output follows
60
60
61 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
61 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
62 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
62 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
63 <head>
63 <head>
64 <link rel="icon" href="/static/hgicon.png" type="image/png" />
64 <link rel="icon" href="/static/hgicon.png" type="image/png" />
65 <meta name="robots" content="index, nofollow" />
65 <meta name="robots" content="index, nofollow" />
66 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
66 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
67
67
68 <title>Mercurial repositories index</title>
68 <title>Mercurial repositories index</title>
69 </head>
69 </head>
70 <body>
70 <body>
71
71
72 <div class="container">
72 <div class="container">
73 <div class="menu">
73 <div class="menu">
74 <a href="http://mercurial.selenic.com/">
74 <a href="http://mercurial.selenic.com/">
75 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
75 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
76 </div>
76 </div>
77 <div class="main">
77 <div class="main">
78 <h2>Mercurial Repositories</h2>
78 <h2>Mercurial Repositories</h2>
79
79
80 <table class="bigtable">
80 <table class="bigtable">
81 <tr>
81 <tr>
82 <th><a href="?sort=name">Name</a></th>
82 <th><a href="?sort=name">Name</a></th>
83 <th><a href="?sort=description">Description</a></th>
83 <th><a href="?sort=description">Description</a></th>
84 <th><a href="?sort=contact">Contact</a></th>
84 <th><a href="?sort=contact">Contact</a></th>
85 <th><a href="?sort=lastchange">Last modified</a></th>
85 <th><a href="?sort=lastchange">Last modified</a></th>
86 <th>&nbsp;</th>
86 <th>&nbsp;</th>
87 </tr>
87 </tr>
88
88
89 <tr class="parity0">
89 <tr class="parity0">
90 <td><a href="/t/a/?style=paper">t/a</a></td>
90 <td><a href="/t/a/?style=paper">t/a</a></td>
91 <td>unknown</td>
91 <td>unknown</td>
92 <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>
92 <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>
93 <td class="age">seconds ago</td>
93 <td class="age">seconds ago</td>
94 <td class="indexlinks"></td>
94 <td class="indexlinks"></td>
95 </tr>
95 </tr>
96
96
97 <tr class="parity1">
97 <tr class="parity1">
98 <td><a href="/b/?style=paper">b</a></td>
98 <td><a href="/b/?style=paper">b</a></td>
99 <td>unknown</td>
99 <td>unknown</td>
100 <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>
100 <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>
101 <td class="age">seconds ago</td>
101 <td class="age">seconds ago</td>
102 <td class="indexlinks"></td>
102 <td class="indexlinks"></td>
103 </tr>
103 </tr>
104
104
105 <tr class="parity0">
105 <tr class="parity0">
106 <td><a href="/coll/a/?style=paper">coll/a</a></td>
106 <td><a href="/coll/a/?style=paper">coll/a</a></td>
107 <td>unknown</td>
107 <td>unknown</td>
108 <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>
108 <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>
109 <td class="age">seconds ago</td>
109 <td class="age">seconds ago</td>
110 <td class="indexlinks"></td>
110 <td class="indexlinks"></td>
111 </tr>
111 </tr>
112
112
113 <tr class="parity1">
113 <tr class="parity1">
114 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
114 <td><a href="/coll/a/.hg/patches/?style=paper">coll/a/.hg/patches</a></td>
115 <td>unknown</td>
115 <td>unknown</td>
116 <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>
116 <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>
117 <td class="age">seconds ago</td>
117 <td class="age">seconds ago</td>
118 <td class="indexlinks"></td>
118 <td class="indexlinks"></td>
119 </tr>
119 </tr>
120
120
121 <tr class="parity0">
121 <tr class="parity0">
122 <td><a href="/coll/b/?style=paper">coll/b</a></td>
122 <td><a href="/coll/b/?style=paper">coll/b</a></td>
123 <td>unknown</td>
123 <td>unknown</td>
124 <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>
124 <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>
125 <td class="age">seconds ago</td>
125 <td class="age">seconds ago</td>
126 <td class="indexlinks"></td>
126 <td class="indexlinks"></td>
127 </tr>
127 </tr>
128
128
129 <tr class="parity1">
129 <tr class="parity1">
130 <td><a href="/coll/c/?style=paper">coll/c</a></td>
130 <td><a href="/coll/c/?style=paper">coll/c</a></td>
131 <td>unknown</td>
131 <td>unknown</td>
132 <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>
132 <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>
133 <td class="age">seconds ago</td>
133 <td class="age">seconds ago</td>
134 <td class="indexlinks"></td>
134 <td class="indexlinks"></td>
135 </tr>
135 </tr>
136
136
137 <tr class="parity0">
137 <tr class="parity0">
138 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
138 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
139 <td>unknown</td>
139 <td>unknown</td>
140 <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>
140 <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>
141 <td class="age">seconds ago</td>
141 <td class="age">seconds ago</td>
142 <td class="indexlinks"></td>
142 <td class="indexlinks"></td>
143 </tr>
143 </tr>
144
144
145 <tr class="parity1">
145 <tr class="parity1">
146 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
146 <td><a href="/rcoll/a/.hg/patches/?style=paper">rcoll/a/.hg/patches</a></td>
147 <td>unknown</td>
147 <td>unknown</td>
148 <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>
148 <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>
149 <td class="age">seconds ago</td>
149 <td class="age">seconds ago</td>
150 <td class="indexlinks"></td>
150 <td class="indexlinks"></td>
151 </tr>
151 </tr>
152
152
153 <tr class="parity0">
153 <tr class="parity0">
154 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
154 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
155 <td>unknown</td>
155 <td>unknown</td>
156 <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>
156 <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>
157 <td class="age">seconds ago</td>
157 <td class="age">seconds ago</td>
158 <td class="indexlinks"></td>
158 <td class="indexlinks"></td>
159 </tr>
159 </tr>
160
160
161 <tr class="parity1">
161 <tr class="parity1">
162 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
162 <td><a href="/rcoll/b/d/?style=paper">rcoll/b/d</a></td>
163 <td>unknown</td>
163 <td>unknown</td>
164 <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>
164 <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>
165 <td class="age">seconds ago</td>
165 <td class="age">seconds ago</td>
166 <td class="indexlinks"></td>
166 <td class="indexlinks"></td>
167 </tr>
167 </tr>
168
168
169 <tr class="parity0">
169 <tr class="parity0">
170 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
170 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
171 <td>unknown</td>
171 <td>unknown</td>
172 <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>
172 <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>
173 <td class="age">seconds ago</td>
173 <td class="age">seconds ago</td>
174 <td class="indexlinks"></td>
174 <td class="indexlinks"></td>
175 </tr>
175 </tr>
176
176
177 <tr class="parity1">
177 <tr class="parity1">
178 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
178 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></td>
179 <td>unknown</td>
179 <td>unknown</td>
180 <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>
180 <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>
181 <td class="age">seconds ago</td>
181 <td class="age">seconds ago</td>
182 <td class="indexlinks"></td>
182 <td class="indexlinks"></td>
183 </tr>
183 </tr>
184
184
185 <tr class="parity0">
185 <tr class="parity0">
186 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
186 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></td>
187 <td>unknown</td>
187 <td>unknown</td>
188 <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>
188 <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>
189 <td class="age">seconds ago</td>
189 <td class="age">seconds ago</td>
190 <td class="indexlinks"></td>
190 <td class="indexlinks"></td>
191 </tr>
191 </tr>
192
192
193 <tr class="parity1">
193 <tr class="parity1">
194 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
194 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></td>
195 <td>unknown</td>
195 <td>unknown</td>
196 <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>
196 <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>
197 <td class="age">seconds ago</td>
197 <td class="age">seconds ago</td>
198 <td class="indexlinks"></td>
198 <td class="indexlinks"></td>
199 </tr>
199 </tr>
200
200
201 <tr class="parity0">
201 <tr class="parity0">
202 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
202 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></td>
203 <td>unknown</td>
203 <td>unknown</td>
204 <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>
204 <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>
205 <td class="age">seconds ago</td>
205 <td class="age">seconds ago</td>
206 <td class="indexlinks"></td>
206 <td class="indexlinks"></td>
207 </tr>
207 </tr>
208
208
209 <tr class="parity1">
209 <tr class="parity1">
210 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
210 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></td>
211 <td>unknown</td>
211 <td>unknown</td>
212 <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>
212 <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>
213 <td class="age">seconds ago</td>
213 <td class="age">seconds ago</td>
214 <td class="indexlinks"></td>
214 <td class="indexlinks"></td>
215 </tr>
215 </tr>
216
216
217 <tr class="parity0">
217 <tr class="parity0">
218 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
218 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></td>
219 <td>unknown</td>
219 <td>unknown</td>
220 <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>
220 <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>
221 <td class="age">seconds ago</td>
221 <td class="age">seconds ago</td>
222 <td class="indexlinks"></td>
222 <td class="indexlinks"></td>
223 </tr>
223 </tr>
224
224
225 <tr class="parity1">
225 <tr class="parity1">
226 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
226 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></td>
227 <td>unknown</td>
227 <td>unknown</td>
228 <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>
228 <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>
229 <td class="age">seconds ago</td>
229 <td class="age">seconds ago</td>
230 <td class="indexlinks"></td>
230 <td class="indexlinks"></td>
231 </tr>
231 </tr>
232
232
233 <tr class="parity0">
233 <tr class="parity0">
234 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
234 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></td>
235 <td>unknown</td>
235 <td>unknown</td>
236 <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>
236 <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>
237 <td class="age">seconds ago</td>
237 <td class="age">seconds ago</td>
238 <td class="indexlinks"></td>
238 <td class="indexlinks"></td>
239 </tr>
239 </tr>
240
240
241 <tr class="parity1">
241 <tr class="parity1">
242 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
242 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></td>
243 <td>unknown</td>
243 <td>unknown</td>
244 <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>
244 <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>
245 <td class="age">seconds ago</td>
245 <td class="age">seconds ago</td>
246 <td class="indexlinks"></td>
246 <td class="indexlinks"></td>
247 </tr>
247 </tr>
248
248
249 </table>
249 </table>
250 </div>
250 </div>
251 </div>
251 </div>
252
252
253
253
254 </body>
254 </body>
255 </html>
255 </html>
256
256
257 200 Script output follows
257 200 Script output follows
258
258
259
259
260 /t/a/
260 /t/a/
261
261
262 200 Script output follows
262 200 Script output follows
263
263
264
264
265 /t/a/
265 /t/a/
266
266
267 200 Script output follows
267 200 Script output follows
268
268
269 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
269 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
270 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
270 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
271 <head>
271 <head>
272 <link rel="icon" href="/static/hgicon.png" type="image/png" />
272 <link rel="icon" href="/static/hgicon.png" type="image/png" />
273 <meta name="robots" content="index, nofollow" />
273 <meta name="robots" content="index, nofollow" />
274 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
274 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
275
275
276 <title>Mercurial repositories index</title>
276 <title>Mercurial repositories index</title>
277 </head>
277 </head>
278 <body>
278 <body>
279
279
280 <div class="container">
280 <div class="container">
281 <div class="menu">
281 <div class="menu">
282 <a href="http://mercurial.selenic.com/">
282 <a href="http://mercurial.selenic.com/">
283 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
283 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
284 </div>
284 </div>
285 <div class="main">
285 <div class="main">
286 <h2>Mercurial Repositories</h2>
286 <h2>Mercurial Repositories</h2>
287
287
288 <table class="bigtable">
288 <table class="bigtable">
289 <tr>
289 <tr>
290 <th><a href="?sort=name">Name</a></th>
290 <th><a href="?sort=name">Name</a></th>
291 <th><a href="?sort=description">Description</a></th>
291 <th><a href="?sort=description">Description</a></th>
292 <th><a href="?sort=contact">Contact</a></th>
292 <th><a href="?sort=contact">Contact</a></th>
293 <th><a href="?sort=lastchange">Last modified</a></th>
293 <th><a href="?sort=lastchange">Last modified</a></th>
294 <th>&nbsp;</th>
294 <th>&nbsp;</th>
295 </tr>
295 </tr>
296
296
297 <tr class="parity0">
297 <tr class="parity0">
298 <td><a href="/t/a/?style=paper">a</a></td>
298 <td><a href="/t/a/?style=paper">a</a></td>
299 <td>unknown</td>
299 <td>unknown</td>
300 <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>
300 <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>
301 <td class="age">seconds ago</td>
301 <td class="age">seconds ago</td>
302 <td class="indexlinks"></td>
302 <td class="indexlinks"></td>
303 </tr>
303 </tr>
304
304
305 </table>
305 </table>
306 </div>
306 </div>
307 </div>
307 </div>
308
308
309
309
310 </body>
310 </body>
311 </html>
311 </html>
312
312
313 200 Script output follows
313 200 Script output follows
314
314
315 <?xml version="1.0" encoding="ascii"?>
315 <?xml version="1.0" encoding="ascii"?>
316 <feed xmlns="http://127.0.0.1/2005/Atom">
316 <feed xmlns="http://127.0.0.1/2005/Atom">
317 <!-- Changelog -->
317 <!-- Changelog -->
318 <id>http://127.0.0.1/t/a/</id>
318 <id>http://127.0.0.1/t/a/</id>
319 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
319 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
320 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
320 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
321 <title>t/a Changelog</title>
321 <title>t/a Changelog</title>
322 <updated>1970-01-01T00:00:01+00:00</updated>
322 <updated>1970-01-01T00:00:01+00:00</updated>
323
323
324 <entry>
324 <entry>
325 <title>a</title>
325 <title>a</title>
326 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
326 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
327 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
327 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
328 <author>
328 <author>
329 <name>test</name>
329 <name>test</name>
330 <email>&#116;&#101;&#115;&#116;</email>
330 <email>&#116;&#101;&#115;&#116;</email>
331 </author>
331 </author>
332 <updated>1970-01-01T00:00:01+00:00</updated>
332 <updated>1970-01-01T00:00:01+00:00</updated>
333 <published>1970-01-01T00:00:01+00:00</published>
333 <published>1970-01-01T00:00:01+00:00</published>
334 <content type="xhtml">
334 <content type="xhtml">
335 <div xmlns="http://127.0.0.1/1999/xhtml">
335 <div xmlns="http://127.0.0.1/1999/xhtml">
336 <pre xml:space="preserve">a</pre>
336 <pre xml:space="preserve">a</pre>
337 </div>
337 </div>
338 </content>
338 </content>
339 </entry>
339 </entry>
340
340
341 </feed>
341 </feed>
342 200 Script output follows
342 200 Script output follows
343
343
344 <?xml version="1.0" encoding="ascii"?>
344 <?xml version="1.0" encoding="ascii"?>
345 <feed xmlns="http://127.0.0.1/2005/Atom">
345 <feed xmlns="http://127.0.0.1/2005/Atom">
346 <!-- Changelog -->
346 <!-- Changelog -->
347 <id>http://127.0.0.1/t/a/</id>
347 <id>http://127.0.0.1/t/a/</id>
348 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
348 <link rel="self" href="http://127.0.0.1/t/a/atom-log"/>
349 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
349 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
350 <title>t/a Changelog</title>
350 <title>t/a Changelog</title>
351 <updated>1970-01-01T00:00:01+00:00</updated>
351 <updated>1970-01-01T00:00:01+00:00</updated>
352
352
353 <entry>
353 <entry>
354 <title>a</title>
354 <title>a</title>
355 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
355 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
356 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
356 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
357 <author>
357 <author>
358 <name>test</name>
358 <name>test</name>
359 <email>&#116;&#101;&#115;&#116;</email>
359 <email>&#116;&#101;&#115;&#116;</email>
360 </author>
360 </author>
361 <updated>1970-01-01T00:00:01+00:00</updated>
361 <updated>1970-01-01T00:00:01+00:00</updated>
362 <published>1970-01-01T00:00:01+00:00</published>
362 <published>1970-01-01T00:00:01+00:00</published>
363 <content type="xhtml">
363 <content type="xhtml">
364 <div xmlns="http://127.0.0.1/1999/xhtml">
364 <div xmlns="http://127.0.0.1/1999/xhtml">
365 <pre xml:space="preserve">a</pre>
365 <pre xml:space="preserve">a</pre>
366 </div>
366 </div>
367 </content>
367 </content>
368 </entry>
368 </entry>
369
369
370 </feed>
370 </feed>
371 200 Script output follows
371 200 Script output follows
372
372
373 a
373 a
374 200 Script output follows
374 200 Script output follows
375
375
376
376
377 /coll/a/
377 /coll/a/
378 /coll/a/.hg/patches/
378 /coll/a/.hg/patches/
379 /coll/b/
379 /coll/b/
380 /coll/c/
380 /coll/c/
381
381
382 200 Script output follows
382 200 Script output follows
383
383
384 a
384 a
385 200 Script output follows
385 200 Script output follows
386
386
387
387
388 /rcoll/a/
388 /rcoll/a/
389 /rcoll/a/.hg/patches/
389 /rcoll/a/.hg/patches/
390 /rcoll/b/
390 /rcoll/b/
391 /rcoll/b/d/
391 /rcoll/b/d/
392 /rcoll/c/
392 /rcoll/c/
393
393
394 200 Script output follows
394 200 Script output follows
395
395
396 d
396 d
397 % test descend = False
397 % test descend = False
398 200 Script output follows
398 200 Script output follows
399
399
400
400
401 /c/
401 /c/
402
402
403 200 Script output follows
403 200 Script output follows
404
404
405
405
406 /t/a/
406 /t/a/
407 /t/b/
407 /t/b/
408
408
409 % test inexistent and inaccessible repo should be ignored silently
410 200 Script output follows
411
412 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
413 <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US">
414 <head>
415 <link rel="icon" href="/static/hgicon.png" type="image/png" />
416 <meta name="robots" content="index, nofollow" />
417 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
418
419 <title>Mercurial repositories index</title>
420 </head>
421 <body>
422
423 <div class="container">
424 <div class="menu">
425 <a href="http://mercurial.selenic.com/">
426 <img src="/static/hglogo.png" width=75 height=90 border=0 alt="mercurial" /></a>
427 </div>
428 <div class="main">
429 <h2>Mercurial Repositories</h2>
430
431 <table class="bigtable">
432 <tr>
433 <th><a href="?sort=name">Name</a></th>
434 <th><a href="?sort=description">Description</a></th>
435 <th><a href="?sort=contact">Contact</a></th>
436 <th><a href="?sort=lastchange">Last modified</a></th>
437 <th>&nbsp;</th>
438 </tr>
439
440 </table>
441 </div>
442 </div>
443
444
445 </body>
446 </html>
447
409 % collections: should succeed
448 % collections: should succeed
410 200 Script output follows
449 200 Script output follows
411
450
412
451
413 /a/
452 /a/
414 /a/.hg/patches/
453 /a/.hg/patches/
415 /b/
454 /b/
416 /c/
455 /c/
417
456
418 200 Script output follows
457 200 Script output follows
419
458
420 a
459 a
421 200 Script output follows
460 200 Script output follows
422
461
423 b
462 b
424 200 Script output follows
463 200 Script output follows
425
464
426 c
465 c
427 % atom-log with basedir /
466 % atom-log with basedir /
428 <link rel="self" href="http://example.com:8080/a/atom-log"/>
467 <link rel="self" href="http://example.com:8080/a/atom-log"/>
429 <link rel="alternate" href="http://example.com:8080/a/"/>
468 <link rel="alternate" href="http://example.com:8080/a/"/>
430 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
469 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
431 % rss-log with basedir /
470 % rss-log with basedir /
432 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
471 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
433 % atom-log with basedir /foo/
472 % atom-log with basedir /foo/
434 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
473 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
435 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
474 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
436 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
475 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
437 % rss-log with basedir /foo/
476 % rss-log with basedir /foo/
438 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
477 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
439 % paths errors 1
478 % paths errors 1
440 % paths errors 2
479 % paths errors 2
441 % paths errors 3
480 % paths errors 3
442 % collections errors
481 % collections errors
443 % collections errors 2
482 % collections errors 2
General Comments 0
You need to be logged in to leave comments. Login now