summaryrefslogtreecommitdiff
path: root/sys/lib/python/mercurial/sshserver.py
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
committercinap_lenrek <cinap_lenrek@localhost>2011-05-03 11:25:13 +0000
commit458120dd40db6b4df55a4e96b650e16798ef06a0 (patch)
tree8f82685be24fef97e715c6f5ca4c68d34d5074ee /sys/lib/python/mercurial/sshserver.py
parent3a742c699f6806c1145aea5149bf15de15a0afd7 (diff)
add hg and python
Diffstat (limited to 'sys/lib/python/mercurial/sshserver.py')
-rw-r--r--sys/lib/python/mercurial/sshserver.py225
1 files changed, 225 insertions, 0 deletions
diff --git a/sys/lib/python/mercurial/sshserver.py b/sys/lib/python/mercurial/sshserver.py
new file mode 100644
index 000000000..d5fccbc43
--- /dev/null
+++ b/sys/lib/python/mercurial/sshserver.py
@@ -0,0 +1,225 @@
+# sshserver.py - ssh protocol server support for mercurial
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+# Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2, incorporated herein by reference.
+
+from i18n import _
+from node import bin, hex
+import streamclone, util, hook
+import os, sys, tempfile, urllib
+
+class sshserver(object):
+ def __init__(self, ui, repo):
+ self.ui = ui
+ self.repo = repo
+ self.lock = None
+ self.fin = sys.stdin
+ self.fout = sys.stdout
+
+ hook.redirect(True)
+ sys.stdout = sys.stderr
+
+ # Prevent insertion/deletion of CRs
+ util.set_binary(self.fin)
+ util.set_binary(self.fout)
+
+ def getarg(self):
+ argline = self.fin.readline()[:-1]
+ arg, l = argline.split()
+ val = self.fin.read(int(l))
+ return arg, val
+
+ def respond(self, v):
+ self.fout.write("%d\n" % len(v))
+ self.fout.write(v)
+ self.fout.flush()
+
+ def serve_forever(self):
+ try:
+ while self.serve_one(): pass
+ finally:
+ if self.lock is not None:
+ self.lock.release()
+ sys.exit(0)
+
+ def serve_one(self):
+ cmd = self.fin.readline()[:-1]
+ if cmd:
+ impl = getattr(self, 'do_' + cmd, None)
+ if impl: impl()
+ else: self.respond("")
+ return cmd != ''
+
+ def do_lookup(self):
+ arg, key = self.getarg()
+ assert arg == 'key'
+ try:
+ r = hex(self.repo.lookup(key))
+ success = 1
+ except Exception, inst:
+ r = str(inst)
+ success = 0
+ self.respond("%s %s\n" % (success, r))
+
+ def do_branchmap(self):
+ branchmap = self.repo.branchmap()
+ heads = []
+ for branch, nodes in branchmap.iteritems():
+ branchname = urllib.quote(branch)
+ branchnodes = [hex(node) for node in nodes]
+ heads.append('%s %s' % (branchname, ' '.join(branchnodes)))
+ self.respond('\n'.join(heads))
+
+ def do_heads(self):
+ h = self.repo.heads()
+ self.respond(" ".join(map(hex, h)) + "\n")
+
+ def do_hello(self):
+ '''the hello command returns a set of lines describing various
+ interesting things about the server, in an RFC822-like format.
+ Currently the only one defined is "capabilities", which
+ consists of a line in the form:
+
+ capabilities: space separated list of tokens
+ '''
+
+ caps = ['unbundle', 'lookup', 'changegroupsubset', 'branchmap']
+ if self.ui.configbool('server', 'uncompressed'):
+ caps.append('stream=%d' % self.repo.changelog.version)
+ self.respond("capabilities: %s\n" % (' '.join(caps),))
+
+ def do_lock(self):
+ '''DEPRECATED - allowing remote client to lock repo is not safe'''
+
+ self.lock = self.repo.lock()
+ self.respond("")
+
+ def do_unlock(self):
+ '''DEPRECATED'''
+
+ if self.lock:
+ self.lock.release()
+ self.lock = None
+ self.respond("")
+
+ def do_branches(self):
+ arg, nodes = self.getarg()
+ nodes = map(bin, nodes.split(" "))
+ r = []
+ for b in self.repo.branches(nodes):
+ r.append(" ".join(map(hex, b)) + "\n")
+ self.respond("".join(r))
+
+ def do_between(self):
+ arg, pairs = self.getarg()
+ pairs = [map(bin, p.split("-")) for p in pairs.split(" ")]
+ r = []
+ for b in self.repo.between(pairs):
+ r.append(" ".join(map(hex, b)) + "\n")
+ self.respond("".join(r))
+
+ def do_changegroup(self):
+ nodes = []
+ arg, roots = self.getarg()
+ nodes = map(bin, roots.split(" "))
+
+ cg = self.repo.changegroup(nodes, 'serve')
+ while True:
+ d = cg.read(4096)
+ if not d:
+ break
+ self.fout.write(d)
+
+ self.fout.flush()
+
+ def do_changegroupsubset(self):
+ argmap = dict([self.getarg(), self.getarg()])
+ bases = [bin(n) for n in argmap['bases'].split(' ')]
+ heads = [bin(n) for n in argmap['heads'].split(' ')]
+
+ cg = self.repo.changegroupsubset(bases, heads, 'serve')
+ while True:
+ d = cg.read(4096)
+ if not d:
+ break
+ self.fout.write(d)
+
+ self.fout.flush()
+
+ def do_addchangegroup(self):
+ '''DEPRECATED'''
+
+ if not self.lock:
+ self.respond("not locked")
+ return
+
+ self.respond("")
+ r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
+ self.respond(str(r))
+
+ def client_url(self):
+ client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
+ return 'remote:ssh:' + client
+
+ def do_unbundle(self):
+ their_heads = self.getarg()[1].split()
+
+ def check_heads():
+ heads = map(hex, self.repo.heads())
+ return their_heads == [hex('force')] or their_heads == heads
+
+ # fail early if possible
+ if not check_heads():
+ self.respond(_('unsynced changes'))
+ return
+
+ self.respond('')
+
+ # write bundle data to temporary file because it can be big
+ tempname = fp = None
+ try:
+ fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
+ fp = os.fdopen(fd, 'wb+')
+
+ count = int(self.fin.readline())
+ while count:
+ fp.write(self.fin.read(count))
+ count = int(self.fin.readline())
+
+ was_locked = self.lock is not None
+ if not was_locked:
+ self.lock = self.repo.lock()
+ try:
+ if not check_heads():
+ # someone else committed/pushed/unbundled while we
+ # were transferring data
+ self.respond(_('unsynced changes'))
+ return
+ self.respond('')
+
+ # push can proceed
+
+ fp.seek(0)
+ r = self.repo.addchangegroup(fp, 'serve', self.client_url())
+ self.respond(str(r))
+ finally:
+ if not was_locked:
+ self.lock.release()
+ self.lock = None
+ finally:
+ if fp is not None:
+ fp.close()
+ if tempname is not None:
+ os.unlink(tempname)
+
+ def do_stream_out(self):
+ try:
+ for chunk in streamclone.stream_out(self.repo):
+ self.fout.write(chunk)
+ self.fout.flush()
+ except streamclone.StreamException, inst:
+ self.fout.write(str(inst))
+ self.fout.flush()