##// END OF EJS Templates
hgweb: descend empty directories in web view...
hgweb: descend empty directories in web view When a manifest has a series of directories with nothing in them but a single directory, displaying the entire chain of empty directories allows for navigation down to the first non-empty directory with a single click. Because Java links package hierarchy to directory hierarchy, and because Java conventions include at least three empty directories at the top of this hierarchy, descending down empty directories is very common in Java web tools.

File last commit:

r7287:6e9fe4ff default
r7305:c21d236c default
Show More
hgweb_mod.py
381 lines | 14.4 KiB | text/x-python | PythonLexer
Eric Hopper
Fixing up comment headers for split up code.
r2391 # hgweb/hgweb_mod.py - Web interface for a repository.
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Eric Hopper
Final stage of the hgweb split up....
r2356 #
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 import os, mimetypes
from mercurial.node import hex, nullid
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 from mercurial.repo import RepoError
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 from mercurial import mdiff, ui, hg, util, patch, hook
Dirkjan Ochtman
hgweb: move capabilities calculation back into hgweb.protocol
r6780 from mercurial import revlog, templater, templatefilters
Dirkjan Ochtman
hgweb: refactor hgweb code
r6393 from common import get_mtime, style_map, paritygen, countgen, ErrorResponse
Dirkjan Ochtman
hgweb: explicit response status
r5993 from common import HTTP_OK, HTTP_BAD_REQUEST, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 from common import HTTP_UNAUTHORIZED, HTTP_METHOD_NOT_ALLOWED
Dirkjan Ochtman
Less indirection in the WSGI web interface. This simplifies some code, and makes it more compliant with WSGI.
r5566 from request import wsgirequest
Dirkjan Ochtman
hgweb: separate out utility functions
r6392 import webcommands, protocol, webutil
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779 perms = {
'changegroup': 'pull',
'changegroupsubset': 'pull',
'unbundle': 'push',
'stream_out': 'pull',
}
Eric Hopper
Final stage of the hgweb split up....
r2356 class hgweb(object):
Thomas Arendsen Hein
Backed out changeset b913d3aacddc (see issue971/msg5317)
r6141 def __init__(self, repo, name=None):
Christian Ebert
Use isinstance instead of type == type
r4874 if isinstance(repo, str):
Thomas Arendsen Hein
Backed out changeset b913d3aacddc (see issue971/msg5317)
r6141 parentui = ui.ui(report_untrusted=False, interactive=False)
Dirkjan Ochtman
Prevent WSGI apps from touching sys.stdin by setting ui.interactive to False.
r5289 self.repo = hg.repository(parentui, repo)
Eric Hopper
Final stage of the hgweb split up....
r2356 else:
self.repo = repo
Matt Mackall
hook: redirect stdout to stderr for ssh and http servers
r5833 hook.redirect(True)
Eric Hopper
Final stage of the hgweb split up....
r2356 self.mtime = -1
self.reponame = name
self.archives = 'zip', 'gz', 'bz2'
Frank Kingswood
hgweb: Configurable zebra stripes...
r2666 self.stripecount = 1
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 # a repo owner may set web.templates in .hg/hgrc to get any file
# readable by the user running the CGI script
self.templatepath = self.config("web", "templates",
templater.templatepath(),
untrusted=False)
# The CGI scripts are often run by a user different from the repo owner.
# Trust the settings from the .hg/hgrc files by default.
def config(self, section, name, default=None, untrusted=True):
return self.repo.ui.config(section, name, default,
untrusted=untrusted)
def configbool(self, section, name, default=False, untrusted=True):
return self.repo.ui.configbool(section, name, default,
untrusted=untrusted)
def configlist(self, section, name, default=None, untrusted=True):
return self.repo.ui.configlist(section, name, default,
untrusted=untrusted)
Eric Hopper
Final stage of the hgweb split up....
r2356
def refresh(self):
mtime = get_mtime(self.repo.root)
if mtime != self.mtime:
self.mtime = mtime
self.repo = hg.repository(self.repo.ui, self.repo.root)
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 self.maxchanges = int(self.config("web", "maxchanges", 10))
self.stripecount = int(self.config("web", "stripes", 1))
self.maxshortchanges = int(self.config("web", "maxshortchanges", 60))
self.maxfiles = int(self.config("web", "maxfiles", 10))
self.allowpull = self.configbool("web", "allowpull", True)
OHASHI Hideya <ohachige at gmail.com>
Enable to select encoding in hgrc web section...
r4690 self.encoding = self.config("web", "encoding", util._encoding)
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 def run(self):
if not os.environ.get('GATEWAY_INTERFACE', '').startswith("CGI/1."):
raise RuntimeError("This function is only intended to be called while running as a CGI script.")
import mercurial.hgweb.wsgicgi as wsgicgi
wsgicgi.launch(self)
def __call__(self, env, respond):
req = wsgirequest(env, respond)
Dirkjan Ochtman
hgweb: all protocol functions have become generators...
r6784 return self.run_wsgi(req)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
def run_wsgi(self, req):
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 self.refresh()
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: protocol requests are processed immediately...
r6777 # process this if it's a protocol request
# protocol bits don't need to create any URLs
# and the clients always use the old URL structure
cmd = req.form.get('cmd', [''])[0]
if cmd and cmd in protocol.__all__:
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 try:
if cmd in perms:
Dirkjan Ochtman
hgweb: be sure to drain request data even in early error conditions...
r7180 try:
self.check_perm(req, perms[cmd])
except ErrorResponse, inst:
if cmd == 'unbundle':
req.drain()
raise
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 method = getattr(protocol, cmd)
return method(self.repo, req)
except ErrorResponse, inst:
req.respond(inst.code, protocol.HGTYPE)
if not inst.message:
return []
return '0\n%s\n' % inst.message,
Dirkjan Ochtman
hgweb: protocol requests are processed immediately...
r6777
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # work with CGI variables to create coherent structure
# use SCRIPT_NAME, PATH_INFO and QUERY_STRING as well as our REPO_NAME
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 req.url = req.env['SCRIPT_NAME']
if not req.url.endswith('/'):
req.url += '/'
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'REPO_NAME' in req.env:
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 req.url += req.env['REPO_NAME'] + '/'
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: make hgwebdir work in the absence of PATH_INFO...
r6459 if 'PATH_INFO' in req.env:
parts = req.env['PATH_INFO'].strip('/').split('/')
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 repo_parts = req.env.get('REPO_NAME', '').split('/')
if parts[:len(repo_parts)] == repo_parts:
parts = parts[len(repo_parts):]
query = '/'.join(parts)
else:
query = req.env['QUERY_STRING'].split('&', 1)[0]
query = query.split(';', 1)[0]
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # translate user-visible url structure to internal structure
args = query.split('/', 2)
if 'cmd' not in req.form and args and args[0]:
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
cmd = args.pop(0)
style = cmd.rfind('-')
if style != -1:
req.form['style'] = [cmd[:style]]
cmd = cmd[style+1:]
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 # avoid accepting e.g. style parameter as command
Dirkjan Ochtman
hgweb: protocol requests are processed immediately...
r6777 if hasattr(webcommands, cmd):
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 req.form['cmd'] = [cmd]
Dirkjan Ochtman
hgweb: protocol requests are processed immediately...
r6777 else:
cmd = ''
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 if cmd == 'static':
req.form['file'] = ['/'.join(args)]
else:
if args and args[0]:
node = args.pop(0)
req.form['node'] = [node]
if args:
req.form['file'] = args
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Brendan Cully
hgweb: handle subdirectories within static directory
r7287 if cmd == 'archive':
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 fn = req.form['node'][0]
for type_, spec in self.archive_specs.iteritems():
ext = spec[2]
if fn.endswith(ext):
req.form['node'] = [fn[:-len(ext)]]
req.form['type'] = [type_]
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 # process the web interface request
Dirkjan Ochtman
hgweb: split out templater definition
r5599
try:
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 tmpl = self.templater(req)
Dirkjan Ochtman
Backed out changeset d2bb66a8a435 (temporary template compatibility)
r6391 ctype = tmpl('mimetype', encoding=self.encoding)
ctype = templater.stringify(ctype)
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149
if cmd == '':
req.form['cmd'] = [tmpl.cache['default']]
cmd = req.form['cmd'][0]
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 if cmd not in webcommands.__all__:
Dirkjan Ochtman
hgweb: better error messages
r6368 msg = 'no such method: %s' % cmd
Dirkjan Ochtman
hgweb: separate protocol calls from interface calls (issue996)...
r6149 raise ErrorResponse(HTTP_BAD_REQUEST, msg)
elif cmd == 'file' and 'raw' in req.form.get('style', []):
self.ctype = ctype
content = webcommands.rawfile(self, req, tmpl)
else:
content = getattr(webcommands, cmd)(self, req, tmpl)
req.respond(HTTP_OK, ctype)
Dirkjan Ochtman
hgweb: fast path for sending raw files
r5890
Dirkjan Ochtman
hgweb: return content iterator instead of using write() callable...
r6945 return ''.join(content),
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600
except revlog.LookupError, err:
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_NOT_FOUND, ctype)
Dirkjan Ochtman
hgweb: fix breakage in python < 2.5 introduced in 2c370f08c486
r6374 msg = str(err)
if 'manifest' not in msg:
Dirkjan Ochtman
hgweb: better error messages
r6368 msg = 'revision not found: %s' % err.name
Dirkjan Ochtman
hgweb: return content iterator instead of using write() callable...
r6945 return ''.join(tmpl('error', error=msg)),
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 except (RepoError, revlog.RevlogError), inst:
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_SERVER_ERROR, ctype)
Dirkjan Ochtman
hgweb: return content iterator instead of using write() callable...
r6945 return ''.join(tmpl('error', error=str(inst))),
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 except ErrorResponse, inst:
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(inst.code, ctype)
Dirkjan Ochtman
hgweb: return content iterator instead of using write() callable...
r6945 return ''.join(tmpl('error', error=inst.message)),
Dirkjan Ochtman
hgweb: split out templater definition
r5599
def templater(self, req):
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # determine scheme, port and server name
# this is needed to create absolute urls
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
proto = req.env.get('wsgi.url_scheme')
if proto == 'https':
proto = 'https'
default_port = "443"
else:
proto = 'http'
default_port = "80"
port = req.env["SERVER_PORT"]
port = port != default_port and (":" + port) or ""
urlbase = '%s://%s%s' % (proto, req.env['SERVER_NAME'], port)
staticurl = self.config("web", "staticurl") or req.url + 'static/'
if not staticurl.endswith('/'):
staticurl += '/'
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 # some functions for the templater
def header(**map):
Dirkjan Ochtman
Backed out changeset d2bb66a8a435 (temporary template compatibility)
r6391 yield tmpl('header', encoding=self.encoding, **map)
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596
def footer(**map):
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 yield tmpl("footer", **map)
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596
def motd(**map):
yield self.config("web", "motd", "")
def sessionvars(**map):
fields = []
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'style' in req.form:
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 style = req.form['style'][0]
if style != self.config('web', 'style', ''):
fields.append(('style', style))
separator = req.url[-1] == '?' and ';' or '?'
for name, value in fields:
yield dict(name=name, value=value, separator=separator)
separator = ';'
Dirkjan Ochtman
hgweb: split out templater definition
r5599 # figure out which style to use
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 style = self.config("web", "style", "")
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'style' in req.form:
Dirkjan Ochtman
hgweb: get rid of some nested functions
r5596 style = req.form['style'][0]
mapfile = style_map(self.templatepath, style)
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591 if not self.reponame:
self.reponame = (self.config("web", "name")
or req.env.get('REPO_NAME')
or req.url.strip('/') or self.repo.root)
Dirkjan Ochtman
hgweb: split out templater definition
r5599 # create the templater
Matt Mackall
templates: move filters to their own module...
r5976 tmpl = templater.templater(mapfile, templatefilters.filters,
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 defaults={"url": req.url,
"staticurl": staticurl,
"urlbase": urlbase,
"repo": self.reponame,
"header": header,
"footer": footer,
"motd": motd,
"sessionvars": sessionvars
})
return tmpl
Dirkjan Ochtman
split out hgweb commands into a separate file, move some code around
r5591
Eric Hopper
Final stage of the hgweb split up....
r2356 def archivelist(self, nodeid):
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 allowed = self.configlist("web", "allow_archive")
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 for i, spec in self.archive_specs.iteritems():
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 if i in allowed or self.configbool("web", "allow" + i):
Brendan Cully
hgweb: accept NewWebInterface URLs
r3260 yield {"type" : i, "extension" : spec[2], "node" : nodeid}
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def listfilediffs(self, tmpl, files, changeset):
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in files[:self.maxfiles]:
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 yield tmpl("filedifflink", node=hex(changeset), file=f)
Eric Hopper
Final stage of the hgweb split up....
r2356 if len(files) > self.maxfiles:
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 yield tmpl("fileellipses")
Eric Hopper
Final stage of the hgweb split up....
r2356
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 def diff(self, tmpl, node1, node2, files):
Eric Hopper
Final stage of the hgweb split up....
r2356 def filterfiles(filters, files):
l = [x for x in files if x in filters]
for t in filters:
if t and t[-1] != os.sep:
t += os.sep
l += [x for x in files if x.startswith(t)]
return l
Thomas Arendsen Hein
hgweb: use generator to count parity of horizontal stripes for easier reading....
r4462 parity = paritygen(self.stripecount)
Eric Hopper
Final stage of the hgweb split up....
r2356 def diffblock(diff, f, fn):
Dirkjan Ochtman
hgweb: explicitly pass around the templater
r5600 yield tmpl("diffblock",
lines=prettyprintlines(diff),
parity=parity.next(),
file=f,
filenode=hex(fn or nullid))
Eric Hopper
Final stage of the hgweb split up....
r2356
Edward Lee
Add line anchors to annotate, changeset, diff, file views for hgweb
r6122 blockcount = countgen()
Eric Hopper
Final stage of the hgweb split up....
r2356 def prettyprintlines(diff):
Edward Lee
Add line anchors to annotate, changeset, diff, file views for hgweb
r6122 blockno = blockcount.next()
for lineno, l in enumerate(diff.splitlines(1)):
if blockno == 0:
lineno = lineno + 1
else:
lineno = "%d.%d" % (blockno, lineno + 1)
Eric Hopper
Final stage of the hgweb split up....
r2356 if l.startswith('+'):
Thomas Arendsen Hein
merged Edward Lee's line anchors patch
r6123 ltype = "difflineplus"
Eric Hopper
Final stage of the hgweb split up....
r2356 elif l.startswith('-'):
Thomas Arendsen Hein
merged Edward Lee's line anchors patch
r6123 ltype = "difflineminus"
Eric Hopper
Final stage of the hgweb split up....
r2356 elif l.startswith('@'):
Thomas Arendsen Hein
merged Edward Lee's line anchors patch
r6123 ltype = "difflineat"
Eric Hopper
Final stage of the hgweb split up....
r2356 else:
Thomas Arendsen Hein
merged Edward Lee's line anchors patch
r6123 ltype = "diffline"
yield tmpl(ltype,
line=l,
lineid="l%s" % lineno,
linenumber="% 8s" % lineno)
Eric Hopper
Final stage of the hgweb split up....
r2356
r = self.repo
Matt Mackall
use repo[changeid] to get a changectx
r6747 c1 = r[node1]
c2 = r[node2]
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 date1 = util.datestr(c1.date())
date2 = util.datestr(c2.date())
Eric Hopper
Final stage of the hgweb split up....
r2356
Giorgos Keramidas
hgweb: repo.changes() is now called repo.status()
r2876 modified, added, removed, deleted, unknown = r.status(node1, node2)[:5]
Eric Hopper
Final stage of the hgweb split up....
r2356 if files:
modified, added, removed = map(lambda x: filterfiles(files, x),
(modified, added, removed))
Alexis S. L. Carvalho
use untrusted settings in hgweb...
r3555 diffopts = patch.diffopts(self.repo.ui, untrusted=True)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in modified:
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 to = c1.filectx(f).data()
tn = c2.filectx(f).data()
Rocco Rutte
hgweb_mod: update unidiff() calls and finish e5eedd74e70f job
r5486 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in added:
to = None
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 tn = c2.filectx(f).data()
Rocco Rutte
hgweb_mod: update unidiff() calls and finish e5eedd74e70f job
r5486 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356 for f in removed:
Benoit Boissinot
hgweb: use contexts, fix coding style
r3973 to = c1.filectx(f).data()
Eric Hopper
Final stage of the hgweb split up....
r2356 tn = None
Rocco Rutte
hgweb_mod: update unidiff() calls and finish e5eedd74e70f job
r5486 yield diffblock(mdiff.unidiff(to, date1, tn, date2, f, f,
Vadim Gelfer
refactor text diff/patch code....
r2874 opts=diffopts), f, tn)
Eric Hopper
Final stage of the hgweb split up....
r2356
archive_specs = {
Thomas Arendsen Hein
Fix automatic decompression of tarballs with Firefox....
r2361 'bz2': ('application/x-tar', 'tbz2', '.tar.bz2', None),
'gz': ('application/x-tar', 'tgz', '.tar.gz', None),
Eric Hopper
Final stage of the hgweb split up....
r2356 'zip': ('application/zip', 'zip', '.zip', None),
}
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779 def check_perm(self, req, op):
'''Check permission for operation based on request data (including
authentication info. Return true if op allowed, else false.'''
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 if op == 'pull' and not self.allowpull:
raise ErrorResponse(HTTP_OK, '')
elif op == 'pull':
return
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779
# enforce that you can only push using POST requests
if req.env['REQUEST_METHOD'] != 'POST':
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 msg = 'push requires POST request'
raise ErrorResponse(HTTP_METHOD_NOT_ALLOWED, msg)
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779
# require ssl by default for pushing, auth info cannot be sniffed
# and replayed
scheme = req.env.get('wsgi.url_scheme')
if self.configbool('web', 'push_ssl', True) and scheme != 'https':
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 raise ErrorResponse(HTTP_OK, 'ssl required')
Vadim Gelfer
push over http: server side authorization support....
r2466
user = req.env.get('REMOTE_USER')
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779 deny = self.configlist('web', 'deny_push')
Vadim Gelfer
push over http: server side authorization support....
r2466 if deny and (not user or deny == ['*'] or user in deny):
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')
Vadim Gelfer
push over http: server side authorization support....
r2466
Dirkjan Ochtman
hgweb: centralize permission checks for protocol commands...
r6779 allow = self.configlist('web', 'allow_push')
result = allow and (allow == ['*'] or user in allow)
if not result:
Dirkjan Ochtman
hgweb: raise ErrorResponses to communicate protocol errors
r6926 raise ErrorResponse(HTTP_UNAUTHORIZED, 'push not authorized')