Mercurial > public > mercurial-scm > hg-stable
comparison mercurial/sshpeer.py @ 43077:687b865b95ad
formatting: byteify all mercurial/ and hgext/ string literals
Done with
python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py')
black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**')
# skip-blame mass-reformatting only
Differential Revision: https://phab.mercurial-scm.org/D6972
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:48:39 -0400 |
parents | 2372284d9457 |
children | c59eb1560c44 |
comparison
equal
deleted
inserted
replaced
43076:2372284d9457 | 43077:687b865b95ad |
---|---|
28 | 28 |
29 def _serverquote(s): | 29 def _serverquote(s): |
30 """quote a string for the remote shell ... which we assume is sh""" | 30 """quote a string for the remote shell ... which we assume is sh""" |
31 if not s: | 31 if not s: |
32 return s | 32 return s |
33 if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s): | 33 if re.match(b'[a-zA-Z0-9@%_+=:,./-]*$', s): |
34 return s | 34 return s |
35 return "'%s'" % s.replace("'", "'\\''") | 35 return b"'%s'" % s.replace(b"'", b"'\\''") |
36 | 36 |
37 | 37 |
38 def _forwardoutput(ui, pipe): | 38 def _forwardoutput(ui, pipe): |
39 """display all data currently available on pipe as remote output. | 39 """display all data currently available on pipe as remote output. |
40 | 40 |
41 This is non blocking.""" | 41 This is non blocking.""" |
42 if pipe: | 42 if pipe: |
43 s = procutil.readpipe(pipe) | 43 s = procutil.readpipe(pipe) |
44 if s: | 44 if s: |
45 for l in s.splitlines(): | 45 for l in s.splitlines(): |
46 ui.status(_("remote: "), l, '\n') | 46 ui.status(_(b"remote: "), l, b'\n') |
47 | 47 |
48 | 48 |
49 class doublepipe(object): | 49 class doublepipe(object): |
50 """Operate a side-channel pipe in addition of a main one | 50 """Operate a side-channel pipe in addition of a main one |
51 | 51 |
89 # non supported yet case, assume all have data. | 89 # non supported yet case, assume all have data. |
90 act = fds | 90 act = fds |
91 return (self._main.fileno() in act, self._side.fileno() in act) | 91 return (self._main.fileno() in act, self._side.fileno() in act) |
92 | 92 |
93 def write(self, data): | 93 def write(self, data): |
94 return self._call('write', data) | 94 return self._call(b'write', data) |
95 | 95 |
96 def read(self, size): | 96 def read(self, size): |
97 r = self._call('read', size) | 97 r = self._call(b'read', size) |
98 if size != 0 and not r: | 98 if size != 0 and not r: |
99 # We've observed a condition that indicates the | 99 # We've observed a condition that indicates the |
100 # stdout closed unexpectedly. Check stderr one | 100 # stdout closed unexpectedly. Check stderr one |
101 # more time and snag anything that's there before | 101 # more time and snag anything that's there before |
102 # letting anyone know the main part of the pipe | 102 # letting anyone know the main part of the pipe |
103 # closed prematurely. | 103 # closed prematurely. |
104 _forwardoutput(self._ui, self._side) | 104 _forwardoutput(self._ui, self._side) |
105 return r | 105 return r |
106 | 106 |
107 def unbufferedread(self, size): | 107 def unbufferedread(self, size): |
108 r = self._call('unbufferedread', size) | 108 r = self._call(b'unbufferedread', size) |
109 if size != 0 and not r: | 109 if size != 0 and not r: |
110 # We've observed a condition that indicates the | 110 # We've observed a condition that indicates the |
111 # stdout closed unexpectedly. Check stderr one | 111 # stdout closed unexpectedly. Check stderr one |
112 # more time and snag anything that's there before | 112 # more time and snag anything that's there before |
113 # letting anyone know the main part of the pipe | 113 # letting anyone know the main part of the pipe |
114 # closed prematurely. | 114 # closed prematurely. |
115 _forwardoutput(self._ui, self._side) | 115 _forwardoutput(self._ui, self._side) |
116 return r | 116 return r |
117 | 117 |
118 def readline(self): | 118 def readline(self): |
119 return self._call('readline') | 119 return self._call(b'readline') |
120 | 120 |
121 def _call(self, methname, data=None): | 121 def _call(self, methname, data=None): |
122 """call <methname> on "main", forward output of "side" while blocking | 122 """call <methname> on "main", forward output of "side" while blocking |
123 """ | 123 """ |
124 # data can be '' or 0 | 124 # data can be '' or 0 |
125 if (data is not None and not data) or self._main.closed: | 125 if (data is not None and not data) or self._main.closed: |
126 _forwardoutput(self._ui, self._side) | 126 _forwardoutput(self._ui, self._side) |
127 return '' | 127 return b'' |
128 while True: | 128 while True: |
129 mainready, sideready = self._wait() | 129 mainready, sideready = self._wait() |
130 if sideready: | 130 if sideready: |
131 _forwardoutput(self._ui, self._side) | 131 _forwardoutput(self._ui, self._side) |
132 if mainready: | 132 if mainready: |
152 | 152 |
153 if pipee: | 153 if pipee: |
154 # Try to read from the err descriptor until EOF. | 154 # Try to read from the err descriptor until EOF. |
155 try: | 155 try: |
156 for l in pipee: | 156 for l in pipee: |
157 ui.status(_('remote: '), l) | 157 ui.status(_(b'remote: '), l) |
158 except (IOError, ValueError): | 158 except (IOError, ValueError): |
159 pass | 159 pass |
160 | 160 |
161 pipee.close() | 161 pipee.close() |
162 | 162 |
165 """Create an SSH connection to a server. | 165 """Create an SSH connection to a server. |
166 | 166 |
167 Returns a tuple of (process, stdin, stdout, stderr) for the | 167 Returns a tuple of (process, stdin, stdout, stderr) for the |
168 spawned process. | 168 spawned process. |
169 """ | 169 """ |
170 cmd = '%s %s %s' % ( | 170 cmd = b'%s %s %s' % ( |
171 sshcmd, | 171 sshcmd, |
172 args, | 172 args, |
173 procutil.shellquote( | 173 procutil.shellquote( |
174 '%s -R %s serve --stdio' | 174 b'%s -R %s serve --stdio' |
175 % (_serverquote(remotecmd), _serverquote(path)) | 175 % (_serverquote(remotecmd), _serverquote(path)) |
176 ), | 176 ), |
177 ) | 177 ) |
178 | 178 |
179 ui.debug('running %s\n' % cmd) | 179 ui.debug(b'running %s\n' % cmd) |
180 cmd = procutil.quotecommand(cmd) | 180 cmd = procutil.quotecommand(cmd) |
181 | 181 |
182 # no buffer allow the use of 'select' | 182 # no buffer allow the use of 'select' |
183 # feel free to remove buffering and select usage when we ultimately | 183 # feel free to remove buffering and select usage when we ultimately |
184 # move to threading. | 184 # move to threading. |
190 def _clientcapabilities(): | 190 def _clientcapabilities(): |
191 """Return list of capabilities of this client. | 191 """Return list of capabilities of this client. |
192 | 192 |
193 Returns a list of capabilities that are supported by this client. | 193 Returns a list of capabilities that are supported by this client. |
194 """ | 194 """ |
195 protoparams = {'partial-pull'} | 195 protoparams = {b'partial-pull'} |
196 comps = [ | 196 comps = [ |
197 e.wireprotosupport().name | 197 e.wireprotosupport().name |
198 for e in util.compengines.supportedwireengines(util.CLIENTROLE) | 198 for e in util.compengines.supportedwireengines(util.CLIENTROLE) |
199 ] | 199 ] |
200 protoparams.add('comp=%s' % ','.join(comps)) | 200 protoparams.add(b'comp=%s' % b','.join(comps)) |
201 return protoparams | 201 return protoparams |
202 | 202 |
203 | 203 |
204 def _performhandshake(ui, stdin, stdout, stderr): | 204 def _performhandshake(ui, stdin, stdout, stderr): |
205 def badresponse(): | 205 def badresponse(): |
206 # Flush any output on stderr. | 206 # Flush any output on stderr. |
207 _forwardoutput(ui, stderr) | 207 _forwardoutput(ui, stderr) |
208 | 208 |
209 msg = _('no suitable response from remote hg') | 209 msg = _(b'no suitable response from remote hg') |
210 hint = ui.config('ui', 'ssherrorhint') | 210 hint = ui.config(b'ui', b'ssherrorhint') |
211 raise error.RepoError(msg, hint=hint) | 211 raise error.RepoError(msg, hint=hint) |
212 | 212 |
213 # The handshake consists of sending wire protocol commands in reverse | 213 # The handshake consists of sending wire protocol commands in reverse |
214 # order of protocol implementation and then sniffing for a response | 214 # order of protocol implementation and then sniffing for a response |
215 # to one of them. | 215 # to one of them. |
260 # print messages to stdout on login. Issuing commands on connection | 260 # print messages to stdout on login. Issuing commands on connection |
261 # allows us to flush this banner output from the server by scanning | 261 # allows us to flush this banner output from the server by scanning |
262 # for output to our well-known ``between`` command. Of course, if | 262 # for output to our well-known ``between`` command. Of course, if |
263 # the banner contains ``1\n\n``, this will throw off our detection. | 263 # the banner contains ``1\n\n``, this will throw off our detection. |
264 | 264 |
265 requestlog = ui.configbool('devel', 'debug.peer-request') | 265 requestlog = ui.configbool(b'devel', b'debug.peer-request') |
266 | 266 |
267 # Generate a random token to help identify responses to version 2 | 267 # Generate a random token to help identify responses to version 2 |
268 # upgrade request. | 268 # upgrade request. |
269 token = pycompat.sysbytes(str(uuid.uuid4())) | 269 token = pycompat.sysbytes(str(uuid.uuid4())) |
270 upgradecaps = [ | 270 upgradecaps = [ |
271 ('proto', wireprotoserver.SSHV2), | 271 (b'proto', wireprotoserver.SSHV2), |
272 ] | 272 ] |
273 upgradecaps = util.urlreq.urlencode(upgradecaps) | 273 upgradecaps = util.urlreq.urlencode(upgradecaps) |
274 | 274 |
275 try: | 275 try: |
276 pairsarg = '%s-%s' % ('0' * 40, '0' * 40) | 276 pairsarg = b'%s-%s' % (b'0' * 40, b'0' * 40) |
277 handshake = [ | 277 handshake = [ |
278 'hello\n', | 278 b'hello\n', |
279 'between\n', | 279 b'between\n', |
280 'pairs %d\n' % len(pairsarg), | 280 b'pairs %d\n' % len(pairsarg), |
281 pairsarg, | 281 pairsarg, |
282 ] | 282 ] |
283 | 283 |
284 # Request upgrade to version 2 if configured. | 284 # Request upgrade to version 2 if configured. |
285 if ui.configbool('experimental', 'sshpeer.advertise-v2'): | 285 if ui.configbool(b'experimental', b'sshpeer.advertise-v2'): |
286 ui.debug('sending upgrade request: %s %s\n' % (token, upgradecaps)) | 286 ui.debug(b'sending upgrade request: %s %s\n' % (token, upgradecaps)) |
287 handshake.insert(0, 'upgrade %s %s\n' % (token, upgradecaps)) | 287 handshake.insert(0, b'upgrade %s %s\n' % (token, upgradecaps)) |
288 | 288 |
289 if requestlog: | 289 if requestlog: |
290 ui.debug('devel-peer-request: hello+between\n') | 290 ui.debug(b'devel-peer-request: hello+between\n') |
291 ui.debug('devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) | 291 ui.debug(b'devel-peer-request: pairs: %d bytes\n' % len(pairsarg)) |
292 ui.debug('sending hello command\n') | 292 ui.debug(b'sending hello command\n') |
293 ui.debug('sending between command\n') | 293 ui.debug(b'sending between command\n') |
294 | 294 |
295 stdin.write(''.join(handshake)) | 295 stdin.write(b''.join(handshake)) |
296 stdin.flush() | 296 stdin.flush() |
297 except IOError: | 297 except IOError: |
298 badresponse() | 298 badresponse() |
299 | 299 |
300 # Assume version 1 of wire protocol by default. | 300 # Assume version 1 of wire protocol by default. |
301 protoname = wireprototypes.SSHV1 | 301 protoname = wireprototypes.SSHV1 |
302 reupgraded = re.compile(b'^upgraded %s (.*)$' % stringutil.reescape(token)) | 302 reupgraded = re.compile(b'^upgraded %s (.*)$' % stringutil.reescape(token)) |
303 | 303 |
304 lines = ['', 'dummy'] | 304 lines = [b'', b'dummy'] |
305 max_noise = 500 | 305 max_noise = 500 |
306 while lines[-1] and max_noise: | 306 while lines[-1] and max_noise: |
307 try: | 307 try: |
308 l = stdout.readline() | 308 l = stdout.readline() |
309 _forwardoutput(ui, stderr) | 309 _forwardoutput(ui, stderr) |
311 # Look for reply to protocol upgrade request. It has a token | 311 # Look for reply to protocol upgrade request. It has a token |
312 # in it, so there should be no false positives. | 312 # in it, so there should be no false positives. |
313 m = reupgraded.match(l) | 313 m = reupgraded.match(l) |
314 if m: | 314 if m: |
315 protoname = m.group(1) | 315 protoname = m.group(1) |
316 ui.debug('protocol upgraded to %s\n' % protoname) | 316 ui.debug(b'protocol upgraded to %s\n' % protoname) |
317 # If an upgrade was handled, the ``hello`` and ``between`` | 317 # If an upgrade was handled, the ``hello`` and ``between`` |
318 # requests are ignored. The next output belongs to the | 318 # requests are ignored. The next output belongs to the |
319 # protocol, so stop scanning lines. | 319 # protocol, so stop scanning lines. |
320 break | 320 break |
321 | 321 |
322 # Otherwise it could be a banner, ``0\n`` response if server | 322 # Otherwise it could be a banner, ``0\n`` response if server |
323 # doesn't support upgrade. | 323 # doesn't support upgrade. |
324 | 324 |
325 if lines[-1] == '1\n' and l == '\n': | 325 if lines[-1] == b'1\n' and l == b'\n': |
326 break | 326 break |
327 if l: | 327 if l: |
328 ui.debug('remote: ', l) | 328 ui.debug(b'remote: ', l) |
329 lines.append(l) | 329 lines.append(l) |
330 max_noise -= 1 | 330 max_noise -= 1 |
331 except IOError: | 331 except IOError: |
332 badresponse() | 332 badresponse() |
333 else: | 333 else: |
339 # ``hello`` command. | 339 # ``hello`` command. |
340 if protoname == wireprototypes.SSHV1: | 340 if protoname == wireprototypes.SSHV1: |
341 for l in reversed(lines): | 341 for l in reversed(lines): |
342 # Look for response to ``hello`` command. Scan from the back so | 342 # Look for response to ``hello`` command. Scan from the back so |
343 # we don't misinterpret banner output as the command reply. | 343 # we don't misinterpret banner output as the command reply. |
344 if l.startswith('capabilities:'): | 344 if l.startswith(b'capabilities:'): |
345 caps.update(l[:-1].split(':')[1].split()) | 345 caps.update(l[:-1].split(b':')[1].split()) |
346 break | 346 break |
347 elif protoname == wireprotoserver.SSHV2: | 347 elif protoname == wireprotoserver.SSHV2: |
348 # We see a line with number of bytes to follow and then a value | 348 # We see a line with number of bytes to follow and then a value |
349 # looking like ``capabilities: *``. | 349 # looking like ``capabilities: *``. |
350 line = stdout.readline() | 350 line = stdout.readline() |
352 valuelen = int(line) | 352 valuelen = int(line) |
353 except ValueError: | 353 except ValueError: |
354 badresponse() | 354 badresponse() |
355 | 355 |
356 capsline = stdout.read(valuelen) | 356 capsline = stdout.read(valuelen) |
357 if not capsline.startswith('capabilities: '): | 357 if not capsline.startswith(b'capabilities: '): |
358 badresponse() | 358 badresponse() |
359 | 359 |
360 ui.debug('remote: %s\n' % capsline) | 360 ui.debug(b'remote: %s\n' % capsline) |
361 | 361 |
362 caps.update(capsline.split(':')[1].split()) | 362 caps.update(capsline.split(b':')[1].split()) |
363 # Trailing newline. | 363 # Trailing newline. |
364 stdout.read(1) | 364 stdout.read(1) |
365 | 365 |
366 # Error if we couldn't find capabilities, this means: | 366 # Error if we couldn't find capabilities, this means: |
367 # | 367 # |
410 self._autoreadstderr = autoreadstderr | 410 self._autoreadstderr = autoreadstderr |
411 | 411 |
412 # Commands that have a "framed" response where the first line of the | 412 # Commands that have a "framed" response where the first line of the |
413 # response contains the length of that response. | 413 # response contains the length of that response. |
414 _FRAMED_COMMANDS = { | 414 _FRAMED_COMMANDS = { |
415 'batch', | 415 b'batch', |
416 } | 416 } |
417 | 417 |
418 # Begin of ipeerconnection interface. | 418 # Begin of ipeerconnection interface. |
419 | 419 |
420 def url(self): | 420 def url(self): |
453 | 453 |
454 __del__ = _cleanup | 454 __del__ = _cleanup |
455 | 455 |
456 def _sendrequest(self, cmd, args, framed=False): | 456 def _sendrequest(self, cmd, args, framed=False): |
457 if self.ui.debugflag and self.ui.configbool( | 457 if self.ui.debugflag and self.ui.configbool( |
458 'devel', 'debug.peer-request' | 458 b'devel', b'debug.peer-request' |
459 ): | 459 ): |
460 dbg = self.ui.debug | 460 dbg = self.ui.debug |
461 line = 'devel-peer-request: %s\n' | 461 line = b'devel-peer-request: %s\n' |
462 dbg(line % cmd) | 462 dbg(line % cmd) |
463 for key, value in sorted(args.items()): | 463 for key, value in sorted(args.items()): |
464 if not isinstance(value, dict): | 464 if not isinstance(value, dict): |
465 dbg(line % ' %s: %d bytes' % (key, len(value))) | 465 dbg(line % b' %s: %d bytes' % (key, len(value))) |
466 else: | 466 else: |
467 for dk, dv in sorted(value.items()): | 467 for dk, dv in sorted(value.items()): |
468 dbg(line % ' %s-%s: %d' % (key, dk, len(dv))) | 468 dbg(line % b' %s-%s: %d' % (key, dk, len(dv))) |
469 self.ui.debug("sending %s command\n" % cmd) | 469 self.ui.debug(b"sending %s command\n" % cmd) |
470 self._pipeo.write("%s\n" % cmd) | 470 self._pipeo.write(b"%s\n" % cmd) |
471 _func, names = wireprotov1server.commands[cmd] | 471 _func, names = wireprotov1server.commands[cmd] |
472 keys = names.split() | 472 keys = names.split() |
473 wireargs = {} | 473 wireargs = {} |
474 for k in keys: | 474 for k in keys: |
475 if k == '*': | 475 if k == b'*': |
476 wireargs['*'] = args | 476 wireargs[b'*'] = args |
477 break | 477 break |
478 else: | 478 else: |
479 wireargs[k] = args[k] | 479 wireargs[k] = args[k] |
480 del args[k] | 480 del args[k] |
481 for k, v in sorted(wireargs.iteritems()): | 481 for k, v in sorted(wireargs.iteritems()): |
482 self._pipeo.write("%s %d\n" % (k, len(v))) | 482 self._pipeo.write(b"%s %d\n" % (k, len(v))) |
483 if isinstance(v, dict): | 483 if isinstance(v, dict): |
484 for dk, dv in v.iteritems(): | 484 for dk, dv in v.iteritems(): |
485 self._pipeo.write("%s %d\n" % (dk, len(dv))) | 485 self._pipeo.write(b"%s %d\n" % (dk, len(dv))) |
486 self._pipeo.write(dv) | 486 self._pipeo.write(dv) |
487 else: | 487 else: |
488 self._pipeo.write(v) | 488 self._pipeo.write(v) |
489 self._pipeo.flush() | 489 self._pipeo.flush() |
490 | 490 |
513 def _callpush(self, cmd, fp, **args): | 513 def _callpush(self, cmd, fp, **args): |
514 # The server responds with an empty frame if the client should | 514 # The server responds with an empty frame if the client should |
515 # continue submitting the payload. | 515 # continue submitting the payload. |
516 r = self._call(cmd, **args) | 516 r = self._call(cmd, **args) |
517 if r: | 517 if r: |
518 return '', r | 518 return b'', r |
519 | 519 |
520 # The payload consists of frames with content followed by an empty | 520 # The payload consists of frames with content followed by an empty |
521 # frame. | 521 # frame. |
522 for d in iter(lambda: fp.read(4096), ''): | 522 for d in iter(lambda: fp.read(4096), b''): |
523 self._writeframed(d) | 523 self._writeframed(d) |
524 self._writeframed("", flush=True) | 524 self._writeframed(b"", flush=True) |
525 | 525 |
526 # In case of success, there is an empty frame and a frame containing | 526 # In case of success, there is an empty frame and a frame containing |
527 # the integer result (as a string). | 527 # the integer result (as a string). |
528 # In case of error, there is a non-empty frame containing the error. | 528 # In case of error, there is a non-empty frame containing the error. |
529 r = self._readframed() | 529 r = self._readframed() |
530 if r: | 530 if r: |
531 return '', r | 531 return b'', r |
532 return self._readframed(), '' | 532 return self._readframed(), b'' |
533 | 533 |
534 def _calltwowaystream(self, cmd, fp, **args): | 534 def _calltwowaystream(self, cmd, fp, **args): |
535 # The server responds with an empty frame if the client should | 535 # The server responds with an empty frame if the client should |
536 # continue submitting the payload. | 536 # continue submitting the payload. |
537 r = self._call(cmd, **args) | 537 r = self._call(cmd, **args) |
538 if r: | 538 if r: |
539 # XXX needs to be made better | 539 # XXX needs to be made better |
540 raise error.Abort(_('unexpected remote reply: %s') % r) | 540 raise error.Abort(_(b'unexpected remote reply: %s') % r) |
541 | 541 |
542 # The payload consists of frames with content followed by an empty | 542 # The payload consists of frames with content followed by an empty |
543 # frame. | 543 # frame. |
544 for d in iter(lambda: fp.read(4096), ''): | 544 for d in iter(lambda: fp.read(4096), b''): |
545 self._writeframed(d) | 545 self._writeframed(d) |
546 self._writeframed("", flush=True) | 546 self._writeframed(b"", flush=True) |
547 | 547 |
548 return self._pipei | 548 return self._pipei |
549 | 549 |
550 def _getamount(self): | 550 def _getamount(self): |
551 l = self._pipei.readline() | 551 l = self._pipei.readline() |
552 if l == '\n': | 552 if l == b'\n': |
553 if self._autoreadstderr: | 553 if self._autoreadstderr: |
554 self._readerr() | 554 self._readerr() |
555 msg = _('check previous remote output') | 555 msg = _(b'check previous remote output') |
556 self._abort(error.OutOfBandError(hint=msg)) | 556 self._abort(error.OutOfBandError(hint=msg)) |
557 if self._autoreadstderr: | 557 if self._autoreadstderr: |
558 self._readerr() | 558 self._readerr() |
559 try: | 559 try: |
560 return int(l) | 560 return int(l) |
561 except ValueError: | 561 except ValueError: |
562 self._abort(error.ResponseError(_("unexpected response:"), l)) | 562 self._abort(error.ResponseError(_(b"unexpected response:"), l)) |
563 | 563 |
564 def _readframed(self): | 564 def _readframed(self): |
565 size = self._getamount() | 565 size = self._getamount() |
566 if not size: | 566 if not size: |
567 return b'' | 567 return b'' |
568 | 568 |
569 return self._pipei.read(size) | 569 return self._pipei.read(size) |
570 | 570 |
571 def _writeframed(self, data, flush=False): | 571 def _writeframed(self, data, flush=False): |
572 self._pipeo.write("%d\n" % len(data)) | 572 self._pipeo.write(b"%d\n" % len(data)) |
573 if data: | 573 if data: |
574 self._pipeo.write(data) | 574 self._pipeo.write(data) |
575 if flush: | 575 if flush: |
576 self._pipeo.flush() | 576 self._pipeo.flush() |
577 if self._autoreadstderr: | 577 if self._autoreadstderr: |
629 autoreadstderr=autoreadstderr, | 629 autoreadstderr=autoreadstderr, |
630 ) | 630 ) |
631 else: | 631 else: |
632 _cleanuppipes(ui, stdout, stdin, stderr) | 632 _cleanuppipes(ui, stdout, stdin, stderr) |
633 raise error.RepoError( | 633 raise error.RepoError( |
634 _('unknown version of SSH protocol: %s') % protoname | 634 _(b'unknown version of SSH protocol: %s') % protoname |
635 ) | 635 ) |
636 | 636 |
637 | 637 |
638 def instance(ui, path, create, intents=None, createopts=None): | 638 def instance(ui, path, create, intents=None, createopts=None): |
639 """Create an SSH peer. | 639 """Create an SSH peer. |
640 | 640 |
641 The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. | 641 The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. |
642 """ | 642 """ |
643 u = util.url(path, parsequery=False, parsefragment=False) | 643 u = util.url(path, parsequery=False, parsefragment=False) |
644 if u.scheme != 'ssh' or not u.host or u.path is None: | 644 if u.scheme != b'ssh' or not u.host or u.path is None: |
645 raise error.RepoError(_("couldn't parse location %s") % path) | 645 raise error.RepoError(_(b"couldn't parse location %s") % path) |
646 | 646 |
647 util.checksafessh(path) | 647 util.checksafessh(path) |
648 | 648 |
649 if u.passwd is not None: | 649 if u.passwd is not None: |
650 raise error.RepoError(_('password in URL not supported')) | 650 raise error.RepoError(_(b'password in URL not supported')) |
651 | 651 |
652 sshcmd = ui.config('ui', 'ssh') | 652 sshcmd = ui.config(b'ui', b'ssh') |
653 remotecmd = ui.config('ui', 'remotecmd') | 653 remotecmd = ui.config(b'ui', b'remotecmd') |
654 sshaddenv = dict(ui.configitems('sshenv')) | 654 sshaddenv = dict(ui.configitems(b'sshenv')) |
655 sshenv = procutil.shellenviron(sshaddenv) | 655 sshenv = procutil.shellenviron(sshaddenv) |
656 remotepath = u.path or '.' | 656 remotepath = u.path or b'.' |
657 | 657 |
658 args = procutil.sshargs(sshcmd, u.host, u.user, u.port) | 658 args = procutil.sshargs(sshcmd, u.host, u.user, u.port) |
659 | 659 |
660 if create: | 660 if create: |
661 # We /could/ do this, but only if the remote init command knows how to | 661 # We /could/ do this, but only if the remote init command knows how to |
662 # handle them. We don't yet make any assumptions about that. And without | 662 # handle them. We don't yet make any assumptions about that. And without |
663 # querying the remote, there's no way of knowing if the remote even | 663 # querying the remote, there's no way of knowing if the remote even |
664 # supports said requested feature. | 664 # supports said requested feature. |
665 if createopts: | 665 if createopts: |
666 raise error.RepoError( | 666 raise error.RepoError( |
667 _('cannot create remote SSH repositories ' 'with extra options') | 667 _( |
668 b'cannot create remote SSH repositories ' | |
669 b'with extra options' | |
670 ) | |
668 ) | 671 ) |
669 | 672 |
670 cmd = '%s %s %s' % ( | 673 cmd = b'%s %s %s' % ( |
671 sshcmd, | 674 sshcmd, |
672 args, | 675 args, |
673 procutil.shellquote( | 676 procutil.shellquote( |
674 '%s init %s' | 677 b'%s init %s' |
675 % (_serverquote(remotecmd), _serverquote(remotepath)) | 678 % (_serverquote(remotecmd), _serverquote(remotepath)) |
676 ), | 679 ), |
677 ) | 680 ) |
678 ui.debug('running %s\n' % cmd) | 681 ui.debug(b'running %s\n' % cmd) |
679 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) | 682 res = ui.system(cmd, blockedtag=b'sshpeer', environ=sshenv) |
680 if res != 0: | 683 if res != 0: |
681 raise error.RepoError(_('could not create remote repo')) | 684 raise error.RepoError(_(b'could not create remote repo')) |
682 | 685 |
683 proc, stdin, stdout, stderr = _makeconnection( | 686 proc, stdin, stdout, stderr = _makeconnection( |
684 ui, sshcmd, args, remotecmd, remotepath, sshenv | 687 ui, sshcmd, args, remotecmd, remotepath, sshenv |
685 ) | 688 ) |
686 | 689 |
687 peer = makepeer(ui, path, proc, stdin, stdout, stderr) | 690 peer = makepeer(ui, path, proc, stdin, stdout, stderr) |
688 | 691 |
689 # Finally, if supported by the server, notify it about our own | 692 # Finally, if supported by the server, notify it about our own |
690 # capabilities. | 693 # capabilities. |
691 if 'protocaps' in peer.capabilities(): | 694 if b'protocaps' in peer.capabilities(): |
692 try: | 695 try: |
693 peer._call( | 696 peer._call( |
694 "protocaps", caps=' '.join(sorted(_clientcapabilities())) | 697 b"protocaps", caps=b' '.join(sorted(_clientcapabilities())) |
695 ) | 698 ) |
696 except IOError: | 699 except IOError: |
697 peer._cleanup() | 700 peer._cleanup() |
698 raise error.RepoError(_('capability exchange failed')) | 701 raise error.RepoError(_(b'capability exchange failed')) |
699 | 702 |
700 return peer | 703 return peer |