##// END OF EJS Templates
Backed out changeset: e1dde7363601
Backed out changeset: e1dde7363601

File last commit:

r10377:04e1e674 default
r11310:ac873ecf default
Show More
sshserver.py
225 lines | 6.5 KiB | text/x-python | PythonLexer
Vadim Gelfer
fix comment.
r2399 # sshserver.py - ssh protocol server support for mercurial
Vadim Gelfer
refactor ssh server.
r2396 #
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
Vadim Gelfer
update copyrights.
r2859 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
Vadim Gelfer
refactor ssh server.
r2396 #
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.
Vadim Gelfer
refactor ssh server.
r2396
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Joel Rosdahl
Expand import * to allow Pyflakes to find problems
r6211 from node import bin, hex
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import streamclone, util, hook
Dirkjan Ochtman
hgweb/sshserver: extract capabilities for easier modification
r9713 import os, sys, tempfile, urllib, copy
Vadim Gelfer
refactor ssh server.
r2396
class sshserver(object):
Dirkjan Ochtman
hgweb/sshserver: extract capabilities for easier modification
r9713
caps = 'unbundle lookup changegroupsubset branchmap'.split()
Vadim Gelfer
refactor ssh server.
r2396 def __init__(self, ui, repo):
self.ui = ui
self.repo = repo
self.lock = None
self.fin = sys.stdin
self.fout = sys.stdout
Matt Mackall
hook: redirect stdout to stderr for ssh and http servers
r5833 hook.redirect(True)
Vadim Gelfer
refactor ssh server.
r2396 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):
Ronny Pfannschmidt
switch lock releasing in the core from gc to explicit
r8109 try:
Matt Mackall
many, many trivial check-code fixups
r10282 while self.serve_one():
pass
Ronny Pfannschmidt
switch lock releasing in the core from gc to explicit
r8109 finally:
if self.lock is not None:
self.lock.release()
Vadim Gelfer
refactor ssh server.
r2396 sys.exit(0)
def serve_one(self):
cmd = self.fin.readline()[:-1]
if cmd:
impl = getattr(self, 'do_' + cmd, None)
Matt Mackall
many, many trivial check-code fixups
r10282 if impl:
impl()
Vadim Gelfer
merge change to ssh protocol.
r2397 else: self.respond("")
Vadim Gelfer
refactor ssh server.
r2396 return cmd != ''
Eric Hopper
Adding changegroupsubset and lookup to ssh protocol so pull -r and...
r3446 def do_lookup(self):
arg, key = self.getarg()
assert arg == 'key'
Eric Hopper
sshrepo: add passing of lookup exceptions
r3447 try:
r = hex(self.repo.lookup(key))
success = 1
Martin Geisler
coding style: use a space after comma...
r9198 except Exception, inst:
Eric Hopper
sshrepo: add passing of lookup exceptions
r3447 r = str(inst)
success = 0
self.respond("%s %s\n" % (success, r))
Eric Hopper
Adding changegroupsubset and lookup to ssh protocol so pull -r and...
r3446
Henrik Stuart
named branches: server branchmap wire protocol support (issue736)...
r8562 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))
Vadim Gelfer
refactor ssh server.
r2396 def do_heads(self):
h = self.repo.heads()
self.respond(" ".join(map(hex, h)) + "\n")
Matt Mackall
Initial implementation of hello command for ssh
r2419 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
'''
Dirkjan Ochtman
hgweb/sshserver: extract capabilities for easier modification
r9713 caps = copy.copy(self.caps)
Matt Mackall
streamclone: allow uncompressed clones by default
r10377 if streamclone.allowed(self.repo.ui):
Matt Mackall
revlog: simplify revlog version handling...
r4258 caps.append('stream=%d' % self.repo.changelog.version)
Vadim Gelfer
clone: disable stream support on server side by default....
r2621 self.respond("capabilities: %s\n" % (' '.join(caps),))
Matt Mackall
Initial implementation of hello command for ssh
r2419
Vadim Gelfer
refactor ssh server.
r2396 def do_lock(self):
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 '''DEPRECATED - allowing remote client to lock repo is not safe'''
Vadim Gelfer
refactor ssh server.
r2396 self.lock = self.repo.lock()
self.respond("")
def do_unlock(self):
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 '''DEPRECATED'''
Vadim Gelfer
refactor ssh server.
r2396 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()
Eric Hopper
Adding changegroupsubset and lookup to ssh protocol so pull -r and...
r3446 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()
Vadim Gelfer
refactor ssh server.
r2396 def do_addchangegroup(self):
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 '''DEPRECATED'''
Vadim Gelfer
refactor ssh server.
r2396 if not self.lock:
self.respond("not locked")
return
self.respond("")
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 r = self.repo.addchangegroup(self.fin, 'serve', self.client_url())
Vadim Gelfer
refactor ssh server.
r2396 self.respond(str(r))
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 def client_url(self):
client = os.environ.get('SSH_CLIENT', '').split(' ', 1)[0]
return 'remote:ssh:' + client
Thomas Arendsen Hein
Whitespace/Tab cleanup
r3223
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 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
Benoit Boissinot
sshrepo: move mkstemp() out of the try block, we don't use the exception...
r9742 fd, tempname = tempfile.mkstemp(prefix='hg-unbundle-')
fp = os.fdopen(fd, 'wb+')
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 try:
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)
Vadim Gelfer
hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks...
r2673 r = self.repo.addchangegroup(fp, 'serve', self.client_url())
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439 self.respond(str(r))
finally:
if not was_locked:
self.lock.release()
self.lock = None
finally:
Benoit Boissinot
sshrepo: move mkstemp() out of the try block, we don't use the exception...
r9742 fp.close()
os.unlink(tempname)
Vadim Gelfer
extend network protocol to stop clients from locking servers...
r2439
Vadim Gelfer
add support for streaming clone....
r2612 def do_stream_out(self):
Dirkjan Ochtman
make streamclone.stream_out() a generator
r6925 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()