Mercurial > hg > mercurial-crew-with-dirclash
annotate mercurial/sshserver.py @ 2435:ff2bac730b99
http client: support persistent connections.
uses keepalive module from urlgrabber package. tested against "hg serve",
cgi server, and through http proxy. used ethereal to verify that only
one tcp connection used during entire "hg pull" sequence.
if server supports keepalive, this makes latency of "hg pull" much lower.
author | Vadim Gelfer <vadim.gelfer@gmail.com> |
---|---|
date | Thu, 15 Jun 2006 12:57:59 -0700 |
parents | b17eebc911ae |
children | e8c4f3d3df8c |
rev | line source |
---|---|
2399 | 1 # sshserver.py - ssh protocol server support for mercurial |
2396 | 2 # |
3 # Copyright 2005 Matt Mackall <mpm@selenic.com> | |
4 # | |
5 # This software may be used and distributed according to the terms | |
6 # of the GNU General Public License, incorporated herein by reference. | |
7 | |
8 from demandload import demandload | |
9 from i18n import gettext as _ | |
10 from node import * | |
11 demandload(globals(), "sys util") | |
12 | |
13 class sshserver(object): | |
14 def __init__(self, ui, repo): | |
15 self.ui = ui | |
16 self.repo = repo | |
17 self.lock = None | |
18 self.fin = sys.stdin | |
19 self.fout = sys.stdout | |
20 | |
21 sys.stdout = sys.stderr | |
22 | |
23 # Prevent insertion/deletion of CRs | |
24 util.set_binary(self.fin) | |
25 util.set_binary(self.fout) | |
26 | |
27 def getarg(self): | |
28 argline = self.fin.readline()[:-1] | |
29 arg, l = argline.split() | |
30 val = self.fin.read(int(l)) | |
31 return arg, val | |
32 | |
33 def respond(self, v): | |
34 self.fout.write("%d\n" % len(v)) | |
35 self.fout.write(v) | |
36 self.fout.flush() | |
37 | |
38 def serve_forever(self): | |
39 while self.serve_one(): pass | |
40 sys.exit(0) | |
41 | |
42 def serve_one(self): | |
43 cmd = self.fin.readline()[:-1] | |
44 if cmd: | |
45 impl = getattr(self, 'do_' + cmd, None) | |
46 if impl: impl() | |
2397
e9d402506514
merge change to ssh protocol.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents:
2396
diff
changeset
|
47 else: self.respond("") |
2396 | 48 return cmd != '' |
49 | |
50 def do_heads(self): | |
51 h = self.repo.heads() | |
52 self.respond(" ".join(map(hex, h)) + "\n") | |
53 | |
2419
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
54 def do_hello(self): |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
55 '''the hello command returns a set of lines describing various |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
56 interesting things about the server, in an RFC822-like format. |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
57 Currently the only one defined is "capabilities", which |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
58 consists of a line in the form: |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
59 |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
60 capabilities: space separated list of tokens |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
61 ''' |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
62 |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
63 r = "capabilities:\n" |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
64 self.respond(r) |
b17eebc911ae
Initial implementation of hello command for ssh
Matt Mackall <mpm@selenic.com>
parents:
2399
diff
changeset
|
65 |
2396 | 66 def do_lock(self): |
67 self.lock = self.repo.lock() | |
68 self.respond("") | |
69 | |
70 def do_unlock(self): | |
71 if self.lock: | |
72 self.lock.release() | |
73 self.lock = None | |
74 self.respond("") | |
75 | |
76 def do_branches(self): | |
77 arg, nodes = self.getarg() | |
78 nodes = map(bin, nodes.split(" ")) | |
79 r = [] | |
80 for b in self.repo.branches(nodes): | |
81 r.append(" ".join(map(hex, b)) + "\n") | |
82 self.respond("".join(r)) | |
83 | |
84 def do_between(self): | |
85 arg, pairs = self.getarg() | |
86 pairs = [map(bin, p.split("-")) for p in pairs.split(" ")] | |
87 r = [] | |
88 for b in self.repo.between(pairs): | |
89 r.append(" ".join(map(hex, b)) + "\n") | |
90 self.respond("".join(r)) | |
91 | |
92 def do_changegroup(self): | |
93 nodes = [] | |
94 arg, roots = self.getarg() | |
95 nodes = map(bin, roots.split(" ")) | |
96 | |
97 cg = self.repo.changegroup(nodes, 'serve') | |
98 while True: | |
99 d = cg.read(4096) | |
100 if not d: | |
101 break | |
102 self.fout.write(d) | |
103 | |
104 self.fout.flush() | |
105 | |
106 def do_addchangegroup(self): | |
107 if not self.lock: | |
108 self.respond("not locked") | |
109 return | |
110 | |
111 self.respond("") | |
112 r = self.repo.addchangegroup(self.fin, 'serve') | |
113 self.respond(str(r)) |