##// END OF EJS Templates
py3: use '%d' to convert integer to bytes...
py3: use '%d' to convert integer to bytes Differential Revision: https://phab.mercurial-scm.org/D2349

File last commit:

r34704:d1fccbd5 default
r36341:920bbfb6 default
Show More
hgwebdir_mod.py
538 lines | 19.2 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/hgwebdir_mod.py - Web interface for a directory of repositories.
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Vadim Gelfer
update copyrights.
r2859 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
Eric Hopper
Final stage of the hgweb split up....
r2356 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Eric Hopper
Final stage of the hgweb split up....
r2356
Yuya Nishihara
hgweb: use absolute_import
r27046 from __future__ import absolute_import
import os
import re
import time
from ..i18n import _
from .common import (
ErrorResponse,
HTTP_NOT_FOUND,
HTTP_OK,
HTTP_SERVER_ERROR,
Gregory Szorc
hgweb: support Content Security Policy...
r30766 cspvalues,
Yuya Nishihara
hgweb: use absolute_import
r27046 get_contact,
get_mtime,
ismember,
paritygen,
staticfile,
)
from .request import wsgirequest
from .. import (
Boris Feld
configitems: register the 'web.refreshinterval' config
r34241 configitems,
Yuya Nishihara
hgweb: use absolute_import
r27046 encoding,
error,
hg,
Gregory Szorc
hgweb: profile HTTP requests...
r29787 profiling,
Yuya Nishihara
py3: remove use of str() in hgwebdir...
r34354 pycompat,
Yuya Nishihara
hgweb: use absolute_import
r27046 scmutil,
templater,
ui as uimod,
util,
)
from . import (
hgweb_mod,
webutil,
wsgicgi,
)
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
hgweb: some cleanups in hgwebdir, remove double defaults...
r8215 def cleannames(items):
return [(util.pconvert(name).strip('/'), path) for name, path in items]
Eric Hopper
Final stage of the hgweb split up....
r2356
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 def findrepos(paths):
Dirkjan Ochtman
hgweb: use a tuple-list instead of dictionary for append-only store
r9723 repos = []
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 for prefix, root in cleannames(paths):
roothead, roottail = os.path.split(root)
Mads Kiilerich
help: improve hgweb help...
r17104 # "foo = /bar/*" or "foo = /bar/**" lets every repo /bar/N in or below
# /bar/ be served as as foo/N .
# '*' will not search inside dirs with .hg (except .hg/patches),
# '**' will search inside dirs with .hg (and thus also find subrepos).
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 try:
recurse = {'*': False, '**': True}[roottail]
except KeyError:
Dirkjan Ochtman
hgweb: use a tuple-list instead of dictionary for append-only store
r9723 repos.append((prefix, root))
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 continue
Mads Kiilerich
hgwebdir: allow pure relative globs in paths...
r11677 roothead = os.path.normpath(os.path.abspath(roothead))
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 paths = scmutil.walkrepos(roothead, followsym=True, recurse=recurse)
Mads Kiilerich
hgweb: doctest of url creation from wildcard expansion
r13402 repos.extend(urlrepos(prefix, roothead, paths))
Dirkjan Ochtman
hgweb: use a tuple-list instead of dictionary for append-only store
r9723 return repos
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529
Mads Kiilerich
hgweb: doctest of url creation from wildcard expansion
r13402 def urlrepos(prefix, roothead, paths):
"""yield url paths and filesystem paths from a list of repo paths
Patrick Mezard
test-doctest: handle unix/windows path discrepancies
r13538 >>> conv = lambda seq: [(v, util.pconvert(p)) for v,p in seq]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> conv(urlrepos(b'hg', b'/opt', [b'/opt/r', b'/opt/r/r', b'/opt']))
Mads Kiilerich
hgweb: make paths wildcards expanding in a repo root match repo correctly...
r13403 [('hg/r', '/opt/r'), ('hg/r/r', '/opt/r/r'), ('hg', '/opt')]
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> conv(urlrepos(b'', b'/opt', [b'/opt/r', b'/opt/r/r', b'/opt']))
Mads Kiilerich
hgweb: doctest of url creation from wildcard expansion
r13402 [('r', '/opt/r'), ('r/r', '/opt/r/r'), ('', '/opt')]
"""
for path in paths:
path = os.path.normpath(path)
Mads Kiilerich
hgweb: make paths wildcards expanding in a repo root match repo correctly...
r13403 yield (prefix + '/' +
util.pconvert(path[len(roothead):]).lstrip('/')).strip('/'), path
Mads Kiilerich
hgweb: doctest of url creation from wildcard expansion
r13402
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 def geturlcgivars(baseurl, port):
"""
Extract CGI variables from baseurl
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b"http://host.org/base", b"80")
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('host.org', '80', '/base')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b"http://host.org:8000/base", b"80")
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('host.org', '8000', '/base')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b'/base', 8000)
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('', '8000', '/base')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b"base", b'8000')
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('', '8000', '/base')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b"http://host", b'8000')
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('host', '8000', '/')
Yuya Nishihara
doctest: bulk-replace string literals with b'' for Python 3...
r34133 >>> geturlcgivars(b"http://host/", b'8000')
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 ('host', '8000', '/')
"""
u = util.url(baseurl)
name = u.host or ''
if u.port:
port = u.port
path = u.path or ""
if not path.startswith('/'):
path = '/' + path
Yuya Nishihara
py3: remove use of str() in hgwebdir...
r34354 return name, pycompat.bytestr(port), path
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003
Eric Hopper
Final stage of the hgweb split up....
r2356 class hgwebdir(object):
Gregory Szorc
hgweb: add some documentation...
r26132 """HTTP server for multiple repositories.
Given a configuration, different repositories will be served depending
on the request path.
Instances are typically used as WSGI applications.
"""
Matt Mackall
hgweb: kill parentui references
r8191 def __init__(self, conf, baseui=None):
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.conf = conf
self.baseui = baseui
Gregory Szorc
hgweb: make refresh interval configurable...
r26072 self.ui = None
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.lastrefresh = 0
Thomas Arendsen Hein
Do not overwrite motd attribute of hgwebdir instances on refresh....
r9903 self.motd = None
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.refresh()
Eric Hopper
Final stage of the hgweb split up....
r2356
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 def refresh(self):
Gregory Szorc
hgweb: make refresh interval configurable...
r26072 if self.ui:
Boris Feld
configitems: register the 'web.refreshinterval' config
r34241 refreshinterval = self.ui.configint('web', 'refreshinterval')
else:
item = configitems.coreitems['web']['refreshinterval']
refreshinterval = item.default
Gregory Szorc
hgweb: make refresh interval configurable...
r26072
# refreshinterval <= 0 means to always refresh.
if (refreshinterval > 0 and
self.lastrefresh + refreshinterval > time.time()):
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 return
if self.baseui:
Matt Mackall
hgweb: fix race in refreshing repo list (issue2188)
r11239 u = self.baseui.copy()
Eric Hopper
Final stage of the hgweb split up....
r2356 else:
Yuya Nishihara
ui: factor out ui.load() to create a ui without loading configs (API)...
r30559 u = uimod.ui.load()
Mads Kiilerich
config: set a 'source' in most cases where config don't come from file but code...
r20790 u.setconfig('ui', 'report_untrusted', 'off', 'hgwebdir')
u.setconfig('ui', 'nontty', 'true', 'hgwebdir')
Pierre-Yves David
hgewb: disable progress when serving (issue4582)...
r25488 # displaying bundling progress bar while serving feels wrong and may
# break some wsgi implementations.
u.setconfig('progress', 'disable', 'true', 'hgweb')
Matt Mackall
ui: refactor option setting...
r8136
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 if not isinstance(self.conf, (dict, list, tuple)):
map = {'paths': 'hgweb-paths'}
Matt Mackall
hgweb: abort if config file isn't found
r13214 if not os.path.exists(self.conf):
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 raise error.Abort(_('config file %s not found!') % self.conf)
Matt Mackall
hgweb: fix race in refreshing repo list (issue2188)
r11239 u.readconfig(self.conf, remap=map, trust=True)
timeless
hgweb: support multiple directories for the same path...
r13667 paths = []
for name, ignored in u.configitems('hgweb-paths'):
for path in u.configlist('hgweb-paths', name):
paths.append((name, path))
Jeremy Whitlock
hgweb: make hgwebdir handle dict/list paths the same as config paths...
r8529 elif isinstance(self.conf, (list, tuple)):
paths = self.conf
elif isinstance(self.conf, dict):
paths = self.conf.items()
Alexander Solovyov
hgwebdir: read --webdir-conf as actual configuration to ui (issue1586)...
r8345
Matt Mackall
hgweb: fix race in refreshing repo list (issue2188)
r11239 repos = findrepos(paths)
for prefix, root in u.configitems('collections'):
prefix = util.pconvert(prefix)
Adrian Buehlmann
move walkrepos from util to scmutil
r13975 for path in scmutil.walkrepos(root, followsym=True):
Matt Mackall
hgweb: fix race in refreshing repo list (issue2188)
r11239 repo = os.path.normpath(path)
name = util.pconvert(repo)
if name.startswith(prefix):
name = name[len(prefix):]
repos.append((name.lstrip('/'), repo))
self.repos = repos
self.ui = u
Boris Feld
configitems: register the 'web.encoding' config
r34236 encoding.encoding = self.ui.config('web', 'encoding')
Boris Feld
configitems: register the 'web.style' config
r34243 self.style = self.ui.config('web', 'style')
Boris Feld
hgwebdir: read 'web.template' untrusted...
r34245 self.templatepath = self.ui.config('web', 'templates', untrusted=False)
Boris Feld
configitems: register the 'web.stripes' config
r34242 self.stripecount = self.ui.config('web', 'stripes')
Dirkjan Ochtman
hgweb: extract config values after reading webdir-config
r8621 if self.stripecount:
self.stripecount = int(self.stripecount)
self._baseurl = self.ui.config('web', 'baseurl')
Boris Feld
configitems: register the 'web.prefix' config
r34240 prefix = self.ui.config('web', 'prefix')
Angel Ezquerra
hgwebdir: use web.prefix when creating url breadcrumbs (issue3790)...
r18515 if prefix.startswith('/'):
prefix = prefix[1:]
if prefix.endswith('/'):
prefix = prefix[:-1]
self.prefix = prefix
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.lastrefresh = time.time()
Eric Hopper
Final stage of the hgweb split up....
r2356
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 def run(self):
Pulkit Goyal
py3: replace os.environ with encoding.environ (part 3 of 5)
r30636 if not encoding.environ.get('GATEWAY_INTERFACE',
'').startswith("CGI/1."):
Martin Geisler
wrap string literals in error messages
r8663 raise RuntimeError("This function is only intended to be "
"called while running as a CGI script.")
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 wsgicgi.launch(self)
def __call__(self, env, respond):
req = wsgirequest(env, respond)
Dirkjan Ochtman
merge another backout
r6797 return self.run_wsgi(req)
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336 def read_allowed(self, ui, req):
"""Check allow_read and deny_read config options of a repo's ui object
to determine user permissions. By default, with neither option set (or
both empty), allow all users to read the repo. There are two ways a
user can be denied read access: (1) deny_read is not empty, and the
user is unauthenticated or deny_read contains user (or *), and (2)
allow_read is not empty and the user is not in allow_read. Return True
if user is allowed to read the repo, else return False."""
user = req.env.get('REMOTE_USER')
Dirkjan Ochtman
hgweb: fix long line lengths introduced in 2dc868712dcc
r7575 deny_read = ui.configlist('web', 'deny_read', untrusted=True)
Wagner Bruna
hgweb: refactor checks for granting and revoking user permissions...
r19032 if deny_read and (not user or ismember(ui, user, deny_read)):
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336 return False
Dirkjan Ochtman
hgweb: fix long line lengths introduced in 2dc868712dcc
r7575 allow_read = ui.configlist('web', 'allow_read', untrusted=True)
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336 # by default, allow reading if no allow_read option has been set
Wagner Bruna
hgweb: refactor checks for granting and revoking user permissions...
r19032 if (not allow_read) or ismember(ui, user, allow_read):
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336 return True
return False
Eric Hopper
Arrange for old copies of CGI scripts to still work.
r2535 def run_wsgi(self, req):
profile: drop maybeprofile...
r32788 profile = self.ui.configbool('profiling', 'enabled')
with profiling.profile(self.ui, enabled=profile):
Gregory Szorc
hgweb: profile HTTP requests...
r29787 for r in self._runwsgi(req):
yield r
Gregory Szorc
hgweb: abstract call to hgwebdir wsgi function...
r29786
def _runwsgi(self, req):
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601 try:
Matt Mackall
hgweb: use try/except/finally
r25083 self.refresh()
Dirkjan Ochtman
hgwebdir: refactor inner loop
r5603
Gregory Szorc
hgweb: support Content Security Policy...
r30766 csp, nonce = cspvalues(self.ui)
if csp:
req.headers.append(('Content-Security-Policy', csp))
Matt Mackall
hgweb: use try/except/finally
r25083 virtual = req.env.get("PATH_INFO", "").strip('/')
Gregory Szorc
hgweb: support Content Security Policy...
r30766 tmpl = self.templater(req, nonce)
Matt Mackall
hgweb: use try/except/finally
r25083 ctype = tmpl('mimetype', encoding=encoding.encoding)
ctype = templater.stringify(ctype)
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Matt Mackall
hgweb: use try/except/finally
r25083 # a static file
if virtual.startswith('static/') or 'static' in req.form:
if virtual.startswith('static/'):
fname = virtual[7:]
else:
fname = req.form['static'][0]
static = self.ui.config("web", "static", None,
untrusted=False)
if not static:
tp = self.templatepath or templater.templatepaths()
if isinstance(tp, str):
tp = [tp]
static = [os.path.join(p, 'static') for p in tp]
staticfile(static, fname, req)
return []
Dirkjan Ochtman
hgwebdir: refactor inner loop
r5603
Matt Mackall
hgweb: use try/except/finally
r25083 # top-level index
Matt Harbison
hgwebdir: add support for explicit index files...
r31482
repos = dict(self.repos)
Matt Harbison
hgwebdir: allow a repository to be hosted at "/"...
r32004 if (not virtual or virtual == 'index') and virtual not in repos:
Matt Mackall
hgweb: use try/except/finally
r25083 req.respond(HTTP_OK, ctype)
return self.makeindex(req, tmpl)
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601
Matt Mackall
hgweb: use try/except/finally
r25083 # nested indexes and hgwebs
Thomas Arendsen Hein
Removed trailing spaces from everything except test output
r6210
Matt Harbison
hgwebdir: add support for explicit index files...
r31482 if virtual.endswith('/index') and virtual not in repos:
subdir = virtual[:-len('index')]
if any(r.startswith(subdir) for r in repos):
req.respond(HTTP_OK, ctype)
return self.makeindex(req, tmpl, subdir)
Matt Harbison
hgwebdir: allow a repository to be hosted at "/"...
r32004 def _virtualdirs():
# Check the full virtual path, each parent, and the root ('')
if virtual != '':
yield virtual
for p in util.finddirs(virtual):
yield p
yield ''
for virtualrepo in _virtualdirs():
Matt Mackall
hgweb: use try/except/finally
r25083 real = repos.get(virtualrepo)
if real:
req.env['REPO_NAME'] = virtualrepo
try:
# ensure caller gets private copy of ui
repo = hg.repository(self.ui.copy(), real)
Yuya Nishihara
hgweb: do not import hgweb_mod.hgweb and .makebreadcrumb as symbol...
r27043 return hgweb_mod.hgweb(repo).run_wsgi(req)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except IOError as inst:
Augie Fackler
python3: wrap all uses of <exception>.strerror with strtolocal...
r34024 msg = encoding.strtolocal(inst.strerror)
Matt Mackall
hgweb: use try/except/finally
r25083 raise ErrorResponse(HTTP_SERVER_ERROR, msg)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except error.RepoError as inst:
Yuya Nishihara
py3: remove use of str() in hgwebdir...
r34354 raise ErrorResponse(HTTP_SERVER_ERROR, bytes(inst))
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601
Matt Mackall
hgweb: use try/except/finally
r25083 # browse subdirectories
subdir = virtual + '/'
if [r for r in repos if r.startswith(subdir)]:
req.respond(HTTP_OK, ctype)
return self.makeindex(req, tmpl, subdir)
Dirkjan Ochtman
hgwebdir: refactor inner loop
r5603
Matt Mackall
hgweb: use try/except/finally
r25083 # prefixes not found
req.respond(HTTP_NOT_FOUND, ctype)
return tmpl("notfound", repo=virtual)
Thomas Arendsen Hein
Removed tabs and trailing whitespace in python files
r5760
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except ErrorResponse as err:
Matt Mackall
hgweb: use try/except/finally
r25083 req.respond(err, ctype)
return tmpl('error', error=err.message or '')
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601 finally:
tmpl = None
def makeindex(self, req, tmpl, subdir=""):
Eric Hopper
Final stage of the hgweb split up....
r2356 def archivelist(ui, nodeid, url):
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 allowed = ui.configlist("web", "allow_archive", untrusted=True)
Wagner Bruna
hgwebdir: reduce memory usage for index generation...
r13436 archives = []
av6
hgweb: use archivespecs for links on repo index page too...
r30749 for typ, spec in hgweb_mod.archivespecs.iteritems():
if typ in allowed or ui.configbool("web", "allow" + typ,
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 untrusted=True):
Alex Gaynor
style: never use a space before a colon or comma...
r34487 archives.append({"type": typ, "extension": spec[2],
Wagner Bruna
hgwebdir: reduce memory usage for index generation...
r13436 "node": nodeid, "url": url})
return archives
Eric Hopper
Final stage of the hgweb split up....
r2356
Benoit Boissinot
hgweb: separate generation of entries and sorting (cleanup)
r10600 def rawentries(subdir="", **map):
Dirkjan Ochtman
hgweb: add web.descend configuration variable
r9363
Boris Feld
configitems: register the 'web.descend' config
r34234 descend = self.ui.configbool('web', 'descend')
Boris Feld
configitems: register the 'web.collapse' config
r34231 collapse = self.ui.configbool('web', 'collapse')
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239 seenrepos = set()
seendirs = set()
Eric Hopper
Final stage of the hgweb split up....
r2356 for name, path in self.repos:
Dirkjan Ochtman
hgweb: add web.descend configuration variable
r9363
Brendan Cully
hgweb: let hgwebdir browse subdirectories
r4841 if not name.startswith(subdir):
continue
Brendan Cully
hgwebdir: show only trailing part of path when browsing subdirectories
r4843 name = name[len(subdir):]
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239 directory = False
if '/' in name:
if not descend:
continue
nameparts = name.split('/')
rootname = nameparts[0]
if not collapse:
pass
elif rootname in seendirs:
continue
elif rootname in seenrepos:
pass
else:
directory = True
name = rootname
# redefine the path to refer to the directory
discarded = '/'.join(nameparts[1:])
# remove name parts plus accompanying slash
path = path[:-len(discarded) - 1]
Matt Harbison
hgwebdir: don't allow the hidden parent of a subrepo to show as a directory...
r25426 try:
r = hg.repository(self.ui, path)
directory = False
except (IOError, error.RepoError):
pass
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239 parts = [name]
Matt Harbison
hgwebdir: add support for explicit index files...
r31482 parts.insert(0, '/' + subdir.rstrip('/'))
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239 if req.env['SCRIPT_NAME']:
parts.insert(0, req.env['SCRIPT_NAME'])
url = re.sub(r'/+', '/', '/'.join(parts) + '/')
# show either a directory entry or a repository
if directory:
# get the directory's time information
try:
d = (get_mtime(path), util.makedate()[1])
except OSError:
continue
Angel Ezquerra
hgwebdir: make collapsed folders easier to distinguish from repositories...
r17838 # add '/' to the name to make it obvious that
# the entry is a directory, not a regular repository
Augie Fackler
hgwebdir_mod: move from dict() construction to {} literals...
r20677 row = {'contact': "",
'contact_sort': "",
'name': name + '/',
'name_sort': name,
'url': url,
'description': "",
'description_sort': "",
'lastchange': d,
'lastchange_sort': d[1]-d[0],
'archives': [],
Gregory Szorc
hgweb: expose list of per-repo labels to templates...
r29471 'isdirectory': True,
'labels': [],
}
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239
seendirs.add(name)
yield row
Dirkjan Ochtman
hgweb: add web.descend configuration variable
r9363 continue
Brendan Cully
hgweb: let hgwebdir browse subdirectories
r4841
Matt Mackall
hgweb: kill parentui references
r8191 u = self.ui.copy()
Eric Hopper
Final stage of the hgweb split up....
r2356 try:
u.readconfig(os.path.join(path, '.hg', 'hgrc'))
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except Exception as e:
Martin Geisler
move % out of translatable strings...
r6913 u.warn(_('error reading %s/.hg/hgrc: %s\n') % (path, e))
Alexis S. L. Carvalho
hgwebdir: ignore hgrc parse errors while building the index page...
r5332 continue
David Demelier
hgweb: use ui._unset to prevent a warning in configitems
r33328 def get(section, name, default=uimod._unset):
Alexis S. L. Carvalho
use untrusted settings in hgwebdir
r3556 return u.config(section, name, default, untrusted=True)
Eric Hopper
Final stage of the hgweb split up....
r2356
Markus F.X.J. Oberhumer
Add option "hidden" to hgwebdir....
r4709 if u.configbool("web", "hidden", untrusted=True):
continue
Mark Edgington
hgweb: support for deny_read/allow_read options...
r7336 if not self.read_allowed(u, req):
continue
Eric Hopper
Final stage of the hgweb split up....
r2356 # update time with local timezone
try:
Brendan Cully
hgweb: Make get_mtime use repository to find store path....
r10078 r = hg.repository(self.ui, path)
timeless@gmail.com
hgwebdir: handle IOErrors from localrepo while enumerating...
r13796 except IOError:
u.warn(_('error accessing repository at %s\n') % path)
continue
Yuya Nishihara
hgweb: handle exception of misconfigured path on index page...
r12038 except error.RepoError:
u.warn(_('error accessing repository at %s\n') % path)
continue
try:
Brendan Cully
hgweb: Make get_mtime use repository to find store path....
r10078 d = (get_mtime(r.spath), util.makedate()[1])
Eric Hopper
Final stage of the hgweb split up....
r2356 except OSError:
continue
Thomas Arendsen Hein
Don't let ui.username override web.contact (issue900)...
r5779 contact = get_contact(get)
Boris Feld
configitems: register the 'web.description' config
r34235 description = get("web", "description")
Matt Harbison
hgwebdir: avoid redundant repo and directory entries when 'web.name' is set...
r25396 seenrepos.add(name)
Eric Hopper
Final stage of the hgweb split up....
r2356 name = get("web", "name", name)
Augie Fackler
hgwebdir_mod: move from dict() construction to {} literals...
r20677 row = {'contact': contact or "unknown",
'contact_sort': contact.upper() or "unknown",
'name': name,
'name_sort': name,
'url': url,
'description': description or "unknown",
'description_sort': description.upper() or "unknown",
'lastchange': d,
'lastchange_sort': d[1]-d[0],
'archives': archivelist(u, "tip", url),
'isdirectory': None,
Gregory Szorc
hgweb: expose list of per-repo labels to templates...
r29471 'labels': u.configlist('web', 'labels', untrusted=True),
Augie Fackler
hgwebdir_mod: move from dict() construction to {} literals...
r20677 }
Paul Boddie
hgweb: support multi-level repository indexes by enabling descend and collapse...
r16239
Benoit Boissinot
hgweb: separate generation of entries and sorting (cleanup)
r10600 yield row
sortdefault = None, False
def entries(sortcolumn="", descending=False, subdir="", **map):
rows = rawentries(subdir=subdir, **map)
if sortcolumn and sortdefault != (sortcolumn, descending):
sortkey = '%s_sort' % sortcolumn
rows = sorted(rows, key=lambda x: x[sortkey],
reverse=descending)
for row, parity in zip(rows, paritygen(self.stripecount)):
row['parity'] = parity
yield row
Eric Hopper
Final stage of the hgweb split up....
r2356
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.refresh()
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601 sortable = ["name", "description", "contact", "lastchange"]
Dirkjan Ochtman
hgweb: get rid of inaccurate hgwebdir.repos_sorted, localize machinery
r8346 sortcolumn, descending = sortdefault
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'sort' in req.form:
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601 sortcolumn = req.form['sort'][0]
descending = sortcolumn.startswith('-')
if descending:
sortcolumn = sortcolumn[1:]
if sortcolumn not in sortable:
sortcolumn = ""
Brendan Cully
hgweb: let hgwebdir browse subdirectories
r4841
Dirkjan Ochtman
hgwebdir: split out makeindex function, facilitate test failure diagnosis
r5601 sort = [("sort_%s" % column,
"%s%s" % ((not descending and column == sortcolumn)
and "-" or "", column))
for column in sortable]
Dirkjan Ochtman
hgweb: move HTTP content types out of header templates...
r5928
Bryan O'Sullivan
hgwebdir: refresh configuration periodically...
r8371 self.refresh()
Yuya Nishihara
hgweb: introduce helper method to update req.env
r10673 self.updatereqenv(req.env)
Brendan Cully
Support web.baseurl in hgwebdir, overriding SCRIPT_NAME
r6221
Dirkjan Ochtman
hgweb: forgot to centralize the req.write() calls in hgwebdir
r5965 return tmpl("index", entries=entries, subdir=subdir,
Yuya Nishihara
hgweb: do not import hgweb_mod.hgweb and .makebreadcrumb as symbol...
r27043 pathdef=hgweb_mod.makebreadcrumb('/' + subdir, self.prefix),
Dirkjan Ochtman
hgweb: forgot to centralize the req.write() calls in hgwebdir
r5965 sortcolumn=sortcolumn, descending=descending,
**dict(sort))
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602
Gregory Szorc
hgweb: support Content Security Policy...
r30766 def templater(self, req, nonce):
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602
def motd(**map):
if self.motd is not None:
yield self.motd
else:
Boris Feld
configitems: register the 'web.motd' config
r34588 yield config('web', 'motd')
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602
Boris Feld
web: use '_unset' default value for proxy config method...
r34223 def config(section, name, default=uimod._unset, untrusted=True):
Matt Mackall
hgweb: kill parentui references
r8191 return self.ui.config(section, name, default, untrusted)
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602
Yuya Nishihara
hgweb: introduce helper method to update req.env
r10673 self.updatereqenv(req.env)
Brendan Cully
Support web.baseurl in hgwebdir, overriding SCRIPT_NAME
r6221
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602 url = req.env.get('SCRIPT_NAME', '')
if not url.endswith('/'):
url += '/'
Dirkjan Ochtman
hgweb: use new sessionvars code in hgwebdir, too
r8216 vars = {}
Augie Fackler
hgweb: extract function for loading style from request context...
r34516 styles, (style, mapfile) = hgweb_mod.getstyle(req, config,
self.templatepath)
Dirkjan Ochtman
hgweb: don't choke when an inexistent style is requested (issue1901)
r9842 if style == styles[0]:
vars['style'] = style
Matt Mackall
many, many trivial check-code fixups
r10282
Augie Fackler
hgweb: use native strings consistently for querystring parsing...
r34704 start = r'&' if url[-1] == r'?' else r'?'
Dirkjan Ochtman
hgweb: use new sessionvars code in hgwebdir, too
r8216 sessionvars = webutil.sessionvars(vars, start)
Boris Feld
configitems: register the 'web.logourl' config
r34613 logourl = config('web', 'logourl')
Boris Feld
configitems: register the 'web.logoimg' config
r34612 logoimg = config('web', 'logoimg')
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602 staticurl = config('web', 'staticurl') or url + 'static/'
if not staticurl.endswith('/'):
staticurl += '/'
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 defaults = {
"encoding": encoding.encoding,
"motd": motd,
"url": url,
"logourl": logourl,
"logoimg": logoimg,
"staticurl": staticurl,
"sessionvars": sessionvars,
"style": style,
Gregory Szorc
hgweb: support Content Security Policy...
r30766 "nonce": nonce,
Yuya Nishihara
templater: separate function to create templater from map file (API)...
r28954 }
tmpl = templater.templater.frommapfile(mapfile, defaults=defaults)
Dirkjan Ochtman
hgwebdir: split out templater creation
r5602 return tmpl
Yuya Nishihara
hgweb: introduce helper method to update req.env
r10673
def updatereqenv(self, env):
if self._baseurl is not None:
Matt Mackall
hgweb: extract the path logic from updatereqenv and add doctests
r15003 name, port, path = geturlcgivars(self._baseurl, env['SERVER_PORT'])
env['SERVER_NAME'] = name
env['SERVER_PORT'] = port
wujek
hgweb: handle 'baseurl' configurations with leading slash (issue2934)
r15001 env['SCRIPT_NAME'] = path