comparison mercurial/sshpeer.py @ 35975:00b9e26d727b

sshpeer: establish SSH connection before class instantiation We want to move the handshake to before peers are created so we can instantiate a different peer class depending on the results of the handshake. This necessitates moving the SSH process invocation to outside the peer class. As part of the code move, some variables were renamed for clarity. util.popen4() returns stdin, stdout, and stderr in their typical file descriptor order. However, stdin and stdout were being mapped to "pipeo" and "pipei" respectively. "o" for "stdin" and "i" for "stdout" is a bit confusing. Although it does make sense for "output" and "input" from the perspective of the client. But in the context of the new function, it makes sense to refer to these as their file descriptor names. In addition, the last use of self._path disappeared, so we stop setting that attribute and we can delete the redundant URL parsing necessary to set it. Differential Revision: https://phab.mercurial-scm.org/D2031
author Gregory Szorc <gregory.szorc@gmail.com>
date Mon, 05 Feb 2018 14:05:59 -0800
parents 94ba29934f00
children f8f034344b39
comparison
equal deleted inserted replaced
35974:94ba29934f00 35975:00b9e26d727b
129 except (IOError, ValueError): 129 except (IOError, ValueError):
130 pass 130 pass
131 131
132 pipee.close() 132 pipee.close()
133 133
134 def _makeconnection(ui, sshcmd, args, remotecmd, path, sshenv=None):
135 """Create an SSH connection to a server.
136
137 Returns a tuple of (process, stdin, stdout, stderr) for the
138 spawned process.
139 """
140 cmd = '%s %s %s' % (
141 sshcmd,
142 args,
143 util.shellquote('%s -R %s serve --stdio' % (
144 _serverquote(remotecmd), _serverquote(path))))
145
146 ui.debug('running %s\n' % cmd)
147 cmd = util.quotecommand(cmd)
148
149 # no buffer allow the use of 'select'
150 # feel free to remove buffering and select usage when we ultimately
151 # move to threading.
152 stdin, stdout, stderr, proc = util.popen4(cmd, bufsize=0, env=sshenv)
153
154 stdout = doublepipe(ui, util.bufferedinputpipe(stdout), stderr)
155 stdin = doublepipe(ui, stdin, stderr)
156
157 return proc, stdin, stdout, stderr
158
134 class sshpeer(wireproto.wirepeer): 159 class sshpeer(wireproto.wirepeer):
135 def __init__(self, ui, path, create=False, sshstate=None): 160 def __init__(self, ui, path, create=False, sshstate=None):
136 self._url = path 161 self._url = path
137 self._ui = ui 162 self._ui = ui
138 self._pipeo = self._pipei = self._pipee = None 163 # self._subprocess is unused. Keeping a handle on the process
139 164 # holds a reference and prevents it from being garbage collected.
140 u = util.url(path, parsequery=False, parsefragment=False) 165 self._subprocess, self._pipei, self._pipeo, self._pipee = sshstate
141 self._path = u.path or '.' 166
142 167 self._validaterepo()
143 self._validaterepo(*sshstate)
144 168
145 # Begin of _basepeer interface. 169 # Begin of _basepeer interface.
146 170
147 @util.propertycache 171 @util.propertycache
148 def ui(self): 172 def ui(self):
170 def capabilities(self): 194 def capabilities(self):
171 return self._caps 195 return self._caps
172 196
173 # End of _basewirecommands interface. 197 # End of _basewirecommands interface.
174 198
175 def _validaterepo(self, sshcmd, args, remotecmd, sshenv=None): 199 def _validaterepo(self):
176 assert self._pipei is None
177
178 cmd = '%s %s %s' % (sshcmd, args,
179 util.shellquote("%s -R %s serve --stdio" %
180 (_serverquote(remotecmd), _serverquote(self._path))))
181 self.ui.debug('running %s\n' % cmd)
182 cmd = util.quotecommand(cmd)
183
184 # while self._subprocess isn't used, having it allows the subprocess to
185 # to clean up correctly later
186 #
187 # no buffer allow the use of 'select'
188 # feel free to remove buffering and select usage when we ultimately
189 # move to threading.
190 sub = util.popen4(cmd, bufsize=0, env=sshenv)
191 self._pipeo, self._pipei, self._pipee, self._subprocess = sub
192
193 self._pipei = util.bufferedinputpipe(self._pipei)
194 self._pipei = doublepipe(self.ui, self._pipei, self._pipee)
195 self._pipeo = doublepipe(self.ui, self._pipeo, self._pipee)
196
197 def badresponse(): 200 def badresponse():
198 msg = _("no suitable response from remote hg") 201 msg = _("no suitable response from remote hg")
199 hint = self.ui.config("ui", "ssherrorhint") 202 hint = self.ui.config("ui", "ssherrorhint")
200 self._abort(error.RepoError(msg, hint=hint)) 203 self._abort(error.RepoError(msg, hint=hint))
201 204
378 ui.debug('running %s\n' % cmd) 381 ui.debug('running %s\n' % cmd)
379 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv) 382 res = ui.system(cmd, blockedtag='sshpeer', environ=sshenv)
380 if res != 0: 383 if res != 0:
381 raise error.RepoError(_('could not create remote repo')) 384 raise error.RepoError(_('could not create remote repo'))
382 385
383 sshstate = (sshcmd, args, remotecmd, sshenv) 386 proc, stdin, stdout, stderr = _makeconnection(ui, sshcmd, args, remotecmd,
387 remotepath, sshenv)
388
389 sshstate = (proc, stdout, stdin, stderr)
384 390
385 return sshpeer(ui, path, create=create, sshstate=sshstate) 391 return sshpeer(ui, path, create=create, sshstate=sshstate)