comparison mercurial/sshrepo.py @ 11586:ddaaaa23bb8f

protocol: move basic ssh client commands to wirerepository
author Matt Mackall <mpm@selenic.com>
date Wed, 14 Jul 2010 16:34:57 -0500
parents 02a4373ca5cd
children 8a1f625e971d
comparison
equal deleted inserted replaced
11585:5d907fbb9703 11586:ddaaaa23bb8f
5 # This software may be used and distributed according to the terms of the 5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version. 6 # GNU General Public License version 2 or any later version.
7 7
8 from node import bin, hex 8 from node import bin, hex
9 from i18n import _ 9 from i18n import _
10 import repo, util, error, encoding 10 import repo, util, error, encoding, wireproto
11 import re, urllib 11 import re, urllib
12 12
13 class remotelock(object): 13 class remotelock(object):
14 def __init__(self, repo): 14 def __init__(self, repo):
15 self.repo = repo 15 self.repo = repo
18 self.repo = None 18 self.repo = None
19 def __del__(self): 19 def __del__(self):
20 if self.repo: 20 if self.repo:
21 self.release() 21 self.release()
22 22
23 class sshrepository(repo.repository): 23 class sshrepository(wireproto.wirerepository):
24 def __init__(self, ui, path, create=0): 24 def __init__(self, ui, path, create=0):
25 self._url = path 25 self._url = path
26 self.ui = ui 26 self.ui = ui
27 27
28 m = re.match(r'^ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?$', path) 28 m = re.match(r'^ssh://(([^@]+)@)?([^:/]+)(:(\d+))?(/(.*))?$', path)
99 99
100 def abort(self, exception): 100 def abort(self, exception):
101 self.cleanup() 101 self.cleanup()
102 raise exception 102 raise exception
103 103
104 def _abort(self, exception):
105 self.cleanup()
106 raise exception
107
104 def cleanup(self): 108 def cleanup(self):
105 try: 109 try:
106 self.pipeo.close() 110 self.pipeo.close()
107 self.pipei.close() 111 self.pipei.close()
108 # read the error descriptor until EOF 112 # read the error descriptor until EOF
126 130
127 def call(self, cmd, **args): 131 def call(self, cmd, **args):
128 self.do_cmd(cmd, **args) 132 self.do_cmd(cmd, **args)
129 return self._recv() 133 return self._recv()
130 134
135 def _call(self, cmd, **args):
136 self.do_cmd(cmd, **args)
137 return self._recv()
138
131 def _recv(self): 139 def _recv(self):
132 l = self.pipei.readline() 140 l = self.pipei.readline()
133 self.readerr() 141 self.readerr()
134 try: 142 try:
135 l = int(l) 143 l = int(l)
149 self.call("lock") 157 self.call("lock")
150 return remotelock(self) 158 return remotelock(self)
151 159
152 def unlock(self): 160 def unlock(self):
153 self.call("unlock") 161 self.call("unlock")
154
155 def lookup(self, key):
156 self.requirecap('lookup', _('look up remote revision'))
157 d = self.call("lookup", key=key)
158 success, data = d[:-1].split(" ", 1)
159 if int(success):
160 return bin(data)
161 else:
162 self.abort(error.RepoError(data))
163
164 def heads(self):
165 d = self.call("heads")
166 try:
167 return map(bin, d[:-1].split(" "))
168 except:
169 self.abort(error.ResponseError(_("unexpected response:"), d))
170
171 def branchmap(self):
172 d = self.call("branchmap")
173 try:
174 branchmap = {}
175 for branchpart in d.splitlines():
176 branchheads = branchpart.split(' ')
177 branchname = urllib.unquote(branchheads[0])
178 # Earlier servers (1.3.x) send branch names in (their) local
179 # charset. The best we can do is assume it's identical to our
180 # own local charset, in case it's not utf-8.
181 try:
182 branchname.decode('utf-8')
183 except UnicodeDecodeError:
184 branchname = encoding.fromlocal(branchname)
185 branchheads = [bin(x) for x in branchheads[1:]]
186 branchmap[branchname] = branchheads
187 return branchmap
188 except:
189 raise error.ResponseError(_("unexpected response:"), d)
190
191 def branches(self, nodes):
192 n = " ".join(map(hex, nodes))
193 d = self.call("branches", nodes=n)
194 try:
195 br = [tuple(map(bin, b.split(" "))) for b in d.splitlines()]
196 return br
197 except:
198 self.abort(error.ResponseError(_("unexpected response:"), d))
199
200 def between(self, pairs):
201 n = " ".join(["-".join(map(hex, p)) for p in pairs])
202 d = self.call("between", pairs=n)
203 try:
204 p = [l and map(bin, l.split(" ")) or [] for l in d.splitlines()]
205 return p
206 except:
207 self.abort(error.ResponseError(_("unexpected response:"), d))
208 162
209 def changegroup(self, nodes, kind): 163 def changegroup(self, nodes, kind):
210 n = " ".join(map(hex, nodes)) 164 n = " ".join(map(hex, nodes))
211 return self.do_cmd("changegroup", roots=n) 165 return self.do_cmd("changegroup", roots=n)
212 166
271 self.abort(error.ResponseError(_("unexpected response:"), r)) 225 self.abort(error.ResponseError(_("unexpected response:"), r))
272 226
273 def stream_out(self): 227 def stream_out(self):
274 return self.do_cmd('stream_out') 228 return self.do_cmd('stream_out')
275 229
276 def pushkey(self, namespace, key, old, new):
277 if not self.capable('pushkey'):
278 return False
279 d = self.call("pushkey",
280 namespace=namespace, key=key, old=old, new=new)
281 return bool(int(d))
282
283 def listkeys(self, namespace):
284 if not self.capable('pushkey'):
285 return {}
286 d = self.call("listkeys", namespace=namespace)
287 r = {}
288 for l in d.splitlines():
289 k, v = l.split('\t')
290 r[k.decode('string-escape')] = v.decode('string-escape')
291 return r
292
293 instance = sshrepository 230 instance = sshrepository