##// END OF EJS Templates
hgwebdir: allow pure relative globs in paths...
Mads Kiilerich -
r11677:8f8a7976 stable
parent child Browse files
Show More
@@ -1,352 +1,352 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(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 d = (get_mtime(r.spath), util.makedate()[1])
236 d = (get_mtime(r.spath), util.makedate()[1])
237 except OSError:
237 except OSError:
238 continue
238 continue
239
239
240 contact = get_contact(get)
240 contact = get_contact(get)
241 description = get("web", "description", "")
241 description = get("web", "description", "")
242 name = get("web", "name", name)
242 name = get("web", "name", name)
243 row = dict(contact=contact or "unknown",
243 row = dict(contact=contact or "unknown",
244 contact_sort=contact.upper() or "unknown",
244 contact_sort=contact.upper() or "unknown",
245 name=name,
245 name=name,
246 name_sort=name,
246 name_sort=name,
247 url=url,
247 url=url,
248 description=description or "unknown",
248 description=description or "unknown",
249 description_sort=description.upper() or "unknown",
249 description_sort=description.upper() or "unknown",
250 lastchange=d,
250 lastchange=d,
251 lastchange_sort=d[1]-d[0],
251 lastchange_sort=d[1]-d[0],
252 archives=archivelist(u, "tip", url))
252 archives=archivelist(u, "tip", url))
253 yield row
253 yield row
254
254
255 sortdefault = None, False
255 sortdefault = None, False
256 def entries(sortcolumn="", descending=False, subdir="", **map):
256 def entries(sortcolumn="", descending=False, subdir="", **map):
257 rows = rawentries(subdir=subdir, **map)
257 rows = rawentries(subdir=subdir, **map)
258
258
259 if sortcolumn and sortdefault != (sortcolumn, descending):
259 if sortcolumn and sortdefault != (sortcolumn, descending):
260 sortkey = '%s_sort' % sortcolumn
260 sortkey = '%s_sort' % sortcolumn
261 rows = sorted(rows, key=lambda x: x[sortkey],
261 rows = sorted(rows, key=lambda x: x[sortkey],
262 reverse=descending)
262 reverse=descending)
263 for row, parity in zip(rows, paritygen(self.stripecount)):
263 for row, parity in zip(rows, paritygen(self.stripecount)):
264 row['parity'] = parity
264 row['parity'] = parity
265 yield row
265 yield row
266
266
267 self.refresh()
267 self.refresh()
268 sortable = ["name", "description", "contact", "lastchange"]
268 sortable = ["name", "description", "contact", "lastchange"]
269 sortcolumn, descending = sortdefault
269 sortcolumn, descending = sortdefault
270 if 'sort' in req.form:
270 if 'sort' in req.form:
271 sortcolumn = req.form['sort'][0]
271 sortcolumn = req.form['sort'][0]
272 descending = sortcolumn.startswith('-')
272 descending = sortcolumn.startswith('-')
273 if descending:
273 if descending:
274 sortcolumn = sortcolumn[1:]
274 sortcolumn = sortcolumn[1:]
275 if sortcolumn not in sortable:
275 if sortcolumn not in sortable:
276 sortcolumn = ""
276 sortcolumn = ""
277
277
278 sort = [("sort_%s" % column,
278 sort = [("sort_%s" % column,
279 "%s%s" % ((not descending and column == sortcolumn)
279 "%s%s" % ((not descending and column == sortcolumn)
280 and "-" or "", column))
280 and "-" or "", column))
281 for column in sortable]
281 for column in sortable]
282
282
283 self.refresh()
283 self.refresh()
284 self.updatereqenv(req.env)
284 self.updatereqenv(req.env)
285
285
286 return tmpl("index", entries=entries, subdir=subdir,
286 return tmpl("index", entries=entries, subdir=subdir,
287 sortcolumn=sortcolumn, descending=descending,
287 sortcolumn=sortcolumn, descending=descending,
288 **dict(sort))
288 **dict(sort))
289
289
290 def templater(self, req):
290 def templater(self, req):
291
291
292 def header(**map):
292 def header(**map):
293 yield tmpl('header', encoding=encoding.encoding, **map)
293 yield tmpl('header', encoding=encoding.encoding, **map)
294
294
295 def footer(**map):
295 def footer(**map):
296 yield tmpl("footer", **map)
296 yield tmpl("footer", **map)
297
297
298 def motd(**map):
298 def motd(**map):
299 if self.motd is not None:
299 if self.motd is not None:
300 yield self.motd
300 yield self.motd
301 else:
301 else:
302 yield config('web', 'motd', '')
302 yield config('web', 'motd', '')
303
303
304 def config(section, name, default=None, untrusted=True):
304 def config(section, name, default=None, untrusted=True):
305 return self.ui.config(section, name, default, untrusted)
305 return self.ui.config(section, name, default, untrusted)
306
306
307 self.updatereqenv(req.env)
307 self.updatereqenv(req.env)
308
308
309 url = req.env.get('SCRIPT_NAME', '')
309 url = req.env.get('SCRIPT_NAME', '')
310 if not url.endswith('/'):
310 if not url.endswith('/'):
311 url += '/'
311 url += '/'
312
312
313 vars = {}
313 vars = {}
314 styles = (
314 styles = (
315 req.form.get('style', [None])[0],
315 req.form.get('style', [None])[0],
316 config('web', 'style'),
316 config('web', 'style'),
317 'paper'
317 'paper'
318 )
318 )
319 style, mapfile = templater.stylemap(styles, self.templatepath)
319 style, mapfile = templater.stylemap(styles, self.templatepath)
320 if style == styles[0]:
320 if style == styles[0]:
321 vars['style'] = style
321 vars['style'] = style
322
322
323 start = url[-1] == '?' and '&' or '?'
323 start = url[-1] == '?' and '&' or '?'
324 sessionvars = webutil.sessionvars(vars, start)
324 sessionvars = webutil.sessionvars(vars, start)
325 staticurl = config('web', 'staticurl') or url + 'static/'
325 staticurl = config('web', 'staticurl') or url + 'static/'
326 if not staticurl.endswith('/'):
326 if not staticurl.endswith('/'):
327 staticurl += '/'
327 staticurl += '/'
328
328
329 tmpl = templater.templater(mapfile,
329 tmpl = templater.templater(mapfile,
330 defaults={"header": header,
330 defaults={"header": header,
331 "footer": footer,
331 "footer": footer,
332 "motd": motd,
332 "motd": motd,
333 "url": url,
333 "url": url,
334 "staticurl": staticurl,
334 "staticurl": staticurl,
335 "sessionvars": sessionvars})
335 "sessionvars": sessionvars})
336 return tmpl
336 return tmpl
337
337
338 def updatereqenv(self, env):
338 def updatereqenv(self, env):
339 def splitnetloc(netloc):
339 def splitnetloc(netloc):
340 if ':' in netloc:
340 if ':' in netloc:
341 return netloc.split(':', 1)
341 return netloc.split(':', 1)
342 else:
342 else:
343 return (netloc, None)
343 return (netloc, None)
344
344
345 if self._baseurl is not None:
345 if self._baseurl is not None:
346 urlcomp = urlparse.urlparse(self._baseurl)
346 urlcomp = urlparse.urlparse(self._baseurl)
347 host, port = splitnetloc(urlcomp[1])
347 host, port = splitnetloc(urlcomp[1])
348 path = urlcomp[2]
348 path = urlcomp[2]
349 env['SERVER_NAME'] = host
349 env['SERVER_NAME'] = host
350 if port:
350 if port:
351 env['SERVER_PORT'] = port
351 env['SERVER_PORT'] = port
352 env['SCRIPT_NAME'] = path
352 env['SCRIPT_NAME'] = path
@@ -1,161 +1,163 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 root=`pwd`
29 root=`pwd`
30 cd ..
30 cd ..
31
31
32
32
33 cat > paths.conf <<EOF
33 cat > paths.conf <<EOF
34 [paths]
34 [paths]
35 a=$root/a
35 a=$root/a
36 b=$root/b
36 b=$root/b
37 EOF
37 EOF
38
38
39 hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
39 hg serve -p $HGPORT -d --pid-file=hg.pid --webdir-conf paths.conf \
40 -A access-paths.log -E error-paths-1.log
40 -A access-paths.log -E error-paths-1.log
41 cat hg.pid >> $DAEMON_PIDS
41 cat hg.pid >> $DAEMON_PIDS
42
42
43 echo % should give a 404 - file does not exist
43 echo % should give a 404 - file does not exist
44 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
44 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/bork?style=raw'
45
45
46 echo % should succeed
46 echo % should succeed
47 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
47 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/?style=raw'
48 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/file/tip/a?style=raw'
48 "$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'
49 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/b/file/tip/b?style=raw'
50
50
51 echo % should give a 404 - repo is not published
51 echo % should give a 404 - repo is not published
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
52 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/c/file/tip/c?style=raw'
53
53
54 echo % atom-log without basedir
54 echo % atom-log without basedir
55 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/atom-log' \
55 "$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/|'
56 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
57
57
58 echo % rss-log without basedir
58 echo % rss-log without basedir
59 "$TESTDIR/get-with-headers.py" localhost:$HGPORT '/a/rss-log' \
59 "$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/|'
60 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
61
61
62 cat > paths.conf <<EOF
62 cat > paths.conf <<EOF
63 [paths]
63 [paths]
64 t/a/=$root/a
64 t/a/=$root/a
65 b=$root/b
65 b=$root/b
66 coll=$root/*
66 coll=$root/*
67 rcoll=$root/**
67 rcoll=$root/**
68 star=*
69 starstar=**
68 EOF
70 EOF
69
71
70 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
72 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
71 -A access-paths.log -E error-paths-2.log
73 -A access-paths.log -E error-paths-2.log
72 cat hg.pid >> $DAEMON_PIDS
74 cat hg.pid >> $DAEMON_PIDS
73
75
74 echo % should succeed, slashy names
76 echo % should succeed, slashy names
75 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
77 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
76 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
78 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=paper' \
77 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
79 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
78 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
80 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t?style=raw'
79 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
81 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
80 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=paper' \
81 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
83 | sed "s/[0-9]\{1,\} seconds\{0,1\} ago/seconds ago/"
82 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a?style=atom' \
83 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
85 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
84 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/?style=atom' \
85 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
87 | sed "s/http:\/\/[^/]*\//http:\/\/127.0.0.1\//"
86 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/a/file/tip/a?style=raw'
87 # Test [paths] '*' extension
89 # Test [paths] '*' extension
88 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
90 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/?style=raw'
89 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
91 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/coll/a/file/tip/a?style=raw'
90 #test [paths] '**' extension
92 #test [paths] '**' extension
91 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
93 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/?style=raw'
92 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
94 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/rcoll/b/d/file/tip/d?style=raw'
93
95
94
96
95 "$TESTDIR/killdaemons.py"
97 "$TESTDIR/killdaemons.py"
96 cat > paths.conf <<EOF
98 cat > paths.conf <<EOF
97 [paths]
99 [paths]
98 t/a = $root/a
100 t/a = $root/a
99 t/b = $root/b
101 t/b = $root/b
100 c = $root/c
102 c = $root/c
101 [web]
103 [web]
102 descend=false
104 descend=false
103 EOF
105 EOF
104
106
105 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
107 hg serve -p $HGPORT1 -d --pid-file=hg.pid --webdir-conf paths.conf \
106 -A access-paths.log -E error-paths-3.log
108 -A access-paths.log -E error-paths-3.log
107 cat hg.pid >> $DAEMON_PIDS
109 cat hg.pid >> $DAEMON_PIDS
108 echo % test descend = False
110 echo % test descend = False
109 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
111 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/?style=raw'
110 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
112 "$TESTDIR/get-with-headers.py" localhost:$HGPORT1 '/t/?style=raw'
111
113
112
114
113 cat > collections.conf <<EOF
115 cat > collections.conf <<EOF
114 [collections]
116 [collections]
115 $root=$root
117 $root=$root
116 EOF
118 EOF
117
119
118 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
120 hg serve --config web.baseurl=http://hg.example.com:8080/ -p $HGPORT2 -d \
119 --pid-file=hg.pid --webdir-conf collections.conf \
121 --pid-file=hg.pid --webdir-conf collections.conf \
120 -A access-collections.log -E error-collections.log
122 -A access-collections.log -E error-collections.log
121 cat hg.pid >> $DAEMON_PIDS
123 cat hg.pid >> $DAEMON_PIDS
122
124
123 echo % collections: should succeed
125 echo % collections: should succeed
124 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
126 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/?style=raw'
125 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
127 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/file/tip/a?style=raw'
126 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
128 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/b/file/tip/b?style=raw'
127 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
129 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/c/file/tip/c?style=raw'
128
130
129 echo % atom-log with basedir /
131 echo % atom-log with basedir /
130 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
132 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
131 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
133 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
132
134
133 echo % rss-log with basedir /
135 echo % rss-log with basedir /
134 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
136 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
135 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
137 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
136
138
137 "$TESTDIR/killdaemons.py"
139 "$TESTDIR/killdaemons.py"
138
140
139 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
141 hg serve --config web.baseurl=http://hg.example.com:8080/foo/ -p $HGPORT2 -d \
140 --pid-file=hg.pid --webdir-conf collections.conf \
142 --pid-file=hg.pid --webdir-conf collections.conf \
141 -A access-collections-2.log -E error-collections-2.log
143 -A access-collections-2.log -E error-collections-2.log
142 cat hg.pid >> $DAEMON_PIDS
144 cat hg.pid >> $DAEMON_PIDS
143
145
144 echo % atom-log with basedir /foo/
146 echo % atom-log with basedir /foo/
145 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
147 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/atom-log' \
146 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
148 | grep '<link' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
147
149
148 echo % rss-log with basedir /foo/
150 echo % rss-log with basedir /foo/
149 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
151 "$TESTDIR/get-with-headers.py" localhost:$HGPORT2 '/a/rss-log' \
150 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
152 | grep '<guid' | sed 's|//[.a-zA-Z0-9_-]*:[0-9][0-9]*/|//example.com:8080/|'
151
153
152 echo % paths errors 1
154 echo % paths errors 1
153 cat error-paths-1.log
155 cat error-paths-1.log
154 echo % paths errors 2
156 echo % paths errors 2
155 cat error-paths-2.log
157 cat error-paths-2.log
156 echo % paths errors 3
158 echo % paths errors 3
157 cat error-paths-3.log
159 cat error-paths-3.log
158 echo % collections errors
160 echo % collections errors
159 cat error-collections.log
161 cat error-collections.log
160 echo % collections errors 2
162 echo % collections errors 2
161 cat error-collections-2.log
163 cat error-collections-2.log
@@ -1,362 +1,443 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/
50 /star/webdir/a/.hg/patches/
51 /star/webdir/b/
52 /star/webdir/c/
53 /starstar/webdir/a/
54 /starstar/webdir/a/.hg/patches/
55 /starstar/webdir/b/
56 /starstar/webdir/b/d/
57 /starstar/webdir/c/
49
58
50 200 Script output follows
59 200 Script output follows
51
60
52 <!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">
53 <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">
54 <head>
63 <head>
55 <link rel="icon" href="/static/hgicon.png" type="image/png" />
64 <link rel="icon" href="/static/hgicon.png" type="image/png" />
56 <meta name="robots" content="index, nofollow" />
65 <meta name="robots" content="index, nofollow" />
57 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
66 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
58
67
59 <title>Mercurial repositories index</title>
68 <title>Mercurial repositories index</title>
60 </head>
69 </head>
61 <body>
70 <body>
62
71
63 <div class="container">
72 <div class="container">
64 <div class="menu">
73 <div class="menu">
65 <a href="http://mercurial.selenic.com/">
74 <a href="http://mercurial.selenic.com/">
66 <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>
67 </div>
76 </div>
68 <div class="main">
77 <div class="main">
69 <h2>Mercurial Repositories</h2>
78 <h2>Mercurial Repositories</h2>
70
79
71 <table class="bigtable">
80 <table class="bigtable">
72 <tr>
81 <tr>
73 <th><a href="?sort=name">Name</a></th>
82 <th><a href="?sort=name">Name</a></th>
74 <th><a href="?sort=description">Description</a></th>
83 <th><a href="?sort=description">Description</a></th>
75 <th><a href="?sort=contact">Contact</a></th>
84 <th><a href="?sort=contact">Contact</a></th>
76 <th><a href="?sort=lastchange">Last modified</a></th>
85 <th><a href="?sort=lastchange">Last modified</a></th>
77 <th>&nbsp;</th>
86 <th>&nbsp;</th>
78 </tr>
87 </tr>
79
88
80 <tr class="parity0">
89 <tr class="parity0">
81 <td><a href="/t/a/?style=paper">t/a</a></td>
90 <td><a href="/t/a/?style=paper">t/a</a></td>
82 <td>unknown</td>
91 <td>unknown</td>
83 <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>
84 <td class="age">seconds ago</td>
93 <td class="age">seconds ago</td>
85 <td class="indexlinks"></td>
94 <td class="indexlinks"></td>
86 </tr>
95 </tr>
87
96
88 <tr class="parity1">
97 <tr class="parity1">
89 <td><a href="/b/?style=paper">b</a></td>
98 <td><a href="/b/?style=paper">b</a></td>
90 <td>unknown</td>
99 <td>unknown</td>
91 <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>
92 <td class="age">seconds ago</td>
101 <td class="age">seconds ago</td>
93 <td class="indexlinks"></td>
102 <td class="indexlinks"></td>
94 </tr>
103 </tr>
95
104
96 <tr class="parity0">
105 <tr class="parity0">
97 <td><a href="/coll/a/?style=paper">coll/a</a></td>
106 <td><a href="/coll/a/?style=paper">coll/a</a></td>
98 <td>unknown</td>
107 <td>unknown</td>
99 <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>
100 <td class="age">seconds ago</td>
109 <td class="age">seconds ago</td>
101 <td class="indexlinks"></td>
110 <td class="indexlinks"></td>
102 </tr>
111 </tr>
103
112
104 <tr class="parity1">
113 <tr class="parity1">
105 <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>
106 <td>unknown</td>
115 <td>unknown</td>
107 <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>
108 <td class="age">seconds ago</td>
117 <td class="age">seconds ago</td>
109 <td class="indexlinks"></td>
118 <td class="indexlinks"></td>
110 </tr>
119 </tr>
111
120
112 <tr class="parity0">
121 <tr class="parity0">
113 <td><a href="/coll/b/?style=paper">coll/b</a></td>
122 <td><a href="/coll/b/?style=paper">coll/b</a></td>
114 <td>unknown</td>
123 <td>unknown</td>
115 <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>
116 <td class="age">seconds ago</td>
125 <td class="age">seconds ago</td>
117 <td class="indexlinks"></td>
126 <td class="indexlinks"></td>
118 </tr>
127 </tr>
119
128
120 <tr class="parity1">
129 <tr class="parity1">
121 <td><a href="/coll/c/?style=paper">coll/c</a></td>
130 <td><a href="/coll/c/?style=paper">coll/c</a></td>
122 <td>unknown</td>
131 <td>unknown</td>
123 <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>
124 <td class="age">seconds ago</td>
133 <td class="age">seconds ago</td>
125 <td class="indexlinks"></td>
134 <td class="indexlinks"></td>
126 </tr>
135 </tr>
127
136
128 <tr class="parity0">
137 <tr class="parity0">
129 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
138 <td><a href="/rcoll/a/?style=paper">rcoll/a</a></td>
130 <td>unknown</td>
139 <td>unknown</td>
131 <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>
132 <td class="age">seconds ago</td>
141 <td class="age">seconds ago</td>
133 <td class="indexlinks"></td>
142 <td class="indexlinks"></td>
134 </tr>
143 </tr>
135
144
136 <tr class="parity1">
145 <tr class="parity1">
137 <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>
138 <td>unknown</td>
147 <td>unknown</td>
139 <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>
140 <td class="age">seconds ago</td>
149 <td class="age">seconds ago</td>
141 <td class="indexlinks"></td>
150 <td class="indexlinks"></td>
142 </tr>
151 </tr>
143
152
144 <tr class="parity0">
153 <tr class="parity0">
145 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
154 <td><a href="/rcoll/b/?style=paper">rcoll/b</a></td>
146 <td>unknown</td>
155 <td>unknown</td>
147 <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>
148 <td class="age">seconds ago</td>
157 <td class="age">seconds ago</td>
149 <td class="indexlinks"></td>
158 <td class="indexlinks"></td>
150 </tr>
159 </tr>
151
160
152 <tr class="parity1">
161 <tr class="parity1">
153 <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>
154 <td>unknown</td>
163 <td>unknown</td>
155 <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>
156 <td class="age">seconds ago</td>
165 <td class="age">seconds ago</td>
157 <td class="indexlinks"></td>
166 <td class="indexlinks"></td>
158 </tr>
167 </tr>
159
168
160 <tr class="parity0">
169 <tr class="parity0">
161 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
170 <td><a href="/rcoll/c/?style=paper">rcoll/c</a></td>
162 <td>unknown</td>
171 <td>unknown</td>
163 <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>
164 <td class="age">seconds ago</td>
173 <td class="age">seconds ago</td>
165 <td class="indexlinks"></td>
174 <td class="indexlinks"></td>
166 </tr>
175 </tr>
167
176
177 <tr class="parity1">
178 <td><a href="/star/webdir/a/?style=paper">star/webdir/a</a></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>
181 <td class="age">seconds ago</td>
182 <td class="indexlinks"></td>
183 </tr>
184
185 <tr class="parity0">
186 <td><a href="/star/webdir/a/.hg/patches/?style=paper">star/webdir/a/.hg/patches</a></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>
189 <td class="age">seconds ago</td>
190 <td class="indexlinks"></td>
191 </tr>
192
193 <tr class="parity1">
194 <td><a href="/star/webdir/b/?style=paper">star/webdir/b</a></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>
197 <td class="age">seconds ago</td>
198 <td class="indexlinks"></td>
199 </tr>
200
201 <tr class="parity0">
202 <td><a href="/star/webdir/c/?style=paper">star/webdir/c</a></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>
205 <td class="age">seconds ago</td>
206 <td class="indexlinks"></td>
207 </tr>
208
209 <tr class="parity1">
210 <td><a href="/starstar/webdir/a/?style=paper">starstar/webdir/a</a></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>
213 <td class="age">seconds ago</td>
214 <td class="indexlinks"></td>
215 </tr>
216
217 <tr class="parity0">
218 <td><a href="/starstar/webdir/a/.hg/patches/?style=paper">starstar/webdir/a/.hg/patches</a></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>
221 <td class="age">seconds ago</td>
222 <td class="indexlinks"></td>
223 </tr>
224
225 <tr class="parity1">
226 <td><a href="/starstar/webdir/b/?style=paper">starstar/webdir/b</a></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>
229 <td class="age">seconds ago</td>
230 <td class="indexlinks"></td>
231 </tr>
232
233 <tr class="parity0">
234 <td><a href="/starstar/webdir/b/d/?style=paper">starstar/webdir/b/d</a></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>
237 <td class="age">seconds ago</td>
238 <td class="indexlinks"></td>
239 </tr>
240
241 <tr class="parity1">
242 <td><a href="/starstar/webdir/c/?style=paper">starstar/webdir/c</a></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>
245 <td class="age">seconds ago</td>
246 <td class="indexlinks"></td>
247 </tr>
248
168 </table>
249 </table>
169 </div>
250 </div>
170 </div>
251 </div>
171
252
172
253
173 </body>
254 </body>
174 </html>
255 </html>
175
256
176 200 Script output follows
257 200 Script output follows
177
258
178
259
179 /t/a/
260 /t/a/
180
261
181 200 Script output follows
262 200 Script output follows
182
263
183
264
184 /t/a/
265 /t/a/
185
266
186 200 Script output follows
267 200 Script output follows
187
268
188 <!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">
189 <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">
190 <head>
271 <head>
191 <link rel="icon" href="/static/hgicon.png" type="image/png" />
272 <link rel="icon" href="/static/hgicon.png" type="image/png" />
192 <meta name="robots" content="index, nofollow" />
273 <meta name="robots" content="index, nofollow" />
193 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
274 <link rel="stylesheet" href="/static/style-paper.css" type="text/css" />
194
275
195 <title>Mercurial repositories index</title>
276 <title>Mercurial repositories index</title>
196 </head>
277 </head>
197 <body>
278 <body>
198
279
199 <div class="container">
280 <div class="container">
200 <div class="menu">
281 <div class="menu">
201 <a href="http://mercurial.selenic.com/">
282 <a href="http://mercurial.selenic.com/">
202 <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>
203 </div>
284 </div>
204 <div class="main">
285 <div class="main">
205 <h2>Mercurial Repositories</h2>
286 <h2>Mercurial Repositories</h2>
206
287
207 <table class="bigtable">
288 <table class="bigtable">
208 <tr>
289 <tr>
209 <th><a href="?sort=name">Name</a></th>
290 <th><a href="?sort=name">Name</a></th>
210 <th><a href="?sort=description">Description</a></th>
291 <th><a href="?sort=description">Description</a></th>
211 <th><a href="?sort=contact">Contact</a></th>
292 <th><a href="?sort=contact">Contact</a></th>
212 <th><a href="?sort=lastchange">Last modified</a></th>
293 <th><a href="?sort=lastchange">Last modified</a></th>
213 <th>&nbsp;</th>
294 <th>&nbsp;</th>
214 </tr>
295 </tr>
215
296
216 <tr class="parity0">
297 <tr class="parity0">
217 <td><a href="/t/a/?style=paper">a</a></td>
298 <td><a href="/t/a/?style=paper">a</a></td>
218 <td>unknown</td>
299 <td>unknown</td>
219 <td>&#70;&#111;&#111;&#32;&#66;&#97;&#114;&#32;&#60;&#102;&#111;&#111;&#46;&#98;&#97;&#114;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;&#62;</td>
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>
220 <td class="age">seconds ago</td>
301 <td class="age">seconds ago</td>
221 <td class="indexlinks"></td>
302 <td class="indexlinks"></td>
222 </tr>
303 </tr>
223
304
224 </table>
305 </table>
225 </div>
306 </div>
226 </div>
307 </div>
227
308
228
309
229 </body>
310 </body>
230 </html>
311 </html>
231
312
232 200 Script output follows
313 200 Script output follows
233
314
234 <?xml version="1.0" encoding="ascii"?>
315 <?xml version="1.0" encoding="ascii"?>
235 <feed xmlns="http://127.0.0.1/2005/Atom">
316 <feed xmlns="http://127.0.0.1/2005/Atom">
236 <!-- Changelog -->
317 <!-- Changelog -->
237 <id>http://127.0.0.1/t/a/</id>
318 <id>http://127.0.0.1/t/a/</id>
238 <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"/>
239 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
320 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
240 <title>t/a Changelog</title>
321 <title>t/a Changelog</title>
241 <updated>1970-01-01T00:00:01+00:00</updated>
322 <updated>1970-01-01T00:00:01+00:00</updated>
242
323
243 <entry>
324 <entry>
244 <title>a</title>
325 <title>a</title>
245 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
326 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
246 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
327 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
247 <author>
328 <author>
248 <name>test</name>
329 <name>test</name>
249 <email>&#116;&#101;&#115;&#116;</email>
330 <email>&#116;&#101;&#115;&#116;</email>
250 </author>
331 </author>
251 <updated>1970-01-01T00:00:01+00:00</updated>
332 <updated>1970-01-01T00:00:01+00:00</updated>
252 <published>1970-01-01T00:00:01+00:00</published>
333 <published>1970-01-01T00:00:01+00:00</published>
253 <content type="xhtml">
334 <content type="xhtml">
254 <div xmlns="http://127.0.0.1/1999/xhtml">
335 <div xmlns="http://127.0.0.1/1999/xhtml">
255 <pre xml:space="preserve">a</pre>
336 <pre xml:space="preserve">a</pre>
256 </div>
337 </div>
257 </content>
338 </content>
258 </entry>
339 </entry>
259
340
260 </feed>
341 </feed>
261 200 Script output follows
342 200 Script output follows
262
343
263 <?xml version="1.0" encoding="ascii"?>
344 <?xml version="1.0" encoding="ascii"?>
264 <feed xmlns="http://127.0.0.1/2005/Atom">
345 <feed xmlns="http://127.0.0.1/2005/Atom">
265 <!-- Changelog -->
346 <!-- Changelog -->
266 <id>http://127.0.0.1/t/a/</id>
347 <id>http://127.0.0.1/t/a/</id>
267 <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"/>
268 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
349 <link rel="alternate" href="http://127.0.0.1/t/a/"/>
269 <title>t/a Changelog</title>
350 <title>t/a Changelog</title>
270 <updated>1970-01-01T00:00:01+00:00</updated>
351 <updated>1970-01-01T00:00:01+00:00</updated>
271
352
272 <entry>
353 <entry>
273 <title>a</title>
354 <title>a</title>
274 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
355 <id>http://127.0.0.1/t/a/#changeset-8580ff50825a50c8f716709acdf8de0deddcd6ab</id>
275 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
356 <link href="http://127.0.0.1/t/a/rev/8580ff50825a"/>
276 <author>
357 <author>
277 <name>test</name>
358 <name>test</name>
278 <email>&#116;&#101;&#115;&#116;</email>
359 <email>&#116;&#101;&#115;&#116;</email>
279 </author>
360 </author>
280 <updated>1970-01-01T00:00:01+00:00</updated>
361 <updated>1970-01-01T00:00:01+00:00</updated>
281 <published>1970-01-01T00:00:01+00:00</published>
362 <published>1970-01-01T00:00:01+00:00</published>
282 <content type="xhtml">
363 <content type="xhtml">
283 <div xmlns="http://127.0.0.1/1999/xhtml">
364 <div xmlns="http://127.0.0.1/1999/xhtml">
284 <pre xml:space="preserve">a</pre>
365 <pre xml:space="preserve">a</pre>
285 </div>
366 </div>
286 </content>
367 </content>
287 </entry>
368 </entry>
288
369
289 </feed>
370 </feed>
290 200 Script output follows
371 200 Script output follows
291
372
292 a
373 a
293 200 Script output follows
374 200 Script output follows
294
375
295
376
296 /coll/a/
377 /coll/a/
297 /coll/a/.hg/patches/
378 /coll/a/.hg/patches/
298 /coll/b/
379 /coll/b/
299 /coll/c/
380 /coll/c/
300
381
301 200 Script output follows
382 200 Script output follows
302
383
303 a
384 a
304 200 Script output follows
385 200 Script output follows
305
386
306
387
307 /rcoll/a/
388 /rcoll/a/
308 /rcoll/a/.hg/patches/
389 /rcoll/a/.hg/patches/
309 /rcoll/b/
390 /rcoll/b/
310 /rcoll/b/d/
391 /rcoll/b/d/
311 /rcoll/c/
392 /rcoll/c/
312
393
313 200 Script output follows
394 200 Script output follows
314
395
315 d
396 d
316 % test descend = False
397 % test descend = False
317 200 Script output follows
398 200 Script output follows
318
399
319
400
320 /c/
401 /c/
321
402
322 200 Script output follows
403 200 Script output follows
323
404
324
405
325 /t/a/
406 /t/a/
326 /t/b/
407 /t/b/
327
408
328 % collections: should succeed
409 % collections: should succeed
329 200 Script output follows
410 200 Script output follows
330
411
331
412
332 /a/
413 /a/
333 /a/.hg/patches/
414 /a/.hg/patches/
334 /b/
415 /b/
335 /c/
416 /c/
336
417
337 200 Script output follows
418 200 Script output follows
338
419
339 a
420 a
340 200 Script output follows
421 200 Script output follows
341
422
342 b
423 b
343 200 Script output follows
424 200 Script output follows
344
425
345 c
426 c
346 % atom-log with basedir /
427 % atom-log with basedir /
347 <link rel="self" href="http://example.com:8080/a/atom-log"/>
428 <link rel="self" href="http://example.com:8080/a/atom-log"/>
348 <link rel="alternate" href="http://example.com:8080/a/"/>
429 <link rel="alternate" href="http://example.com:8080/a/"/>
349 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
430 <link href="http://example.com:8080/a/rev/8580ff50825a"/>
350 % rss-log with basedir /
431 % rss-log with basedir /
351 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
432 <guid isPermaLink="true">http://example.com:8080/a/rev/8580ff50825a</guid>
352 % atom-log with basedir /foo/
433 % atom-log with basedir /foo/
353 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
434 <link rel="self" href="http://example.com:8080/foo/a/atom-log"/>
354 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
435 <link rel="alternate" href="http://example.com:8080/foo/a/"/>
355 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
436 <link href="http://example.com:8080/foo/a/rev/8580ff50825a"/>
356 % rss-log with basedir /foo/
437 % rss-log with basedir /foo/
357 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
438 <guid isPermaLink="true">http://example.com:8080/foo/a/rev/8580ff50825a</guid>
358 % paths errors 1
439 % paths errors 1
359 % paths errors 2
440 % paths errors 2
360 % paths errors 3
441 % paths errors 3
361 % collections errors
442 % collections errors
362 % collections errors 2
443 % collections errors 2
General Comments 0
You need to be logged in to leave comments. Login now