comparison mercurial/hgweb/hgwebdir_mod.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children d783f945a701
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
50 ) 50 )
51 from ..utils import dateutil 51 from ..utils import dateutil
52 52
53 53
54 def cleannames(items): 54 def cleannames(items):
55 return [(util.pconvert(name).strip('/'), path) for name, path in items] 55 return [(util.pconvert(name).strip(b'/'), path) for name, path in items]
56 56
57 57
58 def findrepos(paths): 58 def findrepos(paths):
59 repos = [] 59 repos = []
60 for prefix, root in cleannames(paths): 60 for prefix, root in cleannames(paths):
62 # "foo = /bar/*" or "foo = /bar/**" lets every repo /bar/N in or below 62 # "foo = /bar/*" or "foo = /bar/**" lets every repo /bar/N in or below
63 # /bar/ be served as as foo/N . 63 # /bar/ be served as as foo/N .
64 # '*' will not search inside dirs with .hg (except .hg/patches), 64 # '*' will not search inside dirs with .hg (except .hg/patches),
65 # '**' will search inside dirs with .hg (and thus also find subrepos). 65 # '**' will search inside dirs with .hg (and thus also find subrepos).
66 try: 66 try:
67 recurse = {'*': False, '**': True}[roottail] 67 recurse = {b'*': False, b'**': True}[roottail]
68 except KeyError: 68 except KeyError:
69 repos.append((prefix, root)) 69 repos.append((prefix, root))
70 continue 70 continue
71 roothead = os.path.normpath(os.path.abspath(roothead)) 71 roothead = os.path.normpath(os.path.abspath(roothead))
72 paths = scmutil.walkrepos(roothead, followsym=True, recurse=recurse) 72 paths = scmutil.walkrepos(roothead, followsym=True, recurse=recurse)
84 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')] 84 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
85 """ 85 """
86 for path in paths: 86 for path in paths:
87 path = os.path.normpath(path) 87 path = os.path.normpath(path)
88 yield ( 88 yield (
89 prefix + '/' + util.pconvert(path[len(roothead) :]).lstrip('/') 89 prefix + b'/' + util.pconvert(path[len(roothead) :]).lstrip(b'/')
90 ).strip('/'), path 90 ).strip(b'/'), path
91 91
92 92
93 def readallowed(ui, req): 93 def readallowed(ui, req):
94 """Check allow_read and deny_read config options of a repo's ui object 94 """Check allow_read and deny_read config options of a repo's ui object
95 to determine user permissions. By default, with neither option set (or 95 to determine user permissions. By default, with neither option set (or
99 allow_read is not empty and the user is not in allow_read. Return True 99 allow_read is not empty and the user is not in allow_read. Return True
100 if user is allowed to read the repo, else return False.""" 100 if user is allowed to read the repo, else return False."""
101 101
102 user = req.remoteuser 102 user = req.remoteuser
103 103
104 deny_read = ui.configlist('web', 'deny_read', untrusted=True) 104 deny_read = ui.configlist(b'web', b'deny_read', untrusted=True)
105 if deny_read and (not user or ismember(ui, user, deny_read)): 105 if deny_read and (not user or ismember(ui, user, deny_read)):
106 return False 106 return False
107 107
108 allow_read = ui.configlist('web', 'allow_read', untrusted=True) 108 allow_read = ui.configlist(b'web', b'allow_read', untrusted=True)
109 # by default, allow reading if no allow_read option has been set 109 # by default, allow reading if no allow_read option has been set
110 if not allow_read or ismember(ui, user, allow_read): 110 if not allow_read or ismember(ui, user, allow_read):
111 return True 111 return True
112 112
113 return False 113 return False
114 114
115 115
116 def rawindexentries(ui, repos, req, subdir=''): 116 def rawindexentries(ui, repos, req, subdir=b''):
117 descend = ui.configbool('web', 'descend') 117 descend = ui.configbool(b'web', b'descend')
118 collapse = ui.configbool('web', 'collapse') 118 collapse = ui.configbool(b'web', b'collapse')
119 seenrepos = set() 119 seenrepos = set()
120 seendirs = set() 120 seendirs = set()
121 for name, path in repos: 121 for name, path in repos:
122 122
123 if not name.startswith(subdir): 123 if not name.startswith(subdir):
124 continue 124 continue
125 name = name[len(subdir) :] 125 name = name[len(subdir) :]
126 directory = False 126 directory = False
127 127
128 if '/' in name: 128 if b'/' in name:
129 if not descend: 129 if not descend:
130 continue 130 continue
131 131
132 nameparts = name.split('/') 132 nameparts = name.split(b'/')
133 rootname = nameparts[0] 133 rootname = nameparts[0]
134 134
135 if not collapse: 135 if not collapse:
136 pass 136 pass
137 elif rootname in seendirs: 137 elif rootname in seendirs:
141 else: 141 else:
142 directory = True 142 directory = True
143 name = rootname 143 name = rootname
144 144
145 # redefine the path to refer to the directory 145 # redefine the path to refer to the directory
146 discarded = '/'.join(nameparts[1:]) 146 discarded = b'/'.join(nameparts[1:])
147 147
148 # remove name parts plus accompanying slash 148 # remove name parts plus accompanying slash
149 path = path[: -len(discarded) - 1] 149 path = path[: -len(discarded) - 1]
150 150
151 try: 151 try:
153 directory = False 153 directory = False
154 except (IOError, error.RepoError): 154 except (IOError, error.RepoError):
155 pass 155 pass
156 156
157 parts = [ 157 parts = [
158 req.apppath.strip('/'), 158 req.apppath.strip(b'/'),
159 subdir.strip('/'), 159 subdir.strip(b'/'),
160 name.strip('/'), 160 name.strip(b'/'),
161 ] 161 ]
162 url = '/' + '/'.join(p for p in parts if p) + '/' 162 url = b'/' + b'/'.join(p for p in parts if p) + b'/'
163 163
164 # show either a directory entry or a repository 164 # show either a directory entry or a repository
165 if directory: 165 if directory:
166 # get the directory's time information 166 # get the directory's time information
167 try: 167 try:
170 continue 170 continue
171 171
172 # add '/' to the name to make it obvious that 172 # add '/' to the name to make it obvious that
173 # the entry is a directory, not a regular repository 173 # the entry is a directory, not a regular repository
174 row = { 174 row = {
175 'contact': "", 175 b'contact': b"",
176 'contact_sort': "", 176 b'contact_sort': b"",
177 'name': name + '/', 177 b'name': name + b'/',
178 'name_sort': name, 178 b'name_sort': name,
179 'url': url, 179 b'url': url,
180 'description': "", 180 b'description': b"",
181 'description_sort': "", 181 b'description_sort': b"",
182 'lastchange': d, 182 b'lastchange': d,
183 'lastchange_sort': d[1] - d[0], 183 b'lastchange_sort': d[1] - d[0],
184 'archives': templateutil.mappinglist([]), 184 b'archives': templateutil.mappinglist([]),
185 'isdirectory': True, 185 b'isdirectory': True,
186 'labels': templateutil.hybridlist([], name='label'), 186 b'labels': templateutil.hybridlist([], name=b'label'),
187 } 187 }
188 188
189 seendirs.add(name) 189 seendirs.add(name)
190 yield row 190 yield row
191 continue 191 continue
192 192
193 u = ui.copy() 193 u = ui.copy()
194 try: 194 try:
195 u.readconfig(os.path.join(path, '.hg', 'hgrc')) 195 u.readconfig(os.path.join(path, b'.hg', b'hgrc'))
196 except Exception as e: 196 except Exception as e:
197 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e)) 197 u.warn(_(b'error reading %s/.hg/hgrc: %s\n') % (path, e))
198 continue 198 continue
199 199
200 def get(section, name, default=uimod._unset): 200 def get(section, name, default=uimod._unset):
201 return u.config(section, name, default, untrusted=True) 201 return u.config(section, name, default, untrusted=True)
202 202
203 if u.configbool("web", "hidden", untrusted=True): 203 if u.configbool(b"web", b"hidden", untrusted=True):
204 continue 204 continue
205 205
206 if not readallowed(u, req): 206 if not readallowed(u, req):
207 continue 207 continue
208 208
209 # update time with local timezone 209 # update time with local timezone
210 try: 210 try:
211 r = hg.repository(ui, path) 211 r = hg.repository(ui, path)
212 except IOError: 212 except IOError:
213 u.warn(_('error accessing repository at %s\n') % path) 213 u.warn(_(b'error accessing repository at %s\n') % path)
214 continue 214 continue
215 except error.RepoError: 215 except error.RepoError:
216 u.warn(_('error accessing repository at %s\n') % path) 216 u.warn(_(b'error accessing repository at %s\n') % path)
217 continue 217 continue
218 try: 218 try:
219 d = (get_mtime(r.spath), dateutil.makedate()[1]) 219 d = (get_mtime(r.spath), dateutil.makedate()[1])
220 except OSError: 220 except OSError:
221 continue 221 continue
222 222
223 contact = get_contact(get) 223 contact = get_contact(get)
224 description = get("web", "description") 224 description = get(b"web", b"description")
225 seenrepos.add(name) 225 seenrepos.add(name)
226 name = get("web", "name", name) 226 name = get(b"web", b"name", name)
227 labels = u.configlist('web', 'labels', untrusted=True) 227 labels = u.configlist(b'web', b'labels', untrusted=True)
228 row = { 228 row = {
229 'contact': contact or "unknown", 229 b'contact': contact or b"unknown",
230 'contact_sort': contact.upper() or "unknown", 230 b'contact_sort': contact.upper() or b"unknown",
231 'name': name, 231 b'name': name,
232 'name_sort': name, 232 b'name_sort': name,
233 'url': url, 233 b'url': url,
234 'description': description or "unknown", 234 b'description': description or b"unknown",
235 'description_sort': description.upper() or "unknown", 235 b'description_sort': description.upper() or b"unknown",
236 'lastchange': d, 236 b'lastchange': d,
237 'lastchange_sort': d[1] - d[0], 237 b'lastchange_sort': d[1] - d[0],
238 'archives': webutil.archivelist(u, "tip", url), 238 b'archives': webutil.archivelist(u, b"tip", url),
239 'isdirectory': None, 239 b'isdirectory': None,
240 'labels': templateutil.hybridlist(labels, name='label'), 240 b'labels': templateutil.hybridlist(labels, name=b'label'),
241 } 241 }
242 242
243 yield row 243 yield row
244 244
245 245
249 rows = rawindexentries(ui, repos, req, subdir=subdir) 249 rows = rawindexentries(ui, repos, req, subdir=subdir)
250 250
251 sortdefault = None, False 251 sortdefault = None, False
252 252
253 if sortcolumn and sortdefault != (sortcolumn, descending): 253 if sortcolumn and sortdefault != (sortcolumn, descending):
254 sortkey = '%s_sort' % sortcolumn 254 sortkey = b'%s_sort' % sortcolumn
255 rows = sorted(rows, key=lambda x: x[sortkey], reverse=descending) 255 rows = sorted(rows, key=lambda x: x[sortkey], reverse=descending)
256 256
257 for row, parity in zip(rows, paritygen(stripecount)): 257 for row, parity in zip(rows, paritygen(stripecount)):
258 row['parity'] = parity 258 row[b'parity'] = parity
259 yield row 259 yield row
260 260
261 261
262 def indexentries( 262 def indexentries(
263 ui, repos, req, stripecount, sortcolumn='', descending=False, subdir='' 263 ui, repos, req, stripecount, sortcolumn=b'', descending=False, subdir=b''
264 ): 264 ):
265 args = (ui, repos, req, stripecount, sortcolumn, descending, subdir) 265 args = (ui, repos, req, stripecount, sortcolumn, descending, subdir)
266 return templateutil.mappinggenerator(_indexentriesgen, args=args) 266 return templateutil.mappinggenerator(_indexentriesgen, args=args)
267 267
268 268
287 extensions.loadall(self.ui) 287 extensions.loadall(self.ui)
288 extensions.populateui(self.ui) 288 extensions.populateui(self.ui)
289 289
290 def refresh(self): 290 def refresh(self):
291 if self.ui: 291 if self.ui:
292 refreshinterval = self.ui.configint('web', 'refreshinterval') 292 refreshinterval = self.ui.configint(b'web', b'refreshinterval')
293 else: 293 else:
294 item = configitems.coreitems['web']['refreshinterval'] 294 item = configitems.coreitems[b'web'][b'refreshinterval']
295 refreshinterval = item.default 295 refreshinterval = item.default
296 296
297 # refreshinterval <= 0 means to always refresh. 297 # refreshinterval <= 0 means to always refresh.
298 if ( 298 if (
299 refreshinterval > 0 299 refreshinterval > 0
303 303
304 if self.baseui: 304 if self.baseui:
305 u = self.baseui.copy() 305 u = self.baseui.copy()
306 else: 306 else:
307 u = uimod.ui.load() 307 u = uimod.ui.load()
308 u.setconfig('ui', 'report_untrusted', 'off', 'hgwebdir') 308 u.setconfig(b'ui', b'report_untrusted', b'off', b'hgwebdir')
309 u.setconfig('ui', 'nontty', 'true', 'hgwebdir') 309 u.setconfig(b'ui', b'nontty', b'true', b'hgwebdir')
310 # displaying bundling progress bar while serving feels wrong and may 310 # displaying bundling progress bar while serving feels wrong and may
311 # break some wsgi implementations. 311 # break some wsgi implementations.
312 u.setconfig('progress', 'disable', 'true', 'hgweb') 312 u.setconfig(b'progress', b'disable', b'true', b'hgweb')
313 313
314 if not isinstance(self.conf, (dict, list, tuple)): 314 if not isinstance(self.conf, (dict, list, tuple)):
315 map = {'paths': 'hgweb-paths'} 315 map = {b'paths': b'hgweb-paths'}
316 if not os.path.exists(self.conf): 316 if not os.path.exists(self.conf):
317 raise error.Abort(_('config file %s not found!') % self.conf) 317 raise error.Abort(_(b'config file %s not found!') % self.conf)
318 u.readconfig(self.conf, remap=map, trust=True) 318 u.readconfig(self.conf, remap=map, trust=True)
319 paths = [] 319 paths = []
320 for name, ignored in u.configitems('hgweb-paths'): 320 for name, ignored in u.configitems(b'hgweb-paths'):
321 for path in u.configlist('hgweb-paths', name): 321 for path in u.configlist(b'hgweb-paths', name):
322 paths.append((name, path)) 322 paths.append((name, path))
323 elif isinstance(self.conf, (list, tuple)): 323 elif isinstance(self.conf, (list, tuple)):
324 paths = self.conf 324 paths = self.conf
325 elif isinstance(self.conf, dict): 325 elif isinstance(self.conf, dict):
326 paths = self.conf.items() 326 paths = self.conf.items()
327 extensions.populateui(u) 327 extensions.populateui(u)
328 328
329 repos = findrepos(paths) 329 repos = findrepos(paths)
330 for prefix, root in u.configitems('collections'): 330 for prefix, root in u.configitems(b'collections'):
331 prefix = util.pconvert(prefix) 331 prefix = util.pconvert(prefix)
332 for path in scmutil.walkrepos(root, followsym=True): 332 for path in scmutil.walkrepos(root, followsym=True):
333 repo = os.path.normpath(path) 333 repo = os.path.normpath(path)
334 name = util.pconvert(repo) 334 name = util.pconvert(repo)
335 if name.startswith(prefix): 335 if name.startswith(prefix):
336 name = name[len(prefix) :] 336 name = name[len(prefix) :]
337 repos.append((name.lstrip('/'), repo)) 337 repos.append((name.lstrip(b'/'), repo))
338 338
339 self.repos = repos 339 self.repos = repos
340 self.ui = u 340 self.ui = u
341 encoding.encoding = self.ui.config('web', 'encoding') 341 encoding.encoding = self.ui.config(b'web', b'encoding')
342 self.style = self.ui.config('web', 'style') 342 self.style = self.ui.config(b'web', b'style')
343 self.templatepath = self.ui.config('web', 'templates', untrusted=False) 343 self.templatepath = self.ui.config(
344 self.stripecount = self.ui.config('web', 'stripes') 344 b'web', b'templates', untrusted=False
345 )
346 self.stripecount = self.ui.config(b'web', b'stripes')
345 if self.stripecount: 347 if self.stripecount:
346 self.stripecount = int(self.stripecount) 348 self.stripecount = int(self.stripecount)
347 prefix = self.ui.config('web', 'prefix') 349 prefix = self.ui.config(b'web', b'prefix')
348 if prefix.startswith('/'): 350 if prefix.startswith(b'/'):
349 prefix = prefix[1:] 351 prefix = prefix[1:]
350 if prefix.endswith('/'): 352 if prefix.endswith(b'/'):
351 prefix = prefix[:-1] 353 prefix = prefix[:-1]
352 self.prefix = prefix 354 self.prefix = prefix
353 self.lastrefresh = time.time() 355 self.lastrefresh = time.time()
354 356
355 def run(self): 357 def run(self):
356 if not encoding.environ.get('GATEWAY_INTERFACE', '').startswith( 358 if not encoding.environ.get(b'GATEWAY_INTERFACE', b'').startswith(
357 "CGI/1." 359 b"CGI/1."
358 ): 360 ):
359 raise RuntimeError( 361 raise RuntimeError(
360 "This function is only intended to be " 362 b"This function is only intended to be "
361 "called while running as a CGI script." 363 b"called while running as a CGI script."
362 ) 364 )
363 wsgicgi.launch(self) 365 wsgicgi.launch(self)
364 366
365 def __call__(self, env, respond): 367 def __call__(self, env, respond):
366 baseurl = self.ui.config('web', 'baseurl') 368 baseurl = self.ui.config(b'web', b'baseurl')
367 req = requestmod.parserequestfromenv(env, altbaseurl=baseurl) 369 req = requestmod.parserequestfromenv(env, altbaseurl=baseurl)
368 res = requestmod.wsgiresponse(req, respond) 370 res = requestmod.wsgiresponse(req, respond)
369 371
370 return self.run_wsgi(req, res) 372 return self.run_wsgi(req, res)
371 373
372 def run_wsgi(self, req, res): 374 def run_wsgi(self, req, res):
373 profile = self.ui.configbool('profiling', 'enabled') 375 profile = self.ui.configbool(b'profiling', b'enabled')
374 with profiling.profile(self.ui, enabled=profile): 376 with profiling.profile(self.ui, enabled=profile):
375 try: 377 try:
376 for r in self._runwsgi(req, res): 378 for r in self._runwsgi(req, res):
377 yield r 379 yield r
378 finally: 380 finally:
389 try: 391 try:
390 self.refresh() 392 self.refresh()
391 393
392 csp, nonce = cspvalues(self.ui) 394 csp, nonce = cspvalues(self.ui)
393 if csp: 395 if csp:
394 res.headers['Content-Security-Policy'] = csp 396 res.headers[b'Content-Security-Policy'] = csp
395 397
396 virtual = req.dispatchpath.strip('/') 398 virtual = req.dispatchpath.strip(b'/')
397 tmpl = self.templater(req, nonce) 399 tmpl = self.templater(req, nonce)
398 ctype = tmpl.render('mimetype', {'encoding': encoding.encoding}) 400 ctype = tmpl.render(b'mimetype', {b'encoding': encoding.encoding})
399 401
400 # Global defaults. These can be overridden by any handler. 402 # Global defaults. These can be overridden by any handler.
401 res.status = '200 Script output follows' 403 res.status = b'200 Script output follows'
402 res.headers['Content-Type'] = ctype 404 res.headers[b'Content-Type'] = ctype
403 405
404 # a static file 406 # a static file
405 if virtual.startswith('static/') or 'static' in req.qsparams: 407 if virtual.startswith(b'static/') or b'static' in req.qsparams:
406 if virtual.startswith('static/'): 408 if virtual.startswith(b'static/'):
407 fname = virtual[7:] 409 fname = virtual[7:]
408 else: 410 else:
409 fname = req.qsparams['static'] 411 fname = req.qsparams[b'static']
410 static = self.ui.config("web", "static", untrusted=False) 412 static = self.ui.config(b"web", b"static", untrusted=False)
411 if not static: 413 if not static:
412 tp = self.templatepath or templater.templatepaths() 414 tp = self.templatepath or templater.templatepaths()
413 if isinstance(tp, str): 415 if isinstance(tp, str):
414 tp = [tp] 416 tp = [tp]
415 static = [os.path.join(p, 'static') for p in tp] 417 static = [os.path.join(p, b'static') for p in tp]
416 418
417 staticfile(static, fname, res) 419 staticfile(static, fname, res)
418 return res.sendresponse() 420 return res.sendresponse()
419 421
420 # top-level index 422 # top-level index
421 423
422 repos = dict(self.repos) 424 repos = dict(self.repos)
423 425
424 if (not virtual or virtual == 'index') and virtual not in repos: 426 if (not virtual or virtual == b'index') and virtual not in repos:
425 return self.makeindex(req, res, tmpl) 427 return self.makeindex(req, res, tmpl)
426 428
427 # nested indexes and hgwebs 429 # nested indexes and hgwebs
428 430
429 if virtual.endswith('/index') and virtual not in repos: 431 if virtual.endswith(b'/index') and virtual not in repos:
430 subdir = virtual[: -len('index')] 432 subdir = virtual[: -len(b'index')]
431 if any(r.startswith(subdir) for r in repos): 433 if any(r.startswith(subdir) for r in repos):
432 return self.makeindex(req, res, tmpl, subdir) 434 return self.makeindex(req, res, tmpl, subdir)
433 435
434 def _virtualdirs(): 436 def _virtualdirs():
435 # Check the full virtual path, and each parent 437 # Check the full virtual path, and each parent
448 k.decode('latin1'): v for k, v in uenv.iteritems() 450 k.decode('latin1'): v for k, v in uenv.iteritems()
449 } 451 }
450 req = requestmod.parserequestfromenv( 452 req = requestmod.parserequestfromenv(
451 uenv, 453 uenv,
452 reponame=virtualrepo, 454 reponame=virtualrepo,
453 altbaseurl=self.ui.config('web', 'baseurl'), 455 altbaseurl=self.ui.config(b'web', b'baseurl'),
454 # Reuse wrapped body file object otherwise state 456 # Reuse wrapped body file object otherwise state
455 # tracking can get confused. 457 # tracking can get confused.
456 bodyfh=req.bodyfh, 458 bodyfh=req.bodyfh,
457 ) 459 )
458 try: 460 try:
464 raise ErrorResponse(HTTP_SERVER_ERROR, msg) 466 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
465 except error.RepoError as inst: 467 except error.RepoError as inst:
466 raise ErrorResponse(HTTP_SERVER_ERROR, bytes(inst)) 468 raise ErrorResponse(HTTP_SERVER_ERROR, bytes(inst))
467 469
468 # browse subdirectories 470 # browse subdirectories
469 subdir = virtual + '/' 471 subdir = virtual + b'/'
470 if [r for r in repos if r.startswith(subdir)]: 472 if [r for r in repos if r.startswith(subdir)]:
471 return self.makeindex(req, res, tmpl, subdir) 473 return self.makeindex(req, res, tmpl, subdir)
472 474
473 # prefixes not found 475 # prefixes not found
474 res.status = '404 Not Found' 476 res.status = b'404 Not Found'
475 res.setbodygen(tmpl.generate('notfound', {'repo': virtual})) 477 res.setbodygen(tmpl.generate(b'notfound', {b'repo': virtual}))
476 return res.sendresponse() 478 return res.sendresponse()
477 479
478 except ErrorResponse as e: 480 except ErrorResponse as e:
479 res.status = statusmessage(e.code, pycompat.bytestr(e)) 481 res.status = statusmessage(e.code, pycompat.bytestr(e))
480 res.setbodygen(tmpl.generate('error', {'error': e.message or ''})) 482 res.setbodygen(
483 tmpl.generate(b'error', {b'error': e.message or b''})
484 )
481 return res.sendresponse() 485 return res.sendresponse()
482 finally: 486 finally:
483 tmpl = None 487 tmpl = None
484 488
485 def makeindex(self, req, res, tmpl, subdir=""): 489 def makeindex(self, req, res, tmpl, subdir=b""):
486 self.refresh() 490 self.refresh()
487 sortable = ["name", "description", "contact", "lastchange"] 491 sortable = [b"name", b"description", b"contact", b"lastchange"]
488 sortcolumn, descending = None, False 492 sortcolumn, descending = None, False
489 if 'sort' in req.qsparams: 493 if b'sort' in req.qsparams:
490 sortcolumn = req.qsparams['sort'] 494 sortcolumn = req.qsparams[b'sort']
491 descending = sortcolumn.startswith('-') 495 descending = sortcolumn.startswith(b'-')
492 if descending: 496 if descending:
493 sortcolumn = sortcolumn[1:] 497 sortcolumn = sortcolumn[1:]
494 if sortcolumn not in sortable: 498 if sortcolumn not in sortable:
495 sortcolumn = "" 499 sortcolumn = b""
496 500
497 sort = [ 501 sort = [
498 ( 502 (
499 "sort_%s" % column, 503 b"sort_%s" % column,
500 "%s%s" 504 b"%s%s"
501 % ( 505 % (
502 (not descending and column == sortcolumn) and "-" or "", 506 (not descending and column == sortcolumn) and b"-" or b"",
503 column, 507 column,
504 ), 508 ),
505 ) 509 )
506 for column in sortable 510 for column in sortable
507 ] 511 ]
517 descending=descending, 521 descending=descending,
518 subdir=subdir, 522 subdir=subdir,
519 ) 523 )
520 524
521 mapping = { 525 mapping = {
522 'entries': entries, 526 b'entries': entries,
523 'subdir': subdir, 527 b'subdir': subdir,
524 'pathdef': hgweb_mod.makebreadcrumb('/' + subdir, self.prefix), 528 b'pathdef': hgweb_mod.makebreadcrumb(b'/' + subdir, self.prefix),
525 'sortcolumn': sortcolumn, 529 b'sortcolumn': sortcolumn,
526 'descending': descending, 530 b'descending': descending,
527 } 531 }
528 mapping.update(sort) 532 mapping.update(sort)
529 res.setbodygen(tmpl.generate('index', mapping)) 533 res.setbodygen(tmpl.generate(b'index', mapping))
530 return res.sendresponse() 534 return res.sendresponse()
531 535
532 def templater(self, req, nonce): 536 def templater(self, req, nonce):
533 def config(section, name, default=uimod._unset, untrusted=True): 537 def config(section, name, default=uimod._unset, untrusted=True):
534 return self.ui.config(section, name, default, untrusted) 538 return self.ui.config(section, name, default, untrusted)
536 vars = {} 540 vars = {}
537 styles, (style, mapfile) = hgweb_mod.getstyle( 541 styles, (style, mapfile) = hgweb_mod.getstyle(
538 req, config, self.templatepath 542 req, config, self.templatepath
539 ) 543 )
540 if style == styles[0]: 544 if style == styles[0]:
541 vars['style'] = style 545 vars[b'style'] = style
542 546
543 sessionvars = webutil.sessionvars(vars, '?') 547 sessionvars = webutil.sessionvars(vars, b'?')
544 logourl = config('web', 'logourl') 548 logourl = config(b'web', b'logourl')
545 logoimg = config('web', 'logoimg') 549 logoimg = config(b'web', b'logoimg')
546 staticurl = ( 550 staticurl = (
547 config('web', 'staticurl') or req.apppath.rstrip('/') + '/static/' 551 config(b'web', b'staticurl')
552 or req.apppath.rstrip(b'/') + b'/static/'
548 ) 553 )
549 if not staticurl.endswith('/'): 554 if not staticurl.endswith(b'/'):
550 staticurl += '/' 555 staticurl += b'/'
551 556
552 defaults = { 557 defaults = {
553 "encoding": encoding.encoding, 558 b"encoding": encoding.encoding,
554 "url": req.apppath + '/', 559 b"url": req.apppath + b'/',
555 "logourl": logourl, 560 b"logourl": logourl,
556 "logoimg": logoimg, 561 b"logoimg": logoimg,
557 "staticurl": staticurl, 562 b"staticurl": staticurl,
558 "sessionvars": sessionvars, 563 b"sessionvars": sessionvars,
559 "style": style, 564 b"style": style,
560 "nonce": nonce, 565 b"nonce": nonce,
561 } 566 }
562 templatekeyword = registrar.templatekeyword(defaults) 567 templatekeyword = registrar.templatekeyword(defaults)
563 568
564 @templatekeyword('motd', requires=()) 569 @templatekeyword(b'motd', requires=())
565 def motd(context, mapping): 570 def motd(context, mapping):
566 if self.motd is not None: 571 if self.motd is not None:
567 yield self.motd 572 yield self.motd
568 else: 573 else:
569 yield config('web', 'motd') 574 yield config(b'web', b'motd')
570 575
571 tmpl = templater.templater.frommapfile(mapfile, defaults=defaults) 576 tmpl = templater.templater.frommapfile(mapfile, defaults=defaults)
572 return tmpl 577 return tmpl