154 stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) |
154 stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) |
155 stdin = doublepipe(ui, stdin, stderr) |
155 stdin = doublepipe(ui, stdin, stderr) |
156 |
156 |
157 return proc, stdin, stdout, stderr |
157 return proc, stdin, stdout, stderr |
158 |
158 |
|
159 def _performhandshake(ui, stdin, stdout, stderr): |
|
160 def badresponse(): |
|
161 msg = _('no suitable response from remote hg') |
|
162 hint = ui.config('ui', 'ssherrorhint') |
|
163 raise error.RepoError(msg, hint=hint) |
|
164 |
|
165 requestlog = ui.configbool('devel', 'debug.peer-request') |
|
166 |
|
167 try: |
|
168 pairsarg = '%s-%s' % ('0' * 40, '0' * 40) |
|
169 handshake = [ |
|
170 'hello\n', |
|
171 'between\n', |
|
172 'pairs %d\n' % len(pairsarg), |
|
173 pairsarg, |
|
174 ] |
|
175 |
|
176 if requestlog: |
|
177 ui.debug('devel-peer-request: hello\n') |
|
178 ui.debug('sending hello command\n') |
|
179 if requestlog: |
|
180 ui.debug('devel-peer-request: between\n') |
|
181 ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) |
|
182 ui.debug('sending between command\n') |
|
183 |
|
184 stdin.write(''.join(handshake)) |
|
185 stdin.flush() |
|
186 except IOError: |
|
187 badresponse() |
|
188 |
|
189 lines = ['', 'dummy'] |
|
190 max_noise = 500 |
|
191 while lines[-1] and max_noise: |
|
192 try: |
|
193 l = stdout.readline() |
|
194 _forwardoutput(ui, stderr) |
|
195 if lines[-1] == '1\n' and l == '\n': |
|
196 break |
|
197 if l: |
|
198 ui.debug('remote: ', l) |
|
199 lines.append(l) |
|
200 max_noise -= 1 |
|
201 except IOError: |
|
202 badresponse() |
|
203 else: |
|
204 badresponse() |
|
205 |
|
206 caps = set() |
|
207 for l in reversed(lines): |
|
208 if l.startswith('capabilities:'): |
|
209 caps.update(l[:-1].split(':')[1].split()) |
|
210 break |
|
211 |
|
212 return caps |
|
213 |
159 class sshpeer(wireproto.wirepeer): |
214 class sshpeer(wireproto.wirepeer): |
160 def __init__(self, ui, url, proc, stdin, stdout, stderr): |
215 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps): |
161 """Create a peer from an existing SSH connection. |
216 """Create a peer from an existing SSH connection. |
162 |
217 |
163 ``proc`` is a handle on the underlying SSH process. |
218 ``proc`` is a handle on the underlying SSH process. |
164 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio |
219 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio |
165 pipes for that process. |
220 pipes for that process. |
|
221 ``caps`` is a set of capabilities supported by the remote. |
166 """ |
222 """ |
167 self._url = url |
223 self._url = url |
168 self._ui = ui |
224 self._ui = ui |
169 # self._subprocess is unused. Keeping a handle on the process |
225 # self._subprocess is unused. Keeping a handle on the process |
170 # holds a reference and prevents it from being garbage collected. |
226 # holds a reference and prevents it from being garbage collected. |
171 self._subprocess = proc |
227 self._subprocess = proc |
172 self._pipeo = stdin |
228 self._pipeo = stdin |
173 self._pipei = stdout |
229 self._pipei = stdout |
174 self._pipee = stderr |
230 self._pipee = stderr |
175 |
231 self._caps = caps |
176 self._validaterepo() |
|
177 |
232 |
178 # Begin of _basepeer interface. |
233 # Begin of _basepeer interface. |
179 |
234 |
180 @util.propertycache |
235 @util.propertycache |
181 def ui(self): |
236 def ui(self): |
202 |
257 |
203 def capabilities(self): |
258 def capabilities(self): |
204 return self._caps |
259 return self._caps |
205 |
260 |
206 # End of _basewirecommands interface. |
261 # End of _basewirecommands interface. |
207 |
|
208 def _validaterepo(self): |
|
209 def badresponse(): |
|
210 msg = _("no suitable response from remote hg") |
|
211 hint = self.ui.config("ui", "ssherrorhint") |
|
212 self._abort(error.RepoError(msg, hint=hint)) |
|
213 |
|
214 try: |
|
215 pairsarg = '%s-%s' % ('0' * 40, '0' * 40) |
|
216 |
|
217 handshake = [ |
|
218 'hello\n', |
|
219 'between\n', |
|
220 'pairs %d\n' % len(pairsarg), |
|
221 pairsarg, |
|
222 ] |
|
223 |
|
224 requestlog = self.ui.configbool('devel', 'debug.peer-request') |
|
225 |
|
226 if requestlog: |
|
227 self.ui.debug('devel-peer-request: hello\n') |
|
228 self.ui.debug('sending hello command\n') |
|
229 if requestlog: |
|
230 self.ui.debug('devel-peer-request: between\n') |
|
231 self.ui.debug('devel-peer-request: pairs: %d bytes\n' % |
|
232 len(pairsarg)) |
|
233 self.ui.debug('sending between command\n') |
|
234 |
|
235 self._pipeo.write(''.join(handshake)) |
|
236 self._pipeo.flush() |
|
237 except IOError: |
|
238 badresponse() |
|
239 |
|
240 lines = ["", "dummy"] |
|
241 max_noise = 500 |
|
242 while lines[-1] and max_noise: |
|
243 try: |
|
244 l = self._pipei.readline() |
|
245 _forwardoutput(self.ui, self._pipee) |
|
246 if lines[-1] == "1\n" and l == "\n": |
|
247 break |
|
248 if l: |
|
249 self.ui.debug("remote: ", l) |
|
250 lines.append(l) |
|
251 max_noise -= 1 |
|
252 except IOError: |
|
253 badresponse() |
|
254 else: |
|
255 badresponse() |
|
256 |
|
257 self._caps = set() |
|
258 for l in reversed(lines): |
|
259 if l.startswith("capabilities:"): |
|
260 self._caps.update(l[:-1].split(":")[1].split()) |
|
261 break |
|
262 |
262 |
263 def _readerr(self): |
263 def _readerr(self): |
264 _forwardoutput(self.ui, self._pipee) |
264 _forwardoutput(self.ui, self._pipee) |
265 |
265 |
266 def _abort(self, exception): |
266 def _abort(self, exception): |
412 raise error.RepoError(_('could not create remote repo')) |
412 raise error.RepoError(_('could not create remote repo')) |
413 |
413 |
414 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, |
414 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, |
415 remotepath, sshenv) |
415 remotepath, sshenv) |
416 |
416 |
417 return sshpeer(ui, path, proc, stdin, stdout, stderr) |
417 try: |
|
418 caps = _performhandshake(ui, stdin, stdout, stderr) |
|
419 except Exception: |
|
420 _cleanuppipes(ui, stdout, stdin, stderr) |
|
421 raise |
|
422 |
|
423 return sshpeer(ui, path, proc, stdin, stdout, stderr, caps) |