diff options
author | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@localhost> | 2011-05-03 11:25:13 +0000 |
commit | 458120dd40db6b4df55a4e96b650e16798ef06a0 (patch) | |
tree | 8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/src/cmd/hg/mercurial/hgweb/protocol.py | |
parent | 3a742c699f6806c1145aea5149bf15de15a0afd7 (diff) |
add hg and python
Diffstat (limited to 'sys/src/cmd/hg/mercurial/hgweb/protocol.py')
-rw-r--r-- | sys/src/cmd/hg/mercurial/hgweb/protocol.py | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/sys/src/cmd/hg/mercurial/hgweb/protocol.py b/sys/src/cmd/hg/mercurial/hgweb/protocol.py new file mode 100644 index 000000000..a411fdb97 --- /dev/null +++ b/sys/src/cmd/hg/mercurial/hgweb/protocol.py @@ -0,0 +1,206 @@ +# +# 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 version 2, incorporated herein by reference. + +import cStringIO, zlib, tempfile, errno, os, sys, urllib +from mercurial import util, streamclone +from mercurial.node import bin, hex +from mercurial import changegroup as changegroupmod +from common import ErrorResponse, HTTP_OK, HTTP_NOT_FOUND, HTTP_SERVER_ERROR + +# __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', + 'branchmap', +] + +HGTYPE = 'application/mercurial-0.1' + +def lookup(repo, req): + try: + r = hex(repo.lookup(req.form['key'][0])) + success = 1 + except Exception, inst: + r = str(inst) + success = 0 + resp = "%s %s\n" % (success, r) + req.respond(HTTP_OK, HGTYPE, length=len(resp)) + yield resp + +def heads(repo, req): + resp = " ".join(map(hex, repo.heads())) + "\n" + req.respond(HTTP_OK, HGTYPE, length=len(resp)) + yield resp + +def branchmap(repo, req): + branches = repo.branchmap() + heads = [] + for branch, nodes in branches.iteritems(): + branchname = urllib.quote(branch) + branchnodes = [hex(node) for node in nodes] + heads.append('%s %s' % (branchname, ' '.join(branchnodes))) + resp = '\n'.join(heads) + req.respond(HTTP_OK, HGTYPE, length=len(resp)) + yield resp + +def branches(repo, req): + nodes = [] + if 'nodes' in req.form: + nodes = map(bin, req.form['nodes'][0].split(" ")) + resp = cStringIO.StringIO() + for b in repo.branches(nodes): + resp.write(" ".join(map(hex, b)) + "\n") + resp = resp.getvalue() + req.respond(HTTP_OK, HGTYPE, length=len(resp)) + yield resp + +def between(repo, req): + if 'pairs' in req.form: + pairs = [map(bin, p.split("-")) + for p in req.form['pairs'][0].split(" ")] + resp = cStringIO.StringIO() + for b in repo.between(pairs): + resp.write(" ".join(map(hex, b)) + "\n") + resp = resp.getvalue() + req.respond(HTTP_OK, HGTYPE, length=len(resp)) + yield resp + +def changegroup(repo, req): + req.respond(HTTP_OK, HGTYPE) + nodes = [] + + if 'roots' in req.form: + nodes = map(bin, req.form['roots'][0].split(" ")) + + z = zlib.compressobj() + f = repo.changegroup(nodes, 'serve') + while 1: + chunk = f.read(4096) + if not chunk: + break + yield z.compress(chunk) + + yield z.flush() + +def changegroupsubset(repo, req): + req.respond(HTTP_OK, HGTYPE) + bases = [] + heads = [] + + if 'bases' in req.form: + bases = [bin(x) for x in req.form['bases'][0].split(' ')] + if 'heads' in req.form: + heads = [bin(x) for x in req.form['heads'][0].split(' ')] + + z = zlib.compressobj() + f = repo.changegroupsubset(bases, heads, 'serve') + while 1: + chunk = f.read(4096) + if not chunk: + break + yield z.compress(chunk) + + yield z.flush() + +def capabilities(repo, req): + caps = ['lookup', 'changegroupsubset', 'branchmap'] + if repo.ui.configbool('server', 'uncompressed', untrusted=True): + caps.append('stream=%d' % repo.changelog.version) + if changegroupmod.bundlepriority: + caps.append('unbundle=%s' % ','.join(changegroupmod.bundlepriority)) + rsp = ' '.join(caps) + req.respond(HTTP_OK, HGTYPE, length=len(rsp)) + yield rsp + +def unbundle(repo, req): + + proto = req.env.get('wsgi.url_scheme') or 'http' + their_heads = req.form['heads'][0].split(' ') + + def check_heads(): + heads = map(hex, repo.heads()) + return their_heads == [hex('force')] or their_heads == heads + + # fail early if possible + if not check_heads(): + req.drain() + raise ErrorResponse(HTTP_OK, 'unsynced changes') + + # 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 = repo.lock() + try: + if not check_heads(): + raise ErrorResponse(HTTP_OK, 'unsynced changes') + + fp.seek(0) + header = fp.read(6) + 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) + + # send addchangegroup output to client + + oldio = sys.stdout, sys.stderr + sys.stderr = sys.stdout = cStringIO.StringIO() + + try: + url = 'remote:%s:%s:%s' % ( + proto, + urllib.quote(req.env.get('REMOTE_HOST', '')), + urllib.quote(req.env.get('REMOTE_USER', ''))) + try: + ret = repo.addchangegroup(gen, 'serve', url) + except util.Abort, inst: + sys.stdout.write("abort: %s\n" % inst) + ret = 0 + finally: + val = sys.stdout.getvalue() + sys.stdout, sys.stderr = oldio + req.respond(HTTP_OK, HGTYPE) + return '%d\n%s' % (ret, val), + finally: + lock.release() + except ValueError, inst: + raise ErrorResponse(HTTP_OK, inst) + except (OSError, IOError), inst: + filename = getattr(inst, 'filename', '') + # Don't send our filesystem layout to the client + if filename.startswith(repo.root): + filename = filename[len(repo.root)+1:] + else: + filename = '' + error = getattr(inst, 'strerror', 'Unknown error') + if inst.errno == errno.ENOENT: + code = HTTP_NOT_FOUND + else: + code = HTTP_SERVER_ERROR + raise ErrorResponse(code, '%s: %s' % (error, filename)) + finally: + fp.close() + os.unlink(tempname) + +def stream_out(repo, req): + req.respond(HTTP_OK, HGTYPE) + try: + for chunk in streamclone.stream_out(repo, untrusted=True): + yield chunk + except streamclone.StreamException, inst: + yield str(inst) |