##// END OF EJS Templates
Fixed typo in tag help, found by John Coomes
Fixed typo in tag help, found by John Coomes

File last commit:

r6212:e75aab65 default
r6220:1939e291 default
Show More
protocol.py
220 lines | 6.8 KiB | text/x-python | PythonLexer
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 #
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Joel Rosdahl
Remove unused imports
r6212 import cStringIO, zlib, tempfile, errno, os, sys
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 from mercurial import util, streamclone
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from mercurial.node import bin, hex
Dirkjan Ochtman
improve changegroup.readbundle(), use it in hgweb
r6154 from mercurial import changegroup as changegroupmod
Dirkjan Ochtman
hgweb: explicit response status
r5993 from common import HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598
Dirkjan Ochtman
hgweb: explicitly check if requested command exists
r5963 # __all__ is populated with the allowed commands. Be sure to add to it if
# you're adding a new command, or the new command won't work.
__all__ = [
'lookup', 'heads', 'branches', 'between', 'changegroup',
'changegroupsubset', 'capabilities', 'unbundle', 'stream_out',
]
Dirkjan Ochtman
hgweb: explicit response status
r5993 HGTYPE = 'application/mercurial-0.1'
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 def lookup(web, req):
try:
r = hex(web.repo.lookup(req.form['key'][0]))
success = 1
except Exception,inst:
r = str(inst)
success = 0
resp = "%s %s\n" % (success, r)
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE, length=len(resp))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write(resp)
def heads(web, req):
resp = " ".join(map(hex, web.repo.heads())) + "\n"
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE, length=len(resp))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write(resp)
def branches(web, req):
nodes = []
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'nodes' in req.form:
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 nodes = map(bin, req.form['nodes'][0].split(" "))
resp = cStringIO.StringIO()
for b in web.repo.branches(nodes):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE, length=len(resp))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write(resp)
def between(web, req):
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'pairs' in req.form:
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 pairs = [map(bin, p.split("-"))
for p in req.form['pairs'][0].split(" ")]
resp = cStringIO.StringIO()
for b in web.repo.between(pairs):
resp.write(" ".join(map(hex, b)) + "\n")
resp = resp.getvalue()
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE, length=len(resp))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write(resp)
def changegroup(web, req):
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 nodes = []
if not web.allowpull:
return
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'roots' in req.form:
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 nodes = map(bin, req.form['roots'][0].split(" "))
z = zlib.compressobj()
f = web.repo.changegroup(nodes, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
break
req.write(z.compress(chunk))
req.write(z.flush())
def changegroupsubset(web, req):
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 bases = []
heads = []
if not web.allowpull:
return
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'bases' in req.form:
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 bases = [bin(x) for x in req.form['bases'][0].split(' ')]
Christian Ebert
Prefer i in d over d.has_key(i)
r5915 if 'heads' in req.form:
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 heads = [bin(x) for x in req.form['heads'][0].split(' ')]
z = zlib.compressobj()
f = web.repo.changegroupsubset(bases, heads, 'serve')
while 1:
chunk = f.read(4096)
if not chunk:
break
req.write(z.compress(chunk))
req.write(z.flush())
def capabilities(web, req):
Dirkjan Ochtman
hgweb: use bundletypes from mercurial.changegroup
r6152 resp = ' '.join(web.capabilities())
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE, length=len(resp))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write(resp)
def unbundle(web, req):
def bail(response, headers={}):
length = int(req.env['CONTENT_LENGTH'])
for s in util.filechunkiter(req, limit=length):
# drain incoming bundle, else client will not see
# response when run outside cgi script
pass
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.header(headers.items())
req.respond(HTTP_OK, HGTYPE)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 req.write('0\n')
req.write(response)
# require ssl by default, auth info cannot be sniffed and
# replayed
ssl_req = web.configbool('web', 'push_ssl', True)
if ssl_req:
if req.env.get('wsgi.url_scheme') != 'https':
Dirkjan Ochtman
hgweb: no i18n in protocol responses
r6155 bail('ssl required\n')
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 return
proto = 'https'
else:
proto = 'http'
# do not allow push unless explicitly allowed
if not web.check_perm(req, 'push', False):
Dirkjan Ochtman
hgweb: no i18n in protocol responses
r6155 bail('push not authorized\n',
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 headers={'status': '401 Unauthorized'})
return
their_heads = req.form['heads'][0].split(' ')
def check_heads():
heads = map(hex, web.repo.heads())
return their_heads == [hex('force')] or their_heads == heads
# fail early if possible
if not check_heads():
Dirkjan Ochtman
hgweb: no i18n in protocol responses
r6155 bail('unsynced changes\n')
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 return
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598
# do not lock repo until all changegroup data is
# streamed. save to temporary file.
fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
try:
length = int(req.env['CONTENT_LENGTH'])
for s in util.filechunkiter(req, limit=length):
fp.write(s)
try:
lock = web.repo.lock()
try:
if not check_heads():
req.write('0\n')
Dirkjan Ochtman
hgweb: no i18n in protocol responses
r6155 req.write('unsynced changes\n')
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 return
fp.seek(0)
header = fp.read(6)
Dirkjan Ochtman
improve changegroup.readbundle(), use it in hgweb
r6154 if header.startswith('HG') and not header.startswith('HG10'):
raise ValueError('unknown bundle version')
elif header not in changegroupmod.bundletypes:
raise ValueError('unknown bundle compression type')
gen = changegroupmod.unbundle(header, fp)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598
# send addchangegroup output to client
old_stdout = sys.stdout
sys.stdout = cStringIO.StringIO()
try:
url = 'remote:%s:%s' % (proto,
req.env.get('REMOTE_HOST', ''))
try:
Dirkjan Ochtman
improve changegroup.readbundle(), use it in hgweb
r6154 ret = web.repo.addchangegroup(gen, 'serve', url)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 except util.Abort, inst:
sys.stdout.write("abort: %s\n" % inst)
ret = 0
finally:
val = sys.stdout.getvalue()
sys.stdout = old_stdout
req.write('%d\n' % ret)
req.write(val)
finally:
del lock
Dirkjan Ochtman
improve changegroup.readbundle(), use it in hgweb
r6154 except ValueError, inst:
req.write('0\n')
req.write(str(inst) + '\n')
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 except (OSError, IOError), inst:
req.write('0\n')
filename = getattr(inst, 'filename', '')
# Don't send our filesystem layout to the client
if filename.startswith(web.repo.root):
filename = filename[len(web.repo.root)+1:]
else:
filename = ''
error = getattr(inst, 'strerror', 'Unknown error')
if inst.errno == errno.ENOENT:
Dirkjan Ochtman
hgweb: explicit response status
r5993 code = HTTP_NOT_FOUND
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 else:
Dirkjan Ochtman
hgweb: explicit response status
r5993 code = HTTP_SERVER_ERROR
req.respond(code)
req.write('%s: %s\n' % (error, filename))
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 finally:
fp.close()
os.unlink(tempname)
def stream_out(web, req):
Dirkjan Ochtman
hgweb: explicit response status
r5993 req.respond(HTTP_OK, HGTYPE)
Dirkjan Ochtman
separate the wire protocol commands from the user interface commands
r5598 streamclone.stream_out(web.repo, req, untrusted=True)