Mercurial > public > mercurial-scm > hg
comparison mercurial/sshpeer.py @ 43076:2372284d9457
formatting: blacken the codebase
This is using my patch to black
(https://github.com/psf/black/pull/826) so we don't un-wrap collection
literals.
Done with:
hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S
# skip-blame mass-reformatting only
# no-check-commit reformats foo_bar functions
Differential Revision: https://phab.mercurial-scm.org/D6971
author | Augie Fackler <augie@google.com> |
---|---|
date | Sun, 06 Oct 2019 09:45:02 -0400 |
parents | 089fc0db0954 |
children | 687b865b95ad |
comparison
equal
deleted
inserted
replaced
43075:57875cf423c9 | 43076:2372284d9457 |
---|---|
23 from .utils import ( | 23 from .utils import ( |
24 procutil, | 24 procutil, |
25 stringutil, | 25 stringutil, |
26 ) | 26 ) |
27 | 27 |
28 | |
28 def _serverquote(s): | 29 def _serverquote(s): |
29 """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""" |
30 if not s: | 31 if not s: |
31 return s | 32 return s |
32 if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s): | 33 if re.match('[a-zA-Z0-9@%_+=:,./-]*$', s): |
33 return s | 34 return s |
34 return "'%s'" % s.replace("'", "'\\''") | 35 return "'%s'" % s.replace("'", "'\\''") |
35 | 36 |
37 | |
36 def _forwardoutput(ui, pipe): | 38 def _forwardoutput(ui, pipe): |
37 """display all data currently available on pipe as remote output. | 39 """display all data currently available on pipe as remote output. |
38 | 40 |
39 This is non blocking.""" | 41 This is non blocking.""" |
40 if pipe: | 42 if pipe: |
41 s = procutil.readpipe(pipe) | 43 s = procutil.readpipe(pipe) |
42 if s: | 44 if s: |
43 for l in s.splitlines(): | 45 for l in s.splitlines(): |
44 ui.status(_("remote: "), l, '\n') | 46 ui.status(_("remote: "), l, '\n') |
45 | 47 |
48 | |
46 class doublepipe(object): | 49 class doublepipe(object): |
47 """Operate a side-channel pipe in addition of a main one | 50 """Operate a side-channel pipe in addition of a main one |
48 | 51 |
49 The side-channel pipe contains server output to be forwarded to the user | 52 The side-channel pipe contains server output to be forwarded to the user |
50 input. The double pipe will behave as the "main" pipe, but will ensure the | 53 input. The double pipe will behave as the "main" pipe, but will ensure the |
70 | 73 |
71 return a pair of boolean (ismainready, issideready) | 74 return a pair of boolean (ismainready, issideready) |
72 | 75 |
73 (This will only wait for data if the setup is supported by `util.poll`) | 76 (This will only wait for data if the setup is supported by `util.poll`) |
74 """ | 77 """ |
75 if (isinstance(self._main, util.bufferedinputpipe) and | 78 if ( |
76 self._main.hasbuffer): | 79 isinstance(self._main, util.bufferedinputpipe) |
80 and self._main.hasbuffer | |
81 ): | |
77 # Main has data. Assume side is worth poking at. | 82 # Main has data. Assume side is worth poking at. |
78 return True, True | 83 return True, True |
79 | 84 |
80 fds = [self._main.fileno(), self._side.fileno()] | 85 fds = [self._main.fileno(), self._side.fileno()] |
81 try: | 86 try: |
135 return self._main.close() | 140 return self._main.close() |
136 | 141 |
137 def flush(self): | 142 def flush(self): |
138 return self._main.flush() | 143 return self._main.flush() |
139 | 144 |
145 | |
140 def _cleanuppipes(ui, pipei, pipeo, pipee): | 146 def _cleanuppipes(ui, pipei, pipeo, pipee): |
141 """Clean up pipes used by an SSH connection.""" | 147 """Clean up pipes used by an SSH connection.""" |
142 if pipeo: | 148 if pipeo: |
143 pipeo.close() | 149 pipeo.close() |
144 if pipei: | 150 if pipei: |
152 except (IOError, ValueError): | 158 except (IOError, ValueError): |
153 pass | 159 pass |
154 | 160 |
155 pipee.close() | 161 pipee.close() |
156 | 162 |
163 | |
157 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): | 164 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None): |
158 """Create an SSH connection to a server. | 165 """Create an SSH connection to a server. |
159 | 166 |
160 Returns a tuple of (process, stdin, stdout, stderr) for the | 167 Returns a tuple of (process, stdin, stdout, stderr) for the |
161 spawned process. | 168 spawned process. |
162 """ | 169 """ |
163 cmd = '%s %s %s' % ( | 170 cmd = '%s %s %s' % ( |
164 sshcmd, | 171 sshcmd, |
165 args, | 172 args, |
166 procutil.shellquote('%s -R %s serve --stdio' % ( | 173 procutil.shellquote( |
167 _serverquote(remotecmd), _serverquote(path)))) | 174 '%s -R %s serve --stdio' |
175 % (_serverquote(remotecmd), _serverquote(path)) | |
176 ), | |
177 ) | |
168 | 178 |
169 ui.debug('running %s\n' % cmd) | 179 ui.debug('running %s\n' % cmd) |
170 cmd = procutil.quotecommand(cmd) | 180 cmd = procutil.quotecommand(cmd) |
171 | 181 |
172 # no buffer allow the use of 'select' | 182 # no buffer allow the use of 'select' |
174 # move to threading. | 184 # move to threading. |
175 stdin, stdout, stderr, proc = procutil.popen4(cmd, bufsize=0, env=sshenv) | 185 stdin, stdout, stderr, proc = procutil.popen4(cmd, bufsize=0, env=sshenv) |
176 | 186 |
177 return proc, stdin, stdout, stderr | 187 return proc, stdin, stdout, stderr |
178 | 188 |
189 | |
179 def _clientcapabilities(): | 190 def _clientcapabilities(): |
180 """Return list of capabilities of this client. | 191 """Return list of capabilities of this client. |
181 | 192 |
182 Returns a list of capabilities that are supported by this client. | 193 Returns a list of capabilities that are supported by this client. |
183 """ | 194 """ |
184 protoparams = {'partial-pull'} | 195 protoparams = {'partial-pull'} |
185 comps = [e.wireprotosupport().name for e in | 196 comps = [ |
186 util.compengines.supportedwireengines(util.CLIENTROLE)] | 197 e.wireprotosupport().name |
198 for e in util.compengines.supportedwireengines(util.CLIENTROLE) | |
199 ] | |
187 protoparams.add('comp=%s' % ','.join(comps)) | 200 protoparams.add('comp=%s' % ','.join(comps)) |
188 return protoparams | 201 return protoparams |
202 | |
189 | 203 |
190 def _performhandshake(ui, stdin, stdout, stderr): | 204 def _performhandshake(ui, stdin, stdout, stderr): |
191 def badresponse(): | 205 def badresponse(): |
192 # Flush any output on stderr. | 206 # Flush any output on stderr. |
193 _forwardoutput(ui, stderr) | 207 _forwardoutput(ui, stderr) |
361 # Flush any output on stderr before proceeding. | 375 # Flush any output on stderr before proceeding. |
362 _forwardoutput(ui, stderr) | 376 _forwardoutput(ui, stderr) |
363 | 377 |
364 return protoname, caps | 378 return protoname, caps |
365 | 379 |
380 | |
366 class sshv1peer(wireprotov1peer.wirepeer): | 381 class sshv1peer(wireprotov1peer.wirepeer): |
367 def __init__(self, ui, url, proc, stdin, stdout, stderr, caps, | 382 def __init__( |
368 autoreadstderr=True): | 383 self, ui, url, proc, stdin, stdout, stderr, caps, autoreadstderr=True |
384 ): | |
369 """Create a peer from an existing SSH connection. | 385 """Create a peer from an existing SSH connection. |
370 | 386 |
371 ``proc`` is a handle on the underlying SSH process. | 387 ``proc`` is a handle on the underlying SSH process. |
372 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio | 388 ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio |
373 pipes for that process. | 389 pipes for that process. |
436 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) | 452 _cleanuppipes(self.ui, self._pipei, self._pipeo, self._pipee) |
437 | 453 |
438 __del__ = _cleanup | 454 __del__ = _cleanup |
439 | 455 |
440 def _sendrequest(self, cmd, args, framed=False): | 456 def _sendrequest(self, cmd, args, framed=False): |
441 if (self.ui.debugflag | 457 if self.ui.debugflag and self.ui.configbool( |
442 and self.ui.configbool('devel', 'debug.peer-request')): | 458 'devel', 'debug.peer-request' |
459 ): | |
443 dbg = self.ui.debug | 460 dbg = self.ui.debug |
444 line = 'devel-peer-request: %s\n' | 461 line = 'devel-peer-request: %s\n' |
445 dbg(line % cmd) | 462 dbg(line % cmd) |
446 for key, value in sorted(args.items()): | 463 for key, value in sorted(args.items()): |
447 if not isinstance(value, dict): | 464 if not isinstance(value, dict): |
558 if flush: | 575 if flush: |
559 self._pipeo.flush() | 576 self._pipeo.flush() |
560 if self._autoreadstderr: | 577 if self._autoreadstderr: |
561 self._readerr() | 578 self._readerr() |
562 | 579 |
580 | |
563 class sshv2peer(sshv1peer): | 581 class sshv2peer(sshv1peer): |
564 """A peer that speakers version 2 of the transport protocol.""" | 582 """A peer that speakers version 2 of the transport protocol.""" |
583 | |
565 # Currently version 2 is identical to version 1 post handshake. | 584 # Currently version 2 is identical to version 1 post handshake. |
566 # And handshake is performed before the peer is instantiated. So | 585 # And handshake is performed before the peer is instantiated. So |
567 # we need no custom code. | 586 # we need no custom code. |
587 | |
568 | 588 |
569 def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): | 589 def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): |
570 """Make a peer instance from existing pipes. | 590 """Make a peer instance from existing pipes. |
571 | 591 |
572 ``path`` and ``proc`` are stored on the eventual peer instance and may | 592 ``path`` and ``proc`` are stored on the eventual peer instance and may |
585 except Exception: | 605 except Exception: |
586 _cleanuppipes(ui, stdout, stdin, stderr) | 606 _cleanuppipes(ui, stdout, stdin, stderr) |
587 raise | 607 raise |
588 | 608 |
589 if protoname == wireprototypes.SSHV1: | 609 if protoname == wireprototypes.SSHV1: |
590 return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps, | 610 return sshv1peer( |
591 autoreadstderr=autoreadstderr) | 611 ui, |
612 path, | |
613 proc, | |
614 stdin, | |
615 stdout, | |
616 stderr, | |
617 caps, | |
618 autoreadstderr=autoreadstderr, | |
619 ) | |
592 elif protoname == wireprototypes.SSHV2: | 620 elif protoname == wireprototypes.SSHV2: |
593 return sshv2peer(ui, path, proc, stdin, stdout, stderr, caps, | 621 return sshv2peer( |
594 autoreadstderr=autoreadstderr) | 622 ui, |
623 path, | |
624 proc, | |
625 stdin, | |
626 stdout, | |
627 stderr, | |
628 caps, | |
629 autoreadstderr=autoreadstderr, | |
630 ) | |
595 else: | 631 else: |
596 _cleanuppipes(ui, stdout, stdin, stderr) | 632 _cleanuppipes(ui, stdout, stdin, stderr) |
597 raise error.RepoError(_('unknown version of SSH protocol: %s') % | 633 raise error.RepoError( |
598 protoname) | 634 _('unknown version of SSH protocol: %s') % protoname |
635 ) | |
636 | |
599 | 637 |
600 def instance(ui, path, create, intents=None, createopts=None): | 638 def instance(ui, path, create, intents=None, createopts=None): |
601 """Create an SSH peer. | 639 """Create an SSH peer. |
602 | 640 |
603 The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. | 641 The returned object conforms to the ``wireprotov1peer.wirepeer`` interface. |
623 # 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 |
624 # 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 |
625 # 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 |
626 # supports said requested feature. | 664 # supports said requested feature. |
627 if createopts: | 665 if createopts: |
628 raise error.RepoError(_('cannot create remote SSH repositories ' | 666 raise error.RepoError( |
629 'with extra options')) | 667 _('cannot create remote SSH repositories ' 'with extra options') |
630 | 668 ) |
631 cmd = '%s %s %s' % (sshcmd, args, | 669 |
632 procutil.shellquote('%s init %s' % | 670 cmd = '%s %s %s' % ( |
633 (_serverquote(remotecmd), _serverquote(remotepath)))) | 671 sshcmd, |
672 args, | |
673 procutil.shellquote( | |
674 '%s init %s' | |
675 % (_serverquote(remotecmd), _serverquote(remotepath)) | |
676 ), | |
677 ) | |
634 ui.debug('running %s\n' % cmd) | 678 ui.debug('running %s\n' % cmd) |
635 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) | 679 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) |
636 if res != 0: | 680 if res != 0: |
637 raise error.RepoError(_('could not create remote repo')) | 681 raise error.RepoError(_('could not create remote repo')) |
638 | 682 |
639 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd, | 683 proc, stdin, stdout, stderr = _makeconnection( |
640 remotepath, sshenv) | 684 ui, sshcmd, args, remotecmd, remotepath, sshenv |
685 ) | |
641 | 686 |
642 peer = makepeer(ui, path, proc, stdin, stdout, stderr) | 687 peer = makepeer(ui, path, proc, stdin, stdout, stderr) |
643 | 688 |
644 # Finally, if supported by the server, notify it about our own | 689 # Finally, if supported by the server, notify it about our own |
645 # capabilities. | 690 # capabilities. |
646 if 'protocaps' in peer.capabilities(): | 691 if 'protocaps' in peer.capabilities(): |
647 try: | 692 try: |
648 peer._call("protocaps", | 693 peer._call( |
649 caps=' '.join(sorted(_clientcapabilities()))) | 694 "protocaps", caps=' '.join(sorted(_clientcapabilities())) |
695 ) | |
650 except IOError: | 696 except IOError: |
651 peer._cleanup() | 697 peer._cleanup() |
652 raise error.RepoError(_('capability exchange failed')) | 698 raise error.RepoError(_('capability exchange failed')) |
653 | 699 |
654 return peer | 700 return peer |