# HG changeset patch # User Gregory Szorc # Date 2018-02-26 21:12:03 # Node ID 1a36ef7df70afee16b2e5ed5da7be697c47e0287 # Parent 1138e5c0fbc9b8c5644c6d736151957a3570b088 sshpeer: support not reading and forwarding stderr The "doublepipe" primitive as used by sshpeer will automatically read from stderr and forward output to the local ui. This poses problems for deterministic testing because reads may not be consistent. For example, the server may not be done sending all output to stderr and the client will perform different numbers of read operations or will read from stderr and stdout at different times. To make tests deterministic, we'll need to disable the "doublepipe" primitive and perform stderr I/O explicitly. We add an argument to the sshpeer constructor to disable the use of the doublepipe. Differential Revision: https://phab.mercurial-scm.org/D2467 diff --git a/mercurial/sshpeer.py b/mercurial/sshpeer.py --- a/mercurial/sshpeer.py +++ b/mercurial/sshpeer.py @@ -337,13 +337,16 @@ def _performhandshake(ui, stdin, stdout, return protoname, caps class sshv1peer(wireproto.wirepeer): - def __init__(self, ui, url, proc, stdin, stdout, stderr, caps): + def __init__(self, ui, url, proc, stdin, stdout, stderr, caps, + autoreadstderr=True): """Create a peer from an existing SSH connection. ``proc`` is a handle on the underlying SSH process. ``stdin``, ``stdout``, and ``stderr`` are handles on the stdio pipes for that process. ``caps`` is a set of capabilities supported by the remote. + ``autoreadstderr`` denotes whether to automatically read from + stderr and to forward its output. """ self._url = url self._ui = ui @@ -353,8 +356,9 @@ class sshv1peer(wireproto.wirepeer): # And we hook up our "doublepipe" wrapper to allow querying # stderr any time we perform I/O. - stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) - stdin = doublepipe(ui, stdin, stderr) + if autoreadstderr: + stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr) + stdin = doublepipe(ui, stdin, stderr) self._pipeo = stdin self._pipei = stdout @@ -531,7 +535,7 @@ class sshv2peer(sshv1peer): # And handshake is performed before the peer is instantiated. So # we need no custom code. -def makepeer(ui, path, proc, stdin, stdout, stderr): +def makepeer(ui, path, proc, stdin, stdout, stderr, autoreadstderr=True): """Make a peer instance from existing pipes. ``path`` and ``proc`` are stored on the eventual peer instance and may @@ -552,9 +556,11 @@ def makepeer(ui, path, proc, stdin, stdo raise if protoname == wireprotoserver.SSHV1: - return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps) + return sshv1peer(ui, path, proc, stdin, stdout, stderr, caps, + autoreadstderr=autoreadstderr) elif protoname == wireprotoserver.SSHV2: - return sshv2peer(ui, path, proc, stdin, stdout, stderr, caps) + return sshv2peer(ui, path, proc, stdin, stdout, stderr, caps, + autoreadstderr=autoreadstderr) else: _cleanuppipes(ui, stdout, stdin, stderr) raise error.RepoError(_('unknown version of SSH protocol: %s') %